@takazudo/zudo-doc 0.1.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/LICENSE +21 -0
- package/README.md +18 -0
- package/dist/body-foot-util/body-foot-util-area.d.ts +55 -0
- package/dist/body-foot-util/body-foot-util-area.js +71 -0
- package/dist/body-foot-util/edit-link.d.ts +45 -0
- package/dist/body-foot-util/edit-link.js +42 -0
- package/dist/body-foot-util/index.d.ts +3 -0
- package/dist/body-foot-util/index.js +11 -0
- package/dist/breadcrumb/breadcrumb.d.ts +57 -0
- package/dist/breadcrumb/breadcrumb.js +113 -0
- package/dist/breadcrumb/find-path.d.ts +16 -0
- package/dist/breadcrumb/find-path.js +13 -0
- package/dist/breadcrumb/index.d.ts +4 -0
- package/dist/breadcrumb/index.js +7 -0
- package/dist/breadcrumb/types.d.ts +32 -0
- package/dist/breadcrumb/types.js +0 -0
- package/dist/code-syntax/code-block-enhancer-script.d.ts +3 -0
- package/dist/code-syntax/code-block-enhancer-script.js +165 -0
- package/dist/code-syntax/code-block-enhancer.d.ts +22 -0
- package/dist/code-syntax/code-block-enhancer.js +13 -0
- package/dist/code-syntax/index.d.ts +8 -0
- package/dist/code-syntax/index.js +29 -0
- package/dist/code-syntax/mermaid-init-script.d.ts +51 -0
- package/dist/code-syntax/mermaid-init-script.js +225 -0
- package/dist/code-syntax/mermaid-init.d.ts +48 -0
- package/dist/code-syntax/mermaid-init.js +14 -0
- package/dist/code-syntax/tabs-init-script.d.ts +3 -0
- package/dist/code-syntax/tabs-init-script.js +106 -0
- package/dist/code-syntax/tabs-init.d.ts +24 -0
- package/dist/code-syntax/tabs-init.js +10 -0
- package/dist/code-syntax/tabs.d.ts +36 -0
- package/dist/code-syntax/tabs.js +62 -0
- package/dist/content/component-map.d.ts +51 -0
- package/dist/content/component-map.js +29 -0
- package/dist/content/content-blockquote.d.ts +11 -0
- package/dist/content/content-blockquote.js +14 -0
- package/dist/content/content-code.d.ts +26 -0
- package/dist/content/content-code.js +39 -0
- package/dist/content/content-link.d.ts +12 -0
- package/dist/content/content-link.js +43 -0
- package/dist/content/content-ol.d.ts +11 -0
- package/dist/content/content-ol.js +15 -0
- package/dist/content/content-paragraph.d.ts +10 -0
- package/dist/content/content-paragraph.js +7 -0
- package/dist/content/content-strong.d.ts +11 -0
- package/dist/content/content-strong.js +14 -0
- package/dist/content/content-table.d.ts +11 -0
- package/dist/content/content-table.js +14 -0
- package/dist/content/content-ul.d.ts +11 -0
- package/dist/content/content-ul.js +15 -0
- package/dist/content/heading-h2.d.ts +14 -0
- package/dist/content/heading-h2.js +18 -0
- package/dist/content/heading-h3.d.ts +14 -0
- package/dist/content/heading-h3.js +18 -0
- package/dist/content/heading-h4.d.ts +14 -0
- package/dist/content/heading-h4.js +18 -0
- package/dist/content/index.d.ts +13 -0
- package/dist/content/index.js +27 -0
- package/dist/details/details.d.ts +26 -0
- package/dist/details/details.js +10 -0
- package/dist/details/index.d.ts +2 -0
- package/dist/details/index.js +4 -0
- package/dist/doclayout/anchors.d.ts +55 -0
- package/dist/doclayout/anchors.js +42 -0
- package/dist/doclayout/doc-layout-with-defaults.d.ts +83 -0
- package/dist/doclayout/doc-layout-with-defaults.js +159 -0
- package/dist/doclayout/doc-layout.d.ts +121 -0
- package/dist/doclayout/doc-layout.js +89 -0
- package/dist/doclayout/index.d.ts +6 -0
- package/dist/doclayout/index.js +17 -0
- package/dist/footer/footer.d.ts +42 -0
- package/dist/footer/footer.js +79 -0
- package/dist/footer/index.d.ts +3 -0
- package/dist/footer/index.js +4 -0
- package/dist/footer/types.d.ts +58 -0
- package/dist/footer/types.js +0 -0
- package/dist/head/doc-head.d.ts +33 -0
- package/dist/head/doc-head.js +90 -0
- package/dist/head/index.d.ts +5 -0
- package/dist/head/index.js +8 -0
- package/dist/head/og-tags.d.ts +25 -0
- package/dist/head/og-tags.js +16 -0
- package/dist/head/twitter-card.d.ts +21 -0
- package/dist/head/twitter-card.js +14 -0
- package/dist/head/types.d.ts +83 -0
- package/dist/head/types.js +0 -0
- package/dist/header/header.d.ts +158 -0
- package/dist/header/header.js +367 -0
- package/dist/header/index.d.ts +6 -0
- package/dist/header/index.js +18 -0
- package/dist/header/nav-active.d.ts +39 -0
- package/dist/header/nav-active.js +24 -0
- package/dist/header/nav-overflow-script.d.ts +3 -0
- package/dist/header/nav-overflow-script.js +169 -0
- package/dist/header/right-items.d.ts +38 -0
- package/dist/header/right-items.js +30 -0
- package/dist/header/types.d.ts +40 -0
- package/dist/header/types.js +0 -0
- package/dist/html-preview-wrapper/dedent.d.ts +10 -0
- package/dist/html-preview-wrapper/dedent.js +16 -0
- package/dist/html-preview-wrapper/highlighted-code.d.ts +18 -0
- package/dist/html-preview-wrapper/highlighted-code.js +53 -0
- package/dist/html-preview-wrapper/html-preview-wrapper.d.ts +60 -0
- package/dist/html-preview-wrapper/html-preview-wrapper.js +36 -0
- package/dist/html-preview-wrapper/html-preview.d.ts +35 -0
- package/dist/html-preview-wrapper/html-preview.js +75 -0
- package/dist/html-preview-wrapper/index.d.ts +5 -0
- package/dist/html-preview-wrapper/index.js +12 -0
- package/dist/html-preview-wrapper/preflight.d.ts +13 -0
- package/dist/html-preview-wrapper/preflight.js +108 -0
- package/dist/html-preview-wrapper/preview-base.d.ts +29 -0
- package/dist/html-preview-wrapper/preview-base.js +127 -0
- package/dist/i18n-version/index.d.ts +5 -0
- package/dist/i18n-version/index.js +14 -0
- package/dist/i18n-version/language-switcher.d.ts +24 -0
- package/dist/i18n-version/language-switcher.js +25 -0
- package/dist/i18n-version/types.d.ts +43 -0
- package/dist/i18n-version/types.js +0 -0
- package/dist/i18n-version/version-banner.d.ts +30 -0
- package/dist/i18n-version/version-banner.js +21 -0
- package/dist/i18n-version/version-switcher.d.ts +112 -0
- package/dist/i18n-version/version-switcher.js +157 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +0 -0
- package/dist/integrations/claude-resources/escape-for-mdx.d.ts +8 -0
- package/dist/integrations/claude-resources/escape-for-mdx.js +131 -0
- package/dist/integrations/claude-resources/generate.d.ts +13 -0
- package/dist/integrations/claude-resources/generate.js +404 -0
- package/dist/integrations/claude-resources/index.d.ts +46 -0
- package/dist/integrations/claude-resources/index.js +24 -0
- package/dist/integrations/doc-history/index.d.ts +137 -0
- package/dist/integrations/doc-history/index.js +138 -0
- package/dist/integrations/doc-history/pre-build.d.ts +58 -0
- package/dist/integrations/doc-history/pre-build.js +67 -0
- package/dist/integrations/llms-txt/dev-middleware.d.ts +40 -0
- package/dist/integrations/llms-txt/dev-middleware.js +76 -0
- package/dist/integrations/llms-txt/emit.d.ts +22 -0
- package/dist/integrations/llms-txt/emit.js +55 -0
- package/dist/integrations/llms-txt/generate.d.ts +26 -0
- package/dist/integrations/llms-txt/generate.js +36 -0
- package/dist/integrations/llms-txt/index.d.ts +7 -0
- package/dist/integrations/llms-txt/index.js +27 -0
- package/dist/integrations/llms-txt/load.d.ts +51 -0
- package/dist/integrations/llms-txt/load.js +83 -0
- package/dist/integrations/llms-txt/strip.d.ts +22 -0
- package/dist/integrations/llms-txt/strip.js +10 -0
- package/dist/integrations/llms-txt/types.d.ts +145 -0
- package/dist/integrations/llms-txt/types.js +0 -0
- package/dist/integrations/search-index/build-emitter.d.ts +30 -0
- package/dist/integrations/search-index/build-emitter.js +15 -0
- package/dist/integrations/search-index/collect.d.ts +12 -0
- package/dist/integrations/search-index/collect.js +48 -0
- package/dist/integrations/search-index/content-files.d.ts +32 -0
- package/dist/integrations/search-index/content-files.js +50 -0
- package/dist/integrations/search-index/dev-middleware.d.ts +16 -0
- package/dist/integrations/search-index/dev-middleware.js +30 -0
- package/dist/integrations/search-index/index.d.ts +5 -0
- package/dist/integrations/search-index/index.js +14 -0
- package/dist/integrations/search-index/types.d.ts +38 -0
- package/dist/integrations/search-index/types.js +6 -0
- package/dist/metainfo/doc-metainfo.d.ts +50 -0
- package/dist/metainfo/doc-metainfo.js +107 -0
- package/dist/metainfo/doc-tags.d.ts +66 -0
- package/dist/metainfo/doc-tags.js +53 -0
- package/dist/metainfo/frontmatter-preview.d.ts +95 -0
- package/dist/metainfo/frontmatter-preview.js +55 -0
- package/dist/metainfo/index.d.ts +4 -0
- package/dist/metainfo/index.js +28 -0
- package/dist/nav-indexing/category-nav.d.ts +28 -0
- package/dist/nav-indexing/category-nav.js +41 -0
- package/dist/nav-indexing/category-tree-nav.d.ts +27 -0
- package/dist/nav-indexing/category-tree-nav.js +49 -0
- package/dist/nav-indexing/doc-card-grid.d.ts +38 -0
- package/dist/nav-indexing/doc-card-grid.js +40 -0
- package/dist/nav-indexing/docs-sitemap.d.ts +25 -0
- package/dist/nav-indexing/docs-sitemap.js +40 -0
- package/dist/nav-indexing/index.d.ts +10 -0
- package/dist/nav-indexing/index.js +18 -0
- package/dist/nav-indexing/nav-card-grid.d.ts +31 -0
- package/dist/nav-indexing/nav-card-grid.js +43 -0
- package/dist/nav-indexing/site-tree-nav-demo.d.ts +39 -0
- package/dist/nav-indexing/site-tree-nav-demo.js +65 -0
- package/dist/nav-indexing/tag-nav.d.ts +38 -0
- package/dist/nav-indexing/tag-nav.js +96 -0
- package/dist/nav-indexing/types.d.ts +95 -0
- package/dist/nav-indexing/types.js +0 -0
- package/dist/nav-indexing/versions-page-content.d.ts +29 -0
- package/dist/nav-indexing/versions-page-content.js +76 -0
- package/dist/page-loading/index.d.ts +2 -0
- package/dist/page-loading/index.js +10 -0
- package/dist/page-loading/page-loading-overlay.d.ts +35 -0
- package/dist/page-loading/page-loading-overlay.js +50 -0
- package/dist/sidebar/index.d.ts +3 -0
- package/dist/sidebar/index.js +4 -0
- package/dist/sidebar/sidebar.d.ts +54 -0
- package/dist/sidebar/sidebar.js +35 -0
- package/dist/sidebar/types.d.ts +71 -0
- package/dist/sidebar/types.js +0 -0
- package/dist/sidebar-resizer/index.d.ts +14 -0
- package/dist/sidebar-resizer/index.js +165 -0
- package/dist/sidebar-resizer/sidebar-resizer-init.d.ts +20 -0
- package/dist/sidebar-resizer/sidebar-resizer-init.js +119 -0
- package/dist/sidebar-tree/build-tree.d.ts +43 -0
- package/dist/sidebar-tree/build-tree.js +127 -0
- package/dist/sidebar-tree/category-meta.d.ts +19 -0
- package/dist/sidebar-tree/category-meta.js +63 -0
- package/dist/sidebar-tree/index.d.ts +3 -0
- package/dist/sidebar-tree/index.js +13 -0
- package/dist/sidebar-tree/types.d.ts +120 -0
- package/dist/sidebar-tree/types.js +0 -0
- package/dist/tab-item/index.d.ts +2 -0
- package/dist/tab-item/index.js +5 -0
- package/dist/tab-item/tab-item.d.ts +38 -0
- package/dist/tab-item/tab-item.js +25 -0
- package/dist/theme/color-scheme-provider.d.ts +32 -0
- package/dist/theme/color-scheme-provider.js +43 -0
- package/dist/theme/color-tweak-export-modal.d.ts +20 -0
- package/dist/theme/color-tweak-export-modal.js +138 -0
- package/dist/theme/design-token-serde.d.ts +136 -0
- package/dist/theme/design-token-serde.js +254 -0
- package/dist/theme/design-token-tweak-panel.d.ts +11 -0
- package/dist/theme/design-token-tweak-panel.js +10 -0
- package/dist/theme/design-token-types.d.ts +19 -0
- package/dist/theme/design-token-types.js +6 -0
- package/dist/theme/iframe-bridge.d.ts +44 -0
- package/dist/theme/iframe-bridge.js +70 -0
- package/dist/theme/index.d.ts +9 -0
- package/dist/theme/index.js +42 -0
- package/dist/theme/theme-toggle.d.ts +17 -0
- package/dist/theme/theme-toggle.js +91 -0
- package/dist/toc/cx.d.ts +16 -0
- package/dist/toc/cx.js +22 -0
- package/dist/toc/index.d.ts +5 -0
- package/dist/toc/index.js +9 -0
- package/dist/toc/mobile-toc.d.ts +46 -0
- package/dist/toc/mobile-toc.js +88 -0
- package/dist/toc/smart-break.d.ts +27 -0
- package/dist/toc/smart-break.js +36 -0
- package/dist/toc/toc-title.d.ts +10 -0
- package/dist/toc/toc-title.js +14 -0
- package/dist/toc/toc.d.ts +60 -0
- package/dist/toc/toc.js +56 -0
- package/dist/toc/types.d.ts +23 -0
- package/dist/toc/types.js +0 -0
- package/dist/toc/use-active-heading.d.ts +30 -0
- package/dist/toc/use-active-heading.js +106 -0
- package/dist/transitions/index.d.ts +1 -0
- package/dist/transitions/index.js +12 -0
- package/dist/transitions/page-events.d.ts +41 -0
- package/dist/transitions/page-events.js +20 -0
- package/dist/url-normalizer/index.d.ts +1 -0
- package/dist/url-normalizer/index.js +6 -0
- package/dist/url-normalizer/normalize.d.ts +104 -0
- package/dist/url-normalizer/normalize.js +22 -0
- package/package.json +186 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
function toRouteSlug(id) {
|
|
2
|
+
return id.replace(/\/index$/, "");
|
|
3
|
+
}
|
|
4
|
+
function toTitleCase(str) {
|
|
5
|
+
return str.split("-").map((word) => word.length === 0 ? word : word[0].toUpperCase() + word.slice(1)).join(" ");
|
|
6
|
+
}
|
|
7
|
+
const defaultBuildHref = (slug, locale) => {
|
|
8
|
+
const prefix = locale ? `/${locale}/docs/` : "/docs/";
|
|
9
|
+
return slug ? `${prefix}${slug}/` : prefix;
|
|
10
|
+
};
|
|
11
|
+
function defaultIsNavVisible(entry) {
|
|
12
|
+
return !entry.data.unlisted && !entry.data.standalone;
|
|
13
|
+
}
|
|
14
|
+
function buildSidebarTree(entries, locale, options = {}) {
|
|
15
|
+
const {
|
|
16
|
+
categoryMeta,
|
|
17
|
+
buildHref = defaultBuildHref,
|
|
18
|
+
isNavVisible = defaultIsNavVisible
|
|
19
|
+
} = options;
|
|
20
|
+
const root = {
|
|
21
|
+
segment: "",
|
|
22
|
+
fullPath: "",
|
|
23
|
+
children: /* @__PURE__ */ new Map()
|
|
24
|
+
};
|
|
25
|
+
for (const entry of entries) {
|
|
26
|
+
if (!isNavVisible(entry)) continue;
|
|
27
|
+
const slug = entry.data.slug ?? entry.slug ?? toRouteSlug(entry.id);
|
|
28
|
+
if (!slug) continue;
|
|
29
|
+
const parts = slug.split("/");
|
|
30
|
+
if (parts.length <= 1) {
|
|
31
|
+
const segment = slug;
|
|
32
|
+
let node = root.children.get(segment);
|
|
33
|
+
if (!node) {
|
|
34
|
+
node = { segment, fullPath: segment, children: /* @__PURE__ */ new Map() };
|
|
35
|
+
root.children.set(segment, node);
|
|
36
|
+
}
|
|
37
|
+
node.doc = entry;
|
|
38
|
+
} else {
|
|
39
|
+
let current = root;
|
|
40
|
+
for (let i = 0; i < parts.length; i++) {
|
|
41
|
+
const segment = parts[i];
|
|
42
|
+
const fullPath = parts.slice(0, i + 1).join("/");
|
|
43
|
+
let next = current.children.get(segment);
|
|
44
|
+
if (!next) {
|
|
45
|
+
next = { segment, fullPath, children: /* @__PURE__ */ new Map() };
|
|
46
|
+
current.children.set(segment, next);
|
|
47
|
+
}
|
|
48
|
+
if (i === parts.length - 1) {
|
|
49
|
+
next.doc = entry;
|
|
50
|
+
}
|
|
51
|
+
current = next;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return toSidebarNodes(root, locale, buildHref, categoryMeta);
|
|
56
|
+
}
|
|
57
|
+
function toSidebarNodes(parent, locale, buildHref, categoryMeta, parentSortOrder) {
|
|
58
|
+
const nodes = [];
|
|
59
|
+
for (const child of parent.children.values()) {
|
|
60
|
+
const doc = child.doc;
|
|
61
|
+
const meta = categoryMeta?.get(child.fullPath);
|
|
62
|
+
const sortOrder = meta?.sortOrder ?? "asc";
|
|
63
|
+
const children = toSidebarNodes(
|
|
64
|
+
child,
|
|
65
|
+
locale,
|
|
66
|
+
buildHref,
|
|
67
|
+
categoryMeta,
|
|
68
|
+
sortOrder
|
|
69
|
+
);
|
|
70
|
+
const hasPage = !!doc;
|
|
71
|
+
const isCategory = !hasPage && children.length > 0;
|
|
72
|
+
const label = doc?.data.sidebar_label ?? doc?.data.title ?? meta?.label ?? toTitleCase(child.segment);
|
|
73
|
+
const description = doc?.data.description ?? meta?.description;
|
|
74
|
+
const positionRaw = doc?.data.sidebar_position ?? meta?.position;
|
|
75
|
+
const position = positionRaw ?? 999;
|
|
76
|
+
const href = meta?.noPage ? void 0 : doc || children.length > 0 ? buildHref(child.fullPath, locale) : void 0;
|
|
77
|
+
nodes.push({
|
|
78
|
+
type: isCategory ? "category" : "doc",
|
|
79
|
+
id: child.fullPath,
|
|
80
|
+
label,
|
|
81
|
+
...description !== void 0 ? { description } : {},
|
|
82
|
+
...positionRaw !== void 0 ? { sidebar_position: positionRaw } : {},
|
|
83
|
+
...href !== void 0 ? { href } : {},
|
|
84
|
+
hasPage,
|
|
85
|
+
...meta?.sortOrder ? { sortOrder } : {},
|
|
86
|
+
children
|
|
87
|
+
});
|
|
88
|
+
Object.defineProperty(nodes[nodes.length - 1], "__sortPosition", {
|
|
89
|
+
value: position,
|
|
90
|
+
enumerable: false
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const order = parentSortOrder ?? "asc";
|
|
94
|
+
nodes.sort((a, b) => {
|
|
95
|
+
const aPos = a.__sortPosition;
|
|
96
|
+
const bPos = b.__sortPosition;
|
|
97
|
+
const posCompare = aPos - bPos;
|
|
98
|
+
if (posCompare !== 0) return order === "desc" ? -posCompare : posCompare;
|
|
99
|
+
const slugCompare = a.id.localeCompare(b.id);
|
|
100
|
+
return order === "desc" ? -slugCompare : slugCompare;
|
|
101
|
+
});
|
|
102
|
+
return nodes;
|
|
103
|
+
}
|
|
104
|
+
function findSidebarNode(nodes, id) {
|
|
105
|
+
for (const node of nodes) {
|
|
106
|
+
if (node.id === id) return node;
|
|
107
|
+
const found = findSidebarNode(node.children, id);
|
|
108
|
+
if (found) return found;
|
|
109
|
+
}
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
112
|
+
function flattenSidebarTree(nodes) {
|
|
113
|
+
const acc = [];
|
|
114
|
+
flattenInto(nodes, acc);
|
|
115
|
+
return acc;
|
|
116
|
+
}
|
|
117
|
+
function flattenInto(nodes, acc) {
|
|
118
|
+
for (const node of nodes) {
|
|
119
|
+
if (node.hasPage) acc.push(node);
|
|
120
|
+
flattenInto(node.children, acc);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export {
|
|
124
|
+
buildSidebarTree,
|
|
125
|
+
findSidebarNode,
|
|
126
|
+
flattenSidebarTree
|
|
127
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CategoryMeta } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Scan `contentDir` recursively for `_category_.json` files. Each file's
|
|
5
|
+
* parent directory becomes a map key, expressed as a path relative to
|
|
6
|
+
* `contentDir` and joined with the platform separator (`scanDir` uses
|
|
7
|
+
* `path.relative`, which yields forward slashes on POSIX and backslashes
|
|
8
|
+
* on Windows — that matches the keys produced by the legacy implementation
|
|
9
|
+
* and is what the build-tree code re-uses verbatim).
|
|
10
|
+
*
|
|
11
|
+
* Results are memoised per `contentDir` because Astro builds resolve every
|
|
12
|
+
* page route in the same process; re-reading thousands of `_category_.json`
|
|
13
|
+
* files for each page is wasteful.
|
|
14
|
+
*/
|
|
15
|
+
declare function loadCategoryMeta(contentDir: string): Map<string, CategoryMeta>;
|
|
16
|
+
/** Test/HMR escape hatch — clears the per-directory cache. */
|
|
17
|
+
declare function clearCategoryMetaCache(): void;
|
|
18
|
+
|
|
19
|
+
export { clearCategoryMetaCache, loadCategoryMeta };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4
|
+
function loadCategoryMeta(contentDir) {
|
|
5
|
+
const absolute = path.resolve(contentDir);
|
|
6
|
+
const cached = cache.get(absolute);
|
|
7
|
+
if (cached) return cached;
|
|
8
|
+
const result = /* @__PURE__ */ new Map();
|
|
9
|
+
scanDir(absolute, absolute, result);
|
|
10
|
+
cache.set(absolute, result);
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
function clearCategoryMetaCache() {
|
|
14
|
+
cache.clear();
|
|
15
|
+
}
|
|
16
|
+
function scanDir(baseDir, currentDir, result) {
|
|
17
|
+
let entries;
|
|
18
|
+
try {
|
|
19
|
+
entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
20
|
+
} catch {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
if (!entry.isDirectory()) continue;
|
|
25
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
26
|
+
const categoryFile = path.join(fullPath, "_category_.json");
|
|
27
|
+
if (fs.existsSync(categoryFile)) {
|
|
28
|
+
const meta = readCategoryFile(categoryFile);
|
|
29
|
+
if (meta) {
|
|
30
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
31
|
+
result.set(relativePath, meta);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
scanDir(baseDir, fullPath, result);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function readCategoryFile(filePath) {
|
|
38
|
+
let raw;
|
|
39
|
+
try {
|
|
40
|
+
raw = fs.readFileSync(filePath, "utf-8");
|
|
41
|
+
} catch {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
let parsed;
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(raw);
|
|
47
|
+
} catch {
|
|
48
|
+
return void 0;
|
|
49
|
+
}
|
|
50
|
+
if (typeof parsed !== "object" || parsed === null) return void 0;
|
|
51
|
+
const obj = parsed;
|
|
52
|
+
return {
|
|
53
|
+
label: typeof obj["label"] === "string" ? obj["label"] : void 0,
|
|
54
|
+
position: typeof obj["position"] === "number" ? obj["position"] : void 0,
|
|
55
|
+
description: typeof obj["description"] === "string" ? obj["description"] : void 0,
|
|
56
|
+
sortOrder: obj["sortOrder"] === "asc" || obj["sortOrder"] === "desc" ? obj["sortOrder"] : void 0,
|
|
57
|
+
noPage: obj["noPage"] === true ? true : void 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
clearCategoryMetaCache,
|
|
62
|
+
loadCategoryMeta
|
|
63
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { buildSidebarTree, findSidebarNode, flattenSidebarTree } from './build-tree.js';
|
|
2
|
+
export { clearCategoryMetaCache, loadCategoryMeta } from './category-meta.js';
|
|
3
|
+
export { BuildHref, BuildSidebarTreeOptions, CategoryMeta, CollectionEntryLike, SidebarFrontmatter, SidebarNode } from './types.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildSidebarTree,
|
|
3
|
+
findSidebarNode,
|
|
4
|
+
flattenSidebarTree
|
|
5
|
+
} from "./build-tree.js";
|
|
6
|
+
import { loadCategoryMeta, clearCategoryMetaCache } from "./category-meta.js";
|
|
7
|
+
export {
|
|
8
|
+
buildSidebarTree,
|
|
9
|
+
clearCategoryMetaCache,
|
|
10
|
+
findSidebarNode,
|
|
11
|
+
flattenSidebarTree,
|
|
12
|
+
loadCategoryMeta
|
|
13
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public types for the framework-agnostic sidebar tree builder.
|
|
3
|
+
*
|
|
4
|
+
* These types are deliberately decoupled from astro:content so the helper
|
|
5
|
+
* can run on top of any content collection that exposes a similar shape
|
|
6
|
+
* (Astro, zfb, plain Node fixtures, etc.).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Frontmatter fields the builder reads off of each entry's `data` object.
|
|
10
|
+
* Callers are free to extend this; unrecognised fields are ignored.
|
|
11
|
+
*/
|
|
12
|
+
interface SidebarFrontmatter {
|
|
13
|
+
title: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
sidebar_position?: number;
|
|
16
|
+
sidebar_label?: string;
|
|
17
|
+
draft?: boolean;
|
|
18
|
+
unlisted?: boolean;
|
|
19
|
+
hide_sidebar?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Set to `true` for pages that exist outside the doc tree (404, top-level
|
|
22
|
+
* standalone pages, etc.). The builder skips these entries entirely.
|
|
23
|
+
*/
|
|
24
|
+
standalone?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Optional override for the route slug. When omitted, the builder derives
|
|
27
|
+
* the slug from the entry's id (stripping a trailing `/index`).
|
|
28
|
+
*/
|
|
29
|
+
slug?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Minimum shape required of a content collection entry. Designed to be a
|
|
33
|
+
* structural superset of both Astro's `CollectionEntry` and zfb's
|
|
34
|
+
* `CollectionEntry<T>` so callers can pass either through unchanged.
|
|
35
|
+
*/
|
|
36
|
+
interface CollectionEntryLike<T extends SidebarFrontmatter = SidebarFrontmatter> {
|
|
37
|
+
/**
|
|
38
|
+
* Stable identifier. For Astro entries this is the file path without the
|
|
39
|
+
* extension (e.g. `getting-started/index`). For zfb entries the project
|
|
40
|
+
* convention is to put the cleaned slug here too — either form is fine
|
|
41
|
+
* because the builder strips a trailing `/index`.
|
|
42
|
+
*/
|
|
43
|
+
id: string;
|
|
44
|
+
/**
|
|
45
|
+
* Optional pre-computed slug. When present it wins over the id-derived
|
|
46
|
+
* value. zfb entries always populate this field; Astro callers can leave
|
|
47
|
+
* it undefined.
|
|
48
|
+
*/
|
|
49
|
+
slug?: string;
|
|
50
|
+
data: T;
|
|
51
|
+
/** Free-form fields kept for forward compatibility — never read here. */
|
|
52
|
+
collection?: string;
|
|
53
|
+
body?: string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Metadata supplied by a directory's `_category_.json` file.
|
|
57
|
+
*/
|
|
58
|
+
interface CategoryMeta {
|
|
59
|
+
label?: string;
|
|
60
|
+
position?: number;
|
|
61
|
+
description?: string;
|
|
62
|
+
sortOrder?: "asc" | "desc";
|
|
63
|
+
/**
|
|
64
|
+
* When true, the category renders as a collapsible header with no link of
|
|
65
|
+
* its own — useful for purely structural groupings.
|
|
66
|
+
*/
|
|
67
|
+
noPage?: boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* One node in the sidebar tree. `type` distinguishes leaves (single docs)
|
|
71
|
+
* from categories (groups with children). The fields beyond the manager's
|
|
72
|
+
* sketch — `description`, `hasPage`, `sortOrder`, `collapsed` — are kept
|
|
73
|
+
* because downstream consumers (sidebar config layer, breadcrumb builder)
|
|
74
|
+
* need them. They are all optional from a caller's perspective.
|
|
75
|
+
*/
|
|
76
|
+
interface SidebarNode {
|
|
77
|
+
type: "doc" | "category";
|
|
78
|
+
/** Path-style slug, e.g. `getting-started/introduction`. */
|
|
79
|
+
id: string;
|
|
80
|
+
label: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
href?: string;
|
|
83
|
+
sidebar_position?: number;
|
|
84
|
+
/** True when an actual MDX file backs this slug (vs. directory-only). */
|
|
85
|
+
hasPage: boolean;
|
|
86
|
+
sortOrder?: "asc" | "desc";
|
|
87
|
+
collapsed?: boolean;
|
|
88
|
+
children: SidebarNode[];
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve an href for a given route slug. Defaults to `/<locale>/docs/<slug>/`
|
|
92
|
+
* for non-default locales and `/docs/<slug>/` otherwise — but most projects
|
|
93
|
+
* will inject their own to honour `base`, `trailingSlash`, etc.
|
|
94
|
+
*/
|
|
95
|
+
type BuildHref = (slug: string, locale: string) => string;
|
|
96
|
+
interface BuildSidebarTreeOptions {
|
|
97
|
+
/**
|
|
98
|
+
* Map keyed by slash-joined directory path → category meta. Typically
|
|
99
|
+
* produced by {@link CategoryMetaLoader}.
|
|
100
|
+
*/
|
|
101
|
+
categoryMeta?: Map<string, CategoryMeta>;
|
|
102
|
+
/**
|
|
103
|
+
* Default locale. When the supplied `locale` matches this, the helper
|
|
104
|
+
* skips the locale prefix in default href construction. When omitted,
|
|
105
|
+
* defaults to `"en"`.
|
|
106
|
+
*/
|
|
107
|
+
defaultLocale?: string;
|
|
108
|
+
/**
|
|
109
|
+
* Override the default href builder. Receives the route slug and locale.
|
|
110
|
+
*/
|
|
111
|
+
buildHref?: BuildHref;
|
|
112
|
+
/**
|
|
113
|
+
* Filter predicate run on every entry before tree construction. Defaults
|
|
114
|
+
* to dropping `unlisted` and `standalone` docs. Override to integrate
|
|
115
|
+
* with a project's own visibility rules.
|
|
116
|
+
*/
|
|
117
|
+
isNavVisible?: (entry: CollectionEntryLike<SidebarFrontmatter>) => boolean;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export type { BuildHref, BuildSidebarTreeOptions, CategoryMeta, CollectionEntryLike, SidebarFrontmatter, SidebarNode };
|
|
File without changes
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as preact from 'preact';
|
|
2
|
+
import { ComponentChildren } from 'preact';
|
|
3
|
+
|
|
4
|
+
interface TabItemProps {
|
|
5
|
+
/** Human-readable label rendered by the parent Tabs trigger row. */
|
|
6
|
+
label: string;
|
|
7
|
+
/**
|
|
8
|
+
* Optional stable value for the tab. Falls back to `label` when
|
|
9
|
+
* omitted, matching the Astro original's `value ?? label`.
|
|
10
|
+
*/
|
|
11
|
+
value?: string;
|
|
12
|
+
/**
|
|
13
|
+
* When true, this panel is the initially-active one. Encoded as the
|
|
14
|
+
* empty-string `data-tab-default` attribute so plain attribute
|
|
15
|
+
* selectors (`[data-tab-default]`) still match.
|
|
16
|
+
*/
|
|
17
|
+
default?: boolean;
|
|
18
|
+
/** Panel body. */
|
|
19
|
+
children?: ComponentChildren;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* One tab panel.
|
|
23
|
+
*
|
|
24
|
+
* Wave 11 (zudolab/zudo-doc#1355): the default panel is rendered
|
|
25
|
+
* **without** the `hidden` attribute so the SSR HTML already shows the
|
|
26
|
+
* correct active panel before any JS runs. Non-default panels keep
|
|
27
|
+
* `hidden`. This avoids the post-Wave-10 regression where the tabs
|
|
28
|
+
* init script could land after first paint and flash an empty tab
|
|
29
|
+
* group; it also gives the no-JS path a usable default tab.
|
|
30
|
+
*
|
|
31
|
+
* The companion `TabsInit` script remains the source of truth at
|
|
32
|
+
* runtime — it re-derives the active tab from `localStorage` and
|
|
33
|
+
* `[data-tab-default]` and reapplies `hidden` / `aria-selected` so
|
|
34
|
+
* the SSR-rendered defaults survive group sync and View Transitions.
|
|
35
|
+
*/
|
|
36
|
+
declare function TabItem({ label, value, default: isDefault, children, }: TabItemProps): preact.JSX.Element;
|
|
37
|
+
|
|
38
|
+
export { TabItem, type TabItemProps, TabItem as default };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx } from "preact/jsx-runtime";
|
|
2
|
+
function TabItem({
|
|
3
|
+
label,
|
|
4
|
+
value,
|
|
5
|
+
default: isDefault,
|
|
6
|
+
children
|
|
7
|
+
}) {
|
|
8
|
+
return /* @__PURE__ */ jsx(
|
|
9
|
+
"div",
|
|
10
|
+
{
|
|
11
|
+
class: "tab-panel",
|
|
12
|
+
role: "tabpanel",
|
|
13
|
+
"data-tab-value": value ?? label,
|
|
14
|
+
"data-tab-label": label,
|
|
15
|
+
"data-tab-default": isDefault ? "" : void 0,
|
|
16
|
+
hidden: isDefault ? void 0 : true,
|
|
17
|
+
children
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
var tab_item_default = TabItem;
|
|
22
|
+
export {
|
|
23
|
+
TabItem,
|
|
24
|
+
tab_item_default as default
|
|
25
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as preact from 'preact';
|
|
2
|
+
import { ComponentChildren } from 'preact';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Subset of the host's `ColorModeConfig` that the v2 provider actually
|
|
6
|
+
* consumes. Kept locally so the v2 package does not need to import a host
|
|
7
|
+
* type module — the caller maps its own settings into this shape (or
|
|
8
|
+
* passes `null` for the persisted-tweak / no-light-dark path).
|
|
9
|
+
*/
|
|
10
|
+
interface ColorSchemeProviderColorMode {
|
|
11
|
+
defaultMode: "light" | "dark";
|
|
12
|
+
respectPrefersColorScheme: boolean;
|
|
13
|
+
}
|
|
14
|
+
interface ColorSchemeProviderProps {
|
|
15
|
+
/**
|
|
16
|
+
* Pre-computed `:root { --zd-* }` CSS string. The caller resolves the
|
|
17
|
+
* active color scheme (or the configured light+dark pair) and renders
|
|
18
|
+
* the `<style>` body for us — this component just emits it.
|
|
19
|
+
*/
|
|
20
|
+
cssText: string;
|
|
21
|
+
/**
|
|
22
|
+
* Active light/dark mode config, or `null` for the persisted-tweak
|
|
23
|
+
* bootstrap path (no light/dark; the in-browser tweak panel may inject
|
|
24
|
+
* custom CSS vars from localStorage instead).
|
|
25
|
+
*/
|
|
26
|
+
colorMode: ColorSchemeProviderColorMode | null;
|
|
27
|
+
/** Optional children; preserved for forward compatibility. */
|
|
28
|
+
children?: ComponentChildren;
|
|
29
|
+
}
|
|
30
|
+
declare function ColorSchemeProvider({ cssText, colorMode, }: ColorSchemeProviderProps): preact.JSX.Element;
|
|
31
|
+
|
|
32
|
+
export { type ColorSchemeProviderColorMode, type ColorSchemeProviderProps, ColorSchemeProvider as default };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { AFTER_NAVIGATE_EVENT } from "../transitions/page-events.js";
|
|
3
|
+
function buildColorModeBootstrap(defaultMode, respectPrefersColorScheme) {
|
|
4
|
+
const dm = JSON.stringify(defaultMode);
|
|
5
|
+
const rp = JSON.stringify(Boolean(respectPrefersColorScheme));
|
|
6
|
+
const afterNav = JSON.stringify(AFTER_NAVIGATE_EVENT);
|
|
7
|
+
return `(function(){
|
|
8
|
+
var defaultMode=${dm};
|
|
9
|
+
var respectPrefersColorScheme=${rp};
|
|
10
|
+
var STORAGE_KEY="zudo-doc-theme";
|
|
11
|
+
function getSystemMode(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";}
|
|
12
|
+
function applyTheme(mode){document.documentElement.setAttribute("data-theme",mode);document.documentElement.style.colorScheme=mode;}
|
|
13
|
+
function getEffectiveMode(choice){if(choice==="light"||choice==="dark")return choice;return respectPrefersColorScheme?getSystemMode():defaultMode;}
|
|
14
|
+
var stored=null;try{stored=localStorage.getItem(STORAGE_KEY);}catch(e){}
|
|
15
|
+
applyTheme(getEffectiveMode(stored));
|
|
16
|
+
document.addEventListener(${afterNav},function(){var s=null;try{s=localStorage.getItem(STORAGE_KEY);}catch(e){}applyTheme(getEffectiveMode(s));});
|
|
17
|
+
if(respectPrefersColorScheme){window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",function(){var s=null;try{s=localStorage.getItem(STORAGE_KEY);}catch(e){}if(!s)applyTheme(getSystemMode());});}
|
|
18
|
+
})();`;
|
|
19
|
+
}
|
|
20
|
+
function buildPersistedTweakBootstrap() {
|
|
21
|
+
const afterNav = JSON.stringify(AFTER_NAVIGATE_EVENT);
|
|
22
|
+
return `(function(){
|
|
23
|
+
function applyStoredScheme(){var css=localStorage.getItem("zudo-doc-color-scheme-css");if(!css)return;try{var pairs=JSON.parse(css);var root=document.documentElement;for(var i=0;i<pairs.length;i++){root.style.setProperty(pairs[i][0],pairs[i][1]);}}catch(e){localStorage.removeItem("zudo-doc-color-scheme-css");}}
|
|
24
|
+
applyStoredScheme();
|
|
25
|
+
document.addEventListener(${afterNav},applyStoredScheme);
|
|
26
|
+
})();`;
|
|
27
|
+
}
|
|
28
|
+
function ColorSchemeProvider({
|
|
29
|
+
cssText,
|
|
30
|
+
colorMode
|
|
31
|
+
}) {
|
|
32
|
+
const bootstrap = colorMode ? buildColorModeBootstrap(
|
|
33
|
+
colorMode.defaultMode,
|
|
34
|
+
Boolean(colorMode.respectPrefersColorScheme)
|
|
35
|
+
) : buildPersistedTweakBootstrap();
|
|
36
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
37
|
+
/* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: cssText } }),
|
|
38
|
+
/* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: bootstrap } })
|
|
39
|
+
] });
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
ColorSchemeProvider as default
|
|
43
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as preact from 'preact';
|
|
2
|
+
import { DesignTokenManifest } from './design-token-serde.js';
|
|
3
|
+
import { TweakState, ColorTweakState } from './design-token-types.js';
|
|
4
|
+
import '@takazudo/zdtp';
|
|
5
|
+
|
|
6
|
+
interface DesignTokenExportModalProps {
|
|
7
|
+
onClose: () => void;
|
|
8
|
+
/** Full unified tweak state — the modal serializes all four categories. */
|
|
9
|
+
state: TweakState;
|
|
10
|
+
/** Token manifest (spacing / font / size arrays) used by serialize() to
|
|
11
|
+
* compute diff-only output. The caller is expected to forward the same
|
|
12
|
+
* manifest the panel was configured with. */
|
|
13
|
+
manifest: DesignTokenManifest;
|
|
14
|
+
/** Color baseline used for diff-only output. Optional: callers without DOM
|
|
15
|
+
* access (tests) can omit and we'll treat the entire color block as changed. */
|
|
16
|
+
colorDefaults?: ColorTweakState;
|
|
17
|
+
}
|
|
18
|
+
declare function ColorTweakExportModal({ onClose, state, manifest, colorDefaults, }: DesignTokenExportModalProps): preact.JSX.Element;
|
|
19
|
+
|
|
20
|
+
export { ColorTweakExportModal as default };
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { jsx, jsxs } from "preact/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useMemo, useRef } from "preact/hooks";
|
|
3
|
+
import { serialize } from "./design-token-serde.js";
|
|
4
|
+
import {
|
|
5
|
+
} from "./design-token-types.js";
|
|
6
|
+
const EXPORT_FILENAME_HINT = "zudo-doc-tokens.json";
|
|
7
|
+
function resolveColorDefaults(fallback, explicit) {
|
|
8
|
+
return explicit ?? fallback;
|
|
9
|
+
}
|
|
10
|
+
function ColorTweakExportModal({
|
|
11
|
+
onClose,
|
|
12
|
+
state,
|
|
13
|
+
manifest,
|
|
14
|
+
colorDefaults
|
|
15
|
+
}) {
|
|
16
|
+
const [copyLabel, setCopyLabel] = useState("Copy");
|
|
17
|
+
const [includeDefaults, setIncludeDefaults] = useState(false);
|
|
18
|
+
const dialogRef = useRef(null);
|
|
19
|
+
const copyTimerRef = useRef(null);
|
|
20
|
+
const code = useMemo(() => {
|
|
21
|
+
const baseline = resolveColorDefaults(state.color, colorDefaults);
|
|
22
|
+
const json = serialize(state, {
|
|
23
|
+
manifest,
|
|
24
|
+
includeDefaults,
|
|
25
|
+
colorDefaults: baseline
|
|
26
|
+
});
|
|
27
|
+
return JSON.stringify(json, null, 2);
|
|
28
|
+
}, [state, manifest, colorDefaults, includeDefaults]);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const dialog = dialogRef.current;
|
|
31
|
+
if (!dialog) return;
|
|
32
|
+
dialog.showModal();
|
|
33
|
+
return () => {
|
|
34
|
+
if (dialog.open) dialog.close();
|
|
35
|
+
};
|
|
36
|
+
}, []);
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
const dialog = dialogRef.current;
|
|
39
|
+
if (!dialog) return;
|
|
40
|
+
function handleClose() {
|
|
41
|
+
onClose();
|
|
42
|
+
}
|
|
43
|
+
dialog.addEventListener("close", handleClose);
|
|
44
|
+
return () => dialog.removeEventListener("close", handleClose);
|
|
45
|
+
}, [onClose]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
return () => {
|
|
48
|
+
if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
|
|
49
|
+
};
|
|
50
|
+
}, []);
|
|
51
|
+
function handleBackdropClick(e) {
|
|
52
|
+
const dialog = dialogRef.current;
|
|
53
|
+
if (!dialog) return;
|
|
54
|
+
const rect = dialog.getBoundingClientRect();
|
|
55
|
+
if (e.clientX < rect.left || e.clientX > rect.right || e.clientY < rect.top || e.clientY > rect.bottom) {
|
|
56
|
+
dialog.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function handleCopy() {
|
|
60
|
+
let ok = false;
|
|
61
|
+
const dialog = dialogRef.current;
|
|
62
|
+
if (dialog) {
|
|
63
|
+
try {
|
|
64
|
+
const textarea = document.createElement("textarea");
|
|
65
|
+
textarea.value = code;
|
|
66
|
+
textarea.style.cssText = "position:fixed;opacity:0;left:-9999px";
|
|
67
|
+
dialog.appendChild(textarea);
|
|
68
|
+
textarea.focus();
|
|
69
|
+
textarea.select();
|
|
70
|
+
ok = document.execCommand("copy");
|
|
71
|
+
dialog.removeChild(textarea);
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!ok) {
|
|
76
|
+
try {
|
|
77
|
+
await navigator.clipboard.writeText(code);
|
|
78
|
+
ok = true;
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
setCopyLabel(ok ? "Copied!" : "Failed");
|
|
83
|
+
if (copyTimerRef.current) clearTimeout(copyTimerRef.current);
|
|
84
|
+
copyTimerRef.current = setTimeout(() => setCopyLabel("Copy"), 2e3);
|
|
85
|
+
}
|
|
86
|
+
return /* @__PURE__ */ jsxs(
|
|
87
|
+
"dialog",
|
|
88
|
+
{
|
|
89
|
+
ref: dialogRef,
|
|
90
|
+
onClick: handleBackdropClick,
|
|
91
|
+
className: "mx-auto max-h-[80vh] w-full max-w-[46rem] overflow-y-auto border border-muted bg-surface p-hsp-xl backdrop:bg-bg/80",
|
|
92
|
+
style: { color: "var(--color-fg)", position: "fixed", top: "50%", left: "50%", transform: "translate(-50%, -50%)", userSelect: "text" },
|
|
93
|
+
children: [
|
|
94
|
+
/* @__PURE__ */ jsx("h2", { className: "mb-vsp-sm text-title font-bold text-fg", children: "Export Design Tokens" }),
|
|
95
|
+
/* @__PURE__ */ jsxs("p", { className: "mb-vsp-xs text-small text-muted", children: [
|
|
96
|
+
"Save as ",
|
|
97
|
+
/* @__PURE__ */ jsx("code", { className: "text-fg", children: EXPORT_FILENAME_HINT }),
|
|
98
|
+
" to feed this blob back into the panel (or hand to an AI assistant)."
|
|
99
|
+
] }),
|
|
100
|
+
/* @__PURE__ */ jsxs("label", { className: "mb-vsp-xs flex items-center gap-x-hsp-sm text-small text-fg", children: [
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
"input",
|
|
103
|
+
{
|
|
104
|
+
type: "checkbox",
|
|
105
|
+
checked: includeDefaults,
|
|
106
|
+
onChange: (e) => setIncludeDefaults(e.currentTarget.checked)
|
|
107
|
+
}
|
|
108
|
+
),
|
|
109
|
+
"Show defaults too"
|
|
110
|
+
] }),
|
|
111
|
+
/* @__PURE__ */ jsx("pre", { className: "overflow-x-auto border border-muted bg-code-bg p-hsp-lg text-small text-code-fg", children: /* @__PURE__ */ jsx("code", { children: code }) }),
|
|
112
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-vsp-sm flex items-center gap-x-hsp-md", children: [
|
|
113
|
+
/* @__PURE__ */ jsx(
|
|
114
|
+
"button",
|
|
115
|
+
{
|
|
116
|
+
type: "button",
|
|
117
|
+
onClick: handleCopy,
|
|
118
|
+
className: "border border-muted bg-surface px-hsp-lg py-vsp-2xs text-small text-fg transition-colors hover:border-accent hover:text-accent",
|
|
119
|
+
children: copyLabel
|
|
120
|
+
}
|
|
121
|
+
),
|
|
122
|
+
/* @__PURE__ */ jsx(
|
|
123
|
+
"button",
|
|
124
|
+
{
|
|
125
|
+
type: "button",
|
|
126
|
+
onClick: () => dialogRef.current?.close(),
|
|
127
|
+
className: "border border-muted bg-surface px-hsp-lg py-vsp-2xs text-small text-muted transition-colors hover:border-fg hover:text-fg",
|
|
128
|
+
children: "Close"
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
] })
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
export {
|
|
137
|
+
ColorTweakExportModal as default
|
|
138
|
+
};
|