This is an automated email from the ASF dual-hosted git repository. imbajin pushed a commit to branch feat/oink-core-platform in repository https://gitbox.apache.org/repos/asf/hugegraph-doc.git
commit 4d6593dc6f172ebc15e81f28ccca548c37922dd2 Author: dark <[email protected]> AuthorDate: Fri Sep 4 19:19:18 2026 +0800 fix(ui): harden shell acceptance contracts - compile safe-area and translucent styles with Hugo Sass\n- expose sidebar restore only while the tree is collapsed\n- scope backlinks and image zoom to designed surfaces\n- add enabled and invalid AI build fixtures\n- verify CSP, social image, and feature-scope contracts --- assets/js/hugegraph-shell.js | 1 + assets/scss/_styles_project.scss | 4 +-- layouts/_partials/backlinks-sources.html | 21 +++++++++++++ layouts/_partials/content/image-zoom-config.html | 9 ++++++ layouts/_partials/navbar.html | 2 +- tests/ui-ai/ai-enabled.yaml | 8 +++++ tests/ui-ai/ai-invalid.yaml | 8 +++++ tests/ui-ai/ui-contract.test.cjs | 38 ++++++++++++++++++++++++ 8 files changed, 88 insertions(+), 3 deletions(-) diff --git a/assets/js/hugegraph-shell.js b/assets/js/hugegraph-shell.js index a66f6ec36..6bf630c34 100644 --- a/assets/js/hugegraph-shell.js +++ b/assets/js/hugegraph-shell.js @@ -130,6 +130,7 @@ var drawerOpen = html.getAttribute('data-td-shell-drawer') === 'open'; var isolated = desktop.matches ? collapsed : !drawerOpen; + if (restore) restore.hidden = !desktop.matches || !collapsed; sidebar.inert = isolated; if (isolated) sidebar.setAttribute('aria-hidden', 'true'); else sidebar.removeAttribute('aria-hidden'); diff --git a/assets/scss/_styles_project.scss b/assets/scss/_styles_project.scss index 7bae939f8..14bfd7e77 100644 --- a/assets/scss/_styles_project.scss +++ b/assets/scss/_styles_project.scss @@ -487,7 +487,7 @@ display: none; } -.hg-sidebar-restore { +.td-nav-util.hg-sidebar-restore { display: none; } @@ -507,7 +507,7 @@ pointer-events: none; } - .hg-sidebar-restore { + .td-nav-util.hg-sidebar-restore:not([hidden]) { display: inline-flex; } } diff --git a/layouts/_partials/backlinks-sources.html b/layouts/_partials/backlinks-sources.html new file mode 100644 index 000000000..f76a18b1f --- /dev/null +++ b/layouts/_partials/backlinks-sources.html @@ -0,0 +1,21 @@ +{{- /* HugeGraph exposes backlinks only for latest documentation. Historical + builds and non-doc sections retain their original, uncluttered output. */ -}} +{{- $page := . -}} +{{- $enabled := and + (eq ($page.Site.Params.version | default "latest") "latest") + (eq $page.Section "docs") +-}} +{{- if isset $page.Params "backlinks" -}} + {{- $enabled = partial "validate.html" (dict + "value" (index $page.Params "backlinks") "kind" "bool" + "fallback" $enabled "key" "front matter backlinks" + "where" $page.Path) -}} +{{- end -}} +{{- $sources := slice -}} +{{- if $enabled -}} + {{- $backlinkIndex := partialCached "backlinks-index.html" $page.Site $page.Site.Language.Lang -}} + {{- range sort (index $backlinkIndex $page.Path | default (slice)) "Path" -}} + {{- $sources = $sources | append . -}} + {{- end -}} +{{- end -}} +{{- return $sources -}} diff --git a/layouts/_partials/content/image-zoom-config.html b/layouts/_partials/content/image-zoom-config.html new file mode 100644 index 000000000..d6421621b --- /dev/null +++ b/layouts/_partials/content/image-zoom-config.html @@ -0,0 +1,9 @@ +{{- /* Docs and Blog use OINK's on-demand image preview in every version. */ -}} +{{- $enabled := in (slice "docs" "blog") .Section -}} +{{- if isset .Params "image_zoom" -}} + {{- $enabled = partial "validate.html" (dict + "value" (index .Params "image_zoom") "kind" "bool" + "fallback" $enabled "key" "front matter image_zoom" + "where" .Path) -}} +{{- end -}} +{{- return (dict "enable" $enabled) -}} diff --git a/layouts/_partials/navbar.html b/layouts/_partials/navbar.html index 852b21ecf..19f2d8396 100644 --- a/layouts/_partials/navbar.html +++ b/layouts/_partials/navbar.html @@ -54,7 +54,7 @@ the fixed controls — version, language, theme, GitHub. */ -}} <div class="td-nav-links td-nav-util-zone"> {{- if $drawerMode }} - <button class="td-nav-util hg-sidebar-restore" type="button" + <button class="td-nav-util hg-sidebar-restore" type="button" hidden data-td-shell-sidebar-toggle title="{{ T "ui_sidebar_expand" }}" aria-label="{{ T "ui_sidebar_expand" }}" aria-controls="td-shell-sidebar"> {{- partialCached "shell/icon.html" "panel-left" "sidebar-restore" -}} diff --git a/tests/ui-ai/ai-enabled.yaml b/tests/ui-ai/ai-enabled.yaml new file mode 100644 index 000000000..4ed54da7e --- /dev/null +++ b/tests/ui-ai/ai-enabled.yaml @@ -0,0 +1,8 @@ +params: + ai_search: + enabled: true + provider: kapa + website_id: test-website-id + source_groups: + en: test-latest-en + cn: test-latest-cn diff --git a/tests/ui-ai/ai-invalid.yaml b/tests/ui-ai/ai-invalid.yaml new file mode 100644 index 000000000..48dc01a27 --- /dev/null +++ b/tests/ui-ai/ai-invalid.yaml @@ -0,0 +1,8 @@ +params: + ai_search: + enabled: true + provider: kapa + website_id: test-website-id + source_groups: + en: test-latest-en + cn: '' diff --git a/tests/ui-ai/ui-contract.test.cjs b/tests/ui-ai/ui-contract.test.cjs index 1a18b8de3..fc65cba5b 100644 --- a/tests/ui-ai/ui-contract.test.cjs +++ b/tests/ui-ai/ui-contract.test.cjs @@ -14,6 +14,19 @@ test('disabled AI emits no widget or adapter markup', () => { assert.equal(config.includes('widget.kapa.ai'), false); }); +test('Kapa active resource is dynamic, exact-hosted, and never wildcarded', () => { + const adapter = read('assets/js/kapa-adapter.js'); + const hook = read('layouts/_partials/hooks/body-end.html'); + assert.match( + adapter, + /https:\/\/widget\.kapa\.ai\/kapa-widget\.bundle\.js/, + ); + assert.equal(adapter.includes('*.kapa.ai'), false); + assert.equal(adapter.includes('https://*'), false); + assert.equal(hook.includes('<script src="https://'), false); + assert.equal(hook.includes('widget.kapa.ai'), false); +}); + test('theme color and social fallback have one configuration authority', () => { const config = read('hugo.yaml'); const css = read('assets/scss/_styles_project.scss'); @@ -38,6 +51,18 @@ test('documentation menu has five groups and no duplicate version panel', () => assert.equal(navbarItem.includes('$hasVersionLinks'), false); }); +test('backlinks are limited to latest documentation', () => { + const partial = read('layouts/_partials/backlinks-sources.html'); + assert.match(partial, /Params\.version/); + assert.match(partial, /"latest"/); + assert.match(partial, /\.Section "docs"/); +}); + +test('image zoom is limited to docs and blog', () => { + const partial = read('layouts/_partials/content/image-zoom-config.html'); + assert.match(partial, /slice "docs" "blog"/); +}); + test('shell persistence uses the version and locale scoped key', () => { const source = read('assets/js/hugegraph-shell.js'); assert.match(source, /oink\.sidebar\.v1\./); @@ -45,3 +70,16 @@ test('shell persistence uses the version and locale scoped key', () => { assert.match(source, /config\.locale/); assert.match(source, /sidebar\.inert = isolated/); }); + +test('social fallback asset is exactly 1200 by 630 pixels', () => { + const image = fs.readFileSync( + path.join(root, 'static/img/social/hugegraph-default.png'), + ); + assert.deepEqual( + [...image.subarray(12, 16)], + [0x49, 0x48, 0x44, 0x52], + 'PNG must start with an IHDR chunk', + ); + assert.equal(image.readUInt32BE(16), 1200); + assert.equal(image.readUInt32BE(20), 630); +});
