feat(SPA): media page T0

This commit is contained in:
fsylvain committed 2026-09-30 19:45:47 +02:00
1 parent 0d99544579
commit 67d456baf6
32 files changed
+4874 -40

No files matched your search

+69
View File
@@ -0,0 +1,69 @@
import type { LocationQuery } from 'vue-router'
export type MediaFilter = 'all' | 'unused'
export type MediaSort = 'newest' | 'oldest' | 'name' | 'largest'
export type MediaView = 'grid' | 'list'
export interface MediaControls {
q: string
filter: MediaFilter
sort: MediaSort
view: MediaView
}
export const MEDIA_PAGE_LIMIT = 100
export const DEFAULT_CONTROLS: MediaControls = {
q: '',
filter: 'all',
sort: 'newest',
view: 'grid',
}
const FILTERS: MediaFilter[] = ['all', 'unused']
const SORTS: MediaSort[] = ['newest', 'oldest', 'name', 'largest']
const VIEWS: MediaView[] = ['grid', 'list']
function firstValue(value: LocationQuery[string] | undefined) {
return (Array.isArray(value) ? value[0] : value) ?? ''
}
function pick<T extends string>(allowed: T[], value: string, fallback: T) {
return (allowed as string[]).includes(value) ? (value as T) : fallback
}
export function parseMediaControls(query: LocationQuery): MediaControls {
return {
q: firstValue(query.q).trim(),
filter: pick(FILTERS, firstValue(query.filter), DEFAULT_CONTROLS.filter),
sort: pick(SORTS, firstValue(query.sort), DEFAULT_CONTROLS.sort),
view: pick(VIEWS, firstValue(query.view), DEFAULT_CONTROLS.view),
}
}
export function toRouteQuery(controls: MediaControls) {
const query: Record<string, string> = {}
if (controls.q) {
query.q = controls.q
}
if (controls.filter !== DEFAULT_CONTROLS.filter) {
query.filter = controls.filter
}
if (controls.sort !== DEFAULT_CONTROLS.sort) {
query.sort = controls.sort
}
if (controls.view !== DEFAULT_CONTROLS.view) {
query.view = controls.view
}
return query
}
export function toRequestQuery(controls: MediaControls) {
const parts = [
...(controls.q ? [`q=${encodeURIComponent(controls.q)}`] : []),
`filter=${controls.filter}`,
`sort=${controls.sort}`,
`limit=${MEDIA_PAGE_LIMIT}`,
]
return parts.join('&')
}