/// /// /// /** @jsx h */ /** @jsxFrag Fragment */ import { Fragment, h, render } from "https://esm.sh/preact@10.6.4"; import { useCallback, useMemo, useState, } from "https://esm.sh/preact@10.6.4/hooks"; import { Asearch, MatchResult } from "../deno-asearch/mod.ts"; import { data } from "./data.ts"; import { getMaxDistance } from "./distance.ts"; export const mount = () => { const app = document.createElement("div"); const shadowRoot = app.attachShadow({ mode: "open" }); document.body.append(app); remove = () => app.remove(); render(, shadowRoot); }; let remove: () => void; const App = () => { const [pattern, setPattern] = useState(""); const candidates = useMemo( () => { const match = Asearch(` ${pattern} `).match; const len = pattern.length; if (len === 0) return []; const maxDistance = getMaxDistance[len]; const candidates = data.flatMap( (candidate) => { const result = match(candidate, maxDistance); if (!result.found) return []; return { candidate, distance: result.distance }; } ) /*const candidates = scrapbox.Project.pages.flatMap( (page) => { const result = match(page.title, maxDistance); if (!result.found) return []; return { candidate: page.title, distance: result.distance, updated: page.updated, }; } )*/ // 1. 編集距離 2. 文字列超 3. 辞書順序 が小さい順に並び替える .sort((a, b) => { const diff = a.distance - b.distance; if (diff !== 0) return diff; //const time = b.updated - a.updated; //if (time !== 0) return time; const lenDiff = a.candidate.length - b.candidate.length; if (lenDiff !== 0) return lenDiff; return a.candidate.localeCompare(b.candidate); }); return candidates; }, [pattern], ); const handlePattern = useCallback( (e: h.JSX.TargetedEvent) => setPattern(e.currentTarget.value.trim()), [], ); return ( <>

{candidates.length > 0 ? `Matched ${candidates.length} words` : "No matched"}

    {candidates.map(({ candidate }) => (
  • {candidate}
  • ))}

); };