import type { LocationQuery } from 'vue-router' import { SITE_KEY_MAX } from '@/lib/directory' import { DEFAULT_PAGE_SIZE, PAGE_SIZES, SEARCH_MAX_LENGTH, firstQueryValue, parsePositiveInteger, } from '@/lib/pageQuery' export type ArticleStatus = 'online' | 'draft' export const DEFAULT_ARTICLE_SORT = 'updated_at:desc' export const ARTICLE_SORT_FIELDS = ['title', 'status', 'created_at', 'updated_at'] as const export type ArticleSortField = (typeof ARTICLE_SORT_FIELDS)[number] export const SEO_FILTER = 'suggestions' export interface ArticleListQuery { page: number size: number q: string status: ArticleStatus | '' sort: string site: string seo: '' | typeof SEO_FILTER } const SORT_PATTERN = new RegExp(`^(${ARTICLE_SORT_FIELDS.join('|')}):(asc|desc)$`) function validSort(value: string) { return SORT_PATTERN.test(value) && value !== DEFAULT_ARTICLE_SORT ? value : '' } export function effectiveSort(sort: string) { return sort || DEFAULT_ARTICLE_SORT } export function nextSort(current: string, field: ArticleSortField) { const [activeField, direction] = effectiveSort(current).split(':') return `${field}:${activeField === field && direction === 'asc' ? 'desc' : 'asc'}` } export function parseArticleQuery(query: LocationQuery): ArticleListQuery { const page = firstQueryValue(query.page) const size = Number(firstQueryValue(query.size)) const status = firstQueryValue(query.status) return { page: parsePositiveInteger(page) ?? 1, size: PAGE_SIZES.includes(size) ? size : DEFAULT_PAGE_SIZE, q: firstQueryValue(query.q).slice(0, SEARCH_MAX_LENGTH), status: status === 'online' || status === 'draft' ? status : '', sort: validSort(firstQueryValue(query.sort)), site: firstQueryValue(query.site).slice(0, SITE_KEY_MAX), seo: firstQueryValue(query.seo) === SEO_FILTER ? SEO_FILTER : '', } } export function toRouteQuery(query: ArticleListQuery) { const route: Record = {} if (query.page !== 1) { route.page = String(query.page) } if (query.size !== DEFAULT_PAGE_SIZE) { route.size = String(query.size) } if (query.q) { route.q = query.q } if (query.status) { route.status = query.status } if (effectiveSort(query.sort) !== DEFAULT_ARTICLE_SORT) { route.sort = query.sort } if (query.site) { route.site = query.site } if (query.seo) { route.seo = query.seo } return route } export function sameArticleQuery(left: ArticleListQuery, right: ArticleListQuery) { return ( left.page === right.page && left.size === right.size && left.q === right.q && left.status === right.status && left.site === right.site && left.seo === right.seo && effectiveSort(left.sort) === effectiveSort(right.sort) ) }