enhance(frontend): improve search index

This commit is contained in:
syuilo 2025-04-07 17:03:43 +09:00
parent fa52922331
commit 3a8d015194
5 changed files with 58 additions and 20 deletions

View File

@ -227,10 +227,11 @@ function extractElementText2Inner(node: TemplateChildNode, processingNodeName: s
// region extractUsageInfoFromTemplateAst
/**
* SearchLabelとSearchKeywordを探して抽出する関数
* SearchLabel/SearchKeyword/SearchIconを探して抽出する関数
*/
function extractLabelsAndKeywords(nodes: TemplateChildNode[]): { label: string | null, keywords: string[] } {
function extractSugarTags(nodes: TemplateChildNode[]): { label: string | null, keywords: string[], icon: string | null } {
let label: string | null | undefined = undefined;
let icon: string | null | undefined = undefined;
const keywords: string[] = [];
logger.info(`Extracting labels and keywords from ${nodes.length} nodes`);
@ -253,14 +254,32 @@ function extractLabelsAndKeywords(nodes: TemplateChildNode[]): { label: string |
keywords.push(content);
}
return;
case 'SearchIcon':
if (icon !== undefined) {
logger.warn(`Duplicate SearchIcon found, ignoring the second one at ${node.loc.start.line}`);
break; // 2つ目のSearchIconは無視
}
if (node.children.length !== 1) {
logger.error(`SearchIcon must have exactly one child at ${node.loc.start.line}`);
return;
}
const iconNode = node.children[0];
if (iconNode.type !== NodeTypes.ELEMENT) {
logger.error(`SearchIcon must have a child element at ${node.loc.start.line}`);
return;
}
icon = getStringProp(findAttribute(iconNode.props, 'class'));
return;
}
return;
});
// デバッグ情報
logger.info(`Extraction completed: label=${label}, keywords=[${keywords.join(', ')}]`);
return { label: label ?? null, keywords };
logger.info(`Extraction completed: label=${label}, keywords=[${keywords.join(', ')}, icon=${icon}]`);
return { label: label ?? null, keywords, icon: icon ?? null };
}
function getStringProp(attr: AttributeNode | DirectiveNode | null): string | null {
@ -354,10 +373,12 @@ function extractUsageInfoFromTemplateAst(
// SearchLabelとSearchKeywordを抽出 (AST全体を探索)
{
const extracted = extractLabelsAndKeywords(node.children);
const extracted = extractSugarTags(node.children);
if (extracted.label && markerInfo.label) logger.warn(`Duplicate label found for ${markerId} at ${id}:${node.loc.start.line}`);
if (extracted.icon && markerInfo.icon) logger.warn(`Duplicate icon found for ${markerId} at ${id}:${node.loc.start.line}`);
markerInfo.label = extracted.label ?? markerInfo.label ?? '';
markerInfo.keywords = [...extracted.keywords, ...markerInfo.keywords];
markerInfo.icon = extracted.icon ?? markerInfo.icon ?? undefined;
}
if (!markerInfo.label) {

View File

@ -0,0 +1,14 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<slot></slot>
</template>
<script lang="ts" setup>
</script>
<style lang="scss" module>
</style>

View File

@ -30,6 +30,7 @@ import PageWithAnimBg from './global/PageWithAnimBg.vue';
import SearchMarker from './global/SearchMarker.vue';
import SearchLabel from './global/SearchLabel.vue';
import SearchKeyword from './global/SearchKeyword.vue';
import SearchIcon from './global/SearchIcon.vue';
import type { App } from 'vue';
@ -67,6 +68,7 @@ export const components = {
SearchMarker: SearchMarker,
SearchLabel: SearchLabel,
SearchKeyword: SearchKeyword,
SearchIcon: SearchIcon,
};
declare module '@vue/runtime-core' {
@ -98,5 +100,6 @@ declare module '@vue/runtime-core' {
SearchMarker: typeof SearchMarker;
SearchLabel: typeof SearchLabel;
SearchKeyword: typeof SearchKeyword;
SearchIcon: typeof SearchIcon;
}
}

View File

@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<div class="_gaps_s">
<SearchMarker :keywords="['account', 'info']">
<MkFolder>
<template #icon><i class="ti ti-info-circle"></i></template>
<template #icon><SearchIcon><i class="ti ti-info-circle"></i></SearchIcon></template>
<template #label><SearchLabel>{{ i18n.ts.accountInfo }}</SearchLabel></template>
<div class="_gaps_m">
@ -49,7 +49,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['roles']">
<MkFolder>
<template #icon><i class="ti ti-badges"></i></template>
<template #icon><SearchIcon><i class="ti ti-badges"></i></SearchIcon></template>
<template #label><SearchLabel>{{ i18n.ts.rolesAssignedToMe }}</SearchLabel></template>
<MkRolePreview v-for="role in $i.roles" :key="role.id" :role="role" :forModeration="false"/>
@ -58,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['account', 'move', 'migration']">
<MkFolder>
<template #icon><i class="ti ti-plane"></i></template>
<template #icon><SearchIcon><i class="ti ti-plane"></i></SearchIcon></template>
<template #label><SearchLabel>{{ i18n.ts.accountMigration }}</SearchLabel></template>
<XMigration/>
@ -67,7 +67,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['account', 'close', 'delete']">
<MkFolder>
<template #icon><i class="ti ti-alert-triangle"></i></template>
<template #icon><SearchIcon><i class="ti ti-alert-triangle"></i></SearchIcon></template>
<template #label><SearchLabel>{{ i18n.ts.closeAccount }}</SearchLabel></template>
<div class="_gaps_m">
@ -81,7 +81,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['experimental', 'feature', 'flags']">
<MkFolder>
<template #icon><i class="ti ti-flask"></i></template>
<template #icon><SearchIcon><i class="ti ti-flask"></i></SearchIcon></template>
<template #label><SearchLabel>{{ i18n.ts.experimentalFeatures }}</SearchLabel></template>
<div class="_gaps_m">
@ -100,7 +100,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['developer', 'mode', 'debug']">
<MkFolder>
<template #icon><i class="ti ti-code"></i></template>
<template #icon><SearchIcon><i class="ti ti-code"></i></SearchIcon></template>
<template #label><SearchLabel>{{ i18n.ts.developer }}</SearchLabel></template>
<div class="_gaps_m">

View File

@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['general']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.general }}</SearchLabel></template>
<template #icon><i class="ti ti-settings"></i></template>
<template #icon><SearchIcon><i class="ti ti-settings"></i></SearchIcon></template>
<div class="_gaps_m">
<SearchMarker :keywords="['language']">
@ -111,7 +111,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['timeline', 'note']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts._settings.timelineAndNote }}</SearchLabel></template>
<template #icon><i class="ti ti-notes"></i></template>
<template #icon><SearchIcon><i class="ti ti-notes"></i></SearchIcon></template>
<div class="_gaps_m">
<div class="_gaps_s">
@ -279,7 +279,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['post', 'form']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.postForm }}</SearchLabel></template>
<template #icon><i class="ti ti-edit"></i></template>
<template #icon><SearchIcon><i class="ti ti-edit"></i></SearchIcon></template>
<div class="_gaps_m">
<div class="_gaps_s">
@ -341,7 +341,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['notification']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.notifications }}</SearchLabel></template>
<template #icon><i class="ti ti-bell"></i></template>
<template #icon><SearchIcon><i class="ti ti-bell"></i></SearchIcon></template>
<div class="_gaps_m">
<SearchMarker :keywords="['group']">
@ -382,7 +382,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['chat', 'messaging']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.chat }}</SearchLabel></template>
<template #icon><i class="ti ti-messages"></i></template>
<template #icon><SearchIcon><i class="ti ti-messages"></i></SearchIcon></template>
<div class="_gaps_s">
<SearchMarker :keywords="['show', 'sender', 'name']">
@ -421,7 +421,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['accessibility']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.accessibility }}</SearchLabel></template>
<template #icon><i class="ti ti-accessible"></i></template>
<template #icon><SearchIcon><i class="ti ti-accessible"></i></SearchIcon></template>
<div class="_gaps_m">
<MkFeatureBanner icon="/client-assets/mens_room_3d.png" color="#0011ff">
@ -531,7 +531,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['performance']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.performance }}</SearchLabel></template>
<template #icon><i class="ti ti-battery-vertical-eco"></i></template>
<template #icon><SearchIcon><i class="ti ti-battery-vertical-eco"></i></SearchIcon></template>
<div class="_gaps_s">
<SearchMarker :keywords="['blur']">
@ -567,7 +567,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['datasaver']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.dataSaver }}</SearchLabel></template>
<template #icon><i class="ti ti-antenna-bars-3"></i></template>
<template #icon><SearchIcon><i class="ti ti-antenna-bars-3"></i></SearchIcon></template>
<div class="_gaps_m">
<MkInfo>{{ i18n.ts.reloadRequiredToApplySettings }}</MkInfo>
@ -601,7 +601,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchMarker :keywords="['other']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.other }}</SearchLabel></template>
<template #icon><i class="ti ti-settings-cog"></i></template>
<template #icon><SearchIcon><i class="ti ti-settings-cog"></i></SearchIcon></template>
<div class="_gaps_m">
<div class="_gaps_s">