mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-26 17:01:20 -08:00
fix(site): [SITE-05] repair search interactions and align peer dependency
This commit is contained in:
1 parent
61fe8deb59
commit
6b580d1667
90 files changed
+859
-365
No files matched your search
@@ -31,7 +31,7 @@ not a VitePress page. Keep both URL surfaces compatible.
|
||||
| `docs/proxy/canvas.md`, `docs/en/proxy/canvas.md` | Backing video, draw callbacks/events, Canvas priority, subtitles and compatible types | `/document/proxy/canvas.html`, `/document/en/proxy/canvas.html` |
|
||||
| `docs/proxy/mediabunny.md`, `docs/en/proxy/mediabunny.md` | Input, HLS pairing, synthetic media state, lifecycle and explicit type views | `/document/proxy/mediabunny.html`, `/document/en/proxy/mediabunny.html` |
|
||||
| `docs/.vitepress/config.js` | Navigation, base URL, output path, page head | Repository `docs/document/` |
|
||||
| `docs/vite.config.ts` | Search plugin configuration | VitePress/Vite integration; real search acceptance remains pending |
|
||||
| `docs/vite.config.ts`, `build/search.ts` | Search configuration and pinned upstream interaction adapter | Preserves the search template, CSS hooks, index and result URLs |
|
||||
| `docs/public/main.js` | Run Code links and first-visit language redirect | Copied into the built site |
|
||||
| `docs/public/style.css` | Documentation presentation | Copied into the built site |
|
||||
|
||||
@@ -45,9 +45,38 @@ serve different purposes. Neither path check replaces browser navigation tests.
|
||||
|
||||
The generated site lives in `docs/document/`. The current inventory contains 66 Markdown pages: 33 Chinese
|
||||
and 33 English. All 16 plugins, both tools and both proxies have dedicated guides and navigation in both languages.
|
||||
Core member
|
||||
mapping and the current cross-check of earlier guides remain in SITE-04;
|
||||
navigation links alone are not complete API documentation.
|
||||
SITE-04 completed the 963 core declaration mappings and cross-checked all 40
|
||||
ecosystem guides. Full site execution and delivery remain in SITE-05/SITE-06;
|
||||
navigation links alone do not establish player or plugin playback compatibility.
|
||||
|
||||
### Local documentation search
|
||||
|
||||
`vitepress-plugin-search` 1.0.4-alpha.22 supplies the shared Chinese/English
|
||||
index and existing search UI. Its FlexSearch peer is pinned to 0.7.43 in this
|
||||
workspace, within the declared `^0.7.31` range. The plugin also embeds its own
|
||||
index implementation, so changing this peer alone does not fix UI behavior.
|
||||
Its existing token matching is retained; Chinese substring segmentation is not
|
||||
promised. The Algolia/search-insights peer warnings originate from VitePress's
|
||||
unused hosted-search dependencies; this site does not configure that provider.
|
||||
|
||||
`build/search.ts` runs before Vue compilation. It checks the exact installed
|
||||
component hash, normalizes CRLF for patch matching, and requires each replacement
|
||||
to match once. It prevents Enter from submitting the HTML form, navigates the
|
||||
selected result through the router, handles empty results and composition,
|
||||
resets selection when queries change, and makes Escape close the modal and
|
||||
restore button focus. Focus waits for Vue's DOM update rather than a timer.
|
||||
The component owns its shortcut listener and removes it on unmount; a late index
|
||||
import cannot attach it after unmount. Upstream HTML/CSS and third-party attribution
|
||||
stay intact. Do not modify `node_modules` or simply update the hash on an upgrade:
|
||||
review these interactions and the new upstream component first.
|
||||
|
||||
Use `yarn test:site-build` for the pinned-component compilation and drift guard,
|
||||
`yarn typecheck:docs-tools` for the adapter, and rebuild with `yarn build:docs`
|
||||
before `yarn test:browser:source document-search.spec.js document-site.spec.js`.
|
||||
Browser checks cover both language URLs, pointer navigation, keyboard selection,
|
||||
Escape, focus, no results, and retained document identity (no form reload).
|
||||
They isolate external scripts and do not validate AdSense, physical devices,
|
||||
all search-index anchors or the complete online editor; those remain SITE-05 work.
|
||||
|
||||
Tools have their own navigation group. Iframe explains the required child inject
|
||||
step and serialized commit body, without treating the protocol as a sandbox or
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import type { Plugin } from 'vite'
|
||||
import assert from 'node:assert/strict'
|
||||
import { createHash } from 'node:crypto'
|
||||
|
||||
// Keep the pinned upstream template, CSS, index and URLs; patch interaction ownership only.
|
||||
const componentHash = 'c53a0d2a5b5380123f775b0852b5805a4b0a3d97248d5c296972de30c35f6f9c'
|
||||
|
||||
export function patchSearchComponent(source: string): string {
|
||||
assert.equal(createHash('sha256').update(source).digest('hex'), componentHash, 'Review the search interaction adapter before upgrading vitepress-plugin-search')
|
||||
let result = source.replaceAll('\r\n', '\n')
|
||||
const replace = (before: string, after: string) => {
|
||||
assert.equal(result.split(before).length, 2, `Expected one search patch target: ${before}`)
|
||||
result = result.replace(before, after)
|
||||
}
|
||||
replace('ref, onMounted, computed, nextTick', 'ref, onMounted, onUnmounted, computed, nextTick, watch')
|
||||
replace('if (searchTerm.value) {', 'if (searchTerm.value && searchIndex.value) {')
|
||||
replace(`const openSearch = () => {
|
||||
setTimeout(() => {
|
||||
if (input.value) input.value.focus();
|
||||
}, 100);
|
||||
cleanSearch();
|
||||
open.value = true;
|
||||
};`, `const openSearch = () => {
|
||||
cleanSearch();
|
||||
open.value = true;
|
||||
nextTick(() => { if (alive && open.value) input.value?.focus(); });
|
||||
};`)
|
||||
replace('onMounted(async () => {', `let alive = true;
|
||||
let removeHotKey = () => {};
|
||||
onUnmounted(() => { alive = false; removeHotKey(); });
|
||||
watch(searchTerm, () => { focused.value = 0; }, { flush: "sync" });
|
||||
onMounted(async () => {`)
|
||||
replace('const data = await import("virtual:search-data");', 'const data = await import("virtual:search-data");\n if (!alive) return;')
|
||||
replace('if (searchTerm.value?.length == 0 && open.value)\n open.value = false', 'if (open.value) {\n e.preventDefault();\n cleanSearch();\n documentButton()?.focus();\n }')
|
||||
replace('window.addEventListener("keydown", handleSearchHotKey);', 'window.addEventListener("keydown", handleSearchHotKey);\n removeHotKey = () => window.removeEventListener("keydown", handleSearchHotKey);')
|
||||
replace('<form class="DocSearch-Form">', '<form class="DocSearch-Form" @submit.prevent>')
|
||||
|
||||
const start = result.indexOf('const handleNavigation = (e: KeyboardEvent) => {')
|
||||
const end = result.indexOf('</script>', start)
|
||||
assert(start > 0 && end > start, 'Missing pinned search keyboard handler')
|
||||
result = `${result.slice(0, start)}function documentButton() {
|
||||
return document.querySelector<HTMLButtonElement>("#docsearch button");
|
||||
}
|
||||
const handleNavigation = (e: KeyboardEvent) => {
|
||||
if (e.isComposing || !["ArrowUp", "ArrowDown", "Enter"].includes(e.key)) return;
|
||||
e.preventDefault();
|
||||
const links = Array.from(modal.value?.querySelectorAll<HTMLAnchorElement>(".search-group a") || []);
|
||||
if (!links.length) return;
|
||||
const current = links.findIndex(link => link.classList.contains("link-focused"));
|
||||
if (e.key === "Enter") {
|
||||
const href = links[Math.max(current, 0)].href;
|
||||
cleanSearch();
|
||||
void router.go(href);
|
||||
return;
|
||||
}
|
||||
const delta = e.key === "ArrowDown" ? 1 : -1;
|
||||
const next = (Math.max(current, 0) + delta + links.length) % links.length;
|
||||
focused.value = linksOrder.value[next];
|
||||
links[next].scrollIntoView({ block: "nearest" });
|
||||
};
|
||||
${result.slice(end)}`
|
||||
return result
|
||||
}
|
||||
|
||||
export function searchInteractions(): Plugin {
|
||||
return {
|
||||
name: 'artplayer-search-interactions',
|
||||
enforce: 'pre',
|
||||
transform(source, id) {
|
||||
if (id.replaceAll('\\', '/').endsWith('/vitepress-plugin-search/dist/Search.vue'))
|
||||
return { code: patchSearchComponent(source), map: null }
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
import { SearchPlugin } from "vitepress-plugin-search";
|
||||
import { searchInteractions } from '../build/search.ts';
|
||||
|
||||
export default {
|
||||
plugins: [
|
||||
searchInteractions(),
|
||||
SearchPlugin({
|
||||
placeholder: "Search docs",
|
||||
buttonLabel: "Search",
|
||||
previewLength: 62,
|
||||
}),
|
||||
],
|
||||
};
|
||||
};
|
||||
@@ -8,7 +8,7 @@
|
||||
"preview": "vitepress preview docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"flexsearch": "0.8.158",
|
||||
"flexsearch": "0.7.43",
|
||||
"markdown-it": "14.1.0",
|
||||
"vitepress": "1.6.3",
|
||||
"vitepress-plugin-search": "1.0.4-alpha.22",
|
||||
|
||||
Reference in new issue
Block a user