blume 0.5.3 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +3349 -7024
- package/dist/cli/index.js.map +39 -69
- package/dist/types/core/config.d.ts +0 -8
- package/dist/types/core/data.d.ts +6 -2
- package/dist/types/core/i18n-ui.d.ts +50 -0
- package/dist/types/core/schema.d.ts +379 -485
- package/dist/types/core/types.d.ts +8 -6
- package/docs/advanced/meta.ts +1 -8
- package/docs/advanced/skills.mdx +28 -0
- package/docs/configuration/ai.mdx +58 -0
- package/docs/configuration/index.mdx +13 -17
- package/docs/configuration/seo.mdx +59 -1
- package/docs/configuration/theming.mdx +15 -18
- package/docs/content/components.mdx +2 -53
- package/docs/content/i18n.mdx +0 -4
- package/docs/content/meta.mdx +3 -17
- package/docs/content/navigation.mdx +41 -4
- package/docs/content/syntax.mdx +1 -1
- package/docs/index.mdx +0 -1
- package/docs/reference/cli.mdx +12 -13
- package/package.json +6 -6
- package/skills/blume/SKILL.md +71 -0
- package/skills/blume-update-docs/SKILL.md +52 -0
- package/skills/blume-update-docs/references/audit-checklist.md +46 -0
- package/src/ai/agent-readability.ts +97 -0
- package/src/ai/ask-context.ts +131 -8
- package/src/ai/ask-data.ts +4 -1
- package/src/astro/generate.ts +19 -12
- package/src/astro/integration.ts +0 -21
- package/src/astro/templates.ts +33 -21
- package/src/cli/commands/build.ts +15 -0
- package/src/cli/commands/dev.ts +31 -20
- package/src/cli/commands/validate.ts +0 -2
- package/src/cli/dev-lock.ts +94 -21
- package/src/cli/index.ts +0 -2
- package/src/components/BlumePage.astro +0 -6
- package/src/components/Icon.astro +1 -12
- package/src/components/content/AccordionItem.astro +3 -6
- package/src/components/content/Badge.astro +1 -3
- package/src/components/content/Callout.astro +3 -9
- package/src/components/content/Card.astro +2 -3
- package/src/components/content/ColorItem.astro +2 -2
- package/src/components/content/Column.astro +1 -1
- package/src/components/content/GithubInfo.astro +11 -10
- package/src/components/content/Prompt.astro +1 -1
- package/src/components/content/Step.astro +3 -4
- package/src/components/content/Tab.astro +2 -3
- package/src/components/content/TypeTable.astro +13 -8
- package/src/components/content/Update.astro +1 -1
- package/src/components/islands/AskAI.astro +66 -2
- package/src/components/islands/ask-ai.tsx +289 -53
- package/src/components/layout/Header.astro +27 -4
- package/src/components/layout/Logo.astro +5 -1
- package/src/components/layout/NavSelector.astro +1 -1
- package/src/components/layout/NavTree.astro +15 -15
- package/src/components/layout/PageActions.astro +73 -30
- package/src/components/layout/PageLayout.astro +42 -0
- package/src/components/layout/ReferenceLayout.astro +1 -0
- package/src/components/layout/RootLayout.astro +79 -4
- package/src/components/layout/Search.astro +5 -5
- package/src/components/layout/nav-utils.ts +9 -4
- package/src/components/openapi/ApiOverview.astro +4 -50
- package/src/components/openapi/ApiTagOperations.astro +42 -0
- package/src/core/builtin-tags.ts +1 -3
- package/src/core/config.ts +5 -28
- package/src/core/data.ts +6 -2
- package/src/core/graph.ts +8 -6
- package/src/core/i18n-ui.ts +5 -0
- package/src/core/links.ts +5 -19
- package/src/core/meta.ts +1 -1
- package/src/core/nav-diagnostics.ts +7 -0
- package/src/core/navigation.ts +38 -17
- package/src/core/project-graph.ts +0 -5
- package/src/core/schema.ts +133 -95
- package/src/core/sources/filesystem.ts +5 -1
- package/src/core/sources/resolve.ts +0 -13
- package/src/core/sources/watch.ts +43 -11
- package/src/core/types.ts +8 -6
- package/src/deploy/robots.ts +37 -4
- package/src/openapi/parse.ts +197 -14
- package/src/openapi/render-mdx.ts +44 -10
- package/src/openapi/scalar.ts +1 -1
- package/src/openapi/source.ts +19 -2
- package/src/search/documents.ts +9 -2
- package/src/theme/entry.ts +45 -17
- package/src/theme/icons.ts +18 -109
- package/src/theme/palette.ts +25 -51
- package/src/theme/twoslash.ts +6 -1
- package/dist/types/core/bridge.d.ts +0 -24
- package/dist/types/core/package-json.d.ts +0 -12
- package/dist/types/migrate/mintlify/assets.d.ts +0 -8
- package/dist/types/migrate/mintlify/config.d.ts +0 -16
- package/dist/types/migrate/mintlify/i18n.d.ts +0 -7
- package/dist/types/migrate/shared.d.ts +0 -153
- package/docs/advanced/bridge.mdx +0 -76
- package/docs/advanced/migrate.mdx +0 -124
- package/src/astro/static-assets.ts +0 -124
- package/src/cli/commands/migrate.ts +0 -39
- package/src/components/content/ApiField.astro +0 -75
- package/src/components/content/ParamField.astro +0 -39
- package/src/components/content/RequestField.astro +0 -23
- package/src/components/content/ResponseField.astro +0 -23
- package/src/components/content/Warning.astro +0 -9
- package/src/core/assets.ts +0 -31
- package/src/core/bridge.ts +0 -102
- package/src/core/sources/mintlify.ts +0 -190
- package/src/migrate/fumadocs/config.ts +0 -155
- package/src/migrate/fumadocs/content.ts +0 -376
- package/src/migrate/fumadocs/frontmatter.ts +0 -18
- package/src/migrate/fumadocs/groups.ts +0 -237
- package/src/migrate/fumadocs/index.ts +0 -355
- package/src/migrate/fumadocs/meta.ts +0 -244
- package/src/migrate/migrate.ts +0 -53
- package/src/migrate/mintlify/assets.ts +0 -46
- package/src/migrate/mintlify/config.ts +0 -954
- package/src/migrate/mintlify/content.ts +0 -120
- package/src/migrate/mintlify/frontmatter.ts +0 -126
- package/src/migrate/mintlify/i18n.ts +0 -51
- package/src/migrate/mintlify/icons.ts +0 -128
- package/src/migrate/mintlify/index.ts +0 -459
- package/src/migrate/mintlify/snippets.ts +0 -315
- package/src/migrate/mintlify/transform.ts +0 -82
- package/src/migrate/nextra/content.ts +0 -46
- package/src/migrate/nextra/frontmatter.ts +0 -40
- package/src/migrate/nextra/index.ts +0 -389
- package/src/migrate/nextra/meta.ts +0 -266
- package/src/migrate/shared.ts +0 -801
- package/src/migrate/starlight/config.ts +0 -455
- package/src/migrate/starlight/content.ts +0 -75
- package/src/migrate/starlight/frontmatter.ts +0 -111
- package/src/migrate/starlight/i18n.ts +0 -54
- package/src/migrate/starlight/index.ts +0 -131
|
@@ -18,6 +18,7 @@ interface Props {
|
|
|
18
18
|
dark?: string;
|
|
19
19
|
alt: string;
|
|
20
20
|
href: string;
|
|
21
|
+
text?: string;
|
|
21
22
|
} | null;
|
|
22
23
|
navigation: Navigation;
|
|
23
24
|
route: string;
|
|
@@ -57,6 +58,19 @@ const {
|
|
|
57
58
|
const LogoSlot = resolveSlot(layout.Logo, Logo);
|
|
58
59
|
const SearchSlot = resolveSlot(layout.Search, Search);
|
|
59
60
|
|
|
61
|
+
// The mobile nav-toggle opens a drawer of navigation. On docs pages that drawer
|
|
62
|
+
// is the sidebar tree (`hasSidebar`); on chrome-only pages (a landing page via
|
|
63
|
+
// PageLayout) it's a tabs-only drawer the layout renders — so the button is also
|
|
64
|
+
// needed whenever there are tabs to reveal.
|
|
65
|
+
const showNavToggle = hasSidebar || navigation.tabs.length > 0;
|
|
66
|
+
// Where the header's inline tab bar appears. With a sidebar it shares the `md`
|
|
67
|
+
// breakpoint with the docs drawer; without one, the tabs-only drawer is the sole
|
|
68
|
+
// mobile nav below `lg`, so the inline tabs wait until `lg` to avoid duplicating
|
|
69
|
+
// the drawer's links between `md` and `lg`.
|
|
70
|
+
const tabsNavClass = hasSidebar
|
|
71
|
+
? "hidden gap-1 md:flex"
|
|
72
|
+
: "hidden gap-1 lg:flex";
|
|
73
|
+
|
|
60
74
|
const iconButton =
|
|
61
75
|
"inline-flex size-9 cursor-pointer items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-muted hover:text-foreground";
|
|
62
76
|
|
|
@@ -68,14 +82,23 @@ const iconButton =
|
|
|
68
82
|
// styles fade while the non-animated ones snap, so we disable all transitions
|
|
69
83
|
// for the swap (next-themes' disableTransitionOnChange trick), force a
|
|
70
84
|
// synchronous style flush, then restore them on the next tick.
|
|
71
|
-
|
|
85
|
+
//
|
|
86
|
+
// The mobile drawer sits below the sticky header, but the banner above the
|
|
87
|
+
// header has no fixed height (its text wraps), so the drawer's top offset can't
|
|
88
|
+
// be static: on open we measure the header's on-screen bottom edge into
|
|
89
|
+
// `--blume-drawer-top` (read by the drawer's `top`/`height`), lock page scroll
|
|
90
|
+
// so the offset can't drift while open, and re-measure when a banner dismiss or
|
|
91
|
+
// a resize/rotation moves the header. Crossing into the desktop breakpoint
|
|
92
|
+
// (64rem, Tailwind `lg`) closes the drawer so the scroll lock can't outlive it.
|
|
93
|
+
const clickScript = `(()=>{const dr=()=>{const h=document.querySelector("[data-blume-header]");if(h){document.documentElement.style.setProperty("--blume-drawer-top",h.getBoundingClientRect().bottom+"px");}};document.addEventListener("click",(e)=>{const t=e.target.closest("[data-blume-theme-toggle]");if(t){const d=document.documentElement;const next=d.dataset.theme==="dark"?"light":"dark";const s=document.createElement("style");s.appendChild(document.createTextNode("*,*::before,*::after{transition:none!important}"));document.head.appendChild(s);d.dataset.theme=next;localStorage.setItem("blume-theme",next);window.getComputedStyle(d).opacity;setTimeout(()=>document.head.removeChild(s),1);}const n=e.target.closest("[data-blume-nav-toggle]");if(n){const d=document.documentElement;const open=d.toggleAttribute("data-blume-nav-open");if(open){dr();}d.style.overflow=open?"hidden":"";}const b=e.target.closest("[data-blume-banner-dismiss]");if(b){const bar=b.closest("[data-blume-banner]");const k=bar&&bar.getAttribute("data-banner-key");if(k){localStorage.setItem("blume-banner:"+k,"1");}document.documentElement.setAttribute("data-blume-banner-hidden","");requestAnimationFrame(dr);}});addEventListener("resize",()=>{const d=document.documentElement;if(!d.hasAttribute("data-blume-nav-open")){return;}if(matchMedia("(min-width:64rem)").matches){d.removeAttribute("data-blume-nav-open");d.style.overflow="";}else{dr();}});})();`;
|
|
72
94
|
---
|
|
73
95
|
|
|
74
96
|
<header
|
|
75
97
|
class="sticky top-0 z-40 flex h-16 items-center gap-3 bg-background/90 px-4 backdrop-blur md:px-6"
|
|
98
|
+
data-blume-header
|
|
76
99
|
>
|
|
77
100
|
{
|
|
78
|
-
|
|
101
|
+
showNavToggle && (
|
|
79
102
|
<button
|
|
80
103
|
aria-label="Toggle navigation"
|
|
81
104
|
class={`${iconButton} lg:hidden`}
|
|
@@ -98,7 +121,7 @@ const clickScript = `document.addEventListener("click",(e)=>{const t=e.target.cl
|
|
|
98
121
|
}
|
|
99
122
|
{
|
|
100
123
|
navigation.tabs.length > 0 && (
|
|
101
|
-
<nav aria-label="Sections" class=
|
|
124
|
+
<nav aria-label="Sections" class={tabsNavClass}>
|
|
102
125
|
{navigation.tabs.map((tab) => (
|
|
103
126
|
<a
|
|
104
127
|
aria-current={
|
|
@@ -117,7 +140,6 @@ const clickScript = `document.addEventListener("click",(e)=>{const t=e.target.cl
|
|
|
117
140
|
)
|
|
118
141
|
}
|
|
119
142
|
<div class="flex-1"></div>
|
|
120
|
-
<slot name="ask" />
|
|
121
143
|
{
|
|
122
144
|
localeSwitch && localeSwitch.length > 1 && (
|
|
123
145
|
<LanguageSwitcher
|
|
@@ -168,6 +190,7 @@ const clickScript = `document.addEventListener("click",(e)=>{const t=e.target.cl
|
|
|
168
190
|
<span class="inline-flex dark:hidden"><Icon name="sun" size={18} /></span>
|
|
169
191
|
<span class="hidden dark:inline-flex"><Icon name="moon" size={18} /></span>
|
|
170
192
|
</button>
|
|
193
|
+
<slot name="ask" />
|
|
171
194
|
</div>
|
|
172
195
|
</header>
|
|
173
196
|
<script is:inline set:html={clickScript} />
|
|
@@ -19,6 +19,10 @@ const logoLight = logo?.light;
|
|
|
19
19
|
const logoDark = logo?.dark ?? logo?.light;
|
|
20
20
|
const logoAlt = logo?.alt ?? "";
|
|
21
21
|
const brandHref = logo?.href ?? "/";
|
|
22
|
+
// Wordmark beside the mark: the configured `logo.text`, or the site title when
|
|
23
|
+
// it's omitted. An explicit `""` hides it (an image-only logo whose mark already
|
|
24
|
+
// carries the wordmark).
|
|
25
|
+
const brandText = logo?.text ?? site.title;
|
|
22
26
|
---
|
|
23
27
|
|
|
24
28
|
<a
|
|
@@ -46,5 +50,5 @@ const brandHref = logo?.href ?? "/";
|
|
|
46
50
|
</>
|
|
47
51
|
))
|
|
48
52
|
}
|
|
49
|
-
{
|
|
53
|
+
{brandText && <span>{brandText}</span>}
|
|
50
54
|
</a>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
// A top-level navigation selector
|
|
2
|
+
// A top-level navigation selector: a dropdown that switches
|
|
3
3
|
// between partitions of the site — a product, a version, or any grouped set of
|
|
4
4
|
// destinations (`navigation.selectors` in the config). Zero-JS, built on
|
|
5
5
|
// <details>/<summary> like the language switcher.
|
|
@@ -129,13 +129,13 @@ const initialId =
|
|
|
129
129
|
{panel.route ? (
|
|
130
130
|
<a
|
|
131
131
|
aria-current={panel.route === currentRoute ? "page" : undefined}
|
|
132
|
-
class="
|
|
132
|
+
class="flex-1 truncate font-semibold text-foreground text-sm hover:underline"
|
|
133
133
|
href={panel.route}
|
|
134
134
|
>
|
|
135
135
|
{panel.label}
|
|
136
136
|
</a>
|
|
137
137
|
) : (
|
|
138
|
-
<span class="
|
|
138
|
+
<span class="flex-1 truncate font-semibold text-foreground text-sm">
|
|
139
139
|
{panel.label}
|
|
140
140
|
</span>
|
|
141
141
|
)}
|
|
@@ -151,7 +151,7 @@ const initialId =
|
|
|
151
151
|
))}
|
|
152
152
|
</blume-nav>
|
|
153
153
|
) : (
|
|
154
|
-
<ul class="m-0 list-none p-0">
|
|
154
|
+
<ul class="m-0 list-none space-y-px p-0">
|
|
155
155
|
{items.map((item, index) => {
|
|
156
156
|
if (item.kind === "page") {
|
|
157
157
|
return (
|
|
@@ -161,7 +161,7 @@ const initialId =
|
|
|
161
161
|
class="block rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:font-medium aria-[current=page]:text-foreground"
|
|
162
162
|
href={item.route}
|
|
163
163
|
>
|
|
164
|
-
<span class="flex
|
|
164
|
+
<span class="flex items-center gap-2">
|
|
165
165
|
{item.icon && (
|
|
166
166
|
<Icon
|
|
167
167
|
class="shrink-0 text-muted-foreground"
|
|
@@ -169,7 +169,7 @@ const initialId =
|
|
|
169
169
|
size={14}
|
|
170
170
|
/>
|
|
171
171
|
)}
|
|
172
|
-
<span class="
|
|
172
|
+
<span class="flex-1 truncate">{item.label}</span>
|
|
173
173
|
{item.badge && <span class={badgeClassFor(item.badge)}>{item.badge}</span>}
|
|
174
174
|
{item.deprecated && (
|
|
175
175
|
<span class={deprecatedClass}>deprecated</span>
|
|
@@ -192,7 +192,7 @@ const initialId =
|
|
|
192
192
|
return (
|
|
193
193
|
<li class={spacing}>
|
|
194
194
|
<button
|
|
195
|
-
class="flex w-full
|
|
195
|
+
class="flex w-full items-center gap-2 rounded-[0.65rem] px-2.5 py-1.5 text-left font-medium text-foreground text-sm transition-colors hover:bg-muted"
|
|
196
196
|
data-nav-to={id}
|
|
197
197
|
type="button"
|
|
198
198
|
>
|
|
@@ -203,7 +203,7 @@ const initialId =
|
|
|
203
203
|
size={14}
|
|
204
204
|
/>
|
|
205
205
|
)}
|
|
206
|
-
<span class="
|
|
206
|
+
<span class="flex-1 truncate">{item.label}</span>
|
|
207
207
|
{item.badge && <span class={badgeClassFor(item.badge)}>{item.badge}</span>}
|
|
208
208
|
<Icon
|
|
209
209
|
class="shrink-0 text-muted-foreground"
|
|
@@ -222,13 +222,13 @@ const initialId =
|
|
|
222
222
|
return (
|
|
223
223
|
<li class={spacing}>
|
|
224
224
|
<details class="group" open={open}>
|
|
225
|
-
<summary class="
|
|
225
|
+
<summary class="flex cursor-pointer list-none items-center gap-1.5 rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground [&::-webkit-details-marker]:hidden">
|
|
226
226
|
{item.route ? (
|
|
227
227
|
<a
|
|
228
228
|
aria-current={
|
|
229
229
|
item.route === currentRoute ? "page" : undefined
|
|
230
230
|
}
|
|
231
|
-
class="-my-1 flex
|
|
231
|
+
class="-my-1 flex flex-1 items-center gap-1.5 rounded py-1 transition-colors aria-[current=page]:text-foreground aria-[current=page]:font-semibold"
|
|
232
232
|
href={item.route}
|
|
233
233
|
>
|
|
234
234
|
{item.icon && (
|
|
@@ -238,7 +238,7 @@ const initialId =
|
|
|
238
238
|
size={14}
|
|
239
239
|
/>
|
|
240
240
|
)}
|
|
241
|
-
<span class="
|
|
241
|
+
<span class="flex-1 truncate">{item.label}</span>
|
|
242
242
|
{item.badge && (
|
|
243
243
|
<span class={badgeClassFor(item.badge)}>{item.badge}</span>
|
|
244
244
|
)}
|
|
@@ -252,7 +252,7 @@ const initialId =
|
|
|
252
252
|
size={14}
|
|
253
253
|
/>
|
|
254
254
|
)}
|
|
255
|
-
<span class="
|
|
255
|
+
<span class="flex-1 truncate">{item.label}</span>
|
|
256
256
|
{item.badge && (
|
|
257
257
|
<span class={badgeClassFor(item.badge)}>{item.badge}</span>
|
|
258
258
|
)}
|
|
@@ -279,11 +279,11 @@ const initialId =
|
|
|
279
279
|
// `flat` (default): a non-collapsible header with its items beneath.
|
|
280
280
|
return (
|
|
281
281
|
<li class={spacing}>
|
|
282
|
-
<p class="mb-2 flex
|
|
282
|
+
<p class="mb-2 flex items-center gap-1.5 px-2.5 font-medium text-foreground text-sm">
|
|
283
283
|
{item.route ? (
|
|
284
284
|
<a
|
|
285
285
|
aria-current={item.route === currentRoute ? "page" : undefined}
|
|
286
|
-
class="-ml-1 flex
|
|
286
|
+
class="-ml-1 flex flex-1 items-center gap-1.5 rounded px-1 py-0.5 text-foreground transition-colors hover:bg-muted aria-[current=page]:bg-muted"
|
|
287
287
|
href={item.route}
|
|
288
288
|
>
|
|
289
289
|
{item.icon && (
|
|
@@ -293,7 +293,7 @@ const initialId =
|
|
|
293
293
|
size={14}
|
|
294
294
|
/>
|
|
295
295
|
)}
|
|
296
|
-
<span class="
|
|
296
|
+
<span class="truncate">{item.label}</span>
|
|
297
297
|
{item.badge && (
|
|
298
298
|
<span class={`ml-auto ${badgeClassFor(item.badge)}`}>{item.badge}</span>
|
|
299
299
|
)}
|
|
@@ -307,7 +307,7 @@ const initialId =
|
|
|
307
307
|
size={14}
|
|
308
308
|
/>
|
|
309
309
|
)}
|
|
310
|
-
<span class="
|
|
310
|
+
<span class="truncate">{item.label}</span>
|
|
311
311
|
{item.badge && (
|
|
312
312
|
<span class={`ml-auto ${badgeClassFor(item.badge)}`}>{item.badge}</span>
|
|
313
313
|
)}
|
|
@@ -7,7 +7,6 @@ import Icon from "../Icon.astro";
|
|
|
7
7
|
interface Props {
|
|
8
8
|
route: string;
|
|
9
9
|
editUrl?: string | null;
|
|
10
|
-
askEnabled?: boolean;
|
|
11
10
|
/** Show the "Export to PDF" action (native browser print). */
|
|
12
11
|
exportPdf?: boolean;
|
|
13
12
|
/** Show the "Export to EPUB" action (client-side, current page). */
|
|
@@ -20,17 +19,11 @@ interface Props {
|
|
|
20
19
|
strings?: UIStrings["actions"];
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
exportEpub,
|
|
29
|
-
mcpUrl,
|
|
30
|
-
mcpName,
|
|
31
|
-
strings,
|
|
32
|
-
} = Astro.props;
|
|
33
|
-
const a = strings ?? EN_UI.actions;
|
|
22
|
+
const { route, editUrl, exportPdf, exportEpub, mcpUrl, mcpName, strings } =
|
|
23
|
+
Astro.props;
|
|
24
|
+
// Merge over the English defaults so a label missing from a translation (or from
|
|
25
|
+
// a not-yet-regenerated snapshot) still renders instead of coming out blank.
|
|
26
|
+
const a = { ...EN_UI.actions, ...strings };
|
|
34
27
|
const mdPath = route === "/" ? "/index.md" : `${route}.md`;
|
|
35
28
|
|
|
36
29
|
const GITHUB_LOGO = `<svg class="size-4 shrink-0" fill="currentColor" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">${GITHUB_MARK}</svg>`;
|
|
@@ -41,6 +34,8 @@ const LOGOS: Record<string, string> = {
|
|
|
41
34
|
'<svg class="size-4 shrink-0" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>',
|
|
42
35
|
claude:
|
|
43
36
|
'<svg class="size-4 shrink-0" fill="currentColor" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" fill-rule="evenodd" d="M2.3545 7.9775L4.7145 6.654L4.7545 6.539L4.7145 6.475H4.6L4.205 6.451L2.856 6.4145L1.6865 6.366L0.5535 6.305L0.268 6.2445L0 5.892L0.0275 5.716L0.2675 5.5555L0.6105 5.5855L1.3705 5.637L2.5095 5.716L3.3355 5.7645L4.56 5.892H4.7545L4.782 5.8135L4.715 5.7645L4.6635 5.716L3.4845 4.918L2.2085 4.074L1.5405 3.588L1.1785 3.3425L0.9965 3.1115L0.9175 2.6075L1.2455 2.2465L1.686 2.2765L1.7985 2.307L2.245 2.65L3.199 3.388L4.4445 4.3045L4.627 4.4565L4.6995 4.405L4.709 4.3685L4.627 4.2315L3.9495 3.0085L3.2265 1.7635L2.9045 1.2475L2.8195 0.938C2.78711 0.819128 2.76965 0.696687 2.7675 0.5735L3.1415 0.067L3.348 0L3.846 0.067L4.056 0.249L4.366 0.956L4.867 2.0705L5.6445 3.5855L5.8725 4.0345L5.994 4.4505L6.0395 4.578H6.1185V4.505L6.1825 3.652L6.301 2.6045L6.416 1.257L6.456 0.877L6.644 0.422L7.0175 0.176L7.3095 0.316L7.5495 0.6585L7.516 0.8805L7.373 1.806L7.0935 3.2575L6.9115 4.2285H7.0175L7.139 4.1075L7.6315 3.4545L8.4575 2.4225L8.8225 2.0125L9.2475 1.5605L9.521 1.345H10.0375L10.4175 1.9095L10.2475 2.4925L9.7155 3.166L9.275 3.737L8.643 4.587L8.248 5.267L8.2845 5.322L8.3785 5.312L9.8065 5.009L10.578 4.869L11.4985 4.7115L11.915 4.9055L11.9605 5.103L11.7965 5.5065L10.812 5.7495L9.6575 5.9805L7.938 6.387L7.917 6.402L7.9415 6.4325L8.716 6.5055L9.047 6.5235H9.858L11.368 6.636L11.763 6.897L12 7.216L11.9605 7.4585L11.353 7.7685L10.533 7.574L8.6185 7.119L7.9625 6.9545H7.8715V7.0095L8.418 7.5435L9.421 8.4485L10.6755 9.6135L10.739 9.9025L10.578 10.13L10.408 10.1055L9.3055 9.277L8.88 8.9035L7.917 8.0935H7.853V8.1785L8.075 8.503L9.2475 10.2635L9.3085 10.8035L9.2235 10.98L8.9195 11.0865L8.5855 11.0255L7.8985 10.063L7.191 8.9795L6.6195 8.008L6.5495 8.048L6.2125 11.675L6.0545 11.86L5.69 12L5.3865 11.7695L5.2255 11.396L5.3865 10.658L5.581 9.696L5.7385 8.931L5.8815 7.981L5.9665 7.665L5.9605 7.644L5.8905 7.653L5.1735 8.6365L4.0835 10.109L3.2205 11.0315L3.0135 11.1135L2.655 10.9285L2.6885 10.5975L2.889 10.303L4.083 8.785L4.803 7.844L5.268 7.301L5.265 7.222H5.2375L2.066 9.28L1.501 9.353L1.2575 9.125L1.288 8.752L1.4035 8.6305L2.3575 7.9745L2.3545 7.9775Z"/></svg>',
|
|
37
|
+
codex:
|
|
38
|
+
'<svg class="size-4 shrink-0" fill="currentColor" fill-rule="evenodd" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path clip-rule="evenodd" d="M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z"/></svg>',
|
|
44
39
|
cursor:
|
|
45
40
|
'<svg class="size-4 shrink-0" viewBox="0 0 466.73 532.09" xmlns="http://www.w3.org/2000/svg"><path d="M457.43,125.94L244.42,2.96c-6.84-3.95-15.28-3.95-22.12,0L9.3,125.94c-5.75,3.32-9.3,9.46-9.3,16.11v247.99c0,6.65,3.55,12.79,9.3,16.11l213.01,122.98c6.84,3.95,15.28,3.95,22.12,0l213.01-122.98c5.75-3.32,9.3-9.46,9.3-16.11v-247.99c0-6.65-3.55-12.79-9.3-16.11h-.01ZM444.05,151.99l-205.63,356.16c-1.39,2.4-5.06,1.42-5.06-1.36v-233.21c0-4.66-2.49-8.97-6.53-11.31L24.87,145.67c-2.4-1.39-1.42-5.06,1.36-5.06h411.26c5.84,0,9.49,6.33,6.57,11.39h-.01Z" fill="currentColor"/></svg>',
|
|
46
41
|
scira:
|
|
@@ -110,7 +105,10 @@ const menuRowClass =
|
|
|
110
105
|
size={14}
|
|
111
106
|
/>
|
|
112
107
|
</summary>
|
|
113
|
-
<div
|
|
108
|
+
<div
|
|
109
|
+
class="absolute top-full right-2 z-50 mt-1 w-max min-w-[14rem] max-w-[22rem] rounded-blume border border-border bg-background p-1 shadow-xl"
|
|
110
|
+
data-blume-menu
|
|
111
|
+
>
|
|
114
112
|
{exportPdf && (
|
|
115
113
|
<button class={menuRowClass} data-blume-export-pdf type="button">
|
|
116
114
|
<Icon name="file" size={16} />
|
|
@@ -130,15 +128,6 @@ const menuRowClass =
|
|
|
130
128
|
)
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
{
|
|
134
|
-
askEnabled && (
|
|
135
|
-
<button class={rowClass} data-blume-ask-ai type="button">
|
|
136
|
-
<Icon name="message-circle" size={16} />
|
|
137
|
-
{a.askAI}
|
|
138
|
-
</button>
|
|
139
|
-
)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
131
|
<details class="group relative">
|
|
143
132
|
<summary
|
|
144
133
|
class={`${rowClass} cursor-pointer list-none [&::-webkit-details-marker]:hidden`}
|
|
@@ -151,7 +140,10 @@ const menuRowClass =
|
|
|
151
140
|
size={14}
|
|
152
141
|
/>
|
|
153
142
|
</summary>
|
|
154
|
-
<div
|
|
143
|
+
<div
|
|
144
|
+
class="absolute top-full right-2 z-50 mt-1 w-max min-w-[14rem] max-w-[22rem] rounded-blume border border-border bg-background p-1 shadow-xl"
|
|
145
|
+
data-blume-menu
|
|
146
|
+
>
|
|
155
147
|
{
|
|
156
148
|
PROVIDERS.map((provider, index) => (
|
|
157
149
|
<>
|
|
@@ -186,7 +178,10 @@ const menuRowClass =
|
|
|
186
178
|
size={14}
|
|
187
179
|
/>
|
|
188
180
|
</summary>
|
|
189
|
-
<div
|
|
181
|
+
<div
|
|
182
|
+
class="absolute top-full right-2 z-50 mt-1 w-max min-w-[14rem] max-w-[22rem] rounded-blume border border-border bg-background p-1 shadow-xl"
|
|
183
|
+
data-blume-menu
|
|
184
|
+
>
|
|
190
185
|
<button class={menuRowClass} data-mcp-copy-url type="button">
|
|
191
186
|
<Icon name="link" size={16} />
|
|
192
187
|
<span class="flex-1" data-mcp-url-label>
|
|
@@ -199,6 +194,12 @@ const menuRowClass =
|
|
|
199
194
|
{a.copyClaudeCode}
|
|
200
195
|
</span>
|
|
201
196
|
</button>
|
|
197
|
+
<button class={menuRowClass} data-mcp-copy-codex type="button">
|
|
198
|
+
<span set:html={LOGOS.codex} />
|
|
199
|
+
<span class="flex-1" data-mcp-codex-label>
|
|
200
|
+
{a.copyCodex}
|
|
201
|
+
</span>
|
|
202
|
+
</button>
|
|
202
203
|
<hr class="my-1 border-border border-t" />
|
|
203
204
|
<a class={menuRowClass} data-mcp-cursor rel="noreferrer">
|
|
204
205
|
<span set:html={LOGOS.cursor} />
|
|
@@ -276,6 +277,46 @@ hr { border: 0; border-top: 1px solid #ddd; margin: 2em 0; }`;
|
|
|
276
277
|
|
|
277
278
|
const root = document.querySelector("[data-blume-page-actions]");
|
|
278
279
|
if (root) {
|
|
280
|
+
// The action dropdowns are native <details>. Make them behave like a proper
|
|
281
|
+
// menu: only one open at a time, and flip above the trigger when opening
|
|
282
|
+
// downward would run past the viewport bottom.
|
|
283
|
+
const dropdowns = [...root.querySelectorAll<HTMLDetailsElement>("details")];
|
|
284
|
+
const placeMenu = (details: HTMLDetailsElement) => {
|
|
285
|
+
const menu = details.querySelector<HTMLElement>("[data-blume-menu]");
|
|
286
|
+
const summary = details.querySelector("summary");
|
|
287
|
+
if (!(menu && summary)) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const rect = summary.getBoundingClientRect();
|
|
291
|
+
const margin = 8;
|
|
292
|
+
const flipUp =
|
|
293
|
+
rect.bottom + menu.offsetHeight + margin > window.innerHeight &&
|
|
294
|
+
rect.top - menu.offsetHeight - margin > 0;
|
|
295
|
+
menu.classList.toggle("top-full", !flipUp);
|
|
296
|
+
menu.classList.toggle("mt-1", !flipUp);
|
|
297
|
+
menu.classList.toggle("bottom-full", flipUp);
|
|
298
|
+
menu.classList.toggle("mb-1", flipUp);
|
|
299
|
+
};
|
|
300
|
+
for (const details of dropdowns) {
|
|
301
|
+
details.addEventListener("toggle", () => {
|
|
302
|
+
if (!details.open) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
for (const other of dropdowns) {
|
|
306
|
+
if (other !== details) {
|
|
307
|
+
other.open = false;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
placeMenu(details);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
window.addEventListener("resize", () => {
|
|
314
|
+
const open = dropdowns.find((details) => details.open);
|
|
315
|
+
if (open) {
|
|
316
|
+
placeMenu(open);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
279
320
|
const md = root.getAttribute("data-md") ?? "";
|
|
280
321
|
const copiedLabel = root.getAttribute("data-i18n-copied") || "Copied!";
|
|
281
322
|
const absolute = new URL(md, location.origin).href;
|
|
@@ -296,12 +337,6 @@ hr { border: 0; border-top: 1px solid #ddd; margin: 2em 0; }`;
|
|
|
296
337
|
window.scrollTo({ behavior: "smooth", top: 0 })
|
|
297
338
|
);
|
|
298
339
|
|
|
299
|
-
root
|
|
300
|
-
.querySelector("[data-blume-ask-ai]")
|
|
301
|
-
?.addEventListener("click", () =>
|
|
302
|
-
window.dispatchEvent(new CustomEvent("blume:open-ask-ai"))
|
|
303
|
-
);
|
|
304
|
-
|
|
305
340
|
const mcpUrl = root.getAttribute("data-mcp-url");
|
|
306
341
|
if (mcpUrl) {
|
|
307
342
|
const rawName = root.getAttribute("data-mcp-name") || "docs";
|
|
@@ -360,6 +395,14 @@ hr { border: 0; border-top: 1px solid #ddd; margin: 2em 0; }`;
|
|
|
360
395
|
root.querySelector("[data-mcp-claude-label]")
|
|
361
396
|
)
|
|
362
397
|
);
|
|
398
|
+
root
|
|
399
|
+
.querySelector("[data-mcp-copy-codex]")
|
|
400
|
+
?.addEventListener("click", () =>
|
|
401
|
+
copy(
|
|
402
|
+
`codex mcp add ${id} --url ${mcpUrl}`,
|
|
403
|
+
root.querySelector("[data-mcp-codex-label]")
|
|
404
|
+
)
|
|
405
|
+
);
|
|
363
406
|
}
|
|
364
407
|
|
|
365
408
|
const label = root.querySelector("[data-blume-copy-label]");
|
|
@@ -190,6 +190,48 @@ const bannerScript = banner?.dismissible
|
|
|
190
190
|
</Header>
|
|
191
191
|
<main id="blume-content"><slot /></main>
|
|
192
192
|
<slot name="footer" />
|
|
193
|
+
{
|
|
194
|
+
// Mobile nav for chrome-only pages: the header's inline tab bar is hidden
|
|
195
|
+
// below `lg` and there's no sidebar drawer, so surface the tabs in a
|
|
196
|
+
// slide-in drawer instead. It reuses the header's `data-blume-nav-toggle`
|
|
197
|
+
// machinery (drawer top, scroll lock, resize-close) — the hamburger button
|
|
198
|
+
// lives in the header; this is the panel it opens.
|
|
199
|
+
navigation.tabs.length > 0 && (
|
|
200
|
+
<>
|
|
201
|
+
<aside
|
|
202
|
+
aria-label="Navigation"
|
|
203
|
+
class="fixed top-[var(--blume-drawer-top,4rem)] start-0 z-[35] h-[calc(100dvh-var(--blume-drawer-top,4rem))] w-64 max-w-[80vw] -translate-x-[105%] overflow-y-auto border-border border-e bg-background px-5 pt-4 pb-6 transition-transform rtl:translate-x-[105%] [:where([data-blume-nav-open])_&]:translate-x-0! lg:hidden"
|
|
204
|
+
>
|
|
205
|
+
<nav aria-label="Sections">
|
|
206
|
+
<ul class="m-0 list-none p-0">
|
|
207
|
+
{navigation.tabs.map((tab) => (
|
|
208
|
+
<li>
|
|
209
|
+
<a
|
|
210
|
+
aria-current={
|
|
211
|
+
route === tab.path ||
|
|
212
|
+
(tab.path !== "/" && route.startsWith(tab.path))
|
|
213
|
+
? "page"
|
|
214
|
+
: undefined
|
|
215
|
+
}
|
|
216
|
+
class="block rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
|
217
|
+
href={tab.path}
|
|
218
|
+
>
|
|
219
|
+
{tab.label}
|
|
220
|
+
</a>
|
|
221
|
+
</li>
|
|
222
|
+
))}
|
|
223
|
+
</ul>
|
|
224
|
+
</nav>
|
|
225
|
+
</aside>
|
|
226
|
+
<button
|
|
227
|
+
aria-label="Close navigation"
|
|
228
|
+
class="fixed inset-0 z-[30] hidden cursor-pointer border-0 bg-black/40 [:where([data-blume-nav-open])_&]:block lg:hidden"
|
|
229
|
+
data-blume-nav-toggle
|
|
230
|
+
type="button"
|
|
231
|
+
/>
|
|
232
|
+
</>
|
|
233
|
+
)
|
|
234
|
+
}
|
|
193
235
|
{
|
|
194
236
|
clientDataJson && (
|
|
195
237
|
<script
|
|
@@ -18,6 +18,7 @@ import Favicon from "./Favicon.astro";
|
|
|
18
18
|
import Fonts from "./Fonts.astro";
|
|
19
19
|
import { bannerInitScript, themeInitScript } from "./head-scripts.ts";
|
|
20
20
|
import Header from "./Header.astro";
|
|
21
|
+
import Icon from "../Icon.astro";
|
|
21
22
|
import {
|
|
22
23
|
findBreadcrumbs,
|
|
23
24
|
flattenPages,
|
|
@@ -39,6 +40,7 @@ interface Props {
|
|
|
39
40
|
dark?: string;
|
|
40
41
|
alt: string;
|
|
41
42
|
href: string;
|
|
43
|
+
text?: string;
|
|
42
44
|
} | null;
|
|
43
45
|
favicon?: {
|
|
44
46
|
href: string;
|
|
@@ -341,11 +343,84 @@ const bannerScript = banner?.dismissible
|
|
|
341
343
|
>
|
|
342
344
|
<slot name="ask" slot="ask" />
|
|
343
345
|
</HeaderSlot>
|
|
344
|
-
<div
|
|
346
|
+
<div
|
|
347
|
+
class:list={["mx-auto grid grid-cols-1 items-start", gridClass]}
|
|
348
|
+
data-blume-doc-grid
|
|
349
|
+
>
|
|
345
350
|
<aside
|
|
346
351
|
aria-label="Primary"
|
|
347
|
-
class="fixed top-
|
|
352
|
+
class="fixed top-[var(--blume-drawer-top,4rem)] start-0 z-[35] h-[calc(100dvh-var(--blume-drawer-top,4rem))] w-64 max-w-[80vw] -translate-x-[105%] overflow-y-auto border-border border-e bg-background px-5 pt-4 pb-6 transition-transform rtl:translate-x-[105%] [:where([data-blume-nav-open])_&]:translate-x-0! lg:sticky lg:top-16 lg:z-auto lg:h-[calc(100dvh-4rem)] lg:w-auto lg:max-w-none lg:translate-x-0! lg:border-e-0 lg:bg-transparent lg:px-4"
|
|
348
353
|
>
|
|
354
|
+
{
|
|
355
|
+
// Pinned links (blog, changelog, contact…) sit above every section on
|
|
356
|
+
// all breakpoints, outside the tab-scoped sidebar so they never change
|
|
357
|
+
// with the active tab. External hrefs open in a new tab.
|
|
358
|
+
navigation.featured.length > 0 && (
|
|
359
|
+
<nav aria-label="Featured" class="mb-4 border-border border-b pb-4">
|
|
360
|
+
<ul class="m-0 list-none p-0">
|
|
361
|
+
{navigation.featured.map((link) => {
|
|
362
|
+
const external = /^https?:\/\//u.test(link.href);
|
|
363
|
+
return (
|
|
364
|
+
<li>
|
|
365
|
+
<a
|
|
366
|
+
class="block rounded-[0.65rem] px-2.5 py-1.5 text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground"
|
|
367
|
+
href={link.href}
|
|
368
|
+
rel={external ? "noreferrer" : undefined}
|
|
369
|
+
target={external ? "_blank" : undefined}
|
|
370
|
+
>
|
|
371
|
+
<span class="flex items-center gap-2">
|
|
372
|
+
{link.icon && (
|
|
373
|
+
<Icon
|
|
374
|
+
class="shrink-0 text-muted-foreground"
|
|
375
|
+
name={link.icon}
|
|
376
|
+
size={14}
|
|
377
|
+
/>
|
|
378
|
+
)}
|
|
379
|
+
<span class="flex-1 truncate">{link.label}</span>
|
|
380
|
+
{external && (
|
|
381
|
+
<Icon
|
|
382
|
+
class="shrink-0 text-muted-foreground opacity-60"
|
|
383
|
+
name="arrow-up-right"
|
|
384
|
+
size={12}
|
|
385
|
+
/>
|
|
386
|
+
)}
|
|
387
|
+
</span>
|
|
388
|
+
</a>
|
|
389
|
+
</li>
|
|
390
|
+
);
|
|
391
|
+
})}
|
|
392
|
+
</ul>
|
|
393
|
+
</nav>
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
{
|
|
397
|
+
// The header's tab bar is hidden below `md`, so the drawer is the only
|
|
398
|
+
// way to move between sections on mobile: list the tabs above the
|
|
399
|
+
// page tree, separated by a divider. Hidden from `md` up, where the
|
|
400
|
+
// header tabs take over.
|
|
401
|
+
navigation.tabs.length > 0 && (
|
|
402
|
+
<nav aria-label="Sections" class="mb-4 border-border border-b pb-4 md:hidden">
|
|
403
|
+
<ul class="m-0 list-none p-0">
|
|
404
|
+
{navigation.tabs.map((tab) => (
|
|
405
|
+
<li>
|
|
406
|
+
<a
|
|
407
|
+
aria-current={
|
|
408
|
+
page.route === tab.path ||
|
|
409
|
+
(tab.path !== "/" && page.route.startsWith(tab.path))
|
|
410
|
+
? "page"
|
|
411
|
+
: undefined
|
|
412
|
+
}
|
|
413
|
+
class="block rounded-[0.65rem] px-2.5 py-1.5 font-medium text-muted-foreground text-sm transition-colors hover:bg-muted hover:text-foreground aria-[current=page]:bg-muted aria-[current=page]:text-foreground"
|
|
414
|
+
href={tab.path}
|
|
415
|
+
>
|
|
416
|
+
{tab.label}
|
|
417
|
+
</a>
|
|
418
|
+
</li>
|
|
419
|
+
))}
|
|
420
|
+
</ul>
|
|
421
|
+
</nav>
|
|
422
|
+
)
|
|
423
|
+
}
|
|
349
424
|
<nav>
|
|
350
425
|
{
|
|
351
426
|
MobileNavSlot ? (
|
|
@@ -363,7 +438,7 @@ const bannerScript = banner?.dismissible
|
|
|
363
438
|
}
|
|
364
439
|
</nav>
|
|
365
440
|
</aside>
|
|
366
|
-
<main class="
|
|
441
|
+
<main class="px-6 pt-6 pb-10 lg:px-8 xl:px-10" id="blume-content">
|
|
367
442
|
<BreadcrumbsSlot crumbs={crumbs} wide={isApiOperation} />
|
|
368
443
|
<TableOfContentsSlot
|
|
369
444
|
headings={tocHeadings}
|
|
@@ -398,6 +473,7 @@ const bannerScript = banner?.dismissible
|
|
|
398
473
|
<aside
|
|
399
474
|
aria-label={strings.toc.title}
|
|
400
475
|
class="sticky top-16 hidden h-[calc(100dvh-4rem)] overflow-y-auto px-4 pt-6 pb-10 text-sm xl:block"
|
|
476
|
+
data-blume-toc
|
|
401
477
|
>
|
|
402
478
|
<TableOfContentsSlot
|
|
403
479
|
headings={tocHeadings}
|
|
@@ -405,7 +481,6 @@ const bannerScript = banner?.dismissible
|
|
|
405
481
|
variant="desktop"
|
|
406
482
|
/>
|
|
407
483
|
<PageActions
|
|
408
|
-
askEnabled={askEnabled}
|
|
409
484
|
editUrl={editUrl}
|
|
410
485
|
exportEpub={exportEpub}
|
|
411
486
|
exportPdf={exportPdf}
|
|
@@ -36,12 +36,12 @@ const kbd = "rounded border border-border bg-muted px-1 py-0.5 font-mono";
|
|
|
36
36
|
>
|
|
37
37
|
<button
|
|
38
38
|
aria-label={s.button}
|
|
39
|
-
class="inline-flex h-9
|
|
39
|
+
class="inline-flex h-9 cursor-pointer items-center gap-2 rounded-full border border-border bg-background px-3 text-muted-foreground text-sm transition-colors hover:border-foreground hover:text-foreground sm:min-w-48"
|
|
40
40
|
data-blume-search-open
|
|
41
41
|
type="button"
|
|
42
42
|
>
|
|
43
43
|
<Icon name="search" size={16} />
|
|
44
|
-
<span class="
|
|
44
|
+
<span class="flex-1 text-start max-sm:hidden">{s.button}</span>
|
|
45
45
|
<kbd class="font-mono text-[0.7rem] max-sm:hidden" data-blume-search-kbd
|
|
46
46
|
>⌘K</kbd
|
|
47
47
|
>
|
|
@@ -459,7 +459,7 @@ const kbd = "rounded border border-border bg-muted px-1 py-0.5 font-mono";
|
|
|
459
459
|
: "Ask AI";
|
|
460
460
|
el.innerHTML = `
|
|
461
461
|
<span class="mt-0.5 shrink-0 text-accent">${svg("sparkles")}</span>
|
|
462
|
-
<span class="
|
|
462
|
+
<span class="flex-1">
|
|
463
463
|
<span class="block truncate font-normal text-foreground text-sm">${title}</span>
|
|
464
464
|
<span class="block truncate text-muted-foreground text-sm">Get an instant answer from AI</span>
|
|
465
465
|
</span>`;
|
|
@@ -479,7 +479,7 @@ const kbd = "rounded border border-border bg-muted px-1 py-0.5 font-mono";
|
|
|
479
479
|
: "";
|
|
480
480
|
el.innerHTML = `
|
|
481
481
|
<span class="mt-0.5 shrink-0 text-muted-foreground">${svg("file")}</span>
|
|
482
|
-
<span class="
|
|
482
|
+
<span class="flex-1">
|
|
483
483
|
<span class="block truncate font-normal text-foreground text-sm">${hit.title}</span>
|
|
484
484
|
${excerpt}
|
|
485
485
|
</span>`;
|
|
@@ -494,7 +494,7 @@ const kbd = "rounded border border-border bg-muted px-1 py-0.5 font-mono";
|
|
|
494
494
|
el.className = ROW_CLASS;
|
|
495
495
|
el.innerHTML = `
|
|
496
496
|
<span class="mt-0.5 shrink-0 text-muted-foreground">${svg("file")}</span>
|
|
497
|
-
<span class="
|
|
497
|
+
<span class="flex-1">
|
|
498
498
|
<span class="block truncate font-normal text-foreground text-sm">${escapeHtml(label)}</span>
|
|
499
499
|
</span>`;
|
|
500
500
|
const item: Selectable = { el, kind: "link", url };
|