diff --git a/components/search/SearchItem.vue b/components/search/SearchItem.vue index 7c7a6561f..7fd8eded1 100644 --- a/components/search/SearchItem.vue +++ b/components/search/SearchItem.vue @@ -6,6 +6,7 @@ const props = defineProps<{ }>(); const iconBySearchKind: Record = { + page: 'file', pronoun: 'tags', noun: 'book', source: 'books', diff --git a/server/api/search.get.ts b/server/api/search.get.ts index f21110465..d2d54d5b8 100644 --- a/server/api/search.get.ts +++ b/server/api/search.get.ts @@ -30,6 +30,7 @@ const translator = new Translator(translations, baseTranslations, global.config) interface SearchKind { kind: SearchDocument['kind']; + options?: Partial>; getDocuments(config: Config): Promise; transformDocument?(transformed: SearchDocument, termsByField: Record): void; } @@ -40,7 +41,7 @@ interface LoadedSearchKind { index: MiniSearch; } -const MINISEARCH_OPTIONS: Options = { +const DEFAULT_OPTIONS: Options = { fields: ['title', 'titleSmall', 'content'], storeFields: ['kind'], }; @@ -50,7 +51,7 @@ const getSearchDocumentsAndIndex = defineCachedFunction(async ( config: Config, ): Promise<{ documents: SearchDocument[]; index: MiniSearch | AsPlainObject }> => { const documents = await kind.getDocuments(config); - const index = new MiniSearch(MINISEARCH_OPTIONS); + const index = new MiniSearch({ ...kind.options, ...DEFAULT_OPTIONS }); index.addAll(documents); return { documents, index }; }, { @@ -62,7 +63,7 @@ const getSearchDocumentsAndIndex = defineCachedFunction(async ( const loadSearchDocumentsAndIndex = async (kind: SearchKind, config: Config): Promise => { const { documents, index } = await getSearchDocumentsAndIndex(kind, config); if (!(index instanceof MiniSearch)) { - return { kind, documents, index: MiniSearch.loadJS(index, MINISEARCH_OPTIONS) }; + return { kind, documents, index: MiniSearch.loadJS(index, { ...kind.options, ...DEFAULT_OPTIONS }) }; } return { kind, documents, index }; }; @@ -138,6 +139,249 @@ const transformResult = (indices: Map { + const documents: SearchDocument[] = []; + const addDocument = ({ url, title, content }: { url: string; title: string; content?: string }) => { + documents.push({ + id: documents.length, + kind: this.kind, + url, + title, + content: content ?? '', + }); + }; + + addDocument({ + url: '/', + title: translator.translate('home.link'), + content: [ + translator.translate('home.intro'), + translator.translate('home.why'), + ...translator.get('home.about').map((text) => clearLinkedText(text, false)), + ].join(' '), + }); + + if (config.pronouns.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.pronouns.route)}`, + title: translator.translate('pronouns.prononus'), + content: '', + }); + } + + if (config.nouns.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.nouns.route)}`, + title: translator.translate('nouns.headerLonger'), + content: [ + translator.translate('nouns.description'), + ...translator.get('nouns.intro').map((text) => clearLinkedText(text, false)), + ].join(' '), + }); + } + + if (config.sources.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.sources.route)}`, + title: translator.translate('sources.headerLonger'), + content: translator.translate('sources.subheader'), + }); + } + + if (config.faq.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.faq.route)}`, + title: translator.translate('faq.header'), + content: translator.translate('faq.headerLong'), + }); + } + + if (config.links.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.links.route)}`, + title: translator.translate('links.header'), + content: translator.translate('links.headerLong'), + }); + + if (config.links.academicRoute) { + addDocument({ + url: `/${encodeURIComponent(config.links.academicRoute)}`, + title: translator.translate('links.academic.header'), + content: translator.get('links.academic.intro') + .map((text) => clearLinkedText(text, false)) + .join(' '), + }); + } + if (config.links.translinguisticsRoute) { + addDocument({ + url: `/${encodeURIComponent(config.links.translinguisticsRoute)}`, + title: translator.translate('links.translinguistics.headerLong'), + content: translator.get('links.translinguistics.intro') + .map((text) => clearLinkedText(text, false)) + .join(' '), + }); + } + if (config.links.mediaRoute) { + addDocument({ + url: `/${encodeURIComponent(config.links.mediaRoute)}`, + title: translator.translate('links.media.header'), + content: '', + }); + } + + if (config.links.zine?.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.links.zine.route)}`, + title: translator.translate('links.zine.headerLong'), + content: translator.get('links.zine.info') + .map((text) => clearLinkedText(text, false)) + .join(' '), + }); + } + + if (config.links.blog) { + addDocument({ + url: `/${encodeURIComponent(config.links.blogRoute)}`, + title: translator.translate('links.blog'), + content: '', + }); + } + + if (config.terminology.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.terminology.route)}`, + title: translator.translate('terminology.headerLong'), + content: translator.get('terminology.info') + .map((text) => clearLinkedText(text, false)) + .join(' '), + }); + } + + if (config.calendar?.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.calendar.route)}`, + title: translator.translate('calendar.headerLong'), + content: '', + }); + } + + if (config.census.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.census.route)}`, + title: translator.translate('census.headerLong'), + content: '', + }); + } + + if (config.inclusive.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.inclusive.route)}`, + title: translator.translate('inclusive.headerLong'), + content: translator.get('inclusive.info') + .map((text) => clearLinkedText(text, false)) + .join(' '), + }); + } + + if (config.names.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.names.route)}`, + title: translator.translate('names.headerLong'), + content: [ + translator.translate('inclusive.description'), + ...translator.get('inclusive.info') + .map((text) => clearLinkedText(text, false)), + ].join(' '), + }); + } + + if (config.people.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.people.route)}`, + title: translator.translate('people.headerLonger'), + content: [ + translator.translate('people.description'), + ...translator.get('people.info') + .map((text) => clearLinkedText(text, false)), + ].join(' '), + }); + } + + if (config.contact.enabled && config.contact.team.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.contact.team.route)}`, + title: translator.translate('contact.team.name'), + content: [ + translator.translate('contact.team.description'), + translator.translate('contact.contribute.header'), + translator.translate('home.mission.header'), + translator.translate('home.mission.summary'), + translator.translate('home.mission.freedom'), + translator.translate('home.mission.respect'), + translator.translate('home.mission.inclusivity'), + `${translator.translate('contact.contribute.intro')}:`, + ...['entries', 'translations', 'version', 'technical'].map((area) => { + const header = translator.translate(`contact.contribute.${area}.header`); + const description = translator.translate(`contact.contribute.${area}.description`); + return `${header}: ${clearLinkedText(description, false)}`; + }), + ].join(' '), + }); + } + + if (config.workshops?.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.workshops.route)}`, + title: translator.translate('workshops.headerLong'), + content: translator.get('workshops.content') + .map((text) => clearLinkedText(text, false)) + .join(' '), + }); + } + + if (config.contact.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.contact.route)}`, + title: translator.translate('contact.header'), + content: [ + translator.translate('contact.faq'), + translator.translate('contact.technical'), + translator.translate('contact.hate'), + translator.translate('contact.language'), + ].join(' '), + }); + } + + addDocument({ + url: 'https://shop.pronouns.page', + title: translator.translate('contact.groups.shop'), + content: '', + }); + } + + if (config.english.enabled) { + addDocument({ + url: `/${encodeURIComponent(config.english.route)}`, + title: translator.translate('links.english.header'), + content: [ + translator.translate('english.headerLonger'), + translator.translate('english.description'), + ...translator.get('english.intro') + .map((text) => clearLinkedText(text, false)), + ].join(' '), + }); + } + + return documents; + }, + }, { kind: 'pronoun', async getDocuments(config: Config): Promise { diff --git a/src/search.ts b/src/search.ts index 5d0dbd125..e597c3900 100644 --- a/src/search.ts +++ b/src/search.ts @@ -6,7 +6,7 @@ interface SearchDocumentImage { export interface SearchDocument { id: number; - kind: 'pronoun' | 'noun' | 'source' | 'link' | 'faq' | 'blog' | 'term' | 'inclusive' | 'calendar'; + kind: 'page' | 'pronoun' | 'noun' | 'source' | 'link' | 'faq' | 'blog' | 'term' | 'inclusive' | 'calendar'; url: string; title: string; titleSmall?: string | undefined;