@clidey/dory 1.0.7 → 1.9.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/README.md +12 -1
- package/bin/chat-server.ts +270 -0
- package/bin/dist/analytics-server.d.ts +11 -0
- package/bin/dist/analytics-server.d.ts.map +1 -0
- package/bin/dist/analytics-server.js +121 -0
- package/bin/dist/analytics-server.js.map +1 -0
- package/bin/dist/automation.d.ts +35 -0
- package/bin/dist/automation.d.ts.map +1 -0
- package/bin/dist/automation.js +259 -0
- package/bin/dist/automation.js.map +1 -0
- package/bin/dist/chat-server.d.ts +8 -0
- package/bin/dist/chat-server.d.ts.map +1 -0
- package/bin/dist/chat-server.js +322 -0
- package/bin/dist/chat-server.js.map +1 -0
- package/bin/dist/check.d.ts +16 -0
- package/bin/dist/check.d.ts.map +1 -0
- package/bin/dist/check.js +247 -0
- package/bin/dist/check.js.map +1 -0
- package/bin/dist/dory.js +252 -402
- package/bin/dist/dory.js.map +1 -1
- package/bin/dist/i18n-init.d.ts +6 -0
- package/bin/dist/i18n-init.d.ts.map +1 -0
- package/bin/dist/i18n-init.js +56 -0
- package/bin/dist/i18n-init.js.map +1 -0
- package/bin/dist/mcp-http.d.ts +8 -0
- package/bin/dist/mcp-http.d.ts.map +1 -0
- package/bin/dist/mcp-http.js +72 -0
- package/bin/dist/mcp-http.js.map +1 -0
- package/bin/dist/mcp.d.ts +2 -0
- package/bin/dist/mcp.d.ts.map +1 -0
- package/bin/dist/mcp.js +81 -0
- package/bin/dist/mcp.js.map +1 -0
- package/bin/dist/preview-entry.d.ts +2 -0
- package/bin/dist/preview-entry.d.ts.map +1 -0
- package/bin/dist/preview-entry.js +6 -0
- package/bin/dist/preview-entry.js.map +1 -0
- package/bin/dist/preview-server.d.ts +5 -0
- package/bin/dist/preview-server.d.ts.map +1 -0
- package/bin/dist/preview-server.js +159 -0
- package/bin/dist/preview-server.js.map +1 -0
- package/bin/dist/project-config.d.ts +22 -0
- package/bin/dist/project-config.d.ts.map +1 -0
- package/bin/dist/project-config.js +44 -0
- package/bin/dist/project-config.js.map +1 -0
- package/dist/index.html +57 -0
- package/dist/runtime/dory-runtime.css +2 -0
- package/dist/runtime/dory-runtime.html +14 -0
- package/dist/runtime/dory-runtime.js +5490 -0
- package/docs/api-playground-demo.mdx +119 -0
- package/docs/api-reference/asyncapi.json +324 -0
- package/docs/api-reference/openapi.json +366 -0
- package/docs/api-reference/operations/create.mdx +5 -0
- package/docs/api-reference/operations/delete.mdx +5 -0
- package/docs/api-reference/operations/get.mdx +5 -0
- package/docs/api-reference/operations/update.mdx +5 -0
- package/docs/api-reference/websocket-operations/receive-chat-message.mdx +5 -0
- package/docs/api-reference/websocket-operations/receive-notifications.mdx +5 -0
- package/docs/api-reference/websocket-operations/receive-presence-update.mdx +5 -0
- package/docs/api-reference/websocket-operations/send-chat-message.mdx +5 -0
- package/docs/api-reference/websocket-operations/send-presence-update.mdx +5 -0
- package/docs/assets/dory.jpeg +0 -0
- package/docs/components/accordion.mdx +145 -0
- package/docs/components/callouts.mdx +134 -0
- package/docs/components/cards.mdx +153 -0
- package/docs/components/code-blocks.mdx +281 -0
- package/docs/components/expandable.mdx +189 -0
- package/docs/components/icons.mdx +71 -0
- package/docs/components/images.mdx +82 -0
- package/docs/components/latex.mdx +148 -0
- package/docs/components/layout.mdx +175 -0
- package/docs/components/lists.mdx +134 -0
- package/docs/components/mermaid.mdx +149 -0
- package/docs/components/overview.mdx +81 -0
- package/docs/components/source.mdx +130 -0
- package/docs/components/steps.mdx +122 -0
- package/docs/components/tables.mdx +114 -0
- package/docs/components/tags.mdx +179 -0
- package/docs/components/typography.mdx +185 -0
- package/docs/configuration/analytics.mdx +45 -0
- package/docs/configuration/chat.mdx +59 -0
- package/docs/configuration/dory-json.mdx +278 -0
- package/docs/configuration/embed.mdx +73 -0
- package/docs/configuration/fonts.mdx +86 -0
- package/docs/configuration/internationalization.mdx +61 -0
- package/docs/configuration/navigation.mdx +217 -0
- package/docs/configuration/theming.mdx +166 -0
- package/docs/dory.json +129 -0
- package/docs/embed-example.html +176 -0
- package/docs/favicon.svg +18 -0
- package/docs/features.mdx +440 -0
- package/docs/getting-started/automation.mdx +76 -0
- package/docs/getting-started/configuration.mdx +95 -0
- package/docs/getting-started/installation.mdx +88 -0
- package/docs/getting-started/quick-start.mdx +53 -0
- package/docs/getting-started/whodb-ee-apps.mdx +122 -0
- package/docs/introduction.mdx +50 -0
- package/docs/logo/logo.svg +18 -0
- package/docs/playgrounds/api-playground.mdx +122 -0
- package/docs/playgrounds/websocket-playground.mdx +98 -0
- package/docs/social-card.png +0 -0
- package/docs/social-card.svg +17 -0
- package/docs/websocket-playground-demo.mdx +135 -0
- package/package.json +23 -17
- package/scripts/verify-runtime-parity.mjs +146 -0
- package/src/app.css +19 -1
- package/src/assets/fonts/HankenGrotesk.ttf +0 -0
- package/src/assets/fonts/OFL.txt +94 -0
- package/src/components/chat-assistant.tsx +229 -0
- package/src/components/dropdown.tsx +3 -3
- package/src/components/error-boundary.tsx +2 -2
- package/src/components/hooks.tsx +20 -1
- package/src/components/navigation.tsx +82 -51
- package/src/components/notification.tsx +2 -3
- package/src/components/routes.tsx +17 -19
- package/src/components/search-index.test.ts +15 -0
- package/src/components/search-index.ts +49 -48
- package/src/components/search.tsx +208 -104
- package/src/components/store.ts +27 -9
- package/src/config/mdx-common.ts +11 -0
- package/src/config/mdx.ts +10 -11
- package/src/embed/loader.ts +0 -3
- package/src/embed/types.ts +0 -2
- package/src/embed/widget-iframe.ts +19 -21
- package/src/embedded-runtime/config.ts +138 -0
- package/src/embedded-runtime/index.tsx +680 -0
- package/src/embedded-runtime/runtime.html +14 -0
- package/src/entry-server.tsx +46 -124
- package/src/main.tsx +16 -4
- package/src/mdx/accordion.tsx +3 -3
- package/src/mdx/api-playground.tsx +18 -16
- package/src/mdx/async-api.tsx +2 -2
- package/src/mdx/card.tsx +3 -2
- package/src/mdx/code.tsx +11 -9
- package/src/mdx/fence.tsx +6 -5
- package/src/mdx/icon-grid.tsx +4 -1
- package/src/mdx/icon-names.test.ts +15 -0
- package/src/mdx/icon-names.ts +60 -0
- package/src/mdx/icon-source-variants.ts +102 -0
- package/src/mdx/icon.tsx +12 -73
- package/src/mdx/latex.tsx +3 -2
- package/src/mdx/mdx.tsx +1 -1
- package/src/mdx/mermaid.tsx +12 -6
- package/src/mdx/open-api.tsx +130 -74
- package/src/mdx/preprocess.test.ts +16 -0
- package/src/mdx/preprocess.ts +61 -0
- package/src/mdx/processor.ts +4 -96
- package/src/mdx/source.tsx +5 -4
- package/src/mdx/specimen.tsx +38 -6
- package/src/mdx/tabs.tsx +29 -21
- package/src/mdx/text.tsx +9 -9
- package/src/mdx/try-it-panel.tsx +284 -0
- package/src/mdx/type-scale.tsx +4 -4
- package/src/mdx/websocket-playground.tsx +21 -14
- package/src/plugins/analytics-injector.ts +8 -0
- package/src/plugins/chat-dev-server.ts +32 -0
- package/src/plugins/docs-assets.test.ts +25 -0
- package/src/plugins/docs-assets.ts +6 -2
- package/src/plugins/frontmatter-dev-server.ts +2 -2
- package/src/plugins/frontmatter-generator.ts +1 -1
- package/src/plugins/html-files-middleware.test.ts +21 -1
- package/src/plugins/html-files-middleware.ts +26 -6
- package/src/plugins/html-metadata-injector.ts +24 -4
- package/src/plugins/llm-txt-dev-server.ts +2 -2
- package/src/plugins/llm-txt-generator.ts +21 -4
- package/src/plugins/prerender.ts +47 -20
- package/src/plugins/robots-generator.ts +1 -1
- package/src/plugins/sanitize.ts +1 -1
- package/src/plugins/shared.ts +6 -18
- package/src/plugins/sitemap-generator.ts +1 -1
- package/src/plugins/social-preview.test.ts +71 -0
- package/src/plugins/social-preview.ts +87 -0
- package/src/plugins/unified-mdx-plugin.ts +1 -1
- package/src/theme.scss +630 -207
- package/src/types/config.ts +53 -1
- package/src/ui/breadcrumb.tsx +17 -0
- package/src/ui/docs-header-view.tsx +32 -0
- package/src/ui/docs-navigation-view.tsx +69 -0
- package/src/ui/docs-page-frame.tsx +50 -0
- package/src/ui/dory-mark.tsx +9 -0
- package/src/ui/header.tsx +33 -90
- package/src/ui/layout.tsx +99 -153
- package/src/ui/mobile-navigation.tsx +10 -8
- package/src/ui/page-actions.tsx +67 -0
- package/src/ui/page-feedback.tsx +50 -0
- package/src/ui/page-footer.tsx +23 -0
- package/src/ui/prev-next-link.tsx +15 -69
- package/src/ui/prev-next-view.tsx +27 -0
- package/src/ui/table-of-content-view.tsx +167 -0
- package/src/ui/table-of-content.tsx +25 -183
- package/src/utils/analytics.test.ts +36 -0
- package/src/utils/analytics.ts +35 -0
- package/src/utils/colors.ts +7 -0
- package/src/utils/content-scope.test.ts +26 -0
- package/src/utils/content-scope.ts +39 -0
- package/src/utils/search-content.ts +12 -0
- package/src/utils/theme.ts +1 -7
- package/vite.config.ssr.ts +3 -3
- package/vite.config.ts +21 -15
package/src/types/config.ts
CHANGED
|
@@ -40,9 +40,15 @@ export interface DoryNavigationPage {
|
|
|
40
40
|
[key: string]: string;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/** Page entry with extras, e.g. { "page": "components/overview", "badge": "New" }. */
|
|
44
|
+
export interface DoryNavigationPageEntry {
|
|
45
|
+
page: string;
|
|
46
|
+
badge?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
43
49
|
export interface DoryNavigationGroup {
|
|
44
50
|
group: string;
|
|
45
|
-
pages: string
|
|
51
|
+
pages: Array<string | DoryNavigationPageEntry>;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
export interface DoryNavigationTab {
|
|
@@ -109,6 +115,8 @@ export interface DorySeo {
|
|
|
109
115
|
author?: string;
|
|
110
116
|
/** Absolute URL or path resolved against config.url. */
|
|
111
117
|
ogImage?: string;
|
|
118
|
+
/** Generate a branded PNG for each page at build time. Default: true. */
|
|
119
|
+
generateSocialImages?: boolean;
|
|
112
120
|
twitterCard?: 'summary' | 'summary_large_image';
|
|
113
121
|
/** e.g. "en_US" */
|
|
114
122
|
locale?: string;
|
|
@@ -123,6 +131,40 @@ export interface DoryTheme {
|
|
|
123
131
|
radius?: string;
|
|
124
132
|
}
|
|
125
133
|
|
|
134
|
+
/** One entry in the sidebar version picker. */
|
|
135
|
+
export interface DoryVersion {
|
|
136
|
+
label: string;
|
|
137
|
+
/** Local docs folder and URL prefix, e.g. "v1" for docs/v1/*.mdx. */
|
|
138
|
+
id?: string;
|
|
139
|
+
/** External published site; retained for existing configurations. */
|
|
140
|
+
url?: string;
|
|
141
|
+
navigation?: DoryNavigation;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface DoryLocale {
|
|
145
|
+
code: string;
|
|
146
|
+
label: string;
|
|
147
|
+
/** Optional translated tab and group labels; page keys remain the same. */
|
|
148
|
+
navigation?: DoryNavigation;
|
|
149
|
+
/** Navigation for translated older versions, keyed by version ID. */
|
|
150
|
+
versions?: Record<string, DoryNavigation>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export interface DoryI18n {
|
|
154
|
+
defaultLocale: string;
|
|
155
|
+
locales: DoryLocale[];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Source repository for "Edit this page" and "Report an issue" links. GitHub-style URLs. */
|
|
159
|
+
export interface DoryRepository {
|
|
160
|
+
/** Repository URL, e.g. "https://github.com/clidey/dory". */
|
|
161
|
+
url: string;
|
|
162
|
+
/** Branch the edit link opens. Default: "main". */
|
|
163
|
+
branch?: string;
|
|
164
|
+
/** Folder holding the docs inside the repository, e.g. "docs". Default: the repository root. */
|
|
165
|
+
path?: string;
|
|
166
|
+
}
|
|
167
|
+
|
|
126
168
|
export interface DoryConfig {
|
|
127
169
|
name: string;
|
|
128
170
|
title?: string;
|
|
@@ -132,6 +174,15 @@ export interface DoryConfig {
|
|
|
132
174
|
url?: string;
|
|
133
175
|
/** Path prefix the site is served under, e.g. "/docs". Default: served at the root. */
|
|
134
176
|
basePath?: string;
|
|
177
|
+
/** Shown in the sidebar version card, e.g. "1.0.8 · Latest". */
|
|
178
|
+
version?: string;
|
|
179
|
+
/** Other published versions; when set, the version card becomes a picker that opens the chosen URL. */
|
|
180
|
+
versions?: DoryVersion[];
|
|
181
|
+
/** Place translations in docs/<locale>/ with the same page keys. */
|
|
182
|
+
i18n?: DoryI18n;
|
|
183
|
+
/** Name in the footer copyright line. Default: `name`. */
|
|
184
|
+
copyright?: string;
|
|
185
|
+
repository?: DoryRepository;
|
|
135
186
|
twitter?: string;
|
|
136
187
|
favicon: string;
|
|
137
188
|
colors?: DoryColors;
|
|
@@ -141,5 +192,6 @@ export interface DoryConfig {
|
|
|
141
192
|
logo: DoryLogo;
|
|
142
193
|
embed?: DoryEmbedConfig;
|
|
143
194
|
analytics?: DoryAnalytics;
|
|
195
|
+
chat?: { suggestedQuestions?: string[] };
|
|
144
196
|
seo?: DorySeo;
|
|
145
197
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Mono "Docs / Group / Page" trail above the page title. */
|
|
2
|
+
export function Breadcrumb({ group, title }: { group?: string; title?: string }) {
|
|
3
|
+
const parts = ['Docs', group, title].filter((part): part is string => Boolean(part))
|
|
4
|
+
|
|
5
|
+
return (
|
|
6
|
+
<nav aria-label="Breadcrumb" className="dory-breadcrumb">
|
|
7
|
+
<ol className="flex flex-wrap items-center gap-2">
|
|
8
|
+
{parts.map((part, index) => (
|
|
9
|
+
<li key={index} className="flex items-center gap-2 whitespace-nowrap" aria-current={index === parts.length - 1 ? 'page' : undefined}>
|
|
10
|
+
{index > 0 && <span aria-hidden="true">/</span>}
|
|
11
|
+
<span>{part}</span>
|
|
12
|
+
</li>
|
|
13
|
+
))}
|
|
14
|
+
</ol>
|
|
15
|
+
</nav>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ComponentChildren } from 'preact';
|
|
2
|
+
import { Badge } from '@clidey/ux';
|
|
3
|
+
|
|
4
|
+
export type HeaderTab = { title: string; href: string; active: boolean };
|
|
5
|
+
|
|
6
|
+
type LinkRenderer = (href: string, className: string, children: ComponentChildren) => ComponentChildren;
|
|
7
|
+
|
|
8
|
+
/** The top bar shared by static Dory sites and runtime-loaded documentation. */
|
|
9
|
+
export function DocsHeaderView({ name, logo, homeHref, tabs, renderLink, actions, docsLabel = 'Docs', sectionsLabel = 'Sections', homeClassName, embedded = false }: {
|
|
10
|
+
name: string;
|
|
11
|
+
logo?: string;
|
|
12
|
+
homeHref: string;
|
|
13
|
+
tabs: HeaderTab[];
|
|
14
|
+
renderLink: LinkRenderer;
|
|
15
|
+
actions?: ComponentChildren;
|
|
16
|
+
docsLabel?: string;
|
|
17
|
+
sectionsLabel?: string;
|
|
18
|
+
homeClassName?: string;
|
|
19
|
+
embedded?: boolean;
|
|
20
|
+
}) {
|
|
21
|
+
return <header className="dory-topbar sticky top-0 z-50 flex h-14 shrink-0 items-stretch bg-[var(--sidebar)] text-white">
|
|
22
|
+
{renderLink(homeHref, homeClassName ?? 'flex w-60 shrink-0 items-center gap-2.5 px-4', <>
|
|
23
|
+
{logo && <img data-testid={embedded ? 'embedded-logo' : undefined} src={logo} alt="" className="h-7 w-7" />}
|
|
24
|
+
<span data-testid={embedded ? 'embedded-site-name' : undefined} className="font-heading text-lg font-bold tracking-tight text-white">{name}</span>
|
|
25
|
+
<Badge variant="outline" className="dory-docs-pill">{docsLabel}</Badge>
|
|
26
|
+
</>)}
|
|
27
|
+
<nav className="hidden md:flex items-stretch" aria-label={sectionsLabel}>
|
|
28
|
+
{tabs.map(tab => renderLink(tab.href, `dory-topbar-tab${tab.active ? ' active' : ''}`, tab.title))}
|
|
29
|
+
</nav>
|
|
30
|
+
<div className="ml-auto flex items-center gap-3 pr-4" data-testid="header-actions">{actions}</div>
|
|
31
|
+
</header>;
|
|
32
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import classNames from 'classnames';
|
|
2
|
+
import type { ComponentChildren } from 'preact';
|
|
3
|
+
import { useEffect, useRef } from 'preact/hooks';
|
|
4
|
+
import { Badge } from '@clidey/ux';
|
|
5
|
+
import { DORY_REPO_URL, DoryMark } from './dory-mark';
|
|
6
|
+
|
|
7
|
+
export type NavigationPage = { href: string; title: string; badge?: string; method?: string };
|
|
8
|
+
export type NavigationGroup = { title: string; pages: NavigationPage[] };
|
|
9
|
+
|
|
10
|
+
const methodTone: Record<string, string> = {
|
|
11
|
+
GET: 'text-[var(--sidebar-primary)]',
|
|
12
|
+
POST: 'text-[var(--highlight)]',
|
|
13
|
+
PUT: 'text-[#f4781c]',
|
|
14
|
+
PATCH: 'text-[#f4781c]',
|
|
15
|
+
DEL: 'text-[#ff6668]',
|
|
16
|
+
PUB: 'text-[#f4781c]',
|
|
17
|
+
SUB: 'text-[var(--sidebar-primary)]',
|
|
18
|
+
WS: 'text-[var(--sidebar-primary)]',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
type PageLinkRenderer = (page: NavigationPage, className: string, active: boolean, children: ComponentChildren) => ComponentChildren;
|
|
22
|
+
|
|
23
|
+
/** The navigation tree shared by static Dory sites and runtime-loaded documentation. */
|
|
24
|
+
export function DocsNavigationView({ groups, activeHref, renderPageLink, versionLabel, versionSelect, languageSelect, ariaLabel = 'Documentation', versionCaption = 'Version', footerLabel = 'Built with Dory' }: {
|
|
25
|
+
groups: NavigationGroup[];
|
|
26
|
+
activeHref: string;
|
|
27
|
+
renderPageLink: PageLinkRenderer;
|
|
28
|
+
versionLabel?: string;
|
|
29
|
+
versionSelect?: ComponentChildren;
|
|
30
|
+
languageSelect?: ComponentChildren;
|
|
31
|
+
ariaLabel?: string;
|
|
32
|
+
versionCaption?: string;
|
|
33
|
+
footerLabel?: string;
|
|
34
|
+
}) {
|
|
35
|
+
const navRef = useRef<HTMLElement>(null);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const nav = navRef.current;
|
|
38
|
+
const container = nav?.parentElement;
|
|
39
|
+
const active = nav?.querySelector('a[aria-current="page"], button[aria-current="page"]');
|
|
40
|
+
if (!container || !active) return;
|
|
41
|
+
const item = active.getBoundingClientRect();
|
|
42
|
+
const viewport = container.getBoundingClientRect();
|
|
43
|
+
if (item.top < viewport.top) container.scrollTop += item.top - viewport.top;
|
|
44
|
+
else if (item.bottom > viewport.bottom) container.scrollTop += item.bottom - viewport.bottom;
|
|
45
|
+
}, [activeHref]);
|
|
46
|
+
|
|
47
|
+
return <nav ref={navRef} className="dory-sidebar flex min-h-full flex-col gap-6 text-[13px]" aria-label={ariaLabel}>
|
|
48
|
+
{versionLabel && <div className="relative flex items-center justify-between rounded-lg border border-white/10 bg-white/5 px-3 py-2.5">
|
|
49
|
+
<div><p className="dory-mono-label">{versionCaption}</p><p className="mt-0.5 text-sm font-semibold text-white">{versionLabel}</p></div>
|
|
50
|
+
{versionSelect}
|
|
51
|
+
</div>}
|
|
52
|
+
{languageSelect}
|
|
53
|
+
{groups.map((group, index) => <section key={`${group.title}-${index}`}>
|
|
54
|
+
<h3 className="dory-mono-label flex gap-2 px-2.5 !text-[var(--sidebar-primary)]">
|
|
55
|
+
<span>{String(index + 1).padStart(2, '0')}</span><span className="text-white/55">{group.title}</span>
|
|
56
|
+
</h3>
|
|
57
|
+
<ul role="list" className="mt-2 space-y-0.5">{group.pages.map(page => {
|
|
58
|
+
const isActive = activeHref === page.href;
|
|
59
|
+
const contents = <>
|
|
60
|
+
{page.method && <span className={classNames('dory-method', methodTone[page.method] ?? 'text-white/60')}>{page.method}</span>}
|
|
61
|
+
<span className="truncate">{page.title}</span>
|
|
62
|
+
{page.badge && <Badge variant="secondary" className="dory-badge">{page.badge}</Badge>}
|
|
63
|
+
</>;
|
|
64
|
+
return <li key={page.href}>{renderPageLink(page, classNames('dory-sidebar-link', { active: isActive }), isActive, contents)}</li>;
|
|
65
|
+
})}</ul>
|
|
66
|
+
</section>)}
|
|
67
|
+
<a href={DORY_REPO_URL} target="_blank" rel="noopener noreferrer" className="dory-sidebar-footer mt-auto flex items-center gap-2.5 border-t border-white/10 px-2.5 pt-4"><DoryMark className="h-4 w-4" /><span className="dory-mono-label">{footerLabel}</span></a>
|
|
68
|
+
</nav>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ComponentChildren } from 'preact';
|
|
2
|
+
import { cn } from '@clidey/ux';
|
|
3
|
+
|
|
4
|
+
type DocsPageFrameProps = {
|
|
5
|
+
className?: string;
|
|
6
|
+
header: ComponentChildren;
|
|
7
|
+
sidebar?: ComponentChildren;
|
|
8
|
+
breadcrumb: ComponentChildren;
|
|
9
|
+
actions?: ComponentChildren;
|
|
10
|
+
title?: string;
|
|
11
|
+
lead?: string;
|
|
12
|
+
meta?: ComponentChildren;
|
|
13
|
+
content: ComponentChildren;
|
|
14
|
+
afterContent?: ComponentChildren;
|
|
15
|
+
toc?: ComponentChildren;
|
|
16
|
+
embedded?: boolean;
|
|
17
|
+
wide?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** The page structure shared by a Dory site and its sandboxed app viewer. */
|
|
21
|
+
export function DocsPageFrame({ className, header, sidebar, breadcrumb, actions, title, lead, meta, content, afterContent, toc, embedded = false, wide = false }: DocsPageFrameProps) {
|
|
22
|
+
return <div className={cn('dory-shell flex min-h-screen w-full flex-col bg-[var(--sidebar)]', className)}>
|
|
23
|
+
{header}
|
|
24
|
+
<div className="flex flex-1">
|
|
25
|
+
{sidebar && <aside className="hidden w-60 shrink-0 lg:block">
|
|
26
|
+
<div className="sticky top-14 h-[calc(100vh-3.5rem)] overflow-y-auto px-3 pb-6 pt-4">
|
|
27
|
+
{sidebar}
|
|
28
|
+
</div>
|
|
29
|
+
</aside>}
|
|
30
|
+
<main className={cn('dory-main min-w-0 flex-1 bg-background text-foreground', embedded ? 'p-8' : 'px-6 py-10 sm:px-10 lg:px-12')}>
|
|
31
|
+
<div className="mx-auto flex w-full max-w-[66rem] justify-center gap-14">
|
|
32
|
+
<article className={cn('dory-article flex min-w-0 flex-1 flex-col', wide ? 'max-w-[66rem]' : 'max-w-[47rem]')}>
|
|
33
|
+
<div className="mb-6 flex min-h-9 flex-wrap items-center justify-between gap-4">
|
|
34
|
+
{breadcrumb}
|
|
35
|
+
{actions}
|
|
36
|
+
</div>
|
|
37
|
+
<header className="mb-10">
|
|
38
|
+
{title && <h1 className="dory-page-title">{title}</h1>}
|
|
39
|
+
{lead && <p className="dory-lead">{lead}</p>}
|
|
40
|
+
</header>
|
|
41
|
+
{meta}
|
|
42
|
+
<div className="flex-1 min-h-[calc(100vh-2rem)]">{content}</div>
|
|
43
|
+
{afterContent}
|
|
44
|
+
</article>
|
|
45
|
+
{toc}
|
|
46
|
+
</div>
|
|
47
|
+
</main>
|
|
48
|
+
</div>
|
|
49
|
+
</div>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const mark = "<svg width=\"22\" height=\"24\" viewBox=\"0 0 22 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n<path d=\"M21.9941 4.99951C19.9947 3.00079 19.9947 3.00079 16.9956 0.00271368V4.99951H21.9941Z\" fill=\"#92BFFA\"/>\n<path d=\"M7.49782 3.91843C7.49782 4.5155 7.98183 4.99951 8.5789 4.99951H16.9951V0.00271606H8.5789C7.98183 0.00271606 7.49782 0.486733 7.49782 1.0838V3.91843Z\" fill=\"url(#paint0_linear_66_680)\"/>\n<path d=\"M21.9932 5.01123C22.0049 8.20987 21.9983 17.7036 21.9951 21.9995C21.9943 23.1041 21.0977 23.9995 19.9932 23.9995H2C0.895431 23.9995 3.87055e-07 23.1041 0 21.9995V8.59131C0 7.99426 0.48401 7.51028 1.08105 7.51025H3.91797C4.51481 7.51052 4.99902 7.99441 4.99902 8.59131V19.5024H16.9951V5.01123H21.9932Z\" fill=\"url(#paint1_linear_66_680)\"/>\n<ellipse cx=\"12.3217\" cy=\"14.276\" rx=\"1.2973\" ry=\"1.29647\" fill=\"#1967D2\"/>\n<path d=\"M5 0.00634813C5.55157 0.00730227 5.99805 0.454718 5.99805 1.00635V4.01221C5.99805 4.64068 6.29707 5.23179 6.80273 5.60498L7.46777 6.09619C7.81171 6.35003 8.22878 6.48682 8.65625 6.48682H14.4951C15.0472 6.48682 15.4949 6.93475 15.4951 7.48682V16.98C15.4951 17.5322 15.0474 17.98 14.4951 17.98H7.49805C6.94583 17.9799 6.49808 17.5322 6.49805 16.98V8.67139C6.49806 8.23724 6.35689 7.81407 6.0957 7.46729L5.58691 6.79248C5.21558 6.29954 4.63759 6.00515 4.02051 5.99561H1C0.447722 5.9956 0 5.54789 0 4.99561V1.00049C0.000165845 0.447951 0.448441 -4.60729e-05 1.00098 0.00048876L5 0.00634813Z\" fill=\"#FFC236\"/>\n<ellipse cx=\"12.9961\" cy=\"15.505\" rx=\"1\" ry=\"0.999359\" fill=\"#3630C4\"/>\n<defs>\n<linearGradient id=\"paint0_linear_66_680\" x1=\"10.9999\" y1=\"0.00271606\" x2=\"10.9999\" y2=\"23.9995\" gradientUnits=\"userSpaceOnUse\">\n<stop stop-color=\"#528FF4\"/>\n<stop offset=\"1\" stop-color=\"#92BFFA\"/>\n</linearGradient>\n<linearGradient id=\"paint1_linear_66_680\" x1=\"10.9999\" y1=\"0.00271606\" x2=\"10.9999\" y2=\"23.9995\" gradientUnits=\"userSpaceOnUse\">\n<stop stop-color=\"#528FF4\"/>\n<stop offset=\"1\" stop-color=\"#92BFFA\"/>\n</linearGradient>\n</defs>\n</svg>"
|
|
2
|
+
|
|
3
|
+
/** Dory project page, linked from the "Built with Dory" and "Powered by Dory" credits. */
|
|
4
|
+
export const DORY_REPO_URL = 'https://github.com/clidey/dory'
|
|
5
|
+
|
|
6
|
+
/** Dory logo mark for the "Built with Dory" footer. */
|
|
7
|
+
export function DoryMark({ className }: { className?: string }) {
|
|
8
|
+
return <img src={`data:image/svg+xml;utf8,${encodeURIComponent(mark)}`} alt="" className={className} />
|
|
9
|
+
}
|
package/src/ui/header.tsx
CHANGED
|
@@ -1,110 +1,53 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import type { ComponentChildren } from 'preact';
|
|
2
|
+
import { useMemo } from 'preact/hooks';
|
|
3
3
|
import { Link } from 'wouter-preact';
|
|
4
4
|
import { usePathname } from '../components/hooks';
|
|
5
5
|
import docsConfig from '../../docs/dory.json' with { type: 'json' };
|
|
6
6
|
import type { DoryConfig } from '../types/config';
|
|
7
7
|
import { MobileSearch, Search } from '../components/search';
|
|
8
|
-
import {
|
|
8
|
+
import { getNavigationForPath } from '../components/store';
|
|
9
9
|
import { MobileNavigation } from './mobile-navigation';
|
|
10
10
|
import { ModeToggle } from '@clidey/ux';
|
|
11
11
|
import { useIsEmbedded } from '../components/hooks';
|
|
12
12
|
import { assetUrl } from '../utils/base-path';
|
|
13
|
+
import { DocsHeaderView } from './docs-header-view';
|
|
13
14
|
|
|
14
15
|
const config = docsConfig as DoryConfig;
|
|
15
16
|
const isThemeForced = config.theme?.mode === 'dark' || config.theme?.mode === 'light';
|
|
16
17
|
|
|
17
|
-
function TopLevelNavItem({ href, children, isActive }: { href: string; children: string; isActive?: boolean }) {
|
|
18
|
-
return (
|
|
19
|
-
<li>
|
|
20
|
-
<Link
|
|
21
|
-
to={href}
|
|
22
|
-
className={classNames(
|
|
23
|
-
"text-xs transition hover:opacity-80",
|
|
24
|
-
{
|
|
25
|
-
"text-brand-foreground": isActive,
|
|
26
|
-
},
|
|
27
|
-
)}
|
|
28
|
-
>
|
|
29
|
-
{children}
|
|
30
|
-
</Link>
|
|
31
|
-
</li>
|
|
32
|
-
);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
18
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* structure here, update entry-server.tsx to match or hydration will mismatch.
|
|
19
|
+
* Dark top bar: logo and site name with a DOCS pill, one underlined tab per
|
|
20
|
+
* navigation tab, search with a ⌘K hint, theme toggle and the mobile menu.
|
|
21
|
+
* With `ssr` the client-only widgets (search, toggle, menu) are left out and
|
|
22
|
+
* mount during hydration.
|
|
41
23
|
*/
|
|
42
|
-
export function Header({
|
|
43
|
-
const [isScrolled, setIsScrolled] = useState(false);
|
|
24
|
+
export function Header({ ssr = false }: { ssr?: boolean }) {
|
|
44
25
|
const pathname = usePathname();
|
|
26
|
+
const navigation = getNavigationForPath(pathname);
|
|
45
27
|
const isEmbedded = useIsEmbedded();
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
}, []);
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
function onScroll() {
|
|
53
|
-
setIsScrolled(window.scrollY > 0);
|
|
54
|
-
}
|
|
55
|
-
onScroll();
|
|
56
|
-
window.addEventListener('scroll', onScroll, { passive: true });
|
|
57
|
-
return () => {
|
|
58
|
-
window.removeEventListener('scroll', onScroll);
|
|
59
|
-
}
|
|
60
|
-
}, []);
|
|
28
|
+
const logo = useMemo(() => config.logo?.light ? assetUrl(config.logo.light) : '', []);
|
|
29
|
+
const renderLink = (href: string, className: string, children: ComponentChildren) =>
|
|
30
|
+
<Link key={href} href={href} className={className}>{children}</Link>;
|
|
61
31
|
|
|
62
32
|
return (
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const isActive = tab.groups.some(group =>
|
|
83
|
-
group.pages.some(page => page.href === pathname)
|
|
84
|
-
);
|
|
85
|
-
return (
|
|
86
|
-
<TopLevelNavItem
|
|
87
|
-
key={tab.title}
|
|
88
|
-
href={tab.groups[0].pages[0].href}
|
|
89
|
-
isActive={isActive}
|
|
90
|
-
>
|
|
91
|
-
{tab.title}
|
|
92
|
-
</TopLevelNavItem>
|
|
93
|
-
);
|
|
94
|
-
})}
|
|
95
|
-
</ul>
|
|
96
|
-
</nav>
|
|
97
|
-
<div className="hidden md:block md:h-5 md:w-px md:bg-zinc-900/10 md:dark:bg-white/15" />
|
|
98
|
-
<div className="flex items-center gap-3" data-testid="header-actions">
|
|
99
|
-
<MobileSearch />
|
|
100
|
-
<Search />
|
|
101
|
-
{
|
|
102
|
-
!isEmbedded && !isThemeForced &&
|
|
103
|
-
<ModeToggle data-testid="mode-toggle" />
|
|
104
|
-
}
|
|
105
|
-
<MobileNavigation />
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
</header>
|
|
33
|
+
<DocsHeaderView name={config.name} logo={logo} homeHref={navigation[0]?.groups[0]?.pages[0]?.href ?? '/'}
|
|
34
|
+
tabs={navigation.map(tab => ({ title: tab.title, href: tab.groups[0].pages[0].href, active: tab.groups.some(group => group.pages.some(page => page.href === pathname)) }))}
|
|
35
|
+
renderLink={renderLink}
|
|
36
|
+
actions={!ssr && (
|
|
37
|
+
<>
|
|
38
|
+
<div className="dory-topbar-search relative hidden lg:block">
|
|
39
|
+
<Search />
|
|
40
|
+
<kbd className="dory-kbd" aria-hidden="true">⌘K</kbd>
|
|
41
|
+
</div>
|
|
42
|
+
<div className="lg:hidden [&_[data-slot=search-input-wrapper]]:w-9 [&_[data-slot=search-input-wrapper]]:border-transparent [&_[data-slot=search-input-wrapper]]:bg-white/8 [&_[data-slot=search-input-wrapper]]:px-2.5 [&_svg]:mr-0 [&_svg]:text-white/70 [&_input]:hidden">
|
|
43
|
+
<MobileSearch />
|
|
44
|
+
</div>
|
|
45
|
+
{!isEmbedded && !isThemeForced && (
|
|
46
|
+
<span className="dory-mode"><ModeToggle data-testid="mode-toggle" /></span>
|
|
47
|
+
)}
|
|
48
|
+
<MobileNavigation />
|
|
49
|
+
</>
|
|
50
|
+
)}
|
|
51
|
+
/>
|
|
109
52
|
);
|
|
110
|
-
}
|
|
53
|
+
}
|