Skip to content

Commit 5218675

Browse files
Migrate docs header & footer (server-rendered); header search uses our /search-index.json
- baseof.html renders site-header (top of wrapper) + site-footer (bottom); dropped the wrapper-space-top offset since the header is now in-flow (matches docs.groupdocs.com). - foot.html no longer loads the runtime Containerize menu engine (containerize-menu.html left unused). - site-header.html: docs header markup + current menu links (API Reference → reference.groupdocs.com, Live Demos → products.groupdocs.app, etc.); search slot now renders partials/header-search.html; removed the dark/light theme toggle (site is light-only) and the Dynabic login placeholder. - header-search.html (new): this site's own /search-index.json live search (the same engine as the home page), revealed by the header #search_toggle; result rows reuse the gd-home result styles. - site-footer.html: docs footer. - custom.css: header-search reveal overlay + results dropdown. The 404 (layouts/404.html, which uses define "main" → baseof) inherits the new header/footer.
1 parent 10ae19e commit 5218675

8 files changed

Lines changed: 230 additions & 117 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ tags), so changes accumulate under **[Unreleased]**.
3939
- Comprehensive README, `CLAUDE.md`, and this changelog.
4040

4141
### Changed
42+
- **Migrated the docs.groupdocs.com header & footer** to be **server-rendered** (`partials/site-header.html`
43+
+ `site-footer.html`, wired in `_default/baseof.html`), replacing the runtime Containerize menu engine
44+
(`foot.html` no longer loads `containerize-menu`). The header **search box uses this site's own
45+
`/search-index.json` live search** (new `partials/header-search.html`, the same engine as the home page),
46+
not the docs AI search. Removed the non-functional dark/light theme toggle (the site is light-only) and
47+
the Dynabic login placeholder; dropped the `wrapper-space-top` offset (the header is now in-flow).
4248
- **Redesigned the product family/landing pages** (Claude Design handoff): full-width two-column layout
4349
(platform-variant sidebar + main), breadcrumb, a lead auto-extended with "…a single, consistent API
4450
across <platforms>", a meta row (platforms · formats · **latest = the highest** version across

CLAUDE.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ obvious from the code.
6767

6868
## Theme (`themes/docs/`, vendored Geekdoc — not a submodule)
6969
- `_default/baseof.html`: sidebar nav disabled for `.Kind == "404"` (404 renders full-width/centered).
70+
- **Header & footer** are **server-rendered** in `baseof.html` from `partials/site-header.html` +
71+
`partials/site-footer.html` (migrated from docs.groupdocs.com). This **replaced the runtime Containerize
72+
menu engine**`partials/foot.html` no longer loads `partials/containerize-menu.html` (left in place,
73+
unused). The header **search uses this site's own `/search-index.json`** via `partials/header-search.html`
74+
(same engine as the home `gd-home` search), revealed by the `#search_toggle` button; the docs AI search
75+
(`search-input.html`) is unused for the header. Site is light-only (no theme toggle). The `.gdoc-*`
76+
header/footer CSS is loaded by `head/others` (`main-groupdocs.css` etc.).
7077
- `partials/menu-filetree.html`: **scoped** nav (current branch only) for page weight — **do not revert to the full tree**.
7178
- `assets/custom.css`: fingerprinted (loaded via `head/others`). Holds `gd-family*`, `gd-platform*`, `gd-404*` styles.
7279
Gotcha: theme has `.gdoc-page h2 { line-height/margin-top: 2.5rem }` and global `h1..h6 { display:flex }`

themes/docs/assets/custom.css

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -709,4 +709,25 @@ a.gd-home__ai-card:hover { border-color: #2563eb; box-shadow: 0 6px 18px rgba(37
709709
.gd-home__lead { font-size: 1rem; }
710710
.gd-home__ai { padding: 1.5rem; }
711711
.gd-home__rpath { display: none; }
712-
}
712+
}
713+
714+
/* ===== Header search (this site's /search-index.json engine, revealed by the header #search_toggle) =====
715+
Reuses the home result rows (.gd-home__result*). The .gdoc-header__search slot is display:none by
716+
default (main-groupdocs.css); #search_toggle adds .is-open to reveal it as an overlay over the header. */
717+
.gdoc-header__content { position: relative; }
718+
.gdoc-header__search.is-open {
719+
display: flex; align-items: center; width: auto; margin: 0;
720+
position: absolute; left: 0; right: 0; top: 0; height: 70px;
721+
padding: 0 15px; background: #fff; z-index: 60;
722+
}
723+
.gdoc-header__search.is-open .gdoc-search { flex: 1; width: 100%; }
724+
.gdoc-search__close-btn { flex: none; border: 0; background: transparent; cursor: pointer; padding: .25rem; margin-left: .25rem; color: #94a3b8; display: inline-flex; align-items: center; }
725+
.gdoc-search__close-btn:hover { color: var(--body-font-color, #0f1727); }
726+
.gdoc-search__close-btn .gdoc-search__close-icon { width: 1.15rem; height: 1.15rem; }
727+
.gd-hdr-results {
728+
position: absolute; top: 100%; left: 0; right: 0; z-index: 60;
729+
background: #fff; border: 1px solid #EBEBEC; border-radius: 0 0 12px 12px;
730+
box-shadow: 0 16px 40px rgba(15, 23, 39, .14); overflow: hidden;
731+
max-height: 75vh; overflow-y: auto; text-align: left;
732+
}
733+
@media (max-width: 48rem) { .gd-hdr-results .gd-home__rpath { display: none; } }

themes/docs/layouts/_default/baseof.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,13 @@
3535
{{ partial "svg-icon-symbols" . }}
3636

3737
<div
38-
class="wrapper wrapper-space-top {{ if default false .Site.Params.GeekdocDarkModeDim }}dark-mode-dim{{ end }} {{ if not $navEnabled }}wrapper-bg{{ end }}"
38+
class="wrapper {{ if default false .Site.Params.GeekdocDarkModeDim }}dark-mode-dim{{ end }} {{ if not $navEnabled }}wrapper-bg{{ end }}"
3939
>
4040
<input type="checkbox" class="hidden" id="menu-control" />
4141
<input type="checkbox" class="hidden" id="menu-header-control" />
42-
42+
43+
{{ partial "site-header" . }}
44+
4345
{{ $aiSearchEnabled := false }}
4446
{{ $url := $.RelPermalink }}
4547
{{ $slittedUrl := split $url "/" }}
@@ -67,6 +69,8 @@
6769
</main>
6870

6971
{{ partial "go-top" . }}
72+
73+
{{ partial "site-footer" . }}
7074
</div>
7175
{{ partial "foot" . }}
7276
</body>

themes/docs/layouts/partials/foot.html

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
<!-- JS scripts -->
22
<script defer src="{{ index (index .Site.Data.assets "groupdocs.js") "src" | relURL }}"></script>
33

4-
{{ partial "containerize-menu" . }}
5-
64
{{ if default false .Params.LiveChatScript }}
75
<script>
86
function openLiveChat() {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
{{- /* Header search: reference.groupdocs.com's own live search over the combined /search-index.json —
2+
the SAME engine as the home page (gd-home). Revealed by the header's #search_toggle button.
3+
Replaces the docs AI/geekdoc header search. Global scope (all products); fetches the bucket-root
4+
/search-index.json so it works across every per-product build. Result rows reuse the gd-home
5+
result styles (.gd-home__result*). */ -}}
6+
<div class="gdoc-search flex align-center" role="search">
7+
<svg class="gdoc-search__search-icon"><use xlink:href="/img/groupdocs-stack.svg#search_control"></use></svg>
8+
<input type="text" id="gd-hdr-q" class="gdoc-search__input" placeholder="Search classes, methods, namespaces…"
9+
aria-label="Search the API reference" aria-controls="gd-hdr-results" aria-autocomplete="list"
10+
autocomplete="off" maxlength="64" />
11+
<button type="button" id="gd-hdr-close" class="gdoc-search__close-btn" aria-label="Close search">
12+
<svg class="gdoc-search__close-icon"><use xlink:href="/img/groupdocs-stack.svg#search_close"></use></svg>
13+
</button>
14+
</div>
15+
<div id="gd-hdr-results" class="gd-hdr-results" role="listbox" hidden></div>
16+
17+
<script>
18+
/* Header search — reveal toggle + live results over /search-index.json (same engine as the home page). */
19+
(function () {
20+
var wrap = document.querySelector(".gdoc-header__search");
21+
var toggle = document.getElementById("search_toggle");
22+
var closeB = document.getElementById("gd-hdr-close");
23+
var input = document.getElementById("gd-hdr-q");
24+
var box = document.getElementById("gd-hdr-results");
25+
if (!wrap || !input || !box) return;
26+
27+
function open() { wrap.classList.add("is-open"); setTimeout(function () { input.focus(); }, 0); }
28+
function shut() { wrap.classList.remove("is-open"); hide(); }
29+
if (toggle) toggle.addEventListener("click", function (e) {
30+
e.preventDefault(); wrap.classList.contains("is-open") ? shut() : open();
31+
});
32+
if (closeB) closeB.addEventListener("click", function (e) { e.preventDefault(); shut(); });
33+
document.addEventListener("click", function (e) {
34+
if (!wrap.classList.contains("is-open")) return;
35+
if (wrap.contains(e.target) || (toggle && toggle.contains(e.target))) return;
36+
shut();
37+
});
38+
39+
var index = null, loading = false, items = [], active = -1, MAX = 8;
40+
function load() {
41+
if (index || loading) return;
42+
loading = true;
43+
fetch("/search-index.json").then(function (r) { return r.json(); })
44+
.then(function (d) { index = d; if (input.value.trim()) run(input.value); })
45+
.catch(function () { index = []; });
46+
}
47+
function kindOf(e) {
48+
if (e.u.indexOf("/guides/") !== -1) return ["Guide", "g"];
49+
if (!e.p) return ["Product", "pr"];
50+
var t = e.t || "";
51+
if (t.indexOf(".") !== -1 && t === t.toLowerCase()) return ["Namespace", "ns"];
52+
if (/^[A-Z]/.test(t) && t.indexOf(" ") === -1) return ["Type", "ty"];
53+
return ["Page", "pg"];
54+
}
55+
function pathOf(e) { return e.u.split("/").filter(Boolean).slice(0, -1).join(" / "); }
56+
function esc(s) { return s.replace(/[&<>"]/g, function (c) { return ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;" })[c]; }); }
57+
function highlight(t, q) {
58+
var i = t.toLowerCase().indexOf(q.toLowerCase());
59+
if (i === -1) return esc(t);
60+
return esc(t.slice(0, i)) + "<mark>" + esc(t.slice(i, i + q.length)) + "</mark>" + esc(t.slice(i + q.length));
61+
}
62+
function score(e, q) {
63+
var t = (e.t || "").toLowerCase();
64+
if (t === q) return 0;
65+
if (t.indexOf(q) === 0) return 1;
66+
if (t.indexOf(q) !== -1) return 2;
67+
if (e.u.toLowerCase().indexOf(q) !== -1) return 3;
68+
return 99;
69+
}
70+
function run(q) {
71+
q = q.trim().toLowerCase();
72+
if (!q) { hide(); return; }
73+
if (!index) { load(); return; }
74+
var hits = [];
75+
for (var i = 0; i < index.length; i++) { var s = score(index[i], q); if (s < 99) hits.push([s, index[i]]); }
76+
hits.sort(function (a, b) { return a[0] - b[0] || a[1].t.length - b[1].t.length; });
77+
items = hits.slice(0, MAX).map(function (h) { return h[1]; });
78+
render(q, hits.length);
79+
}
80+
function render(q, total) {
81+
if (!items.length) {
82+
box.innerHTML = '<div class="gd-home__noresult">No results for <strong>' + esc(q) + '</strong>.</div>';
83+
box.hidden = false; active = -1; return;
84+
}
85+
active = 0;
86+
var html = items.map(function (e, i) {
87+
var k = kindOf(e);
88+
return '<a class="gd-home__result' + (i === 0 ? " is-active" : "") + '" role="option" href="' + esc(e.u) + '" data-i="' + i + '">'
89+
+ '<span class="gd-home__rk gd-home__rk--' + k[1] + '">' + k[0] + '</span>'
90+
+ '<span class="gd-home__rmain"><span class="gd-home__rname">' + highlight(e.t, q) + '</span>'
91+
+ '<span class="gd-home__rpath">' + esc(pathOf(e)) + '</span></span>'
92+
+ (e.p ? '<span class="gd-home__rplat">' + esc(e.p) + '</span>' : '') + '</a>';
93+
}).join("");
94+
if (total > items.length) html += '<div class="gd-home__more">' + total + ' matches — refine your search to narrow it down</div>';
95+
box.innerHTML = html; box.hidden = false;
96+
Array.prototype.forEach.call(box.querySelectorAll(".gd-home__result"), function (el) {
97+
el.addEventListener("mouseenter", function () { setActive(+el.getAttribute("data-i")); });
98+
});
99+
}
100+
function hide() { box.hidden = true; box.innerHTML = ""; active = -1; }
101+
function setActive(i) {
102+
var rows = box.querySelectorAll(".gd-home__result");
103+
if (!rows.length) return;
104+
active = (i + rows.length) % rows.length;
105+
Array.prototype.forEach.call(rows, function (el, j) { el.classList.toggle("is-active", j === active); });
106+
rows[active].scrollIntoView({ block: "nearest" });
107+
}
108+
function gotoActive() {
109+
var rows = box.querySelectorAll(".gd-home__result");
110+
if (rows.length && active >= 0) { window.location.href = rows[active].getAttribute("href"); }
111+
}
112+
input.addEventListener("focus", load);
113+
input.addEventListener("input", function () { run(input.value); });
114+
input.addEventListener("keydown", function (e) {
115+
if (e.key === "Escape") { if (input.value) { input.value = ""; hide(); } else { shut(); } return; }
116+
if (box.hidden) return;
117+
if (e.key === "ArrowDown") { e.preventDefault(); setActive(active + 1); }
118+
else if (e.key === "ArrowUp") { e.preventDefault(); setActive(active - 1); }
119+
else if (e.key === "Enter") { e.preventDefault(); gotoActive(); }
120+
});
121+
})();
122+
</script>

themes/docs/layouts/partials/site-footer.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<img class="gdoc-footer__logo" src="/logo-white.svg" />
99

1010
<ul class="gdoc-footer__menu">
11-
<li><a href="https://products.groupdocs.com">Products</a> </li>
11+
<li><a href="https://products.groupdocs.com/">Products</a> </li>
1212
<li><a href="https://helpdesk.groupdocs.com/">Support</a> </li>
1313
<li><a rel="nofollow" href="https://websites.groupdocs.com/">Websites</a></li>
1414
<li><a rel="nofollow" href="https://about.groupdocs.com/">About</a></li>
@@ -22,9 +22,9 @@
2222
© Groupdocs 2001-{{ now.Format "2006"}}. All Rights Reserved.
2323
</div>
2424
<ul class="gdoc-footer__bottom-menu">
25-
<li><a href="https://about.groupdocs.com/legal/privacy-policy">Privacy Policy</a> </li>
26-
<li><a href="https://about.groupdocs.com/legal/terms-of-use">Terms of use</a> </li>
27-
<li><a href="https://about.groupdocs.com/contact">Contact</a></li>
25+
<li><a href="https://about.groupdocs.com/legal/privacy-policy/">Privacy Policy</a> </li>
26+
<li><a href="https://about.groupdocs.com/legal/terms-of-use/">Terms of use</a> </li>
27+
<li><a href="https://about.groupdocs.com/contact/">Contact</a></li>
2828

2929
</ul>
3030
</div>

0 commit comments

Comments
 (0)