feat: extract built-in view presets and add filter chips

This commit is contained in:
2026-08-11 20:08:53 -04:00
parent 4c3fd66a56
commit 0139f6f5eb
4 changed files with 131 additions and 32 deletions
+79
View File
@@ -0,0 +1,79 @@
/**
* Built-in views over a library.
*
* These are navigation, not content — a fixed set of lenses every library has,
* as distinct from shelves, which are named collections a user owns. Nothing
* here is persisted or user-editable.
*
* Defined once and consumed twice: the home route renders them as shelves, and
* the library view renders them as chips. Previously each home shelf was a
* hand-written query string in the loader, which is how `create_at` (missing a
* `d`) went unnoticed — that sort silently did nothing.
*/
export interface BookPreset {
id: string;
label: string;
/** Shown as the shelf heading on the home page. */
heading: string;
/** Filter values, keyed the way the books endpoint expects them. */
filters: Record<string, string[]>;
/** Backend sort field; omitted means "leave the current ordering alone". */
orderBy?: string;
/** asc, desc, or random — the API's CustomOrderBy accepts all three. */
sortOrder?: string;
}
export const BOOK_PRESETS: BookPreset[] = [
{
id: 'continue-reading',
label: 'Reading',
heading: 'Continue Reading',
filters: { progress: ['in_progress'] },
orderBy: 'last_accessed',
sortOrder: 'desc'
},
{
id: 'recently-added',
label: 'Recently added',
heading: 'Recently Added',
filters: { progress: ['unread'] },
orderBy: 'created_at',
sortOrder: 'desc'
},
{
id: 'discover',
label: 'Discover',
heading: 'Discover',
filters: { progress: ['unread'] },
sortOrder: 'random'
},
{
id: 'read-again',
label: 'Read again',
heading: 'Read Again',
filters: { progress: ['read'] },
sortOrder: 'random'
}
];
export function getPreset(id: string) {
return BOOK_PRESETS.find((preset) => preset.id === id);
}
/**
* Query string for the books endpoint, used by the home route's loader.
*/
export function presetQuery(preset: BookPreset, libraryId: string | number) {
const params = new URLSearchParams();
params.set('libraries', String(libraryId));
for (const [key, values] of Object.entries(preset.filters)) {
for (const value of values) params.append(key, value);
}
if (preset.orderBy) params.set('orderBy', preset.orderBy);
if (preset.sortOrder) params.set('sortOrder', preset.sortOrder);
return params.toString();
}