@clidey/dory 1.0.8 → 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
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { iconSourceVariants } from './icon-source-variants'
|
|
2
|
+
|
|
3
|
+
// Keep common names used by existing Dory documents working after the icon migration.
|
|
4
|
+
const aliases: Record<string, string> = {
|
|
5
|
+
activity: 'progress',
|
|
6
|
+
'alert-triangle': 'warning',
|
|
7
|
+
'bar-chart': 'chart',
|
|
8
|
+
box: 'packages',
|
|
9
|
+
'chart-column': 'chart',
|
|
10
|
+
'chevrons-down-up': 'up-down',
|
|
11
|
+
'circle-alert': 'alert-circle',
|
|
12
|
+
'circle-check': 'check-circle',
|
|
13
|
+
'code-2': 'code',
|
|
14
|
+
'columns-2': 'columns',
|
|
15
|
+
'columns-3': 'columns',
|
|
16
|
+
'file-json': 'file-code',
|
|
17
|
+
'external-link': 'external',
|
|
18
|
+
github: 'code',
|
|
19
|
+
'git-branch': 'branch',
|
|
20
|
+
'git-fork': 'branch',
|
|
21
|
+
'git-pull-request': 'branch',
|
|
22
|
+
hammer: 'settings',
|
|
23
|
+
image: 'file-image',
|
|
24
|
+
'layout-dashboard': 'dashboard',
|
|
25
|
+
layers: 'layout',
|
|
26
|
+
'list-ordered': 'list',
|
|
27
|
+
'message-square': 'chat',
|
|
28
|
+
'maximize-2': 'fullscreen',
|
|
29
|
+
map: 'globe',
|
|
30
|
+
package: 'packages',
|
|
31
|
+
palette: 'layout',
|
|
32
|
+
'play-circle': 'play',
|
|
33
|
+
'share-2': 'share',
|
|
34
|
+
'settings-2': 'settings',
|
|
35
|
+
'shield-check': 'shield',
|
|
36
|
+
'sliders-horizontal': 'sliders',
|
|
37
|
+
sparkles: 'ai',
|
|
38
|
+
'square-terminal': 'terminal',
|
|
39
|
+
plug: 'integration',
|
|
40
|
+
tag: 'price-tag',
|
|
41
|
+
heart: 'star',
|
|
42
|
+
rocket: 'promote',
|
|
43
|
+
zap: 'bolt',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function normalize(name: string) {
|
|
47
|
+
const kebab = name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').replace(/_/g, '-').toLowerCase()
|
|
48
|
+
return aliases[kebab] ?? kebab
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Compatibility names accepted by Dory's MDX Icon component. */
|
|
52
|
+
export function resolveIconName(name: string): string {
|
|
53
|
+
const [source, sourceName] = name.split('/', 2)
|
|
54
|
+
if (sourceName) {
|
|
55
|
+
if (source !== 'community' && source !== 'enterprise-core' && source !== 'enterprise') return name
|
|
56
|
+
const normalized = normalize(sourceName)
|
|
57
|
+
return iconSourceVariants[`${source}/${normalized}`] ?? normalized
|
|
58
|
+
}
|
|
59
|
+
return normalize(name)
|
|
60
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/** Published UX names for source-specific variants in the older Dory icon API. */
|
|
2
|
+
export const iconSourceVariants: Record<string, string> = {
|
|
3
|
+
'enterprise-core/banknotes': 'banknotes-alt',
|
|
4
|
+
'enterprise-core/calendar': 'calendar-alt',
|
|
5
|
+
'enterprise-core/check-circle': 'check-circle-alt',
|
|
6
|
+
'enterprise-core/chevron-down': 'chevron-down-alt',
|
|
7
|
+
'enterprise-core/chevron-left': 'chevron-left-alt',
|
|
8
|
+
'enterprise-core/chevron-right': 'chevron-right-alt',
|
|
9
|
+
'enterprise-core/chevron-up': 'chevron-up-alt',
|
|
10
|
+
'enterprise-core/clock': 'clock-alt',
|
|
11
|
+
'enterprise-core/code': 'code-alt',
|
|
12
|
+
'enterprise-core/copy': 'copy-alt',
|
|
13
|
+
'enterprise-core/download': 'download-alt',
|
|
14
|
+
'enterprise-core/file-text': 'file-text-alt',
|
|
15
|
+
'enterprise-core/globe': 'globe-alt',
|
|
16
|
+
'enterprise-core/grid': 'grid-alt',
|
|
17
|
+
'enterprise-core/hash': 'hash-alt',
|
|
18
|
+
'enterprise-core/help': 'help-alt',
|
|
19
|
+
'enterprise-core/home': 'home-alt',
|
|
20
|
+
'enterprise-core/list': 'list-alt',
|
|
21
|
+
'enterprise-core/mail': 'mail-alt',
|
|
22
|
+
'enterprise-core/moon': 'moon-alt',
|
|
23
|
+
'enterprise-core/play': 'play-alt',
|
|
24
|
+
'enterprise-core/plus': 'plus-alt',
|
|
25
|
+
'enterprise-core/plus-circle': 'plus-circle-alt',
|
|
26
|
+
'enterprise-core/search': 'search-alt',
|
|
27
|
+
'enterprise-core/secret': 'secret-alt',
|
|
28
|
+
'enterprise-core/settings': 'settings-alt',
|
|
29
|
+
'enterprise-core/sidebar': 'sidebar-alt',
|
|
30
|
+
'enterprise-core/signout': 'signout-alt',
|
|
31
|
+
'enterprise-core/source': 'source-alt',
|
|
32
|
+
'enterprise-core/sun': 'sun-alt',
|
|
33
|
+
'enterprise-core/trash': 'trash-alt',
|
|
34
|
+
'enterprise-core/upload': 'upload-alt',
|
|
35
|
+
'enterprise/arrow-right': 'arrow-right-alt',
|
|
36
|
+
'enterprise/bag': 'bag-alt',
|
|
37
|
+
'enterprise/bell': 'bell-alt',
|
|
38
|
+
'enterprise/calculator': 'calculator-alt',
|
|
39
|
+
'enterprise/calendar': 'calendar-alt-2',
|
|
40
|
+
'enterprise/card': 'card-alt',
|
|
41
|
+
'enterprise/chat': 'chat-alt',
|
|
42
|
+
'enterprise/check': 'check-alt',
|
|
43
|
+
'enterprise/checkbox': 'select-all',
|
|
44
|
+
'enterprise/chevron-down': 'chevron-down-alt-2',
|
|
45
|
+
'enterprise/chevron-left': 'chevron-left-alt-2',
|
|
46
|
+
'enterprise/chevron-right': 'chevron-right-alt-2',
|
|
47
|
+
'enterprise/chevron-up': 'chevron-up-alt-2',
|
|
48
|
+
'enterprise/clipboard': 'clipboard-alt',
|
|
49
|
+
'enterprise/clock': 'clock-alt-2',
|
|
50
|
+
'enterprise/close': 'close-alt',
|
|
51
|
+
'enterprise/cloud': 'cloud-alt',
|
|
52
|
+
'enterprise/columns': 'columns-alt',
|
|
53
|
+
'enterprise/copy': 'copy-alt-2',
|
|
54
|
+
'enterprise/customer': 'user',
|
|
55
|
+
'enterprise/dashboard': 'dashboard-alt',
|
|
56
|
+
'enterprise/download': 'download-alt-2',
|
|
57
|
+
'enterprise/edit': 'edit-alt',
|
|
58
|
+
'enterprise/external': 'external-alt',
|
|
59
|
+
'enterprise/eye': 'eye-alt',
|
|
60
|
+
'enterprise/eye-off': 'eye-off-alt',
|
|
61
|
+
'enterprise/file': 'file-alt',
|
|
62
|
+
'enterprise/file-text': 'file-text-alt-2',
|
|
63
|
+
'enterprise/filter': 'filter-alt',
|
|
64
|
+
'enterprise/folder': 'folder-alt',
|
|
65
|
+
'enterprise/formula': 'formula-alt',
|
|
66
|
+
'enterprise/globe': 'globe-alt-2',
|
|
67
|
+
'enterprise/group': 'folder-alt',
|
|
68
|
+
'enterprise/hash': 'hash-alt-2',
|
|
69
|
+
'enterprise/help': 'help-alt-2',
|
|
70
|
+
'enterprise/home': 'home-alt-2',
|
|
71
|
+
'enterprise/info': 'info-alt',
|
|
72
|
+
'enterprise/link': 'link-alt',
|
|
73
|
+
'enterprise/lock': 'lock-alt',
|
|
74
|
+
'enterprise/mail': 'mail-alt-2',
|
|
75
|
+
'enterprise/menu': 'menu-alt',
|
|
76
|
+
'enterprise/minus': 'minus-alt',
|
|
77
|
+
'enterprise/monitor': 'monitor-alt',
|
|
78
|
+
'enterprise/moon': 'moon-alt-2',
|
|
79
|
+
'enterprise/more-v': 'more-v-alt',
|
|
80
|
+
'enterprise/order': 'order-alt',
|
|
81
|
+
'enterprise/plus': 'plus-alt-2',
|
|
82
|
+
'enterprise/redo': 'redo-alt',
|
|
83
|
+
'enterprise/refresh': 'refresh-alt',
|
|
84
|
+
'enterprise/save': 'save-alt',
|
|
85
|
+
'enterprise/scan': 'scan-alt',
|
|
86
|
+
'enterprise/search': 'search-alt-2',
|
|
87
|
+
'enterprise/send': 'send-alt',
|
|
88
|
+
'enterprise/settings': 'settings-alt-2',
|
|
89
|
+
'enterprise/share': 'share-alt',
|
|
90
|
+
'enterprise/sidebar': 'sidebar-alt-2',
|
|
91
|
+
'enterprise/sliders': 'sliders-alt',
|
|
92
|
+
'enterprise/star': 'star-alt',
|
|
93
|
+
'enterprise/store': 'store-alt',
|
|
94
|
+
'enterprise/sun': 'sun-alt-2',
|
|
95
|
+
'enterprise/table': 'table-alt',
|
|
96
|
+
'enterprise/toggle': 'toggle-alt',
|
|
97
|
+
'enterprise/trash': 'trash-alt-2',
|
|
98
|
+
'enterprise/undo': 'undo-alt',
|
|
99
|
+
'enterprise/upload': 'upload-alt-2',
|
|
100
|
+
'enterprise/users': 'users-alt',
|
|
101
|
+
'enterprise/warning': 'warning-alt',
|
|
102
|
+
}
|
package/src/mdx/icon.tsx
CHANGED
|
@@ -1,80 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import * as solidIcons from '@fortawesome/free-solid-svg-icons'
|
|
4
|
-
import * as regularIcons from '@fortawesome/free-regular-svg-icons'
|
|
5
|
-
import * as brandIcons from '@fortawesome/free-brands-svg-icons'
|
|
1
|
+
import { CatalogIcon } from '@clidey/ux'
|
|
2
|
+
import { resolveIconName } from './icon-names'
|
|
6
3
|
import classNames from 'classnames'
|
|
7
|
-
import * as LucideIcons from 'lucide-react'
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
const iconSets = {
|
|
11
|
-
solid: solidIcons,
|
|
12
|
-
regular: regularIcons,
|
|
13
|
-
brands: brandIcons,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const prefixes = {
|
|
17
|
-
solid: 'fas',
|
|
18
|
-
regular: 'far',
|
|
19
|
-
brands: 'fab',
|
|
20
|
-
} as const
|
|
21
|
-
|
|
22
|
-
export function Icon({
|
|
23
|
-
icon,
|
|
24
|
-
iconType = 'solid',
|
|
25
|
-
color = '',
|
|
26
|
-
size = 24,
|
|
27
|
-
className,
|
|
28
|
-
...rest
|
|
29
|
-
}: {
|
|
5
|
+
export function Icon({ icon, color, size = 24, className, style, ...rest }: {
|
|
30
6
|
icon: string
|
|
31
|
-
iconType?: keyof typeof iconSets
|
|
32
7
|
color?: string
|
|
33
8
|
size?: number
|
|
34
9
|
} & Omit<React.ComponentPropsWithoutRef<'svg'>, 'color'>) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<LucideComponent
|
|
45
|
-
className={classNames("inline-block align-[-0.2em] stroke-black dark:stroke-white", className)}
|
|
46
|
-
color={color}
|
|
47
|
-
size={size}
|
|
48
|
-
{...rest}
|
|
49
|
-
/>
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// --- Try Font Awesome ---
|
|
54
|
-
// Fall back to the brands set: Lucide 1.x removed all brand icons
|
|
55
|
-
// (github, twitter, npm, ...), which live only in FA brands.
|
|
56
|
-
const iconKey = `fa${pascalCase}`
|
|
57
|
-
const setsToTry: Array<keyof typeof iconSets> =
|
|
58
|
-
iconType === 'brands' ? ['brands'] : [iconType, 'brands']
|
|
59
|
-
|
|
60
|
-
for (const setName of setsToTry) {
|
|
61
|
-
const faSet = iconSets[setName] ?? solidIcons
|
|
62
|
-
const faIcon = faSet[iconKey as keyof typeof faSet]
|
|
63
|
-
|
|
64
|
-
if (faIcon && typeof faIcon === 'object' && 'iconName' in faIcon) {
|
|
65
|
-
library.add(faIcon)
|
|
66
|
-
return (
|
|
67
|
-
<FontAwesomeIcon
|
|
68
|
-
icon={[prefixes[setName] || 'fas', faIcon.iconName] as any}
|
|
69
|
-
className={classNames("inline-block align-[-0.2em] stroke-black dark:stroke-white", className)}
|
|
70
|
-
color={color as any}
|
|
71
|
-
size={size as any}
|
|
72
|
-
{...rest as any}
|
|
73
|
-
/>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
console.warn(`⚠️ Icon not found: "${icon}" (converted to ${iconKey}) in ${iconType}`)
|
|
79
|
-
return null // or return a default/fallback icon if preferred
|
|
10
|
+
return (
|
|
11
|
+
<CatalogIcon
|
|
12
|
+
name={resolveIconName(icon)}
|
|
13
|
+
style={{ color, ...(typeof style === 'object' && style !== null ? style : {}) }}
|
|
14
|
+
size={size}
|
|
15
|
+
className={classNames('inline-block align-[-0.2em]', className)}
|
|
16
|
+
{...rest}
|
|
17
|
+
/>
|
|
18
|
+
)
|
|
80
19
|
}
|
package/src/mdx/latex.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CatalogIcon } from '@clidey/ux'
|
|
2
|
+
|
|
2
3
|
import { useEffect, useRef, useState } from 'react'
|
|
3
4
|
|
|
4
5
|
function extractText(node: React.ReactNode): string {
|
|
@@ -73,7 +74,7 @@ export function Latex({ children, inline = false }: LatexProps) {
|
|
|
73
74
|
<div className="my-4">
|
|
74
75
|
<div className="flex flex-col items-center justify-center py-12 px-6 text-center bg-gradient-to-br from-red-50 to-red-100 dark:from-red-900/20 dark:to-red-800/20 border-2 border-dashed border-red-300 dark:border-red-700 rounded-lg">
|
|
75
76
|
<div className="w-16 h-16 mb-4 flex items-center justify-center bg-red-100 dark:bg-red-900/30 rounded-full">
|
|
76
|
-
<
|
|
77
|
+
<CatalogIcon name="warning" className="w-8 h-8 text-red-500" />
|
|
77
78
|
</div>
|
|
78
79
|
<h3 className="text-lg font-semibold text-red-700 dark:text-red-300 mb-2">
|
|
79
80
|
LaTeX Rendering Error
|
package/src/mdx/mdx.tsx
CHANGED
|
@@ -22,7 +22,7 @@ export { UnorderedList as ul, OrderedList as ol, ListItem as li } from './list';
|
|
|
22
22
|
export { UnorderedList, OrderedList, ListItem } from './list';
|
|
23
23
|
export { AsyncAPI } from './async-api';
|
|
24
24
|
export { Source } from './source';
|
|
25
|
-
export { Specimen, SpecimenProps } from './specimen';
|
|
25
|
+
export { Specimen, SpecimenProps, Prop } from './specimen';
|
|
26
26
|
export { Chip, ChipGroup } from './chip';
|
|
27
27
|
export { Tabs, Tab } from './tabs';
|
|
28
28
|
export { IconGrid } from './icon-grid';
|
package/src/mdx/mermaid.tsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CatalogIcon } from '@clidey/ux'
|
|
2
|
+
|
|
2
3
|
import classNames from 'classnames'
|
|
3
4
|
import { useEffect, useMemo, useRef, useState } from 'preact/compat'
|
|
4
5
|
|
|
@@ -31,7 +32,7 @@ function paletteThemeVariables() {
|
|
|
31
32
|
const v = (name: string) => css.getPropertyValue(name).trim()
|
|
32
33
|
return {
|
|
33
34
|
fontFamily: v('--font-body') || 'inherit',
|
|
34
|
-
fontSize: '
|
|
35
|
+
fontSize: '14px',
|
|
35
36
|
background: v('--card'),
|
|
36
37
|
mainBkg: v('--accent'),
|
|
37
38
|
primaryColor: v('--accent'),
|
|
@@ -114,6 +115,9 @@ export function MermaidRenderer({ content }: { content: string }) {
|
|
|
114
115
|
let mounted = true
|
|
115
116
|
|
|
116
117
|
const renderMermaid = async () => {
|
|
118
|
+
setError(null)
|
|
119
|
+
setIsValid(null)
|
|
120
|
+
setIsLoaded(false)
|
|
117
121
|
try {
|
|
118
122
|
const mermaid = (await import('mermaid')).default
|
|
119
123
|
|
|
@@ -122,6 +126,7 @@ export function MermaidRenderer({ content }: { content: string }) {
|
|
|
122
126
|
mermaid.initialize({
|
|
123
127
|
startOnLoad: false,
|
|
124
128
|
theme: 'base',
|
|
129
|
+
look: 'classic',
|
|
125
130
|
themeVariables: paletteThemeVariables(),
|
|
126
131
|
flowchart: {
|
|
127
132
|
nodeSpacing: 50,
|
|
@@ -164,7 +169,6 @@ export function MermaidRenderer({ content }: { content: string }) {
|
|
|
164
169
|
} catch (err) {
|
|
165
170
|
console.error('Mermaid rendering error:', err)
|
|
166
171
|
if (mounted) {
|
|
167
|
-
setIsValid(false)
|
|
168
172
|
setError(err instanceof Error ? err.message : 'Failed to render diagram')
|
|
169
173
|
}
|
|
170
174
|
}
|
|
@@ -186,13 +190,15 @@ export function MermaidRenderer({ content }: { content: string }) {
|
|
|
186
190
|
<div className="mermaid-wrapper my-8">
|
|
187
191
|
<div className="flex flex-col items-center justify-center py-12 px-6 text-center bg-gradient-to-br from-red-50 to-red-100 dark:from-red-900/20 dark:to-red-800/20 border-2 border-dashed border-red-300 dark:border-red-700 rounded-lg">
|
|
188
192
|
<div className="w-16 h-16 mb-4 flex items-center justify-center bg-red-100 dark:bg-red-900/30 rounded-full">
|
|
189
|
-
<
|
|
193
|
+
<CatalogIcon name="warning" className="w-8 h-8 text-red-500" />
|
|
190
194
|
</div>
|
|
191
195
|
<h3 className="text-lg font-semibold text-red-700 dark:text-red-300 mb-2">
|
|
192
|
-
Diagram Syntax Error
|
|
196
|
+
{isValid === false ? 'Diagram Syntax Error' : 'Diagram Load Error'}
|
|
193
197
|
</h3>
|
|
194
198
|
<p className="text-red-600 dark:text-red-400 mb-4 max-w-md">
|
|
195
|
-
|
|
199
|
+
{isValid === false
|
|
200
|
+
? 'The Mermaid diagram contains invalid syntax and cannot be rendered.'
|
|
201
|
+
: 'The diagram could not be loaded. Please reload the page.'}
|
|
196
202
|
</p>
|
|
197
203
|
<div className="bg-red-50 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded-md p-3 max-w-md">
|
|
198
204
|
<p className="text-sm text-red-700 dark:text-red-300 font-mono break-all">
|
package/src/mdx/open-api.tsx
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CatalogIcon, Button } from "@clidey/ux"
|
|
2
2
|
import classNames from "classnames"
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
import { h } from "preact"
|
|
5
5
|
import { useState } from "preact/hooks"
|
|
6
|
-
import {
|
|
6
|
+
import type { Server } from "./api-playground"
|
|
7
7
|
import { CodeFrame, CodeGroup } from "./code"
|
|
8
8
|
import { Fence, Pre } from "./fence"
|
|
9
9
|
import { Tag } from "./tag"
|
|
10
|
+
import { TryItPanel, type TryItField } from "./try-it-panel"
|
|
10
11
|
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
12
13
|
// Field list used by the API pages and exposed to MDX as Properties/Property.
|
|
@@ -178,6 +179,11 @@ function exampleOf(schema: Schema, depth = 0): unknown {
|
|
|
178
179
|
}
|
|
179
180
|
}
|
|
180
181
|
|
|
182
|
+
/** Short type for a form field: `enum` rather than `enum<string>`. */
|
|
183
|
+
function fieldType(schema: Schema): string {
|
|
184
|
+
return schema.enum ? 'enum' : schema.type ?? 'object'
|
|
185
|
+
}
|
|
186
|
+
|
|
181
187
|
function describeDefault(schema: Schema, description?: string): string | undefined {
|
|
182
188
|
if (description) return description
|
|
183
189
|
if (schema.description) return schema.description
|
|
@@ -223,17 +229,17 @@ function ChildAttributes({ schema, components }: { schema: Schema; components: C
|
|
|
223
229
|
const count = Object.keys(schema.properties ?? {}).length
|
|
224
230
|
if (count === 0) return null
|
|
225
231
|
return (
|
|
226
|
-
<div className="mt-3">
|
|
232
|
+
<div className="mt-3 overflow-hidden rounded-lg border border-[var(--border)]">
|
|
227
233
|
<button
|
|
228
234
|
type="button"
|
|
229
235
|
onClick={() => setOpen((v) => !v)}
|
|
230
236
|
aria-expanded={open}
|
|
231
|
-
className="flex w-full items-center gap-2
|
|
237
|
+
className="flex w-full items-center gap-2 bg-muted px-4 py-2.5 text-left text-sm font-medium text-foreground"
|
|
232
238
|
>
|
|
233
|
-
<
|
|
239
|
+
<CatalogIcon name="chevron-right" aria-hidden="true" className={classNames('h-3.5 w-3.5 transition-transform', { 'rotate-90': open })} />
|
|
234
240
|
{open ? 'Hide' : 'Show'} {count} child attribute{count === 1 ? '' : 's'}
|
|
235
241
|
</button>
|
|
236
|
-
{open && <div className="
|
|
242
|
+
{open && <div className="px-4"><SchemaFields schema={schema} components={components} /></div>}
|
|
237
243
|
</div>
|
|
238
244
|
)
|
|
239
245
|
}
|
|
@@ -247,7 +253,7 @@ function CopyUrl({ value }: { value: string }) {
|
|
|
247
253
|
onClick={() => navigator.clipboard.writeText(value).then(() => { setCopied(true); setTimeout(() => setCopied(false), 1000) })}
|
|
248
254
|
className="rounded-md p-1.5 text-muted-foreground transition hover:bg-muted hover:text-foreground"
|
|
249
255
|
>
|
|
250
|
-
{copied ? <
|
|
256
|
+
{copied ? <CatalogIcon name="check" className="h-3.5 w-3.5" /> : <CatalogIcon name="copy" className="h-3.5 w-3.5" />}
|
|
251
257
|
</button>
|
|
252
258
|
)
|
|
253
259
|
}
|
|
@@ -299,6 +305,32 @@ function ResponseTabs({ responses, components }: { responses: PathMethod['respon
|
|
|
299
305
|
)
|
|
300
306
|
}
|
|
301
307
|
|
|
308
|
+
// Longest line of the cURL `-d` body before it continues on the next line.
|
|
309
|
+
const CURL_BODY_WIDTH = 44
|
|
310
|
+
|
|
311
|
+
/** `-d` lines for cURL, breaking a flat JSON object across lines so it reads without wrapping. */
|
|
312
|
+
function curlBody(body: unknown): string[] {
|
|
313
|
+
const json = JSON.stringify(body)
|
|
314
|
+
if (body === null || typeof body !== 'object' || Array.isArray(body) || json.length <= CURL_BODY_WIDTH) {
|
|
315
|
+
return [` -d '${json}'`]
|
|
316
|
+
}
|
|
317
|
+
const lines: string[] = []
|
|
318
|
+
let line = ''
|
|
319
|
+
for (const [key, value] of Object.entries(body)) {
|
|
320
|
+
const entry = `${JSON.stringify(key)}:${JSON.stringify(value)}`
|
|
321
|
+
if (line && line.length + entry.length + 1 > CURL_BODY_WIDTH) {
|
|
322
|
+
lines.push(`${line},`)
|
|
323
|
+
line = entry
|
|
324
|
+
} else {
|
|
325
|
+
line = line ? `${line},${entry}` : entry
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
lines.push(line)
|
|
329
|
+
return lines.map((text, index) =>
|
|
330
|
+
`${index === 0 ? " -d '{" : ' '}${text}${index === lines.length - 1 ? "}'" : ''}`
|
|
331
|
+
)
|
|
332
|
+
}
|
|
333
|
+
|
|
302
334
|
/** cURL / JavaScript / Python samples generated from the operation. */
|
|
303
335
|
function RequestSamples({ method, url, headers, body }: { method: string; url: string; headers: Record<string, string>; body?: unknown }) {
|
|
304
336
|
const headerLines = Object.entries(headers)
|
|
@@ -306,7 +338,7 @@ function RequestSamples({ method, url, headers, body }: { method: string; url: s
|
|
|
306
338
|
const curl = [
|
|
307
339
|
`curl -X ${method} ${url} \\`,
|
|
308
340
|
...headerLines.map(([key, value]) => ` -H "${key}: ${value}" \\`),
|
|
309
|
-
...(json ?
|
|
341
|
+
...(json ? curlBody(body) : []),
|
|
310
342
|
].join('\n').replace(/ \\$/, '')
|
|
311
343
|
const js = [
|
|
312
344
|
`const response = await fetch("${url}", {`,
|
|
@@ -384,20 +416,39 @@ export function OpenAPI({ openAPIJson, method: selectedMethod, path: selectedPat
|
|
|
384
416
|
}
|
|
385
417
|
if (bodySchema) headers['Content-Type'] = 'application/json'
|
|
386
418
|
|
|
419
|
+
const parameterFields: TryItField[] = parameters.flatMap((param) => {
|
|
420
|
+
if (param.in === 'cookie') return []
|
|
421
|
+
const schema = resolveSchema(param.schema, components)
|
|
422
|
+
const value = schema.example ?? schema.default
|
|
423
|
+
return [{ name: param.name, type: fieldType(schema), value: value === undefined ? '' : String(value), in: param.in ?? 'query' }]
|
|
424
|
+
})
|
|
425
|
+
const bodyFields: TryItField[] = Object.entries(bodySchema?.properties ?? {}).map(([name, raw]) => {
|
|
426
|
+
const schema = resolveSchema(raw, components)
|
|
427
|
+
const value = exampleOf(schema)
|
|
428
|
+
return { name, type: fieldType(schema), value: typeof value === 'string' ? value : JSON.stringify(value) }
|
|
429
|
+
})
|
|
430
|
+
const authInputs: TryItField[] = schemes.flatMap((scheme) => {
|
|
431
|
+
const header = authHeader(scheme)
|
|
432
|
+
if (!header) return []
|
|
433
|
+
return [{ name: header[0], type: 'header', value: header[1].replace(/\$\w+$/, '') }]
|
|
434
|
+
})
|
|
435
|
+
|
|
387
436
|
return (
|
|
388
437
|
<div className="dory-api max-w-none w-full">
|
|
389
|
-
<
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
<
|
|
438
|
+
<TryItPanel
|
|
439
|
+
open={showPlayground}
|
|
440
|
+
onOpenChange={setShowPlayground}
|
|
441
|
+
method={selectedMethod}
|
|
442
|
+
path={selectedPath}
|
|
443
|
+
servers={openAPIJson.servers ?? []}
|
|
444
|
+
parameters={parameterFields}
|
|
445
|
+
body={bodyFields}
|
|
446
|
+
auth={authInputs}
|
|
447
|
+
/>
|
|
448
|
+
|
|
449
|
+
{operation.description && <p className="dory-lead -mt-4! mb-6">{operation.description}</p>}
|
|
450
|
+
|
|
451
|
+
<div className="not-prose flex max-w-[45rem] items-center gap-3 rounded-lg border border-[var(--border)] bg-card py-2 pl-3 pr-2">
|
|
401
452
|
<Tag>{selectedMethod}</Tag>
|
|
402
453
|
<span className="min-w-0 flex-1 truncate font-mono text-sm">
|
|
403
454
|
<span className="text-muted-foreground">{serverUrl}</span>
|
|
@@ -405,63 +456,68 @@ export function OpenAPI({ openAPIJson, method: selectedMethod, path: selectedPat
|
|
|
405
456
|
</span>
|
|
406
457
|
<CopyUrl value={fullUrl} />
|
|
407
458
|
<Button onClick={() => setShowPlayground(true)} className="flex items-center gap-1.5 bg-[var(--primary)] text-white hover:bg-[var(--primary)]/90">
|
|
408
|
-
<
|
|
459
|
+
<CatalogIcon name="play" className="h-3 w-3 fill-current" />
|
|
409
460
|
Try it
|
|
410
461
|
</Button>
|
|
411
462
|
</div>
|
|
412
463
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
464
|
+
<div className="grid gap-x-12 xl:grid-cols-[minmax(0,1fr)_29rem]">
|
|
465
|
+
<div className="min-w-0">
|
|
466
|
+
{schemes.length > 0 && (
|
|
467
|
+
<>
|
|
468
|
+
<SectionTitle>Authorization</SectionTitle>
|
|
469
|
+
<Properties>
|
|
470
|
+
{schemes.map((scheme, index) => {
|
|
471
|
+
const header = authHeader(scheme)
|
|
472
|
+
const name = header?.[0] ?? scheme.name ?? scheme.type
|
|
473
|
+
const location = scheme.type === 'apiKey' ? scheme.in ?? 'header' : 'header'
|
|
474
|
+
return (
|
|
475
|
+
<Property key={index} name={name} type={`${location} · string`} required>
|
|
476
|
+
{scheme.description ?? (scheme.type === 'http' ? `${scheme.scheme === 'basic' ? 'Basic' : 'Bearer'} token.` : 'API key.')}
|
|
477
|
+
</Property>
|
|
478
|
+
)
|
|
479
|
+
})}
|
|
480
|
+
</Properties>
|
|
481
|
+
</>
|
|
482
|
+
)}
|
|
483
|
+
|
|
484
|
+
{parameters.length > 0 && (
|
|
485
|
+
<>
|
|
486
|
+
<SectionTitle>Parameters</SectionTitle>
|
|
487
|
+
<Properties>
|
|
488
|
+
{parameters.map((param) => {
|
|
489
|
+
const schema = resolveSchema(param.schema, components)
|
|
490
|
+
return (
|
|
491
|
+
<Property key={`${param.in}-${param.name}`} name={param.name} type={`${param.in ?? 'query'} · ${typeLabel(schema)}`} required={param.required} defaultValue={schema.default}>
|
|
492
|
+
{describeDefault(schema, param.description)}
|
|
493
|
+
</Property>
|
|
494
|
+
)
|
|
495
|
+
})}
|
|
496
|
+
</Properties>
|
|
497
|
+
</>
|
|
498
|
+
)}
|
|
499
|
+
|
|
500
|
+
{bodySchema && (
|
|
501
|
+
<>
|
|
502
|
+
<SectionTitle note="application/json">Body</SectionTitle>
|
|
503
|
+
{operation.requestBody?.description && <p className="mt-2 text-sm text-muted-foreground">{operation.requestBody.description}</p>}
|
|
504
|
+
<SchemaFields schema={bodySchema} components={components} />
|
|
505
|
+
</>
|
|
506
|
+
)}
|
|
507
|
+
|
|
508
|
+
{responseSchema && (
|
|
509
|
+
<>
|
|
510
|
+
<SectionTitle>Response</SectionTitle>
|
|
511
|
+
<SchemaFields schema={responseSchema} components={components} />
|
|
512
|
+
</>
|
|
513
|
+
)}
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
{/* Samples sit beside the fields on wide screens and follow the reader down the page. */}
|
|
517
|
+
<aside className="mt-10 min-w-0 xl:sticky xl:top-20 xl:self-start">
|
|
518
|
+
<RequestSamples method={selectedMethod} url={fullUrl} headers={headers} body={bodySchema ? exampleOf(bodySchema) : undefined} />
|
|
519
|
+
<ResponseTabs responses={operation.responses} components={components} />
|
|
520
|
+
</aside>
|
|
465
521
|
</div>
|
|
466
522
|
</div>
|
|
467
523
|
)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { expect, test } from 'vitest';
|
|
2
|
+
import { preprocessMdxSource } from './preprocess';
|
|
3
|
+
|
|
4
|
+
test('page title is rendered by the page frame without repeating in MDX', () => {
|
|
5
|
+
const result = preprocessMdxSource('---\ntitle: "Installation"\n---\n# Installation\n\n## Setup\nInstall it.');
|
|
6
|
+
expect(result).not.toMatch(/^# Installation$/m);
|
|
7
|
+
expect(result).toContain('## Setup');
|
|
8
|
+
expect(result).toContain('Install it.');
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('keeps code examples, distinct headings and pages without a frontmatter title', () => {
|
|
12
|
+
const result = preprocessMdxSource('---\ntitle: Guide\n---\n```md\n# Guide\n```\n# A different heading');
|
|
13
|
+
expect(result).toContain('```md\n# Guide\n```');
|
|
14
|
+
expect(result).toContain('# A different heading');
|
|
15
|
+
expect(preprocessMdxSource('# Guide')).toContain('# Guide');
|
|
16
|
+
});
|