feat: opt-in Journal search page and JournalSearchBox
- journal.routes.search (off by default) registers journal-search, the results page for ?q= in the API's relevance order (no sort is sent), server-rendered with a Polish-aware result count. - JournalSearchBox: an icon button and a WAI-ARIA combobox with debounced ?fields=suggest suggestions, stale answers dropped, query words marked ignoring diacritics; a plain GET form without JS. - The module keeps the search path out of the route cache and the sitemap and marks it noindex, follow. - Client: suggestPosts and the fields option; useJournalLinks.searchLink.
This commit is contained in:
@@ -16,6 +16,7 @@ const PAGE_FILES: Record<keyof JournalRoutes, string> = {
|
||||
category: 'CategoryPage',
|
||||
tag: 'TagPage',
|
||||
author: 'AuthorPage',
|
||||
search: 'SearchPage',
|
||||
}
|
||||
|
||||
const pagesDir = fileURLToPath(new URL('../app/journal-pages/', import.meta.url))
|
||||
@@ -39,7 +40,7 @@ export default defineNuxtModule<JournalModuleOptions>({
|
||||
},
|
||||
defaults: {
|
||||
routes: { ...DEFAULT_JOURNAL_ROUTES },
|
||||
perPage: { index: 9, category: 9, tag: 9, author: 9 },
|
||||
perPage: { index: 9, category: 9, tag: 9, author: 9, search: 9 },
|
||||
sort: 'published_at desc',
|
||||
relatedCount: 3,
|
||||
rss: true,
|
||||
@@ -55,6 +56,21 @@ export default defineNuxtModule<JournalModuleOptions>({
|
||||
}
|
||||
})
|
||||
|
||||
// The search page renders per ?q, so it is never route-cached: Nitro's
|
||||
// cache keys by path, and an app rule such as '/**': { swr } would serve
|
||||
// one query's results for every query. It is noindex, follow and left
|
||||
// out of the sitemap. The locale-prefixed copies get the same rules. An
|
||||
// app's own rule for the path wins key by key.
|
||||
if (routes.search !== false) {
|
||||
const i18n = (nuxt.options as { i18n?: { locales?: unknown } }).i18n
|
||||
const paths = [routes.search, ...enabledLocaleCodes(i18n?.locales).map((code) => `/${code}${routes.search}`)]
|
||||
const options = nuxt.options as { routeRules?: Record<string, Record<string, unknown>> }
|
||||
const rules = (options.routeRules ??= {})
|
||||
for (const path of paths) rules[path] = { cache: false, robots: 'noindex, follow', ...(rules[path] ?? {}) }
|
||||
const opts = nuxt.options as { sitemap?: { exclude?: Array<string | RegExp> } }
|
||||
opts.sitemap = { ...(opts.sitemap ?? {}), exclude: [...(opts.sitemap?.exclude ?? []), ...paths] }
|
||||
}
|
||||
|
||||
// Register the layer's strings only for locales the app enables. The
|
||||
// layer config declares no locales: @nuxtjs/i18n merges every locale a
|
||||
// layer declares into the app, which would add /en routes to an app that
|
||||
|
||||
Reference in New Issue
Block a user