diff --git a/packages/frontend/lib/vite-plugin-create-search-index.ts b/packages/frontend/lib/vite-plugin-create-search-index.ts index 3c1950687a..fad2b36045 100644 --- a/packages/frontend/lib/vite-plugin-create-search-index.ts +++ b/packages/frontend/lib/vite-plugin-create-search-index.ts @@ -8,47 +8,235 @@ import type { Plugin } from 'vite'; import fs from 'node:fs'; import { glob } from 'glob'; import JSON5 from 'json5'; -import { randomUUID } from 'crypto'; import MagicString from 'magic-string'; import path from 'node:path' import { hash, toBase62 } from '../vite.config'; -export interface AnalysisResult { +export type AnalysisResult = { filePath: string; - usage: ComponentUsageInfo[]; + usage: SearchIndexItem[]; } -export interface ComponentUsageInfo { - staticProps: Record; - bindProps: Record; +export type SearchIndexItem = { + id: string; + path?: string; + label: string; + keywords: string | string[]; + icon?: string; + children?: (SearchIndexItem[] | string); } function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisResult[]): void { - // (outputAnalysisResultAsTS 関数の実装は前回と同様) - const varName = 'searchIndexes'; //  変数名 + console.log(`[create-search-index] Processing ${analysisResults.length} files for output`); - const jsonString = JSON5.stringify(analysisResults, { space: "\t", quote: "'" }); //  JSON.stringify で JSON 文字列を生成 + // 新しいツリー構造を構築 + const allMarkers = new Map(); - //  bindProps の値を文字列置換で修正する関数 - function modifyBindPropsInString(jsonString: string): string { - const modifiedString = jsonString.replace( - /bindProps:\s*\{([^}]*)\}/g, //  bindProps: { ... } にマッチ (g フラグで複数箇所を置換) - (match, bindPropsBlock) => { - //  bindPropsBlock ( { ... } 内) の各プロパティをさらに置換 - const modifiedBlock = bindPropsBlock.replace( - /(.*):\s*\'(.*)\'/g, //  propName: 'propValue' にマッチ - (propMatch, propName, propValue) => { - return `${propName}: ${propValue}`; // propValue のクォートを除去 - } - ).replaceAll("\\'", "'"); - return `bindProps: {${modifiedBlock}}`; //  置換後の block で bindProps: { ... } を再構成 - } - ); - return modifiedString; - } + // 1. すべてのマーカーを一旦フラットに収集 + for (const file of analysisResults) { + console.log(`[create-search-index] Processing file: ${file.filePath} with ${file.usage.length} markers`); + for (const marker of file.usage) { + if (marker.id) { + // キーワードの処理(文字列から配列へ変換) + let keywords = marker.keywords; + if (typeof keywords === 'string' && keywords.startsWith('[') && keywords.endsWith(']')) { + try { + // JSON5解析を試みる(ただしi18n参照などがある場合は例外発生) + keywords = JSON5.parse(keywords.replace(/'/g, '"')); + } catch (e) { + // 解析に失敗した場合は文字列のままにする + console.log(`[create-search-index] Keeping keywords as string expression: ${keywords}`); + } + } + // 子要素の処理(文字列から配列へ変換) + let children = marker.children || []; + if (typeof children === 'string' && children.startsWith('[') && children.endsWith(']')) { + try { + // JSON5解析を試みる + children = JSON5.parse(children.replace(/'/g, '"')); + } catch (e) { + // 解析に失敗した場合は空配列に + console.log(`[create-search-index] Could not parse children: ${children}, using empty array`); + children = []; + } + } - const tsOutput = ` + // 子マーカーの内部構造を適切に更新 + if (Array.isArray(children) && children.length > 0) { + console.log(`[create-search-index] Marker ${marker.id} has ${children.length} children: ${JSON.stringify(children)}`); + } + + allMarkers.set(marker.id, { + ...marker, + keywords, + children: Array.isArray(children) ? children : [] + }); + } + } + } + + console.log(`[create-search-index] Collected total ${allMarkers.size} unique markers`); + + // 2. 子マーカーIDの収集 + const childIds = new Set(); + + allMarkers.forEach((marker, id) => { + const children = marker.children; + if (Array.isArray(children)) { + children.forEach(childId => { + if (typeof childId === 'string') { + if (!allMarkers.has(childId)) { + console.warn(`[create-search-index] Warning: Child marker ID ${childId} referenced but not found`); + } else { + childIds.add(childId); + } + } + }); + } + }); + + console.log(`[create-search-index] Found ${childIds.size} child markers`); + + // 3. ルートマーカーの特定(他の誰かの子でないマーカー) + const rootMarkers: SearchIndexItem[] = []; + + allMarkers.forEach((marker, id) => { + if (!childIds.has(id)) { + // このマーカーはルート(他の誰の子でもない) + rootMarkers.push(marker); + console.log(`[create-search-index] Added root marker to output: ${id} with label ${marker.label}`); + } + }); + + console.log(`[create-search-index] Found ${rootMarkers.length} root markers`); + + // 4. 子マーカーの参照を解決(IDから実際のオブジェクトに) + function resolveChildrenReferences(marker: SearchIndexItem): SearchIndexItem { + // マーカーのディープコピーを作成 + const resolvedMarker = { ...marker }; + + // 子リファレンスを解決 + if (Array.isArray(marker.children)) { + const children: SearchIndexItem[] = []; + + for (const childId of marker.children) { + if (typeof childId === 'string') { + const childMarker = allMarkers.get(childId); + + if (childMarker) { + // 子マーカーの子も再帰的に解決 + const resolvedChild = resolveChildrenReferences(childMarker); + children.push(resolvedChild); + console.log(`[create-search-index] Resolved child ${childId} for parent ${marker.id}`); + } + } + } + + // 子が存在する場合のみchildrenプロパティを設定 + if (children.length > 0) { + resolvedMarker.children = children; + } else { + // 子がない場合はchildrenプロパティを削除 + delete resolvedMarker.children; + } + } + + return resolvedMarker; + } + + // すべてのルートマーカーに対して子の参照を解決 + const resolvedRootMarkers = rootMarkers.map(marker => { + return resolveChildrenReferences(marker); + }); + + // 特殊なプロパティ変換用の関数 + function formatSpecialProperty(key: string, value: any): string { + // 値がundefinedの場合は空文字列を返す + if (value === undefined) { + return '""'; + } + + // childrenが配列の場合は特別に処理 + if (key === 'children' && Array.isArray(value)) { + return customStringify(value); + } + + // 文字列でない場合はJSON5で文字列化 + if (typeof value !== 'string') { + return JSON5.stringify(value); + } + + // i18n.ts 参照を含む場合 + if (value.includes('i18n.ts.')) { + return value; // クォートなしで直接返す + } + + // keywords が配列リテラルの形式の場合 + if (key === 'keywords' && value.startsWith('[') && value.endsWith(']')) { + return value; // クォートなしで直接返す + } + + // 上記以外は通常の JSON5 文字列として返す + return JSON5.stringify(value); + } + + // オブジェクトをカスタム形式に変換する関数 + function customStringify(obj: any, depth = 0): string { + const INDENT_STR = '\t'; + if (Array.isArray(obj)) { + if (obj.length === 0) return '[]'; + const indent = INDENT_STR.repeat(depth); + const childIndent = INDENT_STR.repeat(depth + 1); + const items = obj.map(item => `${childIndent}${customStringify(item, depth + 1)}`).join(',\n'); + return `[\n${items},\n${indent}]`; + } + + if (obj === null || typeof obj !== 'object') { + return JSON5.stringify(obj); + } + + const indent = INDENT_STR.repeat(depth); + const childIndent = INDENT_STR.repeat(depth + 1); + const entries = Object.entries(obj) + .filter(([key, value]) => { + // valueがundefinedの場合は出力しない + if (value === undefined) return false; + // childrenが空配列の場合は出力しない + if (key === 'children' && Array.isArray(value) && value.length === 0) return false; + return true; + }) + .map(([key, value]) => { + // childrenが配列の場合で要素がある場合のみ特別処理 + if (key === 'children' && Array.isArray(value) && value.length > 0) { + return `${childIndent}${key}: ${customStringify(value, depth + 1)}`; + } + return `${childIndent}${key}: ${formatSpecialProperty(key, value)}`; + }); + + if (entries.length === 0) return '{}'; + return `{\n${entries.join(',\n')},\n${indent}}`; + } + + // 最終出力用のデバッグ情報を生成 + let totalMarkers = resolvedRootMarkers.length; + let totalChildren = 0; + + function countNestedMarkers(markers: SearchIndexItem[]): void { + for (const marker of markers) { + if (marker.children && Array.isArray(marker.children)) { + totalChildren += marker.children.length; + totalMarkers += marker.children.length; + countNestedMarkers(marker.children as SearchIndexItem[]); + } + } + } + + countNestedMarkers(resolvedRootMarkers); + console.log(`[create-search-index] Total markers in tree: ${totalMarkers} (${resolvedRootMarkers.length} roots + ${totalChildren} nested children)`); + + // 結果をTS形式で出力 + const tsOutput = ` /* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only @@ -57,93 +245,167 @@ function outputAnalysisResultAsTS(outputPath: string, analysisResults: AnalysisR // This file was automatically generated by create-search-index. // Do not edit this file. +/* eslint-disable @stylistic/comma-spacing */ + import { i18n } from '@/i18n.js'; -export const ${varName} = ${modifyBindPropsInString(jsonString)} as const; +export type SearchIndexItem = { + id: string; + path?: string; + label: string; + keywords: string | string[]; + icon?: string; + children?: (SearchIndexItem[] | string); +}; -export type AnalysisResults = typeof ${varName}; -export type ComponentUsageInfo = AnalysisResults[number]['usage'][number]; +export const searchIndexes:SearchIndexItem[] = ${customStringify(resolvedRootMarkers)} as const; + +export type SearchIndex = typeof searchIndexes; + +/* eslint-enable @stylistic/comma-spacing */ `; - try { - fs.writeFileSync(outputPath, tsOutput, 'utf-8'); - } catch (error) { - console.error('[create-search-index]: error: ', error); - } + try { + fs.writeFileSync(outputPath, tsOutput, 'utf-8'); + console.log(`[create-search-index] Successfully wrote search index to ${outputPath} with ${resolvedRootMarkers.length} root entries and ${totalChildren} nested children`); + } catch (error) { + console.error('[create-search-index]: error: ', error); + } } function extractUsageInfoFromTemplateAst( - templateAst: any, - code: string, -): ComponentUsageInfo[] { - const usageInfoList: ComponentUsageInfo[] = []; + templateAst: any, + code: string, +): SearchIndexItem[] { + // すべてのマーカー情報を保持するために、結果をトップレベルマーカー+すべての子マーカーを含む配列に変更 + const allMarkers: SearchIndexItem[] = []; + // マーカーIDからオブジェクトへのマップ + const markerMap = new Map(); + // 子マーカーIDを集約するためのセット + const childrenIds = new Set(); - if (!templateAst) { - return usageInfoList; - } + if (!templateAst) { + return allMarkers; + } - function traverse(node: any) { - if (node.type === 1 && node.tag === 'SearchMarker') { - // 元々の props を staticProps に全て展開する - const staticProps: Record = {}; - if (node.props && Array.isArray(node.props)) { - node.props.forEach((prop: any) => { - if (prop.type === 6 && prop.name) { - staticProps[prop.name] = prop.value?.content || ''; - } - }); - } - // markerId は __markerId または既存の props から取得 - const markerId = node.__markerId || staticProps['markerId']; - if (markerId) { - staticProps['markerId'] = markerId; - } + // デバッグ情報 + console.log('[create-search-index] Started extracting markers from AST'); - const bindProps: Record = {}; + // マーカーの基本情報を収集 + function collectMarkers(node: any, parentId: string | null = null) { + // SearchMarkerコンポーネントの検出 + if (node.type === 1 && node.tag === 'SearchMarker') { + // マーカーID生成 (markerId属性またはDOM内に記録されているものを使用) + const markerIdProp = node.props?.find((p: any) => p.name === 'markerId'); + const markerId = markerIdProp?.value?.content || + node.__markerId || + `marker-${Math.random().toString(36).substring(2, 10)}`; - // 元々の props から bindProps を抽出 - if (node.props && Array.isArray(node.props)) { - node.props.forEach((prop: any) => { - if (prop.type === 7 && prop.name === 'bind' && prop.arg.content) { - bindProps[prop.arg.content] = prop.exp?.content || ''; - } - }); - } + console.log(`[create-search-index] Found SearchMarker with ID: ${markerId}`); - // __children がある場合、bindProps に children を追加 - if (node.__children) { - bindProps['children'] = node.__children; - } else if (node.props && Array.isArray(node.props)) { - const childrenProp = node.props.find( - (prop: any) => - prop.type === 7 && - prop.name === 'bind' && - prop.arg?.content === 'children' - ); - if (childrenProp && childrenProp.exp) { - try { - bindProps['children'] = JSON5.parse( - code.slice(childrenProp.exp.loc.start.offset, childrenProp.exp.loc.end.offset).replace(/'/g, '"') - ); - } catch (e) { - console.error('Error parsing :children attribute', e); - } - } - } + // マーカー基本情報 + const markerInfo: SearchIndexItem = { + id: markerId, + children: [], + label: '', + keywords: [], + }; - usageInfoList.push({ - staticProps, - bindProps, - }); - } + // 静的プロパティを抽出 + if (node.props && Array.isArray(node.props)) { + node.props.forEach((prop: any) => { + if (prop.type === 6 && prop.name && prop.name !== 'markerId') { + // 静的プロパティの抽出 + if (prop.name === 'path') markerInfo.path = prop.value?.content || ''; + else if (prop.name === 'icon') markerInfo.icon = prop.value?.content || ''; + else if (prop.name === 'label') markerInfo.label = prop.value?.content || ''; - if (node.children && Array.isArray(node.children)) { - node.children.forEach((child: any) => traverse(child)); - } - } + console.log(`[create-search-index] Static prop ${prop.name}:`, prop.value?.content); + } + }); + } - traverse(templateAst); - return usageInfoList; + // バインドプロパティを抽出 + if (node.props && Array.isArray(node.props)) { + node.props.forEach((prop: any) => { + if (prop.type === 7 && prop.name === 'bind' && prop.arg?.content) { + const propName = prop.arg.content; + const propValue = prop.exp?.content || ''; + + console.log(`[create-search-index] Bind prop ${propName}:`, propValue); + + if (propName === 'label') { + markerInfo.label = propValue; + } else if (propName === 'path') { + markerInfo.path = propValue; + } else if (propName === 'icon') { + markerInfo.icon = propValue; + } else if (propName === 'keywords') { + markerInfo.keywords = propValue || '[]'; + } else if (propName === 'children') { + markerInfo.children = propValue || '[]'; + } + } + }); + } + + // ラベルがない場合はデフォルト値を設定 + if (!markerInfo.label) { + markerInfo.label = 'Unnamed marker'; + } + + // キーワードがない場合はデフォルト値を設定 + if (!markerInfo.keywords || (Array.isArray(markerInfo.keywords) && markerInfo.keywords.length === 0)) { + markerInfo.keywords = '[]'; + } + + // マーカーをマップに保存し、すべてのマーカーリストにも追加 + markerMap.set(markerId, markerInfo); + allMarkers.push(markerInfo); // すべてのマーカーを保持 + + // 親子関係を記録 + if (parentId) { + const parent = markerMap.get(parentId); + if (parent) { + if (!parent.children) parent.children = []; + if (Array.isArray(parent.children)) { + parent.children.push(markerId); + } else { + parent.children = [markerId]; + } + childrenIds.add(markerId); + console.log(`[create-search-index] Added ${markerId} as child of ${parentId}`); + } + } + + // 子ノードを処理(親は現在のノード) + if (node.children && Array.isArray(node.children)) { + node.children.forEach((child: any) => { + collectMarkers(child, markerId); + }); + } + + return markerId; + } + + // SearchMarkerでない場合は、子ノードを同じ親コンテキストで処理 + if (node.children && Array.isArray(node.children)) { + node.children.forEach((child: any) => { + collectMarkers(child, parentId); + }); + } + + return null; + } + + // AST解析を開始 + collectMarkers(templateAst); + + // デバッグ情報 + console.log(`[create-search-index] Found ${markerMap.size} markers, ${childrenIds.size} children`); + + // 重要: すべてのマーカー情報を返す + return allMarkers; } export async function analyzeVueProps(options: { @@ -151,42 +413,64 @@ export async function analyzeVueProps(options: { exportFilePath: string, transformedCodeCache: Record }): Promise { - const analysisResults: AnalysisResult[] = []; + const allMarkers: SearchIndexItem[] = []; - //  対象ファイルパスを glob で展開 + // 対象ファイルパスを glob で展開 const filePaths = options.targetFilePaths.reduce((acc, filePathPattern) => { const matchedFiles = glob.sync(filePathPattern); return [...acc, ...matchedFiles]; }, []); + console.log(`[create-search-index] Found ${filePaths.length} matching files to analyze`); for (const filePath of filePaths) { - const code = options.transformedCodeCache[path.resolve(filePath)]; // options 経由でキャッシュ参照 + const id = path.resolve(filePath); // 絶対パスに変換 + const code = options.transformedCodeCache[id]; // options 経由でキャッシュ参照 if (!code) { // キャッシュミスの場合 console.error(`[create-search-index] Error: No cached code found for: ${filePath}.`); // エラーログ - continue; - } - const { descriptor, errors } = vueSfcParse(code, { - filename: filePath, - }); - - if (errors.length) { - console.error(`[create-search-index] Compile Error: ${filePath}`, errors); - continue; // エラーが発生したファイルはスキップ + // ファイルを直接読み込む代替策を実行 + try { + const directCode = fs.readFileSync(filePath, 'utf-8'); + options.transformedCodeCache[id] = directCode; + console.log(`[create-search-index] Loaded file directly instead: ${filePath}`); + } catch (err) { + console.error(`[create-search-index] Failed to load file directly: ${filePath}`, err); + continue; + } } - const usageInfo = extractUsageInfoFromTemplateAst(descriptor.template?.ast, code); - if (!usageInfo) continue; - - if (usageInfo.length > 0) { - analysisResults.push({ - filePath: filePath, - usage: usageInfo, + try { + const { descriptor, errors } = vueSfcParse(options.transformedCodeCache[id], { + filename: filePath, }); + + if (errors.length) { + console.error(`[create-search-index] Compile Error: ${filePath}`, errors); + continue; // エラーが発生したファイルはスキップ + } + + const fileMarkers = extractUsageInfoFromTemplateAst(descriptor.template?.ast, options.transformedCodeCache[id]); + + if (fileMarkers && fileMarkers.length > 0) { + allMarkers.push(...fileMarkers); // すべてのマーカーを収集 + console.log(`[create-search-index] Successfully extracted ${fileMarkers.length} markers from ${filePath}`); + } else { + console.log(`[create-search-index] No markers found in ${filePath}`); + } + } catch (error) { + console.error(`[create-search-index] Error analyzing file ${filePath}:`, error); } } - outputAnalysisResultAsTS(options.exportFilePath, analysisResults); // outputAnalysisResultAsTS を呼び出す + // 収集したすべてのマーカー情報を使用 + const analysisResult: AnalysisResult[] = [ + { + filePath: "combined-markers", // すべてのファイルのマーカーを1つのエントリとして扱う + usage: allMarkers, + } + ]; + + outputAnalysisResultAsTS(options.exportFilePath, analysisResult); // すべてのマーカー情報を渡す } interface MarkerRelation { @@ -333,7 +617,7 @@ async function processVueFile( const newIds = childIds.filter(id => !childrenArray.includes(id)); if (newIds.length > 0) { childrenArray = [...childrenArray, ...newIds]; - const updatedChildrenArrayStr = JSON.stringify(childrenArray).replace(/"/g, "'"); + const updatedChildrenArrayStr = JSON5.stringify(childrenArray).replace(/"/g, "'"); s.overwrite(childrenStart, childrenEnd + 1, updatedChildrenArrayStr); console.log(`[create-search-index] Added ${newIds.length} child markerIds to existing :children in ${id}`); } @@ -366,7 +650,7 @@ async function processVueFile( if (attrValueStart > -1 && attrValueEnd > -1) { const absoluteStart = parentNodeStart + attrValueStart; const absoluteEnd = parentNodeStart + attrValueEnd; - const updatedArrayStr = JSON.stringify(childrenArray).replace(/"/g, "'"); + const updatedArrayStr = JSON5.stringify(childrenArray).replace(/"/g, "'"); s.overwrite(absoluteStart, absoluteEnd, updatedArrayStr); console.log(`[create-search-index] Updated existing :children in tag text for ${id}`); } @@ -377,7 +661,7 @@ async function processVueFile( } } else { // :children 属性がまだない場合、新規作成 - s.appendRight(endOfParentStartTag, ` :children="${JSON.stringify(childIds).replace(/"/g, "'")}"`); + s.appendRight(endOfParentStartTag, ` :children="${JSON5.stringify(childIds).replace(/"/g, "'")}"`); console.log(`[create-search-index] Created new :children attribute with ${childIds.length} markerIds in ${id}`); } } diff --git a/packages/frontend/src/scripts/autogen/settings-search-index.ts b/packages/frontend/src/scripts/autogen/settings-search-index.ts index 87c2f878c0..810a2659bc 100644 --- a/packages/frontend/src/scripts/autogen/settings-search-index.ts +++ b/packages/frontend/src/scripts/autogen/settings-search-index.ts @@ -7,70 +7,506 @@ // This file was automatically generated by create-search-index. // Do not edit this file. +/* eslint-disable @stylistic/comma-spacing */ + import { i18n } from '@/i18n.js'; -export const searchIndexes = [ +export type SearchIndexItem = { + id: string; + path?: string; + label: string; + keywords: string | string[]; + icon?: string; + children?: (SearchIndexItem[] | string); +}; + +export const searchIndexes:SearchIndexItem[] = [ { - filePath: 'src/pages/settings/profile.vue', - usage: [ + id: 'EfN1JU93S', + children: [ { - staticProps: { - markerId: '4mWPWOqkN', - }, - bindProps: {}, + id: 'uHreVVQIS', + label: i18n.ts._profile.name, + keywords: ['name'], }, { - staticProps: { - markerId: 'gw1zundQ3', - }, - bindProps: {}, + id: 'gAvOWkPnm', + label: i18n.ts._profile.description, + keywords: ['description','bio'], + }, + { + id: 'jDQ9ug9JI', + label: i18n.ts.location, + keywords: ['location','locale'], + }, + { + id: '4IINpCs7w', + label: i18n.ts.birthday, + keywords: ['birthday','birthdate','age'], + }, + { + id: 'nrKSnXwYN', + label: i18n.ts.language, + keywords: ['language','locale'], + }, + { + id: 'xpFKUEupm', + label: i18n.ts._profile.metadataEdit, + keywords: ['metadata'], + }, + { + id: 'EAdtWppOM', + label: i18n.ts._profile.followedMessage, + keywords: ['follow', 'message', i18n.ts._profile.followedMessageDescription], + }, + { + id: 'agaHOwYSm', + label: i18n.ts.reactionAcceptance, + keywords: ['reaction'], + }, + { + id: 'E3EMH8zsB', + children: [ + { + id: 'xYknyiCsI', + label: i18n.ts.flagAsCat, + keywords: ['cat', i18n.ts.flagAsCatDescription], + }, + { + id: '2yIzPU9hg', + label: i18n.ts.flagAsBot, + keywords: ['bot', i18n.ts.flagAsBotDescription], + }, + ], + label: i18n.ts.advancedSettings, + keywords: [], }, ], + label: i18n.ts.profile, + keywords: ['profile'], + path: '/settings/profile', + icon: 'ti ti-user', }, { - filePath: 'src/pages/settings/privacy.vue', - usage: [ + id: 'zUK4HIXfh', + children: [ { - staticProps: { - icon: 'ti ti-lock-open', - markerId: 'ssTCH2oBL', - }, - bindProps: { - locationLabel: [i18n.ts.privacy, i18n.ts.makeFollowManuallyApprove], - keywords: ['follow', 'lock', i18n.ts.lockedAccountInfo], - }, + id: '46jUHufEx', + label: i18n.ts.makeFollowManuallyApprove, + keywords: ['follow', 'lock', i18n.ts.lockedAccountInfo], + }, + { + id: 'yGVh4afrC', + label: i18n.ts.autoAcceptFollowed, + keywords: ['follow','auto','accept'], + }, + { + id: 'vomfIAjG2', + label: i18n.ts.makeReactionsPublic, + keywords: ['reaction', 'public', i18n.ts.makeReactionsPublicDescription], + }, + { + id: 'BakhCOlGl', + label: i18n.ts.followingVisibility, + keywords: ['following','visibility'], + }, + { + id: 'nALctPZes', + label: i18n.ts.followersVisibility, + keywords: ['follower','visibility'], + }, + { + id: 'g39hgvANq', + label: i18n.ts.hideOnlineStatus, + keywords: ['online', 'status', i18n.ts.hideOnlineStatusDescription], + }, + { + id: 'jFd8aByjS', + label: i18n.ts.noCrawle, + keywords: ['crawle', 'index', 'search', i18n.ts.noCrawleDescription], + }, + { + id: 'qlcVI7TvT', + label: i18n.ts.preventAiLearning, + keywords: ['crawle', 'ai', i18n.ts.preventAiLearningDescription], + }, + { + id: 'nGm8gxxph', + label: i18n.ts.makeExplorable, + keywords: ['explore', i18n.ts.makeExplorableDescription], + }, + { + id: 'o8bJdIWBc', + children: [ + { + id: '5V4EcXjrc', + label: i18n.ts._accountSettings.requireSigninToViewContents, + keywords: ['login', 'signin', i18n.ts._accountSettings.requireSigninToViewContentsDescription1, i18n.ts._accountSettings.requireSigninToViewContentsDescription2, i18n.ts._accountSettings.requireSigninToViewContentsDescription3], + }, + { + id: 'huYLq7zx9', + label: i18n.ts._accountSettings.makeNotesFollowersOnlyBefore, + keywords: ['follower', i18n.ts._accountSettings.makeNotesFollowersOnlyBeforeDescription], + }, + { + id: '4HRzEG7td', + label: i18n.ts._accountSettings.makeNotesHiddenBefore, + keywords: ['hidden', i18n.ts._accountSettings.makeNotesHiddenBeforeDescription], + }, + ], + label: i18n.ts.lockdown, + keywords: ['lockdown'], + }, + { + id: '6AAT3LUIL', + label: i18n.ts.rememberNoteVisibility, + keywords: ['remember','keep','note','visibility'], + }, + { + id: '8d0FCNIgm', + label: i18n.ts.defaultNoteVisibility, + keywords: ['default','note','visibility'], + }, + { + id: 'o3hisYwlV', + label: i18n.ts.keepCw, + keywords: ['remember','keep','note','cw'], }, ], + label: i18n.ts.privacy, + keywords: ['privacy'], + path: '/settings/privacy', + icon: 'ti ti-lock-open', }, { - filePath: 'src/pages/settings/mute-block.vue', - usage: [ + id: 'rbnN7S4RC', + children: [ { - staticProps: { - icon: 'ti ti-ban', - markerId: 'CVhDOYgMv', - }, - bindProps: { - locationLabel: [i18n.ts.muteAndBlock], - keywords: ['mute', i18n.ts.wordMute], - children: [ - 'kcHPXo5ZV', - ], - }, + id: 'wAnn0Z9zp', + children: [ + { + id: '5tIsotvIk', + label: i18n.ts.showMutedWord, + keywords: ['show'], + }, + ], + label: i18n.ts.wordMute, + keywords: ['note','word','soft','mute','hide'], }, { - staticProps: { - icon: 'ti ti-ban', - markerId: 'kcHPXo5ZV', - }, - bindProps: { - locationLabel: [i18n.ts.muteAndBlock, i18n.ts.wordMute], - keywords: ['showMutedWord', i18n.ts.showMutedWord], - }, + id: 'evlmsuKtu', + label: i18n.ts.hardWordMute, + keywords: ['note','word','hard','mute','hide'], + }, + { + id: 'zLHWO9mBm', + label: i18n.ts.instanceMute, + keywords: ['note','server','instance','host','federation','mute','hide'], + }, + { + id: 's3IxYcSKj', + label: `${i18n.ts.mutedUsers} (${ i18n.ts.renote })`, + keywords: ['renote','mute','hide','user'], + }, + { + id: 'iBnGIbcys', + label: i18n.ts.mutedUsers, + keywords: ['note','mute','hide','user'], + }, + { + id: 'g6aGcN8X5', + label: i18n.ts.blockedUsers, + keywords: ['block','user'], }, ], + label: i18n.ts.muteAndBlock, + keywords: ['mute','block'], + path: '/settings/mute-block', + icon: 'ti ti-ban', + }, + { + id: 'qZGmAjsxj', + children: [ + { + id: 'ln8mPGca4', + label: i18n.ts.uiLanguage, + keywords: ['language'], + }, + { + id: '3zpvHzV5g', + label: i18n.ts.overridedDeviceKind, + keywords: ['device','type','kind','smartphone','tablet','desktop'], + }, + { + id: '1QvSeZtNe', + label: i18n.ts.showFixedPostForm, + keywords: ['post','form','timeline'], + }, + { + id: 'oVjAZ97m1', + label: i18n.ts.showFixedPostFormInChannel, + keywords: ['post','form','timeline','channel'], + }, + { + id: '6sIzeMWoB', + label: i18n.ts.pinnedList, + keywords: ['pinned','list'], + }, + { + id: '6HbFzMsfZ', + children: [ + { + id: 'pQO0HwBg5', + label: i18n.ts.collapseRenotes, + keywords: ['renote', i18n.ts.collapseRenotesDescription], + }, + { + id: 'r8RoaDGyB', + label: i18n.ts.showNoteActionsOnlyHover, + keywords: ['hover','show','footer','action'], + }, + { + id: 'dhe5ltCVy', + label: i18n.ts.showClipButtonInNoteFooter, + keywords: ['footer','action','clip','show'], + }, + { + id: 'lJijzarvh', + label: i18n.ts.enableAdvancedMfm, + keywords: ['mfm','enable','show','advanced'], + }, + { + id: 'plFY7Zr0Y', + label: i18n.ts.enableAnimatedMfm, + keywords: ['mfm','enable','show','animated'], + }, + { + id: 'uCWeJdWGo', + label: i18n.ts.enableQuickAddMfmFunction, + keywords: ['mfm','enable','show','advanced','picker','form','function','fn'], + }, + { + id: 'jojGm1s0T', + label: i18n.ts.showReactionsCount, + keywords: ['reaction','count','show'], + }, + { + id: 'gob3LGyDO', + label: i18n.ts.showGapBetweenNotesInTimeline, + keywords: ['note','timeline','gap'], + }, + { + id: 'v5IaTjjUK', + label: i18n.ts.loadRawImages, + keywords: ['image','photo','picture','media','thumbnail','quality','raw','attachment'], + }, + { + id: '9rlymuz2e', + label: i18n.ts.reactionsDisplaySize, + keywords: ['reaction','size','scale','display'], + }, + { + id: 'a6JkO6iHN', + label: i18n.ts.limitWidthOfReaction, + keywords: ['reaction','size','scale','display','width','limit'], + }, + { + id: 'B2C8Chpn3', + label: i18n.ts.instanceTicker, + keywords: ['ticker','information','label','instance','server','host','federation'], + }, + { + id: 'lXGQcJA0m', + label: i18n.ts.displayOfSensitiveMedia, + keywords: ['attachment','image','photo','picture','media','thumbnail','nsfw','sensitive','display','show','hide','visibility'], + }, + { + id: 'fI9unfBG9', + label: i18n.ts.mediaListWithOneImageAppearance, + keywords: ['attachment','image','photo','picture','media','thumbnail','list','size','height'], + }, + ], + label: i18n.ts.displayOfNote, + keywords: ['note','display'], + }, + { + id: 'ksPnvPfsq', + children: [ + { + id: 'rlKh8qQSy', + label: i18n.ts.useGroupedNotifications, + keywords: ['group'], + }, + { + id: 'mZoLcRxn9', + label: i18n.ts.position, + keywords: ['position'], + }, + { + id: 'mu8Fghr9P', + label: i18n.ts.stackAxis, + keywords: ['stack','axis','direction'], + }, + ], + label: i18n.ts.notificationDisplay, + keywords: ['notification','display'], + }, + { + id: 'sUAe1tYeV', + children: [ + { + id: 'pXk2Bq5c7', + label: i18n.ts.reduceUiAnimation, + keywords: ['animation','motion','reduce'], + }, + { + id: 'l92lxxESG', + label: i18n.ts.useBlurEffect, + keywords: ['blur'], + }, + { + id: '5fw6zkK39', + label: i18n.ts.useBlurEffectForModal, + keywords: ['blur','modal'], + }, + { + id: 'm3kpvUE3f', + label: i18n.ts.disableShowingAnimatedImages, + keywords: ['disable','animation','image','photo','picture','media','thumbnail','gif'], + }, + { + id: 'EEHGMwhkC', + label: i18n.ts.highlightSensitiveMedia, + keywords: ['highlight','sensitive','nsfw','image','photo','picture','media','thumbnail'], + }, + { + id: 'hBnm0B8aI', + label: i18n.ts.squareAvatars, + keywords: ['avatar','icon','square'], + }, + { + id: 'm9Q5z11L8', + label: i18n.ts.showAvatarDecorations, + keywords: ['avatar','icon','decoration','show'], + }, + { + id: 'pHvwcwF4c', + label: i18n.ts.useSystemFont, + keywords: ['font','system','native'], + }, + { + id: '3lcbrBHYZ', + label: i18n.ts.forceShowAds, + keywords: ['ad','show'], + }, + { + id: '523Bx87JU', + label: i18n.ts.seasonalScreenEffect, + keywords: ['effect','show'], + }, + { + id: '7dFSaWz4u', + label: i18n.ts.useNativeUIForVideoAudioPlayer, + keywords: ['native','system','video','audio','player','media'], + }, + { + id: 'q3Vv5zIZu', + label: i18n.ts.menuStyle, + keywords: ['menu','style','popup','drawer'], + }, + { + id: 'd1Gno6GaT', + label: i18n.ts.emojiStyle, + keywords: ['emoji','style','native','system','fluent','twemoji'], + }, + { + id: '3sV67CRuN', + label: i18n.ts.fontSize, + keywords: ['font','size'], + }, + ], + label: i18n.ts.appearance, + keywords: ['appearance'], + }, + { + id: 'AOASYDlhv', + children: [ + { + id: 'rwvOv068t', + label: i18n.ts.openImageInNewTab, + keywords: ['image','photo','picture','media','thumbnail','new','tab'], + }, + { + id: '1XB7XWwbI', + label: i18n.ts.useReactionPickerForContextMenu, + keywords: ['reaction','picker','contextmenu','open'], + }, + { + id: '4fjitJYAl', + label: i18n.ts.enableInfiniteScroll, + keywords: ['load','auto','more'], + }, + { + id: 'f2Nk4GdTa', + label: i18n.ts.keepScreenOn, + keywords: ['keep','screen','display','on'], + }, + { + id: '3D54jQsGn', + label: i18n.ts.disableStreamingTimeline, + keywords: ['disable','streaming','timeline'], + }, + { + id: '6MKp7i7iH', + label: i18n.ts.enableHorizontalSwipe, + keywords: ['swipe','horizontal','tab'], + }, + { + id: 'eSvGS9DsY', + label: i18n.ts.alwaysConfirmFollow, + keywords: ['follow','confirm','always'], + }, + { + id: 'kGYY8LCdK', + label: i18n.ts.confirmWhenRevealingSensitiveMedia, + keywords: ['sensitive','nsfw','media','image','photo','picture','attachment','confirm'], + }, + { + id: 'fdOu3BDKL', + label: i18n.ts.confirmOnReact, + keywords: ['reaction','confirm'], + }, + { + id: 'isbDLeTjm', + label: i18n.ts.whenServerDisconnected, + keywords: ['server','disconnect','reconnect','reload','streaming'], + }, + { + id: 'F5werzQkF', + label: i18n.ts._contextMenu.title, + keywords: ['contextmenu','system','native'], + }, + { + id: 'CPNGOZAoV', + label: i18n.ts.numberOfPageCache, + keywords: ['cache','page'], + }, + { + id: '5XHiLyaol', + label: i18n.ts.dataSaver, + keywords: ['datasaver'], + }, + ], + label: i18n.ts.behavior, + keywords: ['behavior'], + }, + ], + label: i18n.ts.general, + keywords: ['general'], + icon: 'ti ti-adjustments', }, ] as const; -export type AnalysisResults = typeof searchIndexes; -export type ComponentUsageInfo = AnalysisResults[number]['usage'][number]; +export type SearchIndex = typeof searchIndexes; + +/* eslint-enable @stylistic/comma-spacing */