feat: entry list at /content/:key
This commit is contained in:
1 parent
b4cbcb0395
commit
91d916fb74
44 files changed
+4984
-32
No files matched your search
@@ -0,0 +1,90 @@
|
||||
import type { LocationQuery } from 'vue-router'
|
||||
import { t } from '@/i18n'
|
||||
import {
|
||||
DEFAULT_PAGE_SIZE,
|
||||
PAGE_SIZES,
|
||||
firstQueryValue,
|
||||
parsePositiveInteger,
|
||||
} from '@/lib/pageQuery'
|
||||
|
||||
export const ENTRY_SORT_FIELDS = ['id', 'created_at', 'updated_at'] as const
|
||||
export type EntrySortField = (typeof ENTRY_SORT_FIELDS)[number]
|
||||
export type EntrySortDirection = 'asc' | 'desc'
|
||||
|
||||
export const DEFAULT_ENTRY_SORT = 'updated_at:desc'
|
||||
|
||||
export interface EntryListQuery {
|
||||
page: number
|
||||
size: number
|
||||
q: string
|
||||
sort: string
|
||||
}
|
||||
|
||||
const SORT_PATTERN = new RegExp(`^(${ENTRY_SORT_FIELDS.join('|')}):(asc|desc)$`)
|
||||
|
||||
export function parseEntryQuery(query: LocationQuery): EntryListQuery {
|
||||
const size = parsePositiveInteger(firstQueryValue(query.size))
|
||||
const sort = firstQueryValue(query.sort)
|
||||
return {
|
||||
page: parsePositiveInteger(firstQueryValue(query.page)) ?? 1,
|
||||
size: size !== null && PAGE_SIZES.includes(size) ? size : DEFAULT_PAGE_SIZE,
|
||||
q: '',
|
||||
sort: SORT_PATTERN.test(sort) ? sort : DEFAULT_ENTRY_SORT,
|
||||
}
|
||||
}
|
||||
|
||||
export function toEntryRouteQuery(query: EntryListQuery) {
|
||||
const route: Record<string, string> = {}
|
||||
if (query.size !== DEFAULT_PAGE_SIZE) {
|
||||
route.size = String(query.size)
|
||||
}
|
||||
if (query.sort !== DEFAULT_ENTRY_SORT) {
|
||||
route.sort = query.sort
|
||||
}
|
||||
if (query.page !== 1) {
|
||||
route.page = String(query.page)
|
||||
}
|
||||
return route
|
||||
}
|
||||
|
||||
export function sameEntryQuery(left: EntryListQuery, right: EntryListQuery) {
|
||||
return left.page === right.page && left.size === right.size && left.sort === right.sort
|
||||
}
|
||||
|
||||
export function sortParts(sort: string) {
|
||||
const [field, direction] = sort.split(':') as [EntrySortField, EntrySortDirection]
|
||||
return { field, direction }
|
||||
}
|
||||
|
||||
export function withSortField(sort: string, field: EntrySortField) {
|
||||
return `${field}:${sortParts(sort).direction}`
|
||||
}
|
||||
|
||||
export function withOppositeDirection(sort: string) {
|
||||
const { field, direction } = sortParts(sort)
|
||||
return `${field}:${direction === 'asc' ? 'desc' : 'asc'}`
|
||||
}
|
||||
|
||||
export function sortFieldLabel(field: EntrySortField) {
|
||||
if (field === 'id') {
|
||||
return t('ID')
|
||||
}
|
||||
return field === 'created_at' ? t('Created') : t('Last updated')
|
||||
}
|
||||
|
||||
export function sortDirectionLabel(sort: string) {
|
||||
return sortParts(sort).direction === 'asc' ? t('Sort descending') : t('Sort ascending')
|
||||
}
|
||||
|
||||
export function entryCaption(name: string, sort: string) {
|
||||
const { field, direction } = sortParts(sort)
|
||||
if (sort === DEFAULT_ENTRY_SORT) {
|
||||
return t('{0}, sorted by last updated, newest first', [name])
|
||||
}
|
||||
const column = { id: t('id'), created_at: t('created'), updated_at: t('updated') }[field]
|
||||
return t('{0}, sorted by {1}, {2}', [
|
||||
name,
|
||||
column,
|
||||
direction === 'desc' ? t('descending') : t('ascending'),
|
||||
])
|
||||
}
|
||||
Reference in new issue
Block a user