@clidey/dory 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/.dockerignore +4 -0
- package/.github/ISSUE_TEMPLATE/anything-else.md +10 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +39 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/dependabot.yml +11 -0
- package/.github/workflows/claude.yml +37 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/CONTRIBUTING.md +91 -0
- package/LICENSE +201 -0
- package/README.md +185 -0
- package/SECURITY.md +11 -0
- package/assets/dory_logo.png +0 -0
- package/bin/dory.js +131 -0
- package/docs/README.md +2 -0
- package/docs/configuration/app-settings/feature-flags.mdx +157 -0
- package/docs/configuration/app-settings/user-settings.mdx +201 -0
- package/docs/configuration/installation-setup/env-vars.mdx +198 -0
- package/docs/configuration/installation-setup/installation.mdx +127 -0
- package/docs/dory.json +162 -0
- package/docs/integrations/analytics-monitoring/error-tracking.mdx +199 -0
- package/docs/integrations/analytics-monitoring/notifications.mdx +189 -0
- package/docs/integrations/analytics-monitoring/user-analytics.mdx +182 -0
- package/docs/integrations/shopify-integration/shopify-setup.mdx +226 -0
- package/docs/integrations/shopify-integration/shopify-webhooks.mdx +207 -0
- package/docs/overview/developer-overview/dev-architecture.mdx +292 -0
- package/docs/overview/product-intro/app-overview.mdx +167 -0
- package/docs/overview/product-intro/architecture.mdx +203 -0
- package/docs/overview/product-intro/core-concepts.mdx +267 -0
- package/docs/platform-admin/billing-subscriptions/billing.mdx +176 -0
- package/docs/platform-admin/system-maintenance/db-migrations.mdx +184 -0
- package/docs/platform-admin/system-maintenance/health-monitoring.mdx +222 -0
- package/docs/platform-admin/system-maintenance/queue-management.mdx +234 -0
- package/docs/platform-admin/user-team-management/teams.mdx +170 -0
- package/docs/platform-admin/user-team-management/users.mdx +185 -0
- package/docs/support/legal/dependency-analysis.mdx +132 -0
- package/docs/support/legal/privacy-terms.mdx +73 -0
- package/docs/support/troubleshooting/common-issues.mdx +159 -0
- package/docs/usage/api-usage/api-inventory.mdx +213 -0
- package/docs/usage/api-usage/api-products.mdx +249 -0
- package/docs/usage/api-usage/api-purchase-orders.mdx +289 -0
- package/docs/usage/api-usage/api-reports.mdx +227 -0
- package/docs/usage/api-usage/api-suppliers.mdx +171 -0
- package/docs/usage/api-usage/api-user-management.mdx +171 -0
- package/docs/usage/ui-workflows/bundles.mdx +157 -0
- package/docs/usage/ui-workflows/demand-planning.mdx +210 -0
- package/docs/usage/ui-workflows/favorites.mdx +167 -0
- package/docs/usage/ui-workflows/inventory-management.mdx +179 -0
- package/docs/usage/ui-workflows/onboarding.mdx +215 -0
- package/docs/usage/ui-workflows/purchase-orders.mdx +200 -0
- package/docs/usage/ui-workflows/reports.mdx +257 -0
- package/index.html +54 -0
- package/k8s/Dockerfile +15 -0
- package/k8s/config/nginx-default.conf +22 -0
- package/k8s/dev.Dockerfile +16 -0
- package/package.json +71 -0
- package/src/app.css +3 -0
- package/src/app.tsx +13 -0
- package/src/components/dark-mode-toggle.tsx +25 -0
- package/src/components/dropdown.tsx +49 -0
- package/src/components/hooks.tsx +28 -0
- package/src/components/loading.tsx +23 -0
- package/src/components/mdx-provider.tsx +13 -0
- package/src/components/navigation.tsx +53 -0
- package/src/components/notification.tsx +97 -0
- package/src/components/routes.tsx +89 -0
- package/src/components/search-index.ts +43 -0
- package/src/components/search.tsx +508 -0
- package/src/components/store.ts +144 -0
- package/src/index.css +24 -0
- package/src/main.tsx +18 -0
- package/src/mdx/accordion.tsx +48 -0
- package/src/mdx/api-playground.tsx +674 -0
- package/src/mdx/api.tsx +354 -0
- package/src/mdx/callout.tsx +80 -0
- package/src/mdx/card.tsx +48 -0
- package/src/mdx/code.tsx +289 -0
- package/src/mdx/expandable.tsx +40 -0
- package/src/mdx/fence.tsx +73 -0
- package/src/mdx/icon.tsx +73 -0
- package/src/mdx/latex.tsx +26 -0
- package/src/mdx/list.tsx +7 -0
- package/src/mdx/mdx.tsx +43 -0
- package/src/mdx/mermaid.tsx +102 -0
- package/src/mdx/open-api.tsx +325 -0
- package/src/mdx/source.tsx +47 -0
- package/src/mdx/step.tsx +49 -0
- package/src/mdx/table.tsx +15 -0
- package/src/mdx/tag.tsx +66 -0
- package/src/mdx/text.tsx +98 -0
- package/src/plugins/sanitize.ts +15 -0
- package/src/theme.scss +124 -0
- package/src/ui/header.tsx +88 -0
- package/src/ui/layout.tsx +167 -0
- package/src/ui/mobile-navigation.tsx +91 -0
- package/src/ui/prev-next-link.tsx +74 -0
- package/src/ui/table-of-content.tsx +166 -0
- package/src/utils/fonts.ts +20 -0
- package/src/utils/functions.ts +12 -0
- package/src/utils/hooks.ts +46 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.app.json +32 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +25 -0
- package/vite.config.ts +27 -0
package/src/mdx/api.tsx
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { Tab, TabGroup, TabList, TabPanel, TabPanels } from '@headlessui/react'
|
|
2
|
+
import classNames from 'classnames'
|
|
3
|
+
import {
|
|
4
|
+
Children,
|
|
5
|
+
createContext,
|
|
6
|
+
isValidElement,
|
|
7
|
+
useContext,
|
|
8
|
+
useEffect,
|
|
9
|
+
useRef,
|
|
10
|
+
useState,
|
|
11
|
+
} from 'react'
|
|
12
|
+
import { Tag } from './tag'
|
|
13
|
+
|
|
14
|
+
const languageNames: Record<string, string> = {
|
|
15
|
+
js: 'JavaScript',
|
|
16
|
+
ts: 'TypeScript',
|
|
17
|
+
javascript: 'JavaScript',
|
|
18
|
+
typescript: 'TypeScript',
|
|
19
|
+
php: 'PHP',
|
|
20
|
+
python: 'Python',
|
|
21
|
+
ruby: 'Ruby',
|
|
22
|
+
go: 'Go',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getPanelTitle({
|
|
26
|
+
title,
|
|
27
|
+
language,
|
|
28
|
+
}: {
|
|
29
|
+
title?: string
|
|
30
|
+
language?: string
|
|
31
|
+
}) {
|
|
32
|
+
if (title) {
|
|
33
|
+
return title
|
|
34
|
+
}
|
|
35
|
+
if (language && language in languageNames) {
|
|
36
|
+
return languageNames[language]
|
|
37
|
+
}
|
|
38
|
+
return 'API'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function ClipboardIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
|
|
42
|
+
return (
|
|
43
|
+
<svg viewBox="0 0 20 20" aria-hidden="true" {...props}>
|
|
44
|
+
<path
|
|
45
|
+
strokeWidth="0"
|
|
46
|
+
d="M5.5 13.5v-5a2 2 0 0 1 2-2l.447-.894A2 2 0 0 1 9.737 4.5h.527a2 2 0 0 1 1.789 1.106l.447.894a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2Z"
|
|
47
|
+
/>
|
|
48
|
+
<path
|
|
49
|
+
fill="none"
|
|
50
|
+
strokeLinejoin="round"
|
|
51
|
+
d="M12.5 6.5a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-5a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2m5 0-.447-.894a2 2 0 0 0-1.79-1.106h-.527a2 2 0 0 0-1.789 1.106L7.5 6.5m5 0-1 1h-3l-1-1"
|
|
52
|
+
/>
|
|
53
|
+
</svg>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function CopyButton({ code }: { code: string }) {
|
|
58
|
+
const [copyCount, setCopyCount] = useState(0)
|
|
59
|
+
const copied = copyCount > 0
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (copyCount > 0) {
|
|
63
|
+
const timeout = setTimeout(() => setCopyCount(0), 1000)
|
|
64
|
+
return () => {
|
|
65
|
+
clearTimeout(timeout)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}, [copyCount])
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<button
|
|
72
|
+
type="button"
|
|
73
|
+
className={classNames(
|
|
74
|
+
'group/button absolute top-3.5 right-4 overflow-hidden rounded-full py-1 pr-3 pl-2 text-2xs font-medium opacity-0 backdrop-blur-sm transition group-hover:opacity-100 focus:opacity-100',
|
|
75
|
+
copied
|
|
76
|
+
? 'bg-sky-400/10 ring-1 ring-sky-400/20 ring-inset'
|
|
77
|
+
: 'bg-white/5 hover:bg-white/7.5 dark:bg-white/2.5 dark:hover:bg-white/5',
|
|
78
|
+
)}
|
|
79
|
+
onClick={() => {
|
|
80
|
+
window.navigator.clipboard.writeText(code).then(() => {
|
|
81
|
+
setCopyCount((count) => count + 1)
|
|
82
|
+
})
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
<span
|
|
86
|
+
aria-hidden={copied}
|
|
87
|
+
className={classNames(
|
|
88
|
+
'pointer-events-none flex items-center gap-0.5 text-zinc-400 transition duration-300',
|
|
89
|
+
copied && '-translate-y-1.5 opacity-0',
|
|
90
|
+
)}
|
|
91
|
+
>
|
|
92
|
+
<ClipboardIcon className="h-5 w-5 fill-zinc-500/20 stroke-zinc-500 transition-colors group-hover/button:stroke-zinc-400" />
|
|
93
|
+
Copy
|
|
94
|
+
</span>
|
|
95
|
+
<span
|
|
96
|
+
aria-hidden={!copied}
|
|
97
|
+
className={classNames(
|
|
98
|
+
'pointer-events-none absolute inset-0 flex items-center justify-center text-sky-400 transition duration-300',
|
|
99
|
+
!copied && 'translate-y-1.5 opacity-0',
|
|
100
|
+
)}
|
|
101
|
+
>
|
|
102
|
+
Copied!
|
|
103
|
+
</span>
|
|
104
|
+
</button>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function APIPanelHeader({ tag, label }: { tag?: string; label?: string }) {
|
|
109
|
+
if (!tag && !label) {
|
|
110
|
+
return null
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div className="flex h-9 items-center gap-2 border-y border-t-transparent border-b-white/7.5 bg-zinc-900 px-4 dark:border-b-white/5 dark:bg-white/1">
|
|
115
|
+
{tag && (
|
|
116
|
+
<div className="dark flex">
|
|
117
|
+
<Tag variant="small">{tag}</Tag>
|
|
118
|
+
</div>
|
|
119
|
+
)}
|
|
120
|
+
{tag && label && (
|
|
121
|
+
<span className="h-0.5 w-0.5 rounded-full bg-zinc-500" />
|
|
122
|
+
)}
|
|
123
|
+
{label && (
|
|
124
|
+
<span className="font-mono text-xs text-zinc-400">{label}</span>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function APIPanel({
|
|
131
|
+
children,
|
|
132
|
+
tag,
|
|
133
|
+
label,
|
|
134
|
+
code,
|
|
135
|
+
}: {
|
|
136
|
+
children: React.ReactNode
|
|
137
|
+
tag?: string
|
|
138
|
+
label?: string
|
|
139
|
+
code?: string
|
|
140
|
+
}) {
|
|
141
|
+
const child = Children.only(children)
|
|
142
|
+
|
|
143
|
+
if (isValidElement(child)) {
|
|
144
|
+
// @ts-expect-error child.props is not typed
|
|
145
|
+
tag = child.props.tag ?? tag
|
|
146
|
+
// @ts-expect-error child.props is not typed
|
|
147
|
+
label = child.props.label ?? label
|
|
148
|
+
// @ts-expect-error child.props is not typed
|
|
149
|
+
code = child.props.code ?? code
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return (
|
|
153
|
+
<div className="group dark:bg-white/2.5">
|
|
154
|
+
<APIPanelHeader tag={tag} label={label} />
|
|
155
|
+
<div className="relative">
|
|
156
|
+
<pre className="overflow-x-auto p-4 text-xs text-white">{children}</pre>
|
|
157
|
+
{/* @ts-expect-error code is not typed */}
|
|
158
|
+
<CopyButton code={code} />
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function APIGroupHeader({
|
|
165
|
+
title,
|
|
166
|
+
children,
|
|
167
|
+
selectedIndex,
|
|
168
|
+
}: {
|
|
169
|
+
title: string
|
|
170
|
+
children: React.ReactNode
|
|
171
|
+
selectedIndex: number
|
|
172
|
+
}) {
|
|
173
|
+
const hasTabs = Children.count(children) > 1
|
|
174
|
+
|
|
175
|
+
if (!title && !hasTabs) {
|
|
176
|
+
return null
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<div className="flex min-h-[calc(--spacing(12)+1px)] flex-wrap items-start gap-x-4 border-b border-zinc-700 bg-zinc-800 px-4 dark:border-zinc-800 dark:bg-transparent">
|
|
181
|
+
{title && (
|
|
182
|
+
<h3 className="mr-auto pt-3 text-xs font-semibold text-white">
|
|
183
|
+
{title}
|
|
184
|
+
</h3>
|
|
185
|
+
)}
|
|
186
|
+
{hasTabs && (
|
|
187
|
+
<TabList className="-mb-px flex gap-4 text-xs font-medium">
|
|
188
|
+
{Children.map(children, (child, childIndex) => (
|
|
189
|
+
<Tab
|
|
190
|
+
className={classNames(
|
|
191
|
+
'border-b py-3 transition data-selected:not-data-focus:outline-hidden',
|
|
192
|
+
childIndex === selectedIndex
|
|
193
|
+
? 'border-sky-500 text-sky-400'
|
|
194
|
+
: 'border-transparent text-zinc-400 hover:text-zinc-300',
|
|
195
|
+
)}
|
|
196
|
+
>
|
|
197
|
+
{/* @ts-expect-error child.props is not typed */}
|
|
198
|
+
{getPanelTitle(isValidElement(child) ? child.props : {})}
|
|
199
|
+
</Tab>
|
|
200
|
+
))}
|
|
201
|
+
</TabList>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function APIGroupPanels({
|
|
208
|
+
children,
|
|
209
|
+
...props
|
|
210
|
+
}: React.ComponentPropsWithoutRef<typeof APIPanel>) {
|
|
211
|
+
const hasTabs = Children.count(children) > 1
|
|
212
|
+
|
|
213
|
+
if (hasTabs) {
|
|
214
|
+
return (
|
|
215
|
+
<TabPanels>
|
|
216
|
+
{Children.map(children, (child) => (
|
|
217
|
+
<TabPanel>
|
|
218
|
+
<APIPanel {...props}>{child}</APIPanel>
|
|
219
|
+
</TabPanel>
|
|
220
|
+
))}
|
|
221
|
+
</TabPanels>
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return <APIPanel {...props}>{children}</APIPanel>
|
|
226
|
+
}
|
|
227
|
+
function usePreventLayoutShift() {
|
|
228
|
+
const positionRef = useRef<HTMLElement>(null)
|
|
229
|
+
const rafRef = useRef<number>()
|
|
230
|
+
|
|
231
|
+
useEffect(() => {
|
|
232
|
+
return () => {
|
|
233
|
+
if (typeof rafRef.current !== 'undefined') {
|
|
234
|
+
window.cancelAnimationFrame(rafRef.current)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}, [])
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
positionRef,
|
|
241
|
+
preventLayoutShift(callback: () => void) {
|
|
242
|
+
if (!positionRef.current) {
|
|
243
|
+
return
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const initialTop = positionRef.current.getBoundingClientRect().top
|
|
247
|
+
|
|
248
|
+
callback()
|
|
249
|
+
|
|
250
|
+
rafRef.current = window.requestAnimationFrame(() => {
|
|
251
|
+
const newTop =
|
|
252
|
+
positionRef.current?.getBoundingClientRect().top ?? initialTop
|
|
253
|
+
window.scrollBy(0, newTop - initialTop)
|
|
254
|
+
})
|
|
255
|
+
},
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function useTabGroupProps(availableLanguages: Array<string>) {
|
|
260
|
+
const [selectedIndex, setSelectedIndex] = useState(0)
|
|
261
|
+
const [preferredLanguages, setPreferredLanguages] = useState<string[]>([])
|
|
262
|
+
|
|
263
|
+
const activeLanguage = [...availableLanguages].sort(
|
|
264
|
+
(a, z) => preferredLanguages.indexOf(z) - preferredLanguages.indexOf(a),
|
|
265
|
+
)[0]
|
|
266
|
+
const languageIndex = availableLanguages.indexOf(activeLanguage)
|
|
267
|
+
const newSelectedIndex = languageIndex === -1 ? selectedIndex : languageIndex
|
|
268
|
+
|
|
269
|
+
if (newSelectedIndex !== selectedIndex) {
|
|
270
|
+
setSelectedIndex(newSelectedIndex)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const { positionRef, preventLayoutShift } = usePreventLayoutShift()
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
as: 'div' as const,
|
|
277
|
+
ref: positionRef,
|
|
278
|
+
selectedIndex,
|
|
279
|
+
onChange: (newSelectedIndex: number) => {
|
|
280
|
+
preventLayoutShift(() => {
|
|
281
|
+
const newLanguage = availableLanguages[newSelectedIndex]
|
|
282
|
+
setPreferredLanguages(prev => [
|
|
283
|
+
...prev.filter(lang => lang !== newLanguage),
|
|
284
|
+
newLanguage
|
|
285
|
+
])
|
|
286
|
+
})
|
|
287
|
+
},
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const APIGroupContext = createContext(false)
|
|
292
|
+
|
|
293
|
+
export function APIGroup({
|
|
294
|
+
children,
|
|
295
|
+
title,
|
|
296
|
+
...props
|
|
297
|
+
}: React.ComponentPropsWithoutRef<typeof APIGroupPanels> & { title: string }) {
|
|
298
|
+
const languages =
|
|
299
|
+
Children.map(children, (child) =>
|
|
300
|
+
// @ts-expect-error child.props is not typed
|
|
301
|
+
getPanelTitle(isValidElement(child) ? child.props : {}),
|
|
302
|
+
) ?? []
|
|
303
|
+
const tabGroupProps = useTabGroupProps(languages)
|
|
304
|
+
const hasTabs = Children.count(children) > 1
|
|
305
|
+
|
|
306
|
+
const containerClassName =
|
|
307
|
+
'my-6 overflow-hidden rounded-2xl bg-zinc-900 shadow-md dark:ring-1 dark:ring-white/10 w-full'
|
|
308
|
+
const header = (
|
|
309
|
+
<APIGroupHeader title={title} selectedIndex={tabGroupProps.selectedIndex}>
|
|
310
|
+
{children}
|
|
311
|
+
</APIGroupHeader>
|
|
312
|
+
)
|
|
313
|
+
const panels = <APIGroupPanels {...props}>{children}</APIGroupPanels>
|
|
314
|
+
|
|
315
|
+
return (
|
|
316
|
+
<APIGroupContext.Provider value={true}>
|
|
317
|
+
{hasTabs ? (
|
|
318
|
+
<TabGroup {...tabGroupProps} className={containerClassName}>
|
|
319
|
+
<div className="not-prose">
|
|
320
|
+
{header}
|
|
321
|
+
{panels}
|
|
322
|
+
</div>
|
|
323
|
+
</TabGroup>
|
|
324
|
+
) : (
|
|
325
|
+
<div className={containerClassName}>
|
|
326
|
+
<div className="not-prose">
|
|
327
|
+
{header}
|
|
328
|
+
{panels}
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
)}
|
|
332
|
+
</APIGroupContext.Provider>
|
|
333
|
+
)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function API({
|
|
337
|
+
children,
|
|
338
|
+
...props
|
|
339
|
+
}: React.ComponentPropsWithoutRef<'code'>) {
|
|
340
|
+
const isGrouped = useContext(APIGroupContext)
|
|
341
|
+
|
|
342
|
+
if (isGrouped) {
|
|
343
|
+
if (typeof children !== 'string') {
|
|
344
|
+
throw new Error(
|
|
345
|
+
'`API` children must be a string when nested inside a `APIGroup`.',
|
|
346
|
+
)
|
|
347
|
+
}
|
|
348
|
+
return <code {...props}>
|
|
349
|
+
{children}
|
|
350
|
+
</code>
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
return <code {...props}>{children}</code>
|
|
354
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import classNames from "classnames"
|
|
2
|
+
import { Icon } from "./icon"
|
|
3
|
+
|
|
4
|
+
const styles = {
|
|
5
|
+
note: {
|
|
6
|
+
container: 'my-6 flex gap-2.5 rounded-2xl border border-emerald-500/20 bg-emerald-50/50 p-4 text-sm/6 text-emerald-900 dark:border-emerald-500/30 dark:bg-emerald-500/5 dark:text-emerald-200 dark:[--tw-prose-links-hover:var(--color-emerald-300)] dark:[--tw-prose-links:var(--color-white)]',
|
|
7
|
+
title: 'text-emerald-900 dark:text-emerald-200',
|
|
8
|
+
body: 'text-emerald-900 dark:text-emerald-200',
|
|
9
|
+
},
|
|
10
|
+
warning: {
|
|
11
|
+
container: 'my-6 flex gap-2.5 rounded-2xl border border-amber-500/20 bg-amber-50/50 p-4 text-sm/6 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/5 dark:text-amber-200 dark:[--tw-prose-links-hover:var(--color-amber-300)] dark:[--tw-prose-links:var(--color-white)]',
|
|
12
|
+
title: 'text-amber-900 dark:text-amber-200',
|
|
13
|
+
body: 'text-amber-900 dark:text-amber-200',
|
|
14
|
+
},
|
|
15
|
+
info: {
|
|
16
|
+
container: 'my-6 flex gap-2.5 rounded-2xl border border-blue-500/20 bg-blue-50/50 p-4 text-sm/6 text-blue-900 dark:border-blue-500/30 dark:bg-blue-500/5 dark:text-blue-200 dark:[--tw-prose-links-hover:var(--color-blue-300)] dark:[--tw-prose-links:var(--color-white)]',
|
|
17
|
+
title: 'text-blue-900 dark:text-blue-200',
|
|
18
|
+
body: 'text-blue-900 dark:text-blue-200',
|
|
19
|
+
},
|
|
20
|
+
tip: {
|
|
21
|
+
container: 'my-6 flex gap-2.5 rounded-2xl border border-green-500/20 bg-green-50/50 p-4 text-sm/6 text-green-900 dark:border-green-500/30 dark:bg-green-500/5 dark:text-green-200 dark:[--tw-prose-links-hover:var(--color-green-300)] dark:[--tw-prose-links:var(--color-white)]',
|
|
22
|
+
title: 'text-green-900 dark:text-green-200',
|
|
23
|
+
body: 'text-green-900 dark:text-green-200',
|
|
24
|
+
},
|
|
25
|
+
check: {
|
|
26
|
+
container: 'my-6 flex gap-2.5 rounded-2xl border border-purple-500/20 bg-purple-50/50 p-4 text-sm/6 text-purple-900 dark:border-purple-500/30 dark:bg-purple-500/5 dark:text-purple-200 dark:[--tw-prose-links-hover:var(--color-purple-300)] dark:[--tw-prose-links:var(--color-white)]',
|
|
27
|
+
title: 'text-purple-900 dark:text-purple-200',
|
|
28
|
+
body: 'text-purple-900 dark:text-purple-200',
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const icons = {
|
|
33
|
+
note: (props: { className?: string }) => <Icon icon="InfoCircle" {...props} />,
|
|
34
|
+
warning: (props: { className?: string }) => <Icon icon="AlertTriangle" {...props} />,
|
|
35
|
+
info: (props: { className?: string }) => <Icon icon="InfoCircle" {...props} />,
|
|
36
|
+
tip: (props: { className?: string }) => <Icon icon="Lightbulb" {...props} />,
|
|
37
|
+
check: (props: { className?: string }) => <Icon icon="CheckCircle" {...props} />,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function Callout({
|
|
41
|
+
title,
|
|
42
|
+
children,
|
|
43
|
+
type = 'note',
|
|
44
|
+
}: {
|
|
45
|
+
title: string
|
|
46
|
+
children: React.ReactNode
|
|
47
|
+
type?: keyof typeof styles
|
|
48
|
+
}) {
|
|
49
|
+
const IconComponent = icons[type]
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<div className={classNames(styles[type].container)}>
|
|
53
|
+
<IconComponent className="mt-1 h-4 w-4 flex-none" />
|
|
54
|
+
<div className="[&>:first-child]:mt-0 [&>:last-child]:mb-0">
|
|
55
|
+
<div className={styles[type].title}>{title}</div>
|
|
56
|
+
<div className={styles[type].body}>{children}</div>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function Note({ children }: { children: React.ReactNode }) {
|
|
63
|
+
return <Callout type="note" title="Note">{children}</Callout>
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function Warning({ children }: { children: React.ReactNode }) {
|
|
67
|
+
return <Callout type="warning" title="Warning">{children}</Callout>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function Info({ children }: { children: React.ReactNode }) {
|
|
71
|
+
return <Callout type="info" title="Info">{children}</Callout>
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function Tip({ children }: { children: React.ReactNode }) {
|
|
75
|
+
return <Callout type="tip" title="Tip">{children}</Callout>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function Check({ children }: { children: React.ReactNode }) {
|
|
79
|
+
return <Callout type="check" title="Check">{children}</Callout>
|
|
80
|
+
}
|
package/src/mdx/card.tsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import classNames from "classnames";
|
|
2
|
+
import { Icon } from "./icon";
|
|
3
|
+
import type { ComponentChildren } from "preact";
|
|
4
|
+
|
|
5
|
+
export function CardGroup({ children, cols = 2 }: { children: React.ReactNode; cols?: number }) {
|
|
6
|
+
return (
|
|
7
|
+
<div className={classNames(
|
|
8
|
+
'not-prose my-12 grid grid-cols-1 gap-6',
|
|
9
|
+
cols === 2 && 'sm:grid-cols-2',
|
|
10
|
+
cols === 3 && 'sm:grid-cols-3',
|
|
11
|
+
cols === 4 && 'sm:grid-cols-4'
|
|
12
|
+
)}>
|
|
13
|
+
{children}
|
|
14
|
+
</div>
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function Card({
|
|
19
|
+
title,
|
|
20
|
+
description,
|
|
21
|
+
href,
|
|
22
|
+
icon,
|
|
23
|
+
children,
|
|
24
|
+
}: {
|
|
25
|
+
title: string
|
|
26
|
+
description: string
|
|
27
|
+
href: string
|
|
28
|
+
icon: string
|
|
29
|
+
children?: ComponentChildren
|
|
30
|
+
}) {
|
|
31
|
+
return (
|
|
32
|
+
<div className="group relative rounded-xl border border-slate-200 dark:border-slate-700">
|
|
33
|
+
<div className="absolute -inset-px rounded-xl border-2 border-transparent opacity-0 [background:linear-gradient(var(--quick-links-hover-bg,var(--color-sky-50)),var(--quick-links-hover-bg,var(--color-sky-50)))_padding-box,linear-gradient(to_top,var(--color-indigo-400),var(--color-cyan-400),var(--color-sky-500))_border-box] group-hover:opacity-100 dark:[--quick-links-hover-bg:var(--color-slate-800)]" />
|
|
34
|
+
<div className="relative overflow-hidden rounded-xl p-6 flex gap-2 items-center">
|
|
35
|
+
<Icon icon={icon} className="h-8 w-8" />
|
|
36
|
+
<h2 className="mt-4 font-display text-base text-slate-900 dark:text-white">
|
|
37
|
+
<a href={href}>
|
|
38
|
+
<span className="absolute -inset-px rounded-xl" />
|
|
39
|
+
{title}
|
|
40
|
+
</a>
|
|
41
|
+
</h2>
|
|
42
|
+
<div className="text-sm text-slate-700 dark:text-slate-400 leading-tight [&>p]:mb-0">
|
|
43
|
+
{description ?? children}
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|