@umami/shiso 1.9.0 → 1.11.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/chunks/App.js +112 -25
- package/dist/chunks/docs.js +32 -40
- package/docs.schema.json +8 -0
- package/package.json +1 -1
- package/src/components/CodeBlock.tsx +1 -1
- package/src/components/DocContent.tsx +24 -11
- package/src/components/Docs.tsx +3 -1
- package/src/components/Header.tsx +7 -10
- package/src/components/Search.tsx +45 -5
- package/src/components/SideNav.tsx +3 -4
- package/src/components/docs/Card.tsx +1 -1
- package/src/components/docs/CodeGroup.tsx +1 -1
- package/src/components/docs/Expandable.tsx +1 -1
- package/src/components/docs/PropertiesTable.tsx +12 -25
- package/src/components/docs/styles.ts +7 -4
- package/src/components/icons/index.ts +2 -0
- package/src/lib/search/config.ts +29 -1
- package/src/lib/site-model.ts +2 -0
- package/src/lib/types.ts +14 -1
- package/src/styles/global.css +12 -3
package/dist/chunks/App.js
CHANGED
|
@@ -14,6 +14,40 @@ import shiso from "virtual:shiso-config";
|
|
|
14
14
|
import rawConfig from "virtual:shiso-docs-config";
|
|
15
15
|
import { LAST_MODIFIED } from "@/generated/last-modified";
|
|
16
16
|
|
|
17
|
+
//#region ../../node_modules/.pnpm/lucide-react@1.28.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/arrow-left.mjs
|
|
18
|
+
/**
|
|
19
|
+
* @license lucide-react v1.28.0 - ISC
|
|
20
|
+
*
|
|
21
|
+
* This source code is licensed under the ISC license.
|
|
22
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
23
|
+
*/
|
|
24
|
+
const __iconNode$10 = [["path", {
|
|
25
|
+
d: "m12 19-7-7 7-7",
|
|
26
|
+
key: "1l729n"
|
|
27
|
+
}], ["path", {
|
|
28
|
+
d: "M19 12H5",
|
|
29
|
+
key: "x3x0zl"
|
|
30
|
+
}]];
|
|
31
|
+
const ArrowLeft = createLucideIcon("arrow-left", __iconNode$10);
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region ../../node_modules/.pnpm/lucide-react@1.28.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/arrow-right.mjs
|
|
35
|
+
/**
|
|
36
|
+
* @license lucide-react v1.28.0 - ISC
|
|
37
|
+
*
|
|
38
|
+
* This source code is licensed under the ISC license.
|
|
39
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
40
|
+
*/
|
|
41
|
+
const __iconNode$9 = [["path", {
|
|
42
|
+
d: "M5 12h14",
|
|
43
|
+
key: "1ays0h"
|
|
44
|
+
}], ["path", {
|
|
45
|
+
d: "m12 5 7 7-7 7",
|
|
46
|
+
key: "xquz4c"
|
|
47
|
+
}]];
|
|
48
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$9);
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
17
51
|
//#region ../../node_modules/.pnpm/lucide-react@1.28.0_react@19.2.8/node_modules/lucide-react/dist/esm/icons/copy.mjs
|
|
18
52
|
/**
|
|
19
53
|
* @license lucide-react v1.28.0 - ISC
|
|
@@ -1159,7 +1193,7 @@ function CodeBlock({ children, className }) {
|
|
|
1159
1193
|
};
|
|
1160
1194
|
return /* @__PURE__ */ jsxs("div", {
|
|
1161
1195
|
"data-slot": "code-block",
|
|
1162
|
-
className: "relative my-5 overflow-hidden rounded-lg bg-
|
|
1196
|
+
className: "relative my-5 overflow-hidden rounded-lg bg-card",
|
|
1163
1197
|
children: [/* @__PURE__ */ jsx(ScrollArea, {
|
|
1164
1198
|
scrollbars: "horizontal",
|
|
1165
1199
|
className: "w-full",
|
|
@@ -4026,11 +4060,24 @@ const DEFAULT_SEARCH_PROMPT = "Search...";
|
|
|
4026
4060
|
const DEFAULT_SEARCH_PROVIDER = "local";
|
|
4027
4061
|
const DEFAULT_SEARCH_SHORTCUT = "k";
|
|
4028
4062
|
const DEFAULT_SEARCH_SHORTCUT_LABEL = "Ctrl K";
|
|
4063
|
+
const DEFAULT_SEARCH_POSITION = "header";
|
|
4064
|
+
/** Positions the built-in theme knows how to render. */
|
|
4065
|
+
const SEARCH_POSITIONS = ["header", "sidebar"];
|
|
4066
|
+
/**
|
|
4067
|
+
* Themes must always support "header", so anything unrecognized (or not
|
|
4068
|
+
* implemented by the active theme) lands there instead of vanishing.
|
|
4069
|
+
*/
|
|
4070
|
+
function resolveSearchPosition(position, supported = SEARCH_POSITIONS) {
|
|
4071
|
+
if (typeof position === "string" && supported.includes(position)) return position;
|
|
4072
|
+
if (position !== void 0 && position !== "header") console.warn(`[shiso] Unsupported search.position "${String(position)}" — using "${DEFAULT_SEARCH_POSITION}".`);
|
|
4073
|
+
return DEFAULT_SEARCH_POSITION;
|
|
4074
|
+
}
|
|
4029
4075
|
/** Normalizes docs.json search settings for both the UI and provider loader. */
|
|
4030
4076
|
function resolveSearchConfig(config) {
|
|
4031
4077
|
if (config === false) return {
|
|
4032
4078
|
enabled: false,
|
|
4033
4079
|
prompt: DEFAULT_SEARCH_PROMPT,
|
|
4080
|
+
position: DEFAULT_SEARCH_POSITION,
|
|
4034
4081
|
provider: DEFAULT_SEARCH_PROVIDER,
|
|
4035
4082
|
options: {},
|
|
4036
4083
|
shortcut: false,
|
|
@@ -4039,6 +4086,7 @@ function resolveSearchConfig(config) {
|
|
|
4039
4086
|
return {
|
|
4040
4087
|
enabled: true,
|
|
4041
4088
|
prompt: config?.prompt?.trim() || "Search...",
|
|
4089
|
+
position: resolveSearchPosition(config?.position),
|
|
4042
4090
|
provider: config?.provider?.trim().toLowerCase() || "local",
|
|
4043
4091
|
options: config?.options || {},
|
|
4044
4092
|
shortcut: config?.shortcut === false ? false : config?.shortcut?.trim().toLowerCase() || "k",
|
|
@@ -4060,6 +4108,8 @@ const SHISO_THEME_LABELS = {
|
|
|
4060
4108
|
noResults: "No results",
|
|
4061
4109
|
lastUpdated: "Last updated on",
|
|
4062
4110
|
relatedTopics: "Related topics",
|
|
4111
|
+
previousPage: "Previous",
|
|
4112
|
+
nextPage: "Next",
|
|
4063
4113
|
notFound: "Page not found",
|
|
4064
4114
|
dismissBanner: "Dismiss banner",
|
|
4065
4115
|
toggleTheme: "Toggle theme",
|
|
@@ -7205,7 +7255,7 @@ function renderWithQueryHighlight(text, query) {
|
|
|
7205
7255
|
* Provider-neutral search dialog. The selected provider and its index or
|
|
7206
7256
|
* client are loaded on demand, so search stays out of the initial bundle.
|
|
7207
7257
|
*/
|
|
7208
|
-
function Search({ config, labels }) {
|
|
7258
|
+
function Search({ config, labels, className }) {
|
|
7209
7259
|
const navigate = useNavigate();
|
|
7210
7260
|
const { pathname } = useLocation();
|
|
7211
7261
|
const [open, setOpen] = useState(false);
|
|
@@ -7294,12 +7344,12 @@ function Search({ config, labels }) {
|
|
|
7294
7344
|
children: [/* @__PURE__ */ jsxs(DialogTrigger, {
|
|
7295
7345
|
render: /* @__PURE__ */ jsx(Button, {
|
|
7296
7346
|
variant: "outline",
|
|
7297
|
-
className: "h-auto gap-2 rounded-md bg-card px-2.5 py-1.5 text-muted-foreground hover:border-input hover:bg-card hover:text-foreground"
|
|
7347
|
+
className: cn("h-auto gap-2 rounded-md bg-card px-2.5 py-1.5 text-muted-foreground hover:border-input hover:bg-card hover:text-foreground", className)
|
|
7298
7348
|
}),
|
|
7299
7349
|
children: [
|
|
7300
7350
|
/* @__PURE__ */ jsx(Search$1, { className: "size-3.5" }),
|
|
7301
7351
|
/* @__PURE__ */ jsx("span", {
|
|
7302
|
-
className: "min-w-24 text-left",
|
|
7352
|
+
className: "min-w-24 grow text-left",
|
|
7303
7353
|
children: config.prompt
|
|
7304
7354
|
}),
|
|
7305
7355
|
config.shortcut ? /* @__PURE__ */ jsx("kbd", {
|
|
@@ -7348,6 +7398,21 @@ function Search({ config, labels }) {
|
|
|
7348
7398
|
})]
|
|
7349
7399
|
});
|
|
7350
7400
|
}
|
|
7401
|
+
/**
|
|
7402
|
+
* Renders the search control only when `search.position` targets this slot.
|
|
7403
|
+
* Layout components drop one of these into each position they support; the
|
|
7404
|
+
* per-page `search: false` frontmatter flag is honored here as well.
|
|
7405
|
+
*/
|
|
7406
|
+
function SearchSlot({ site, position, className }) {
|
|
7407
|
+
const { pathname } = useLocation();
|
|
7408
|
+
if (!site.search.enabled || site.search.position !== position) return null;
|
|
7409
|
+
if (getPageFrontmatter(pathname)?.search === false) return null;
|
|
7410
|
+
return /* @__PURE__ */ jsx(Search, {
|
|
7411
|
+
config: site.search,
|
|
7412
|
+
labels: site.labels,
|
|
7413
|
+
className
|
|
7414
|
+
});
|
|
7415
|
+
}
|
|
7351
7416
|
|
|
7352
7417
|
//#endregion
|
|
7353
7418
|
//#region src/components/ThemeToggle.tsx
|
|
@@ -7527,10 +7592,9 @@ function NavbarLinkItem({ link, primary = false }) {
|
|
|
7527
7592
|
});
|
|
7528
7593
|
}
|
|
7529
7594
|
function Header({ site }) {
|
|
7530
|
-
const { logo, navbar, name, appearance, labels
|
|
7595
|
+
const { logo, navbar, name, appearance, labels } = site;
|
|
7531
7596
|
const { pathname } = useLocation();
|
|
7532
7597
|
const docs = getScopeByPathname(pathname).docs;
|
|
7533
|
-
const showSearch = getPageFrontmatter(pathname)?.search !== false;
|
|
7534
7598
|
const brandHref = logo?.href || (hasRootStandalonePage ? "/" : docsHomeUrl);
|
|
7535
7599
|
const hasBrand = !!name || !!logo?.light || !!logo?.dark;
|
|
7536
7600
|
const brandClassName = "inline-flex items-center gap-2 text-xl font-bold text-foreground tracking-[-0.03em]";
|
|
@@ -7579,10 +7643,15 @@ function Header({ site }) {
|
|
|
7579
7643
|
/* @__PURE__ */ jsxs("div", {
|
|
7580
7644
|
className: "flex min-w-0 items-center gap-2 justify-self-end",
|
|
7581
7645
|
children: [
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
})
|
|
7646
|
+
/* @__PURE__ */ jsx(SearchSlot, {
|
|
7647
|
+
site,
|
|
7648
|
+
position: "header"
|
|
7649
|
+
}),
|
|
7650
|
+
/* @__PURE__ */ jsx(SearchSlot, {
|
|
7651
|
+
site,
|
|
7652
|
+
position: "sidebar",
|
|
7653
|
+
className: "lg:hidden"
|
|
7654
|
+
}),
|
|
7586
7655
|
navbar?.links.map((link) => /* @__PURE__ */ jsx(NavbarLinkItem, { link }, link.href)),
|
|
7587
7656
|
!appearance.strict && /* @__PURE__ */ jsx(ThemeToggle, { label: labels.toggleTheme }),
|
|
7588
7657
|
navbar?.primary ? /* @__PURE__ */ jsx(NavbarLinkItem, {
|
|
@@ -8001,30 +8070,44 @@ function DocContent({ page, doc, site }) {
|
|
|
8001
8070
|
})]
|
|
8002
8071
|
}),
|
|
8003
8072
|
/* @__PURE__ */ jsxs("div", {
|
|
8004
|
-
className: "mt-8 flex items-
|
|
8073
|
+
className: "mt-8 flex items-end justify-between",
|
|
8005
8074
|
"data-pagefind-ignore": true,
|
|
8006
8075
|
children: [/* @__PURE__ */ jsx(NavigationButton, {
|
|
8007
8076
|
...prev,
|
|
8077
|
+
eyebrow: site.labels.previousPage,
|
|
8008
8078
|
isPrev: true
|
|
8009
|
-
}), /* @__PURE__ */ jsx(NavigationButton, {
|
|
8079
|
+
}), /* @__PURE__ */ jsx(NavigationButton, {
|
|
8080
|
+
...next,
|
|
8081
|
+
eyebrow: site.labels.nextPage
|
|
8082
|
+
})]
|
|
8010
8083
|
})
|
|
8011
8084
|
]
|
|
8012
8085
|
});
|
|
8013
8086
|
}
|
|
8014
|
-
const NavigationButton = ({ label, url, isPrev }) => {
|
|
8015
|
-
if (!url || !label) return /* @__PURE__ */ jsx("div", {});
|
|
8087
|
+
const NavigationButton = ({ label, url, eyebrow, isPrev }) => {
|
|
8088
|
+
if (!url || !label) return /* @__PURE__ */ jsx("div", { className: "flex-1" });
|
|
8016
8089
|
return /* @__PURE__ */ jsxs(Link, {
|
|
8017
8090
|
to: url,
|
|
8018
|
-
className: "group
|
|
8091
|
+
className: cn("group flex flex-1 items-end gap-3 py-3 text-base text-foreground", { "justify-end text-right": !isPrev }),
|
|
8092
|
+
rel: isPrev ? "prev" : "next",
|
|
8019
8093
|
children: [
|
|
8020
|
-
isPrev && /* @__PURE__ */ jsx(
|
|
8094
|
+
isPrev && /* @__PURE__ */ jsx(ArrowLeft, {
|
|
8021
8095
|
size: 14,
|
|
8022
|
-
className: "
|
|
8096
|
+
className: "mb-[0.3rem] text-muted-foreground transition-colors group-hover:text-foreground"
|
|
8023
8097
|
}),
|
|
8024
|
-
|
|
8025
|
-
|
|
8098
|
+
/* @__PURE__ */ jsxs("span", {
|
|
8099
|
+
className: "flex flex-col",
|
|
8100
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
8101
|
+
className: "text-xs font-bold text-muted-foreground",
|
|
8102
|
+
children: eyebrow
|
|
8103
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
8104
|
+
className: "font-medium transition-colors group-hover:text-primary",
|
|
8105
|
+
children: label
|
|
8106
|
+
})]
|
|
8107
|
+
}),
|
|
8108
|
+
!isPrev && /* @__PURE__ */ jsx(ArrowRight, {
|
|
8026
8109
|
size: 14,
|
|
8027
|
-
className: "text-muted-foreground transition-colors group-hover:text-foreground"
|
|
8110
|
+
className: "mb-[0.3rem] text-muted-foreground transition-colors group-hover:text-foreground"
|
|
8028
8111
|
})
|
|
8029
8112
|
]
|
|
8030
8113
|
});
|
|
@@ -8307,7 +8390,7 @@ function SideNav({ tabs, navigation, anchors, activeTabId, isSticky, drilldown,
|
|
|
8307
8390
|
const { pathname } = useLocation();
|
|
8308
8391
|
const nodes = navigation[activeTabId] || navigation[tabs[0]?.id] || [];
|
|
8309
8392
|
return /* @__PURE__ */ jsx(ScrollArea, {
|
|
8310
|
-
className: cn("w-full max-w-full", { "h-
|
|
8393
|
+
className: cn("w-full max-w-full", { "min-h-0 grow": isSticky }),
|
|
8311
8394
|
children: /* @__PURE__ */ jsxs("nav", {
|
|
8312
8395
|
className: "flex w-full flex-col gap-6 pr-4 text-sm",
|
|
8313
8396
|
"aria-label": navigationLabel,
|
|
@@ -8462,9 +8545,13 @@ function Docs({ page, doc, site }) {
|
|
|
8462
8545
|
})]
|
|
8463
8546
|
}), /* @__PURE__ */ jsxs("div", {
|
|
8464
8547
|
className: "flex items-start gap-12 lg:min-h-[calc(100dvh-var(--header-height))] lg:pt-6",
|
|
8465
|
-
children: [/* @__PURE__ */
|
|
8466
|
-
className: "hidden min-w-0 max-w-60 basis-60 self-start lg:sticky lg:top-[calc(var(--header-height)+1.5rem)] lg:
|
|
8467
|
-
children: /* @__PURE__ */ jsx(
|
|
8548
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
8549
|
+
className: "hidden min-w-0 max-w-60 basis-60 flex-col gap-4 self-start lg:sticky lg:top-[calc(var(--header-height)+1.5rem)] lg:flex lg:h-[calc(100dvh-var(--header-height)-3rem)] lg:shrink-0",
|
|
8550
|
+
children: [/* @__PURE__ */ jsx(SearchSlot, {
|
|
8551
|
+
site,
|
|
8552
|
+
position: "sidebar",
|
|
8553
|
+
className: "w-full"
|
|
8554
|
+
}), /* @__PURE__ */ jsx(SideNav, {
|
|
8468
8555
|
tabs,
|
|
8469
8556
|
navigation,
|
|
8470
8557
|
anchors: scopeDocs.anchors,
|
|
@@ -8474,7 +8561,7 @@ function Docs({ page, doc, site }) {
|
|
|
8474
8561
|
navigationLabel: site.labels.documentationNavigation,
|
|
8475
8562
|
expandLabel: site.labels.expand,
|
|
8476
8563
|
collapseLabel: site.labels.collapse
|
|
8477
|
-
})
|
|
8564
|
+
})]
|
|
8478
8565
|
}), /* @__PURE__ */ jsxs("div", {
|
|
8479
8566
|
className: "flex min-w-0 grow self-stretch flex-col",
|
|
8480
8567
|
children: [/* @__PURE__ */ jsxs("div", {
|
package/dist/chunks/docs.js
CHANGED
|
@@ -9832,7 +9832,8 @@ const styles = {
|
|
|
9832
9832
|
accordionItem: "",
|
|
9833
9833
|
accordionTrigger: "text-foreground",
|
|
9834
9834
|
accordionContent: "text-muted-foreground [&_p]:mt-0 [&_p:last-child]:mb-0",
|
|
9835
|
-
expandableTrigger: "items-center
|
|
9835
|
+
expandableTrigger: "items-center py-3 text-sm font-normal text-foreground hover:no-underline",
|
|
9836
|
+
expandableContent: "pl-6",
|
|
9836
9837
|
callout: "my-4 flex items-start gap-3 rounded-lg border px-3 py-2.5 text-sm leading-6",
|
|
9837
9838
|
calloutIcon: "flex h-6 w-5 shrink-0 items-center justify-center [&_svg]:block [&_svg]:size-4",
|
|
9838
9839
|
calloutBody: "flex min-w-0 flex-1 flex-col gap-[0.35rem] [&>:first-child]:mt-0 [&>:last-child]:mb-0 [&_:where(p,ul,ol)]:my-[0.35rem] [&>:where(p,ul,ol):first-child]:mt-0 [&>:where(p,ul,ol):last-child]:mb-0",
|
|
@@ -9844,7 +9845,8 @@ const styles = {
|
|
|
9844
9845
|
tip: "border-green-300 bg-green-50 text-green-900 dark:border-green-400/40 dark:bg-green-400/10 dark:text-green-300",
|
|
9845
9846
|
check: "border-emerald-300 bg-emerald-50 text-emerald-900 dark:border-emerald-400/40 dark:bg-emerald-400/10 dark:text-emerald-300",
|
|
9846
9847
|
danger: "border-destructive/40 bg-destructive/10 text-destructive",
|
|
9847
|
-
card: "block h-full gap-0 rounded-lg border border-border
|
|
9848
|
+
card: "block h-full gap-0 rounded-lg border border-border p-4 text-sm ring-0 hover:border-primary",
|
|
9849
|
+
cardPlain: "bg-card",
|
|
9848
9850
|
cardHorizontal: "[&_[data-slot=card-inner]]:items-center [&_[data-slot=card-main]]:flex-row [&_[data-slot=card-main]]:items-center [&_[data-slot=card-main]]:gap-3 [&_[data-slot=card-body]]:m-0 [&_[data-slot=card-header]]:flex-row [&_[data-slot=card-header]]:items-center [&_[data-slot=card-header]]:gap-2",
|
|
9849
9851
|
cardTyped: "[&_[data-slot=card-title]]:text-inherit [&_[data-slot=card-body]]:text-inherit [&_[data-slot=card-cta]]:text-inherit [&_[data-slot=card-arrow]]:text-inherit",
|
|
9850
9852
|
cardImageLayout: "p-0 [&_[data-slot=card-inner]]:p-6",
|
|
@@ -9853,7 +9855,7 @@ const styles = {
|
|
|
9853
9855
|
cardMain: "flex min-w-0 flex-col gap-2",
|
|
9854
9856
|
cardHeader: "flex flex-col items-start gap-3",
|
|
9855
9857
|
cardIcon: "inline-flex shrink-0 items-center justify-center [&_img]:size-6 [&_svg]:size-6",
|
|
9856
|
-
cardTitle: "text-
|
|
9858
|
+
cardTitle: "text-sm font-semibold text-foreground",
|
|
9857
9859
|
cardBody: "text-muted-foreground [&>:first-child]:mt-0 [&>:last-child]:mb-0",
|
|
9858
9860
|
cardCta: "flex shrink-0 items-center gap-[0.35rem] text-[0.9rem] font-medium text-muted-foreground",
|
|
9859
9861
|
cardArrow: "shrink-0 text-muted-foreground",
|
|
@@ -10377,7 +10379,7 @@ function DocsCardContent({ title, icon, color, img, cta, arrow, type, children }
|
|
|
10377
10379
|
function Card({ title, href, icon, color, img, cta, horizontal, arrow, type, children }) {
|
|
10378
10380
|
const external = typeof href === "string" && /^https?:\/\//i.test(href);
|
|
10379
10381
|
const showArrow = arrow ?? external;
|
|
10380
|
-
const className = `${styles.card} ${type ? `${styles.cardTyped} ${styles[type]} ${CARD_TYPE_HOVER[type]}` :
|
|
10382
|
+
const className = `${styles.card} ${type ? `${styles.cardTyped} ${styles[type]} ${CARD_TYPE_HOVER[type]}` : styles.cardPlain} ${horizontal ? styles.cardHorizontal : ""} ${img ? styles.cardImageLayout : ""}`;
|
|
10381
10383
|
const content = /* @__PURE__ */ jsx(Card$1, {
|
|
10382
10384
|
className,
|
|
10383
10385
|
children: /* @__PURE__ */ jsx(DocsCardContent, {
|
|
@@ -11304,7 +11306,7 @@ function CodeGroup({ children }) {
|
|
|
11304
11306
|
return /* @__PURE__ */ jsxs(Tabs$1, {
|
|
11305
11307
|
value: selected,
|
|
11306
11308
|
onValueChange: setSelectedKey,
|
|
11307
|
-
className: "my-4 gap-0 overflow-hidden rounded-lg bg-
|
|
11309
|
+
className: "my-4 gap-0 overflow-hidden rounded-lg bg-card [&_[data-slot=code-block]]:my-0 [&_[data-slot=code-block]]:rounded-none [&_[data-slot=code-block]]:border-0 [&_[data-slot=code-block]]:bg-transparent",
|
|
11308
11310
|
children: [/* @__PURE__ */ jsx(TabsList, {
|
|
11309
11311
|
variant: "line",
|
|
11310
11312
|
className: "h-9 w-full justify-start gap-5 overflow-x-auto overflow-y-hidden rounded-none px-3 py-0 shadow-[inset_0_-1px_0_var(--border)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
@@ -11541,7 +11543,7 @@ function Expandable({ title, children, defaultOpen = false }) {
|
|
|
11541
11543
|
className: `${styles.expandableTrigger} group/collapsible-trigger flex w-full justify-start gap-2 text-left outline-none focus-visible:ring-3 focus-visible:ring-ring/50`,
|
|
11542
11544
|
children: [/* @__PURE__ */ jsx(ChevronRight, { className: "size-4 shrink-0 text-muted-foreground transition-transform group-aria-expanded/collapsible-trigger:rotate-90" }), title]
|
|
11543
11545
|
}), /* @__PURE__ */ jsx(CollapsibleContent, { children: /* @__PURE__ */ jsx("div", {
|
|
11544
|
-
className: styles.accordionContent
|
|
11546
|
+
className: `${styles.accordionContent} ${styles.expandableContent}`,
|
|
11545
11547
|
children
|
|
11546
11548
|
}) })]
|
|
11547
11549
|
})
|
|
@@ -11725,53 +11727,43 @@ function PropertiesTable({ children }) {
|
|
|
11725
11727
|
const rows = toElementArray(children);
|
|
11726
11728
|
if (!rows.length) return null;
|
|
11727
11729
|
return /* @__PURE__ */ jsx("div", {
|
|
11728
|
-
className: "my-4 overflow-x-auto
|
|
11730
|
+
className: "my-4 overflow-x-auto",
|
|
11729
11731
|
children: /* @__PURE__ */ jsxs("table", {
|
|
11730
|
-
className: "m-0 min-w-[40rem] table-fixed
|
|
11732
|
+
className: "m-0 min-w-[40rem] table-fixed",
|
|
11731
11733
|
children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
11732
11734
|
/* @__PURE__ */ jsx("th", {
|
|
11733
|
-
className: "w-1/5
|
|
11735
|
+
className: "w-1/5",
|
|
11734
11736
|
children: "Name"
|
|
11735
11737
|
}),
|
|
11736
11738
|
/* @__PURE__ */ jsx("th", {
|
|
11737
|
-
className: "w-1/4
|
|
11739
|
+
className: "w-1/4",
|
|
11738
11740
|
children: "Type"
|
|
11739
11741
|
}),
|
|
11740
|
-
/* @__PURE__ */ jsx("th", {
|
|
11741
|
-
|
|
11742
|
-
children: "Description"
|
|
11743
|
-
})
|
|
11744
|
-
] }) }), /* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => {
|
|
11742
|
+
/* @__PURE__ */ jsx("th", { children: "Description" })
|
|
11743
|
+
] }) }), /* @__PURE__ */ jsx("tbody", { children: rows.map((row) => {
|
|
11745
11744
|
const { name, type, required, deprecated, children: description } = row.props;
|
|
11746
11745
|
const defaultValue = displayValue(row.props.default);
|
|
11747
|
-
const borderClass = index === rows.length - 1 ? "border-b-0" : "border-b";
|
|
11748
11746
|
return /* @__PURE__ */ jsxs("tr", { children: [
|
|
11749
|
-
/* @__PURE__ */ jsx("td", {
|
|
11750
|
-
className:
|
|
11751
|
-
children:
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
deprecated
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
})
|
|
11766
|
-
}),
|
|
11767
|
-
/* @__PURE__ */ jsx("td", {
|
|
11768
|
-
className: `${borderClass} border-x-0 border-t-0 border-border px-0 py-2 pr-6 align-top text-sm text-foreground`,
|
|
11769
|
-
children: displayValue(type)
|
|
11770
|
-
}),
|
|
11747
|
+
/* @__PURE__ */ jsx("td", { children: /* @__PURE__ */ jsxs("span", {
|
|
11748
|
+
className: "inline-flex flex-wrap items-center gap-2",
|
|
11749
|
+
children: [
|
|
11750
|
+
name,
|
|
11751
|
+
required ? /* @__PURE__ */ jsx(Badge, {
|
|
11752
|
+
size: "xs",
|
|
11753
|
+
tone: "primary",
|
|
11754
|
+
children: "required"
|
|
11755
|
+
}) : null,
|
|
11756
|
+
deprecated ? /* @__PURE__ */ jsx(Badge, {
|
|
11757
|
+
size: "xs",
|
|
11758
|
+
children: "deprecated"
|
|
11759
|
+
}) : null
|
|
11760
|
+
]
|
|
11761
|
+
}) }),
|
|
11762
|
+
/* @__PURE__ */ jsx("td", { children: displayValue(type) }),
|
|
11771
11763
|
/* @__PURE__ */ jsxs("td", {
|
|
11772
|
-
className:
|
|
11764
|
+
className: "[&_p]:m-0",
|
|
11773
11765
|
children: [description, defaultValue ? /* @__PURE__ */ jsxs("span", {
|
|
11774
|
-
className: "mt-1 block text-
|
|
11766
|
+
className: "mt-1 block text-muted-foreground",
|
|
11775
11767
|
children: ["Default: ", defaultValue]
|
|
11776
11768
|
}) : null]
|
|
11777
11769
|
})
|
package/docs.schema.json
CHANGED
|
@@ -279,6 +279,14 @@
|
|
|
279
279
|
"allOf": [{ "$ref": "#/definitions/stringValue" }],
|
|
280
280
|
"description": "Placeholder text for the search input."
|
|
281
281
|
},
|
|
282
|
+
"position": {
|
|
283
|
+
"anyOf": [
|
|
284
|
+
{ "type": "string", "enum": ["header", "sidebar"] },
|
|
285
|
+
{ "$ref": "#/definitions/configRefValue" }
|
|
286
|
+
],
|
|
287
|
+
"default": "header",
|
|
288
|
+
"description": "Where the search control renders: \"header\" (right side of the header) or \"sidebar\" (top of the navigation column; stays in the header on small screens). Themes that do not support a position fall back to \"header\"."
|
|
289
|
+
},
|
|
282
290
|
"provider": {
|
|
283
291
|
"allOf": [{ "$ref": "#/definitions/nonEmptyStringValue" }],
|
|
284
292
|
"description": "Search provider id: \"local\" (default), \"pagefind\", or a provider registered at runtime."
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ export function CodeBlock({ children, className }: CodeBlockProps) {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
|
-
<div data-slot="code-block" className="relative my-5 overflow-hidden rounded-lg bg-
|
|
25
|
+
<div data-slot="code-block" className="relative my-5 overflow-hidden rounded-lg bg-card">
|
|
26
26
|
<ScrollArea scrollbars="horizontal" className="w-full">
|
|
27
27
|
<pre
|
|
28
28
|
ref={textInput}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Link } from 'react-router';
|
|
2
2
|
import { ContextualMenu } from '@/components/ContextualMenu';
|
|
3
|
-
import {
|
|
3
|
+
import { ArrowLeft, ArrowRight, FileText } from '@/components/icons';
|
|
4
4
|
import { getLastModified } from '@/lib/content';
|
|
5
5
|
import { getScopeForPage } from '@/lib/docs-config';
|
|
6
6
|
import { resolveLocale } from '@/lib/locale';
|
|
7
7
|
import { docsSite, getPageByPathname } from '@/lib/site-config';
|
|
8
8
|
import { resolveContextualOptions } from '@/lib/site-model';
|
|
9
9
|
import type { DocModule, NormalizedDocsPage, RelatedEntry, SiteModel } from '@/lib/types';
|
|
10
|
+
import { cn } from '@/lib/utils';
|
|
10
11
|
|
|
11
12
|
interface RelatedLink {
|
|
12
13
|
href: string;
|
|
@@ -148,9 +149,9 @@ export function DocContent({ page, doc, site }: DocContentProps) {
|
|
|
148
149
|
</ul>
|
|
149
150
|
</nav>
|
|
150
151
|
)}
|
|
151
|
-
<div className="mt-8 flex items-
|
|
152
|
-
<NavigationButton {...prev} isPrev />
|
|
153
|
-
<NavigationButton {...next} />
|
|
152
|
+
<div className="mt-8 flex items-end justify-between" data-pagefind-ignore>
|
|
153
|
+
<NavigationButton {...prev} eyebrow={site.labels.previousPage} isPrev />
|
|
154
|
+
<NavigationButton {...next} eyebrow={site.labels.nextPage} />
|
|
154
155
|
</div>
|
|
155
156
|
</article>
|
|
156
157
|
);
|
|
@@ -159,32 +160,44 @@ export function DocContent({ page, doc, site }: DocContentProps) {
|
|
|
159
160
|
const NavigationButton = ({
|
|
160
161
|
label,
|
|
161
162
|
url,
|
|
163
|
+
eyebrow,
|
|
162
164
|
isPrev,
|
|
163
165
|
}: {
|
|
164
166
|
label?: string;
|
|
165
167
|
url?: string;
|
|
168
|
+
/** Direction caption ("Previous" / "Next") shown above the page title. */
|
|
169
|
+
eyebrow: string;
|
|
166
170
|
isPrev?: boolean;
|
|
167
171
|
}) => {
|
|
168
172
|
if (!url || !label) {
|
|
169
|
-
return <div />;
|
|
173
|
+
return <div className="flex-1" />;
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
return (
|
|
173
177
|
<Link
|
|
174
178
|
to={url}
|
|
175
|
-
|
|
179
|
+
// The link stretches across its half of the row so the whole box is
|
|
180
|
+
// clickable, not just the text. Vertical margin became padding for the
|
|
181
|
+
// same reason.
|
|
182
|
+
className={cn('group flex flex-1 items-end gap-3 py-3 text-base text-foreground', {
|
|
183
|
+
'justify-end text-right': !isPrev,
|
|
184
|
+
})}
|
|
185
|
+
rel={isPrev ? 'prev' : 'next'}
|
|
176
186
|
>
|
|
177
187
|
{isPrev && (
|
|
178
|
-
<
|
|
188
|
+
<ArrowLeft
|
|
179
189
|
size={14}
|
|
180
|
-
className="
|
|
190
|
+
className="mb-[0.3rem] text-muted-foreground transition-colors group-hover:text-foreground"
|
|
181
191
|
/>
|
|
182
192
|
)}
|
|
183
|
-
|
|
193
|
+
<span className="flex flex-col">
|
|
194
|
+
<span className="text-xs font-bold text-muted-foreground">{eyebrow}</span>
|
|
195
|
+
<span className="font-medium transition-colors group-hover:text-primary">{label}</span>
|
|
196
|
+
</span>
|
|
184
197
|
{!isPrev && (
|
|
185
|
-
<
|
|
198
|
+
<ArrowRight
|
|
186
199
|
size={14}
|
|
187
|
-
className="text-muted-foreground transition-colors group-hover:text-foreground"
|
|
200
|
+
className="mb-[0.3rem] text-muted-foreground transition-colors group-hover:text-foreground"
|
|
188
201
|
/>
|
|
189
202
|
)}
|
|
190
203
|
</Link>
|
package/src/components/Docs.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { Footer } from '@/components/Footer';
|
|
|
5
5
|
import { Menu } from '@/components/icons';
|
|
6
6
|
import { LanguageSwitcher } from '@/components/LanguageSwitcher';
|
|
7
7
|
import { PageLinks } from '@/components/PageLinks';
|
|
8
|
+
import { SearchSlot } from '@/components/Search';
|
|
8
9
|
import { SideNav } from '@/components/SideNav';
|
|
9
10
|
import { Button } from '@/components/ui/button';
|
|
10
11
|
import { Sheet, SheetContent, SheetTitle, SheetTrigger } from '@/components/ui/sheet';
|
|
@@ -104,7 +105,8 @@ export function Docs({ page, doc, site }: DocsProps) {
|
|
|
104
105
|
</SheetContent>
|
|
105
106
|
</Sheet>
|
|
106
107
|
<div className="flex items-start gap-12 lg:min-h-[calc(100dvh-var(--header-height))] lg:pt-6">
|
|
107
|
-
<div className="hidden min-w-0 max-w-60 basis-60 self-start lg:sticky lg:top-[calc(var(--header-height)+1.5rem)] lg:
|
|
108
|
+
<div className="hidden min-w-0 max-w-60 basis-60 flex-col gap-4 self-start lg:sticky lg:top-[calc(var(--header-height)+1.5rem)] lg:flex lg:h-[calc(100dvh-var(--header-height)-3rem)] lg:shrink-0">
|
|
109
|
+
<SearchSlot site={site} position="sidebar" className="w-full" />
|
|
108
110
|
<SideNav
|
|
109
111
|
tabs={tabs}
|
|
110
112
|
navigation={navigation}
|
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
import { Link, useLocation } from 'react-router';
|
|
2
2
|
import { ConfiguredIcon } from '@/components/ConfiguredIcon';
|
|
3
3
|
import { LanguageSwitcher } from '@/components/LanguageSwitcher';
|
|
4
|
-
import {
|
|
4
|
+
import { SearchSlot } from '@/components/Search';
|
|
5
5
|
import { ThemeToggle } from '@/components/ThemeToggle';
|
|
6
6
|
import { TopNav } from '@/components/TopNav';
|
|
7
7
|
import { VersionSwitcher } from '@/components/VersionSwitcher';
|
|
8
8
|
import { isExternalHref } from '@/lib/paths';
|
|
9
|
-
import {
|
|
10
|
-
docsHomeUrl,
|
|
11
|
-
getPageFrontmatter,
|
|
12
|
-
getScopeByPathname,
|
|
13
|
-
hasRootStandalonePage,
|
|
14
|
-
} from '@/lib/site-config';
|
|
9
|
+
import { docsHomeUrl, getScopeByPathname, hasRootStandalonePage } from '@/lib/site-config';
|
|
15
10
|
import type { NormalizedLink, SiteModel } from '@/lib/types';
|
|
16
11
|
|
|
17
12
|
/**
|
|
@@ -63,11 +58,10 @@ function NavbarLinkItem({ link, primary = false }: { link: NormalizedLink; prima
|
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
export function Header({ site }: { site: SiteModel }) {
|
|
66
|
-
const { logo, navbar, name, appearance, labels
|
|
61
|
+
const { logo, navbar, name, appearance, labels } = site;
|
|
67
62
|
const { pathname } = useLocation();
|
|
68
63
|
// The header renders the navigation of whichever scope owns the current page.
|
|
69
64
|
const docs = getScopeByPathname(pathname).docs;
|
|
70
|
-
const showSearch = getPageFrontmatter(pathname)?.search !== false;
|
|
71
65
|
// The brand links to the standalone home page when one owns "/".
|
|
72
66
|
const brandHref = logo?.href || (hasRootStandalonePage ? '/' : docsHomeUrl);
|
|
73
67
|
const hasBrand = !!name || !!logo?.light || !!logo?.dark;
|
|
@@ -120,7 +114,10 @@ export function Header({ site }: { site: SiteModel }) {
|
|
|
120
114
|
{docs.showTabs ? <TopNav docs={docs} label={labels.sections} /> : null}
|
|
121
115
|
</div>
|
|
122
116
|
<div className="flex min-w-0 items-center gap-2 justify-self-end">
|
|
123
|
-
|
|
117
|
+
<SearchSlot site={site} position="header" />
|
|
118
|
+
{/* The sidebar collapses into a sheet on small screens, so its
|
|
119
|
+
search control moves up here until the column is visible. */}
|
|
120
|
+
<SearchSlot site={site} position="sidebar" className="lg:hidden" />
|
|
124
121
|
{navbar?.links.map(link => (
|
|
125
122
|
<NavbarLinkItem key={link.href} link={link} />
|
|
126
123
|
))}
|
|
@@ -14,8 +14,9 @@ import { Dialog, DialogContent, DialogTitle, DialogTrigger } from '@/components/
|
|
|
14
14
|
import { highlightTerms, type SearchResult } from '@/lib/search';
|
|
15
15
|
import type { ResolvedSearchConfig } from '@/lib/search/config';
|
|
16
16
|
import { resolveSearchProvider, type SearchProvider } from '@/lib/search/provider';
|
|
17
|
-
import { getScopeByPathname } from '@/lib/site-config';
|
|
18
|
-
import type { ThemeLabels } from '@/lib/types';
|
|
17
|
+
import { getPageFrontmatter, getScopeByPathname } from '@/lib/site-config';
|
|
18
|
+
import type { SearchPosition, SiteModel, ThemeLabels } from '@/lib/types';
|
|
19
|
+
import { cn } from '@/lib/utils';
|
|
19
20
|
|
|
20
21
|
/** Enough results to make the list scroll; the dialog caps its own height. */
|
|
21
22
|
const RESULT_LIMIT = 30;
|
|
@@ -54,7 +55,16 @@ function renderWithQueryHighlight(text: string, query: string) {
|
|
|
54
55
|
* Provider-neutral search dialog. The selected provider and its index or
|
|
55
56
|
* client are loaded on demand, so search stays out of the initial bundle.
|
|
56
57
|
*/
|
|
57
|
-
export function Search({
|
|
58
|
+
export function Search({
|
|
59
|
+
config,
|
|
60
|
+
labels,
|
|
61
|
+
className,
|
|
62
|
+
}: {
|
|
63
|
+
config: ResolvedSearchConfig;
|
|
64
|
+
labels: ThemeLabels;
|
|
65
|
+
/** Extra classes for the trigger button (e.g. to stretch it in a column). */
|
|
66
|
+
className?: string;
|
|
67
|
+
}) {
|
|
58
68
|
const navigate = useNavigate();
|
|
59
69
|
const { pathname } = useLocation();
|
|
60
70
|
const [open, setOpen] = useState(false);
|
|
@@ -179,12 +189,15 @@ export function Search({ config, labels }: { config: ResolvedSearchConfig; label
|
|
|
179
189
|
render={
|
|
180
190
|
<Button
|
|
181
191
|
variant="outline"
|
|
182
|
-
className=
|
|
192
|
+
className={cn(
|
|
193
|
+
'h-auto gap-2 rounded-md bg-card px-2.5 py-1.5 text-muted-foreground hover:border-input hover:bg-card hover:text-foreground',
|
|
194
|
+
className,
|
|
195
|
+
)}
|
|
183
196
|
/>
|
|
184
197
|
}
|
|
185
198
|
>
|
|
186
199
|
<SearchIcon className="size-3.5" />
|
|
187
|
-
<span className="min-w-24 text-left">{config.prompt}</span>
|
|
200
|
+
<span className="min-w-24 grow text-left">{config.prompt}</span>
|
|
188
201
|
{config.shortcut ? (
|
|
189
202
|
<kbd className="rounded-sm border border-border bg-muted px-[0.3rem] py-[0.05rem] text-[0.7rem] font-sans">
|
|
190
203
|
{config.shortcutLabel}
|
|
@@ -253,3 +266,30 @@ export function Search({ config, labels }: { config: ResolvedSearchConfig; label
|
|
|
253
266
|
</Dialog>
|
|
254
267
|
);
|
|
255
268
|
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Renders the search control only when `search.position` targets this slot.
|
|
272
|
+
* Layout components drop one of these into each position they support; the
|
|
273
|
+
* per-page `search: false` frontmatter flag is honored here as well.
|
|
274
|
+
*/
|
|
275
|
+
export function SearchSlot({
|
|
276
|
+
site,
|
|
277
|
+
position,
|
|
278
|
+
className,
|
|
279
|
+
}: {
|
|
280
|
+
site: SiteModel;
|
|
281
|
+
position: SearchPosition;
|
|
282
|
+
className?: string;
|
|
283
|
+
}) {
|
|
284
|
+
const { pathname } = useLocation();
|
|
285
|
+
|
|
286
|
+
if (!site.search.enabled || site.search.position !== position) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (getPageFrontmatter(pathname)?.search === false) {
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return <Search config={site.search} labels={site.labels} className={className} />;
|
|
295
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { cn } from '@/lib/utils';
|
|
2
1
|
import { type ReactNode, useEffect, useState } from 'react';
|
|
3
2
|
import { Link, useLocation, useNavigate } from 'react-router';
|
|
4
3
|
import { resolveIcon } from '@/components/docs/utils';
|
|
@@ -9,9 +8,9 @@ import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/component
|
|
|
9
8
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
10
9
|
import { flattenNav, isNodeHidden } from '@/lib/docs-config';
|
|
11
10
|
import type { DocsTab, NavGroupNode, NavNode } from '@/lib/types';
|
|
11
|
+
import { cn } from '@/lib/utils';
|
|
12
12
|
|
|
13
|
-
const sectionLabelClass =
|
|
14
|
-
'flex min-w-0 items-center gap-[0.4rem] pb-2 pr-1 font-bold text-inherit';
|
|
13
|
+
const sectionLabelClass = 'flex min-w-0 items-center gap-[0.4rem] pb-2 pr-1 font-bold text-inherit';
|
|
15
14
|
const groupLabelClass =
|
|
16
15
|
'flex min-w-0 items-center gap-[0.4rem] py-2 pl-3 pr-1 font-medium text-inherit';
|
|
17
16
|
const selectedClass =
|
|
@@ -319,7 +318,7 @@ export function SideNav({
|
|
|
319
318
|
const nodes = navigation[activeTabId] || navigation[tabs[0]?.id] || [];
|
|
320
319
|
|
|
321
320
|
return (
|
|
322
|
-
<ScrollArea className={cn('w-full max-w-full', { 'h-
|
|
321
|
+
<ScrollArea className={cn('w-full max-w-full', { 'min-h-0 grow': isSticky })}>
|
|
323
322
|
<nav className="flex w-full flex-col gap-6 pr-4 text-sm" aria-label={navigationLabel}>
|
|
324
323
|
{anchors.length ? (
|
|
325
324
|
<NavNodes
|
|
@@ -110,7 +110,7 @@ export function Card({
|
|
|
110
110
|
}: CardProps) {
|
|
111
111
|
const external = typeof href === 'string' && /^https?:\/\//i.test(href);
|
|
112
112
|
const showArrow = arrow ?? external;
|
|
113
|
-
const className = `${styles.card} ${type ? `${styles.cardTyped} ${styles[type]} ${CARD_TYPE_HOVER[type]}` :
|
|
113
|
+
const className = `${styles.card} ${type ? `${styles.cardTyped} ${styles[type]} ${CARD_TYPE_HOVER[type]}` : styles.cardPlain} ${horizontal ? styles.cardHorizontal : ''} ${img ? styles.cardImageLayout : ''}`;
|
|
114
114
|
const content = (
|
|
115
115
|
<CardPrimitive className={className}>
|
|
116
116
|
<DocsCardContent
|
|
@@ -46,7 +46,7 @@ export function CodeGroup({ children }: CodeGroupProps) {
|
|
|
46
46
|
<TabsPrimitive
|
|
47
47
|
value={selected}
|
|
48
48
|
onValueChange={setSelectedKey}
|
|
49
|
-
className="my-4 gap-0 overflow-hidden rounded-lg bg-
|
|
49
|
+
className="my-4 gap-0 overflow-hidden rounded-lg bg-card [&_[data-slot=code-block]]:my-0 [&_[data-slot=code-block]]:rounded-none [&_[data-slot=code-block]]:border-0 [&_[data-slot=code-block]]:bg-transparent"
|
|
50
50
|
>
|
|
51
51
|
<TabsList
|
|
52
52
|
variant="line"
|
|
@@ -20,7 +20,7 @@ export function Expandable({ title, children, defaultOpen = false }: ExpandableP
|
|
|
20
20
|
{title}
|
|
21
21
|
</CollapsibleTrigger>
|
|
22
22
|
<CollapsibleContent>
|
|
23
|
-
<div className={styles.accordionContent}>{children}</div>
|
|
23
|
+
<div className={`${styles.accordionContent} ${styles.expandableContent}`}>{children}</div>
|
|
24
24
|
</CollapsibleContent>
|
|
25
25
|
</div>
|
|
26
26
|
</Collapsible>
|
|
@@ -22,33 +22,26 @@ export function PropertiesTable({ children }: PropertiesTableProps) {
|
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
// Rendered as a plain table so the .docs-markdown table rules in global.css
|
|
26
|
+
// style it exactly like a GFM table; only column widths are set here.
|
|
25
27
|
return (
|
|
26
|
-
<div className="my-4 overflow-x-auto
|
|
27
|
-
<table className="m-0 min-w-[40rem] table-fixed
|
|
28
|
+
<div className="my-4 overflow-x-auto">
|
|
29
|
+
<table className="m-0 min-w-[40rem] table-fixed">
|
|
28
30
|
<thead>
|
|
29
31
|
<tr>
|
|
30
|
-
<th className="w-1/5
|
|
31
|
-
|
|
32
|
-
</th>
|
|
33
|
-
<th className="w-1/4 border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-2 pr-6 text-left text-sm font-semibold text-foreground">
|
|
34
|
-
Type
|
|
35
|
-
</th>
|
|
36
|
-
<th className="border-x-0 border-t-0 border-b border-border bg-transparent px-0 py-2 text-left text-sm font-semibold text-foreground">
|
|
37
|
-
Description
|
|
38
|
-
</th>
|
|
32
|
+
<th className="w-1/5">Name</th>
|
|
33
|
+
<th className="w-1/4">Type</th>
|
|
34
|
+
<th>Description</th>
|
|
39
35
|
</tr>
|
|
40
36
|
</thead>
|
|
41
37
|
<tbody>
|
|
42
|
-
{rows.map(
|
|
38
|
+
{rows.map(row => {
|
|
43
39
|
const { name, type, required, deprecated, children: description } = row.props;
|
|
44
40
|
const defaultValue = displayValue(row.props.default);
|
|
45
|
-
const borderClass = index === rows.length - 1 ? 'border-b-0' : 'border-b';
|
|
46
41
|
|
|
47
42
|
return (
|
|
48
43
|
<tr key={row.key ?? name}>
|
|
49
|
-
<td
|
|
50
|
-
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-2 pr-6 align-top text-sm text-foreground`}
|
|
51
|
-
>
|
|
44
|
+
<td>
|
|
52
45
|
<span className="inline-flex flex-wrap items-center gap-2">
|
|
53
46
|
{name}
|
|
54
47
|
{required ? (
|
|
@@ -59,17 +52,11 @@ export function PropertiesTable({ children }: PropertiesTableProps) {
|
|
|
59
52
|
{deprecated ? <Badge size="xs">deprecated</Badge> : null}
|
|
60
53
|
</span>
|
|
61
54
|
</td>
|
|
62
|
-
<td
|
|
63
|
-
|
|
64
|
-
>
|
|
65
|
-
{displayValue(type)}
|
|
66
|
-
</td>
|
|
67
|
-
<td
|
|
68
|
-
className={`${borderClass} border-x-0 border-t-0 border-border px-0 py-2 align-top text-sm leading-6 text-foreground [&_p]:m-0`}
|
|
69
|
-
>
|
|
55
|
+
<td>{displayValue(type)}</td>
|
|
56
|
+
<td className="[&_p]:m-0">
|
|
70
57
|
{description}
|
|
71
58
|
{defaultValue ? (
|
|
72
|
-
<span className="mt-1 block text-
|
|
59
|
+
<span className="mt-1 block text-muted-foreground">
|
|
73
60
|
Default: {defaultValue}
|
|
74
61
|
</span>
|
|
75
62
|
) : null}
|
|
@@ -9,8 +9,9 @@ export const styles = {
|
|
|
9
9
|
accordionItem: '',
|
|
10
10
|
accordionTrigger: 'text-foreground',
|
|
11
11
|
accordionContent: 'text-muted-foreground [&_p]:mt-0 [&_p:last-child]:mb-0',
|
|
12
|
-
expandableTrigger:
|
|
13
|
-
|
|
12
|
+
expandableTrigger: 'items-center py-3 text-sm font-normal text-foreground hover:no-underline',
|
|
13
|
+
/* Indent by chevron width + gap so body text lines up with the title. */
|
|
14
|
+
expandableContent: 'pl-6',
|
|
14
15
|
|
|
15
16
|
callout: 'my-4 flex items-start gap-3 rounded-lg border px-3 py-2.5 text-sm leading-6',
|
|
16
17
|
calloutIcon: 'flex h-6 w-5 shrink-0 items-center justify-center [&_svg]:block [&_svg]:size-4',
|
|
@@ -27,7 +28,9 @@ export const styles = {
|
|
|
27
28
|
'border-emerald-300 bg-emerald-50 text-emerald-900 dark:border-emerald-400/40 dark:bg-emerald-400/10 dark:text-emerald-300',
|
|
28
29
|
danger: 'border-destructive/40 bg-destructive/10 text-destructive',
|
|
29
30
|
|
|
30
|
-
card: 'block h-full gap-0 rounded-lg border border-border
|
|
31
|
+
card: 'block h-full gap-0 rounded-lg border border-border p-4 text-sm ring-0 hover:border-primary',
|
|
32
|
+
/* Typed cards bring their own tinted background; plain cards get the surface tint. */
|
|
33
|
+
cardPlain: 'bg-card',
|
|
31
34
|
cardHorizontal:
|
|
32
35
|
'[&_[data-slot=card-inner]]:items-center [&_[data-slot=card-main]]:flex-row [&_[data-slot=card-main]]:items-center [&_[data-slot=card-main]]:gap-3 [&_[data-slot=card-body]]:m-0 [&_[data-slot=card-header]]:flex-row [&_[data-slot=card-header]]:items-center [&_[data-slot=card-header]]:gap-2',
|
|
33
36
|
cardTyped:
|
|
@@ -38,7 +41,7 @@ export const styles = {
|
|
|
38
41
|
cardMain: 'flex min-w-0 flex-col gap-2',
|
|
39
42
|
cardHeader: 'flex flex-col items-start gap-3',
|
|
40
43
|
cardIcon: 'inline-flex shrink-0 items-center justify-center [&_img]:size-6 [&_svg]:size-6',
|
|
41
|
-
cardTitle: 'text-
|
|
44
|
+
cardTitle: 'text-sm font-semibold text-foreground',
|
|
42
45
|
cardBody: 'text-muted-foreground [&>:first-child]:mt-0 [&>:last-child]:mb-0',
|
|
43
46
|
cardCta:
|
|
44
47
|
'flex shrink-0 items-center gap-[0.35rem] text-[0.9rem] font-medium text-muted-foreground',
|
package/src/lib/search/config.ts
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
import type { SearchConfig } from '@/lib/types';
|
|
1
|
+
import type { SearchConfig, SearchPosition } from '@/lib/types';
|
|
2
2
|
|
|
3
3
|
export const DEFAULT_SEARCH_PROMPT = 'Search...';
|
|
4
4
|
export const DEFAULT_SEARCH_PROVIDER = 'local';
|
|
5
5
|
export const DEFAULT_SEARCH_SHORTCUT = 'k';
|
|
6
6
|
export const DEFAULT_SEARCH_SHORTCUT_LABEL = 'Ctrl K';
|
|
7
|
+
export const DEFAULT_SEARCH_POSITION: SearchPosition = 'header';
|
|
8
|
+
|
|
9
|
+
/** Positions the built-in theme knows how to render. */
|
|
10
|
+
export const SEARCH_POSITIONS: readonly SearchPosition[] = ['header', 'sidebar'];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Themes must always support "header", so anything unrecognized (or not
|
|
14
|
+
* implemented by the active theme) lands there instead of vanishing.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveSearchPosition(
|
|
17
|
+
position: unknown,
|
|
18
|
+
supported: readonly SearchPosition[] = SEARCH_POSITIONS,
|
|
19
|
+
): SearchPosition {
|
|
20
|
+
if (typeof position === 'string' && (supported as readonly string[]).includes(position)) {
|
|
21
|
+
return position as SearchPosition;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (position !== undefined && position !== DEFAULT_SEARCH_POSITION) {
|
|
25
|
+
console.warn(
|
|
26
|
+
`[shiso] Unsupported search.position "${String(position)}" — using "${DEFAULT_SEARCH_POSITION}".`,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return DEFAULT_SEARCH_POSITION;
|
|
31
|
+
}
|
|
7
32
|
|
|
8
33
|
export interface ResolvedSearchConfig {
|
|
9
34
|
enabled: boolean;
|
|
10
35
|
prompt: string;
|
|
36
|
+
position: SearchPosition;
|
|
11
37
|
provider: string;
|
|
12
38
|
options: Record<string, unknown>;
|
|
13
39
|
shortcut: string | false;
|
|
@@ -22,6 +48,7 @@ export function resolveSearchConfig(
|
|
|
22
48
|
return {
|
|
23
49
|
enabled: false,
|
|
24
50
|
prompt: DEFAULT_SEARCH_PROMPT,
|
|
51
|
+
position: DEFAULT_SEARCH_POSITION,
|
|
25
52
|
provider: DEFAULT_SEARCH_PROVIDER,
|
|
26
53
|
options: {},
|
|
27
54
|
shortcut: false,
|
|
@@ -32,6 +59,7 @@ export function resolveSearchConfig(
|
|
|
32
59
|
return {
|
|
33
60
|
enabled: true,
|
|
34
61
|
prompt: config?.prompt?.trim() || DEFAULT_SEARCH_PROMPT,
|
|
62
|
+
position: resolveSearchPosition(config?.position),
|
|
35
63
|
provider: config?.provider?.trim().toLowerCase() || DEFAULT_SEARCH_PROVIDER,
|
|
36
64
|
options: config?.options || {},
|
|
37
65
|
shortcut:
|
package/src/lib/site-model.ts
CHANGED
|
@@ -29,6 +29,8 @@ const SHISO_THEME_LABELS: ThemeLabels = {
|
|
|
29
29
|
noResults: 'No results',
|
|
30
30
|
lastUpdated: 'Last updated on',
|
|
31
31
|
relatedTopics: 'Related topics',
|
|
32
|
+
previousPage: 'Previous',
|
|
33
|
+
nextPage: 'Next',
|
|
32
34
|
notFound: 'Page not found',
|
|
33
35
|
dismissBanner: 'Dismiss banner',
|
|
34
36
|
toggleTheme: 'Toggle theme',
|
package/src/lib/types.ts
CHANGED
|
@@ -255,9 +255,20 @@ export interface FontsConfig extends FontSpec {
|
|
|
255
255
|
body?: FontSpec;
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
/**
|
|
259
|
+
* Named slots a theme can place the search control in. Every theme must
|
|
260
|
+
* support "header"; unsupported positions fall back to it.
|
|
261
|
+
*/
|
|
262
|
+
export type SearchPosition = 'header' | 'sidebar';
|
|
263
|
+
|
|
258
264
|
export interface SearchConfig {
|
|
259
265
|
/** Placeholder text for the search input. */
|
|
260
266
|
prompt?: string;
|
|
267
|
+
/**
|
|
268
|
+
* Where the search control renders: "header" (default, right side of the
|
|
269
|
+
* header) or "sidebar" (top of the navigation column).
|
|
270
|
+
*/
|
|
271
|
+
position?: SearchPosition;
|
|
261
272
|
/** Provider id: "local" (default), "pagefind", or a runtime-registered id. */
|
|
262
273
|
provider?: string;
|
|
263
274
|
/** Provider-specific configuration. */
|
|
@@ -487,6 +498,8 @@ export interface ThemeLabels {
|
|
|
487
498
|
noResults: string;
|
|
488
499
|
lastUpdated: string;
|
|
489
500
|
relatedTopics: string;
|
|
501
|
+
previousPage: string;
|
|
502
|
+
nextPage: string;
|
|
490
503
|
notFound: string;
|
|
491
504
|
dismissBanner: string;
|
|
492
505
|
toggleTheme: string;
|
|
@@ -555,7 +568,7 @@ export interface DocFrontmatter {
|
|
|
555
568
|
title?: string;
|
|
556
569
|
description?: string;
|
|
557
570
|
noindex?: boolean;
|
|
558
|
-
/** Hide the
|
|
571
|
+
/** Hide the search control and disable its shortcut on this page. */
|
|
559
572
|
search?: false;
|
|
560
573
|
/** Overrides the site-wide `metadata.timestamp` setting for this page. */
|
|
561
574
|
timestamp?: boolean;
|
package/src/styles/global.css
CHANGED
|
@@ -186,8 +186,8 @@
|
|
|
186
186
|
font-size: 0.875rem;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
-
/*
|
|
190
|
-
horizontal row separators only, and
|
|
189
|
+
/* Shared by GFM tables and the PropertiesTable component: rounded outer border,
|
|
190
|
+
horizontal row separators only, and a card-colored header fill. */
|
|
191
191
|
.docs-markdown table:not(:where(.not-prose, .not-prose *)) {
|
|
192
192
|
width: 100%;
|
|
193
193
|
margin: 1rem 0;
|
|
@@ -222,10 +222,19 @@
|
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
.docs-markdown th:not(:where(.not-prose, .not-prose *)) {
|
|
225
|
-
background:
|
|
225
|
+
background: var(--card);
|
|
226
226
|
font-weight: 600;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
/* The header fill must follow the table's rounded top corners. */
|
|
230
|
+
.docs-markdown th:first-child:not(:where(.not-prose, .not-prose *)) {
|
|
231
|
+
border-top-left-radius: calc(var(--radius-lg) - 1px);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.docs-markdown th:last-child:not(:where(.not-prose, .not-prose *)) {
|
|
235
|
+
border-top-right-radius: calc(var(--radius-lg) - 1px);
|
|
236
|
+
}
|
|
237
|
+
|
|
229
238
|
.docs-markdown tbody tr:last-child td:not(:where(.not-prose, .not-prose *)) {
|
|
230
239
|
border-bottom: none;
|
|
231
240
|
}
|