From 6a7bde3976ca622f6b95faa77e79c087b04f8d32 Mon Sep 17 00:00:00 2001 From: Karsa Date: Tue, 23 May 2023 13:37:17 +0200 Subject: [PATCH] Sort related icons by similarity + somewhat better name similarity matching --- docs/.vitepress/theme/types.ts | 1 + docs/icons/[name].paths.ts | 41 +++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/docs/.vitepress/theme/types.ts b/docs/.vitepress/theme/types.ts index 34e60c6d9..9d455a47a 100644 --- a/docs/.vitepress/theme/types.ts +++ b/docs/.vitepress/theme/types.ts @@ -5,6 +5,7 @@ export interface IconEntity { tags: string[]; categories: string[]; contributors: string[]; + aliases?: string[]; iconNode: IconNode; createdRelease?: Release; changedRelease?: Release; diff --git a/docs/icons/[name].paths.ts b/docs/icons/[name].paths.ts index 5c0a1065e..25ec0bfda 100644 --- a/docs/icons/[name].paths.ts +++ b/docs/icons/[name].paths.ts @@ -2,19 +2,38 @@ import Fuse from "fuse.js"; import { getAllData } from "../.vitepress/lib/icons"; import { IconEntity } from "../.vitepress/theme/types"; -// TODO: This should be ordered by relevance -const getRelatedIcons = (currentIcon:IconEntity, icons: IconEntity[]) => { - return icons.filter((icon) => { - const { name: iconName, tags, categories } = icon; - const isNameRelated = iconName.includes(currentIcon.name); +const nameWeight = 5; +const tagWeight = 4; +const categoryWeight = 3; - const hasRelatedTags = tags?.some((tag) => currentIcon?.tags?.includes(tag)); - const hasRelatedCategories = categories?.some((category) => - currentIcon?.categories?.includes(category) - ); +const arrayMatches = (a: string[], b: string[]) => { + let matches = 0; + for (let i = 0; i < a.length; ++i) { + if (b.indexOf(a[i]) != -1) { + matches++; + } + } + return matches; +} - return isNameRelated || hasRelatedTags || hasRelatedCategories; - }); +const nameParts = (icon: IconEntity) => [icon.name, ...icon.aliases ?? []] + .join('-') + .split('-') + .filter(word => word.length > 2) + +const getRelatedIcons = (currentIcon: IconEntity, icons: IconEntity[]) => { + const iconSimilarity = (item: IconEntity) => + nameWeight * arrayMatches(nameParts(item), nameParts(currentIcon)) + + categoryWeight * arrayMatches(item.categories, currentIcon.categories) + + tagWeight * arrayMatches(item.tags, currentIcon.tags) + ; + return icons + .filter(i => i.name !== currentIcon.name) + .map(icon => ({icon, similarity: iconSimilarity(icon)})) + .filter(a => a.similarity > 0) // @todo: maybe require a minimal non-zero similarity + .sort((a, b) => b.similarity - a.similarity) + .map(i => i.icon) + ; } export default {