@tenphi/starlight 0.5.0 → 0.6.1

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.
Files changed (38) hide show
  1. package/dist/components/Card.astro +5 -3
  2. package/dist/components/GlobalStyles.js +761 -0
  3. package/dist/components/LayoutComponents.js +404 -0
  4. package/dist/components/Logo.astro +39 -0
  5. package/dist/components/MobileNavigationTabs.astro +7 -2
  6. package/dist/components/PackageVersion.astro +22 -0
  7. package/dist/components/Preview.astro +21 -10
  8. package/dist/components/Steps.astro +5 -1
  9. package/dist/components/Tabs.astro +9 -2
  10. package/dist/components/TastyComponents.js +156 -0
  11. package/dist/components/component-styles.test.ts +75 -0
  12. package/dist/components/component-styles.ts +79 -0
  13. package/dist/components/customize-component.js +10 -0
  14. package/dist/components/svg-icon.test.ts +11 -0
  15. package/dist/components/svg-icon.ts +11 -0
  16. package/dist/components/tasty-states.d.ts +2 -0
  17. package/dist/components/tasty-states.js +21 -0
  18. package/dist/components-public.d.ts +1 -0
  19. package/dist/components.d.ts +2 -1
  20. package/dist/components.js +2 -1
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +297 -163
  24. package/dist/index.js.map +1 -1
  25. package/dist/{navigation-CC0dlAL8.js → navigation-CkQXI2Zb.js} +41 -2
  26. package/dist/navigation-CkQXI2Zb.js.map +1 -0
  27. package/dist/navigation.d.ts +11 -2
  28. package/dist/navigation.d.ts.map +1 -1
  29. package/dist/navigation.js +2 -2
  30. package/dist/overrides/Header.astro +28 -5
  31. package/dist/overrides/MobileMenuFooter.astro +15 -0
  32. package/dist/overrides/ThemeSelect.astro +69 -0
  33. package/dist/routes/DocsPage.astro +43 -145
  34. package/package.json +5 -9
  35. package/dist/components/NavigationTree.astro +0 -98
  36. package/dist/navigation-CC0dlAL8.js.map +0 -1
  37. package/dist/styles.css +0 -1346
  38. package/dist/styles.d.ts +0 -1
@@ -1,156 +1,54 @@
1
1
  ---
2
- import { createMarkdownProcessor } from "@astrojs/markdown-remark";
2
+ import StarlightPage from "@astrojs/starlight/components/StarlightPage.astro";
3
3
  import { content } from "virtual:cookbook/config";
4
4
  import { layout } from "virtual:cookbook/layout";
5
- import MobileNavigationTabs from "../components/MobileNavigationTabs.astro";
6
- import NavigationTree from "../components/NavigationTree.astro";
7
- import { activeNavigationTab, navigationItemsForPath } from "../navigation.js";
8
- import "virtual:cookbook/theme.css";
9
- import "../styles.css";
5
+ import { starlightPageSidebar } from "../navigation.js";
10
6
 
11
7
  export const prerender = true;
12
8
 
13
- export async function getStaticPaths() {
14
- const processor = await createMarkdownProcessor();
15
- return Promise.all(
16
- content.entries.map(async (entry) => ({
9
+ export function getStaticPaths() {
10
+ return content.entries
11
+ .filter(
12
+ (entry) =>
13
+ import.meta.env.MODE !== "production" || !entry.frontmatter.draft,
14
+ )
15
+ .map((entry) => ({
17
16
  params: { route: entry.route === "/" ? undefined : entry.route.slice(1) },
18
- props: {
19
- entry,
20
- routes: content.routes,
21
- html: (await processor.render(entry.transformedBody)).code,
22
- site: content.site,
23
- base: content.base,
24
- search: content.search,
25
- },
26
- })),
27
- );
17
+ props: { entry, routes: content.routes },
18
+ }));
28
19
  }
29
20
 
30
- const { entry, routes, html, site, base, search } = Astro.props;
31
- const withBase = (route) =>
32
- `${base === "/" ? "" : `/${base.replace(/^\/+|\/+$/g, "")}`}${route}` || "/";
33
- const activeTab = activeNavigationTab(layout.tabs, entry.route);
34
- const navigationItems =
35
- navigationItemsForPath(layout, entry.route) ??
36
- routes.map((route) => route.route);
21
+ const { entry, routes } = Astro.props;
22
+ if (!entry.rendered) {
23
+ throw new Error(`Cookbook did not render ${entry.sourcePath}.`);
24
+ }
25
+ const frontmatter = {
26
+ title: entry.title,
27
+ ...(entry.description ? { description: entry.description } : {}),
28
+ ...(entry.frontmatter.toc !== undefined
29
+ ? { tableOfContents: entry.frontmatter.toc }
30
+ : {}),
31
+ ...(entry.frontmatter.editUrl !== undefined
32
+ ? { editUrl: entry.frontmatter.editUrl }
33
+ : {}),
34
+ ...(entry.frontmatter.prev !== undefined
35
+ ? { prev: entry.frontmatter.prev }
36
+ : {}),
37
+ ...(entry.frontmatter.next !== undefined
38
+ ? { next: entry.frontmatter.next }
39
+ : {}),
40
+ ...(entry.frontmatter.search !== undefined
41
+ ? { pagefind: entry.frontmatter.search }
42
+ : {}),
43
+ ...(entry.frontmatter.head ? { head: entry.frontmatter.head } : {}),
44
+ ...(entry.frontmatter.draft ? { draft: true } : {}),
45
+ };
37
46
  ---
38
47
 
39
- <!doctype html>
40
- <html lang="en">
41
- <head>
42
- <meta charset="utf-8" />
43
- <meta name="viewport" content="width=device-width" />
44
- <title>{entry.title} | {site.title ?? "Documentation"}</title>
45
- {
46
- entry.description && (
47
- <meta name="description" content={entry.description} />
48
- )
49
- }
50
- </head>
51
- <body class="td-shell">
52
- <a class="td-skip" href="#main-content">Skip to content</a>
53
- <header
54
- class="td-shell__header"
55
- data-tasty-anatomy="Header"
56
- data-docs-base={base}
57
- >
58
- <div class="td-shell__header-primary">
59
- <a href={withBase("/")}>{site.title ?? "Documentation"}</a>
60
- <div class="td-shell__actions">
61
- <label class="td-appearance-control" title="Color theme">
62
- <span class="td-visually-hidden">Color theme</span>
63
- <select data-docs-theme aria-label="Color theme">
64
- <option value="system">System theme</option>
65
- <option value="light">Light theme</option>
66
- <option value="dark">Dark theme</option>
67
- </select>
68
- </label>
69
- <label
70
- class="td-appearance-control td-appearance-control--contrast"
71
- title="Contrast"
72
- >
73
- <span class="td-visually-hidden">Contrast</span>
74
- <select data-docs-contrast aria-label="Contrast">
75
- <option value="system">System contrast</option>
76
- <option value="normal">Normal contrast</option>
77
- <option value="more">High contrast</option>
78
- </select>
79
- </label>
80
- {
81
- search && (
82
- <button
83
- type="button"
84
- data-docs-search-open
85
- aria-haspopup="dialog"
86
- aria-keyshortcuts="Control+K"
87
- >
88
- <span>Search</span>
89
- <kbd data-docs-search-shortcut>
90
- <>
91
- <kbd>Ctrl</kbd>
92
- <kbd>K</kbd>
93
- </>
94
- </kbd>
95
- </button>
96
- )
97
- }
98
- </div>
99
- </div>
100
- {
101
- layout.tabs.length > 0 && (
102
- <nav class="td-top-tabs" aria-label="Primary">
103
- {layout.tabs.map((tab, index) => (
104
- <a
105
- href={tab.link.startsWith("/") ? withBase(tab.link) : tab.link}
106
- aria-current={index === activeTab ? "page" : undefined}
107
- >
108
- {tab.label}
109
- </a>
110
- ))}
111
- </nav>
112
- )
113
- }
114
- </header>
115
- <div class="td-shell__layout">
116
- <nav
117
- class="td-shell__nav"
118
- aria-label="Documentation"
119
- data-tasty-anatomy="Sidebar"
120
- >
121
- <MobileNavigationTabs base={base} currentPath={entry.route} />
122
- <NavigationTree
123
- items={navigationItems}
124
- routes={routes}
125
- current={entry.route}
126
- base={base}
127
- />
128
- </nav>
129
- <main
130
- id="main-content"
131
- class="td-shell__main"
132
- data-pagefind-body
133
- data-tasty-anatomy="Article"
134
- >
135
- <h1>{entry.title}</h1>
136
- <div set:html={html} />
137
- </main>
138
- </div>
139
- {
140
- search && (
141
- <dialog data-docs-search aria-labelledby="td-search-title">
142
- <form method="dialog">
143
- <button aria-label="Close search">Close</button>
144
- </form>
145
- <h2 id="td-search-title">Search documentation</h2>
146
- <label>
147
- Search{" "}
148
- <input type="search" data-docs-search-input autocomplete="off" />
149
- </label>
150
- <div data-docs-search-status aria-live="polite" />
151
- <ul data-docs-search-results />
152
- </dialog>
153
- )
154
- }
155
- </body>
156
- </html>
48
+ <StarlightPage
49
+ frontmatter={frontmatter}
50
+ headings={entry.rendered.headings}
51
+ sidebar={starlightPageSidebar(layout, routes)}
52
+ >
53
+ <div set:html={entry.rendered.html} />
54
+ </StarlightPage>
package/package.json CHANGED
@@ -1,10 +1,9 @@
1
1
  {
2
2
  "name": "@tenphi/starlight",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "Astro and Starlight renderer for Cookbook",
5
5
  "type": "module",
6
6
  "sideEffects": [
7
- "./dist/styles.css",
8
7
  "./dist/client/*.js"
9
8
  ],
10
9
  "exports": {
@@ -20,10 +19,6 @@
20
19
  "types": "./dist/components-public.d.ts",
21
20
  "import": "./dist/components.js"
22
21
  },
23
- "./styles": {
24
- "types": "./dist/styles.d.ts",
25
- "default": "./dist/styles.css"
26
- },
27
22
  "./client/*": "./dist/client/*.js"
28
23
  },
29
24
  "files": [
@@ -50,14 +45,15 @@
50
45
  "license": "MIT",
51
46
  "dependencies": {
52
47
  "@astrojs/markdown-remark": "^7.2.4",
48
+ "@astrojs/react": "^5.0.3",
53
49
  "@astrojs/starlight": "^0.41.10",
54
50
  "@fontsource-variable/jetbrains-mono": "^5.3.0",
55
51
  "@fontsource-variable/onest": "^5.3.0",
56
- "@tenphi/docs": "0.5.0",
52
+ "@tenphi/docs": "0.6.1",
57
53
  "@tenphi/glaze": "2.0.0",
58
- "@tenphi/tasty": "3.4.0",
59
- "pagefind": "^1.5.2",
54
+ "@tenphi/tasty": "3.6.0",
60
55
  "react": "^18.3.1 || ^19.0.0",
56
+ "react-dom": "^18.3.1 || ^19.0.0",
61
57
  "tsx": "^4.20.6"
62
58
  },
63
59
  "peerDependencies": {
@@ -1,98 +0,0 @@
1
- ---
2
- import type { DocsRoute, NavigationItem } from "@tenphi/docs";
3
- import { normalizeNavigationPath } from "../navigation.js";
4
-
5
- interface Props {
6
- items: NavigationItem[];
7
- routes: DocsRoute[];
8
- current: string;
9
- base: string;
10
- nested?: boolean;
11
- }
12
-
13
- const { items, routes, current, base, nested = false } = Astro.props;
14
- const routeTitle = new Map(routes.map((route) => [route.route, route.title]));
15
- const withBase = (route: string) =>
16
- route.startsWith("/")
17
- ? `${base === "/" ? "" : `/${base.replace(/^\/+|\/+$/g, "")}`}${route}` ||
18
- "/"
19
- : route;
20
- const labelFor = (route: string) =>
21
- routeTitle.get(normalizeNavigationPath(route)) ??
22
- normalizeNavigationPath(route).split("/").filter(Boolean).at(-1) ??
23
- "Home";
24
- const isCurrent = (route: string) =>
25
- route.startsWith("/") && normalizeNavigationPath(route) === current;
26
- const generatedItems = (directory: string): NavigationItem[] => {
27
- const root = normalizeNavigationPath(directory);
28
- return routes
29
- .filter(
30
- (route) =>
31
- root === "/" ||
32
- route.route === root ||
33
- route.route.startsWith(`${root}/`),
34
- )
35
- .map((route) => route.route);
36
- };
37
- ---
38
-
39
- <ul class:list={{ "td-shell__nav-root": !nested }}>
40
- {
41
- items.map((item) => {
42
- if (typeof item === "string") {
43
- return (
44
- <li>
45
- <a
46
- href={withBase(item)}
47
- aria-current={isCurrent(item) ? "page" : undefined}
48
- >
49
- {labelFor(item)}
50
- </a>
51
- </li>
52
- );
53
- }
54
- if ("items" in item) {
55
- return (
56
- <li>
57
- <details open>
58
- <summary>{item.label}</summary>
59
- <Astro.self
60
- items={item.items}
61
- routes={routes}
62
- current={current}
63
- base={base}
64
- nested
65
- />
66
- </details>
67
- </li>
68
- );
69
- }
70
- if ("autogenerate" in item) {
71
- return (
72
- <li>
73
- <details open>
74
- <summary>{item.label}</summary>
75
- <Astro.self
76
- items={generatedItems(item.autogenerate.directory)}
77
- routes={routes}
78
- current={current}
79
- base={base}
80
- nested
81
- />
82
- </details>
83
- </li>
84
- );
85
- }
86
- return (
87
- <li>
88
- <a
89
- href={withBase(item.link)}
90
- aria-current={isCurrent(item.link) ? "page" : undefined}
91
- >
92
- {item.label}
93
- </a>
94
- </li>
95
- );
96
- })
97
- }
98
- </ul>
@@ -1 +0,0 @@
1
- {"version":3,"file":"navigation-CC0dlAL8.js","names":[],"sources":["../src/navigation.ts"],"sourcesContent":["import type { DocsConfig, NavigationItem, NavigationTab } from \"@tenphi/docs\";\n\nexport interface ResolvedNavigationTab extends NavigationTab {\n /** Index of the tab's resolved Starlight sidebar group. */\n sidebarGroup?: number;\n}\n\nexport interface ResolvedNavigationLayout {\n fallbackSidebarGroup?: number;\n items?: NavigationItem[];\n tabs: ResolvedNavigationTab[];\n sectioned: boolean;\n}\n\nexport function resolveNavigationLayout(\n navigation: DocsConfig[\"navigation\"],\n): ResolvedNavigationLayout {\n const items = Array.isArray(navigation) ? navigation : navigation?.items;\n const configuredTabs = Array.isArray(navigation)\n ? []\n : (navigation?.tabs ?? []);\n const fallbackSidebarGroup = items !== undefined ? 0 : undefined;\n let sidebarGroup = fallbackSidebarGroup === undefined ? 0 : 1;\n const tabs = configuredTabs.map((tab) => ({\n ...tab,\n ...(tab.items !== undefined ? { sidebarGroup: sidebarGroup++ } : {}),\n }));\n\n return {\n ...(fallbackSidebarGroup !== undefined ? { fallbackSidebarGroup } : {}),\n ...(items !== undefined ? { items } : {}),\n tabs,\n sectioned: tabs.some((tab) => tab.sidebarGroup !== undefined),\n };\n}\n\nexport function navigationItemsForPath(\n layout: ResolvedNavigationLayout,\n pathname: string,\n): NavigationItem[] | undefined {\n const active = activeNavigationTab(layout.tabs, pathname);\n return active >= 0 && layout.tabs[active]?.items !== undefined\n ? layout.tabs[active].items\n : layout.items;\n}\n\n/** Pick one tab, preferring its own URL before routes owned by its sidebar. */\nexport function activeNavigationTab(\n tabs: NavigationTab[],\n pathname: string,\n): number {\n const current = normalizeNavigationPath(pathname);\n let winner = -1;\n let winningScore = -1;\n\n for (const [index, tab] of tabs.entries()) {\n const score = Math.max(\n linkMatchScore(tab.link, current, 30_000),\n navigationMatchScore(tab.items ?? [], current),\n );\n if (score > winningScore) {\n winner = index;\n winningScore = score;\n }\n }\n\n return winningScore >= 0 ? winner : -1;\n}\n\nexport function navigationPath(pathname: string, base = \"/\"): string {\n const normalizedBase = normalizeNavigationPath(base);\n const withoutBase =\n normalizedBase !== \"/\" &&\n (pathname === normalizedBase || pathname.startsWith(`${normalizedBase}/`))\n ? pathname.slice(normalizedBase.length) || \"/\"\n : pathname;\n return normalizeNavigationPath(withoutBase);\n}\n\nexport function normalizeNavigationPath(path: string): string {\n const clean = path.split(/[?#]/, 1)[0]?.replace(/\\\\/g, \"/\") ?? \"/\";\n const normalized = `/${clean.replace(/^\\/+|\\/+$/g, \"\")}`;\n return normalized === \"/\" ? normalized : normalized.replace(/\\/$/, \"\");\n}\n\nfunction navigationMatchScore(\n items: NavigationItem[],\n current: string,\n): number {\n let score = -1;\n for (const item of items) {\n if (typeof item === \"string\") {\n if (normalizeNavigationPath(item) === current)\n score = Math.max(score, 20_000);\n continue;\n }\n if (\"items\" in item) {\n score = Math.max(score, navigationMatchScore(item.items, current));\n continue;\n }\n if (\"autogenerate\" in item) {\n score = Math.max(\n score,\n directoryMatchScore(item.autogenerate.directory, current),\n );\n continue;\n }\n score = Math.max(score, linkMatchScore(item.link, current, 20_000));\n }\n return score;\n}\n\nfunction linkMatchScore(link: string, current: string, base: number): number {\n if (!link.startsWith(\"/\")) return -1;\n const target = normalizeNavigationPath(link);\n if (target === current) return base + 1_000 + target.length;\n if (target !== \"/\" && current.startsWith(`${target}/`)) {\n return base + target.length;\n }\n return -1;\n}\n\nfunction directoryMatchScore(directory: string, current: string): number {\n const target = normalizeNavigationPath(directory);\n if (target === \"/\") return 10_000;\n return current === target || current.startsWith(`${target}/`)\n ? 10_000 + target.length\n : -1;\n}\n"],"mappings":"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"}