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);
+});

Reply via email to