fix(filters): the year dialog fits a tablet, walks by arrow keys, names one year once
- a decade cell is a 36-high box with its count under the year (owner A) - arrow keys walk the cells: along a decade, then to the nearest year below - clearing the kept older year hands the focus on instead of dropping it - More... shows while a year with titles is hidden, as a plain chip - the decade caption is not read twice; the Plex range fields have names - one Plex year is labelled 1999, not 1999-1999, via oneYear/singleYear - tests for the Plex wiring and the feed year clearing the upload date
This commit is contained in:
@@ -52,6 +52,8 @@ import { plexApi } from "./api/plex";
|
||||
export type * from "./api/plex";
|
||||
export {
|
||||
EMPTY_PLEX_FILTERS,
|
||||
oneYear,
|
||||
singleYear,
|
||||
plexFilterCount,
|
||||
coercePlexFilters,
|
||||
plexFiltersSignature,
|
||||
|
||||
@@ -261,6 +261,17 @@ export interface PlexPersonDetail {
|
||||
movies: PlexCard[]; // enabled-library movies whose cast OR directors include this person
|
||||
shows: PlexCard[]; // enabled-library shows, same
|
||||
}
|
||||
/** One year as a Plex filter: a range of one, both ends set (the year picker, a year on an info page).
|
||||
* `null` clears it. */
|
||||
export const oneYear = (year?: number | null): Pick<PlexFilters, "yearMin" | "yearMax"> => ({
|
||||
yearMin: year ?? null,
|
||||
yearMax: year ?? null,
|
||||
});
|
||||
|
||||
/** The one year a filter narrows to, when its range is a single year. */
|
||||
export const singleYear = (f: Pick<PlexFilters, "yearMin" | "yearMax">): number | undefined =>
|
||||
f.yearMin != null && f.yearMin === f.yearMax ? f.yearMin : undefined;
|
||||
|
||||
// The expanded Plex browse filters (movie libraries). Persisted per-account as JSON.
|
||||
export interface PlexFilters {
|
||||
genres: string[];
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { buildPlexActiveFilters } from "./plexActiveFilters";
|
||||
import { EMPTY_PLEX_FILTERS, type PlexFilters } from "./api";
|
||||
|
||||
const t = (key: string) => key;
|
||||
const yearLabel = (f: Partial<PlexFilters>) =>
|
||||
buildPlexActiveFilters(
|
||||
{ ...EMPTY_PLEX_FILTERS, ...f },
|
||||
"",
|
||||
() => {},
|
||||
() => {},
|
||||
t,
|
||||
).find((c) => c.key === "year")?.label;
|
||||
|
||||
describe("the Plex year chip", () => {
|
||||
it("names one year as the year, not a range of one", () => {
|
||||
expect(yearLabel({ yearMin: 1999, yearMax: 1999 })).toBe("plex.filter.year: 1999");
|
||||
});
|
||||
|
||||
it("names a range and an open end as before", () => {
|
||||
expect(yearLabel({ yearMin: 1990, yearMax: 1999 })).toBe("plex.filter.year: 1990–1999");
|
||||
expect(yearLabel({ yearMin: 1990 })).toBe("plex.filter.year: ≥1990");
|
||||
expect(yearLabel({ yearMax: 1999 })).toBe("plex.filter.year: ≤1999");
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
import { vocabI18nKey } from "./vocab";
|
||||
import { type ActiveFilter } from "./useActiveFilters";
|
||||
import { type PlexFilters } from "./api";
|
||||
import { singleYear, type PlexFilters } from "./api";
|
||||
|
||||
type TFn = (key: string, options?: Record<string, unknown>) => string;
|
||||
|
||||
@@ -42,12 +42,15 @@ export function buildPlexActiveFilters(
|
||||
});
|
||||
}
|
||||
if (has(filters.yearMin) || has(filters.yearMax)) {
|
||||
const one = singleYear(filters);
|
||||
const range =
|
||||
has(filters.yearMin) && has(filters.yearMax)
|
||||
? `${filters.yearMin}–${filters.yearMax}`
|
||||
: has(filters.yearMin)
|
||||
? `≥${filters.yearMin}`
|
||||
: `≤${filters.yearMax}`;
|
||||
one != null
|
||||
? String(one)
|
||||
: has(filters.yearMin) && has(filters.yearMax)
|
||||
? `${filters.yearMin}–${filters.yearMax}`
|
||||
: has(filters.yearMin)
|
||||
? `≥${filters.yearMin}`
|
||||
: `≤${filters.yearMax}`;
|
||||
out.push({
|
||||
key: "year",
|
||||
label: `${t("plex.filter.year")}: ${range}`,
|
||||
|
||||
Reference in New Issue
Block a user