@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
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { useState } from "preact/hooks"
|
|
2
|
+
import { APIGroup } from "./api"
|
|
3
|
+
import { APIPlayground, PlayButton, type Server } from "./api-playground"
|
|
4
|
+
import { Fence } from "./fence"
|
|
5
|
+
import { Tag } from "./tag"
|
|
6
|
+
import { Col, Row } from "./text"
|
|
7
|
+
import { motion } from "motion/react"
|
|
8
|
+
|
|
9
|
+
export function Properties({ children }: { children: React.ReactNode }) {
|
|
10
|
+
return (
|
|
11
|
+
<div className="my-2">
|
|
12
|
+
<ul
|
|
13
|
+
role="list"
|
|
14
|
+
className="m-0 max-w-[calc(var(--container-lg)-(--spacing(8)))] list-none divide-y divide-zinc-900/5 p-0 dark:divide-white/10"
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</ul>
|
|
18
|
+
</div>
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function Property({
|
|
23
|
+
name,
|
|
24
|
+
children,
|
|
25
|
+
type,
|
|
26
|
+
required = false,
|
|
27
|
+
}: {
|
|
28
|
+
name: string
|
|
29
|
+
children: React.ReactNode
|
|
30
|
+
type?: string
|
|
31
|
+
required?: boolean
|
|
32
|
+
}) {
|
|
33
|
+
return (
|
|
34
|
+
<div className="m-0 px-0 first:pt-0 last:pb-0">
|
|
35
|
+
<div className="my-4 flex flex-wrap items-center gap-x-3 gap-2">
|
|
36
|
+
<Tag className="px-4 py-1">{name}</Tag>
|
|
37
|
+
<p className="font-mono text-xs text-zinc-400 dark:text-zinc-500">
|
|
38
|
+
{type}
|
|
39
|
+
</p>
|
|
40
|
+
{required && <span className="text-rose-400 ml-1 text-xs">Required</span>}
|
|
41
|
+
<p className="w-full flex-none [&>:first-child]:mt-0 [&>:last-child]:mb-0 text-sm">
|
|
42
|
+
{children}
|
|
43
|
+
</p>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface ParamFieldProps {
|
|
50
|
+
body: string;
|
|
51
|
+
type: string;
|
|
52
|
+
default?: string | number;
|
|
53
|
+
required?: boolean;
|
|
54
|
+
children: React.ReactNode;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function ParamField({ body, type, default: defaultValue, required, children }: ParamFieldProps) {
|
|
58
|
+
return (
|
|
59
|
+
<Property name={body} type={type} required={required}>
|
|
60
|
+
{children}
|
|
61
|
+
{defaultValue != null && (
|
|
62
|
+
<span className="text-gray-500 ml-1">(default: {defaultValue})</span>
|
|
63
|
+
)}
|
|
64
|
+
</Property>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ResponseFieldProps {
|
|
69
|
+
name: string;
|
|
70
|
+
type: string;
|
|
71
|
+
required?: boolean;
|
|
72
|
+
children: React.ReactNode;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function ResponseField({ name, type, required, children }: ResponseFieldProps) {
|
|
76
|
+
return (
|
|
77
|
+
<Property name={name} type={type} required={required}>
|
|
78
|
+
{children}
|
|
79
|
+
</Property>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface Schema {
|
|
84
|
+
$ref?: string;
|
|
85
|
+
type?: string;
|
|
86
|
+
items?: Schema;
|
|
87
|
+
properties?: Record<string, Schema>;
|
|
88
|
+
required?: boolean;
|
|
89
|
+
description?: string;
|
|
90
|
+
default?: string | number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
interface Components {
|
|
94
|
+
schemas?: Record<string, Schema>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
interface Parameter {
|
|
98
|
+
name: string;
|
|
99
|
+
schema?: Schema;
|
|
100
|
+
required?: boolean;
|
|
101
|
+
description?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
interface Content {
|
|
105
|
+
schema?: Schema;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface RequestBody {
|
|
109
|
+
description?: string;
|
|
110
|
+
content?: {
|
|
111
|
+
'application/json'?: Content;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface Response {
|
|
116
|
+
content?: {
|
|
117
|
+
'application/json'?: Content;
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
interface PathMethod {
|
|
122
|
+
description?: string;
|
|
123
|
+
parameters?: Parameter[];
|
|
124
|
+
requestBody?: RequestBody;
|
|
125
|
+
responses: Record<string, Response>;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface OpenAPIJson {
|
|
129
|
+
paths: Record<string, Record<string, PathMethod>>;
|
|
130
|
+
components: Components;
|
|
131
|
+
servers?: Server[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function resolveSchema(schema: Schema | undefined, components: Components): Schema {
|
|
135
|
+
if (!schema) return {};
|
|
136
|
+
|
|
137
|
+
if (schema.$ref) {
|
|
138
|
+
const refPath = schema.$ref.replace(/^#\/components\/schemas\//, '');
|
|
139
|
+
return resolveSchema(components.schemas?.[refPath], components);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (schema.type === 'array' && schema.items) {
|
|
143
|
+
return {
|
|
144
|
+
...schema,
|
|
145
|
+
items: resolveSchema(schema.items, components)
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (schema.properties) {
|
|
150
|
+
const resolvedProps: Record<string, Schema> = {};
|
|
151
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
152
|
+
resolvedProps[key] = resolveSchema(value, components);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
...schema,
|
|
156
|
+
properties: resolvedProps
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return schema;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function OpenAPI({ openAPIJson, method: selectedMethod, path: selectedPath }: { openAPIJson: OpenAPIJson, method: string, path: string }) {
|
|
164
|
+
const { paths, components } = openAPIJson;
|
|
165
|
+
const [showPlayground, setShowPlayground] = useState(false);
|
|
166
|
+
|
|
167
|
+
const handleShowPlayground = () => {
|
|
168
|
+
setShowPlayground(true);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<div className="max-w-none w-full">
|
|
173
|
+
{
|
|
174
|
+
showPlayground &&
|
|
175
|
+
<motion.div
|
|
176
|
+
initial={{ x: "100%" }}
|
|
177
|
+
animate={{ x: 0 }}
|
|
178
|
+
exit={{ x: "100%" }}
|
|
179
|
+
transition={{ type: "spring", damping: 20 }}
|
|
180
|
+
className="fixed inset-y-0 right-0 w-full max-w-3xl bg-white dark:bg-[#1e1e1e] shadow-xl z-50 overflow-y-auto border-l border-zinc-200 dark:border-zinc-800"
|
|
181
|
+
>
|
|
182
|
+
<div className="p-6">
|
|
183
|
+
<div className="flex justify-between items-center mb-6">
|
|
184
|
+
<h2 className="text-xl font-semibold">API Playground</h2>
|
|
185
|
+
<button
|
|
186
|
+
onClick={() => setShowPlayground(false)}
|
|
187
|
+
className="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
|
|
188
|
+
>
|
|
189
|
+
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
190
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
|
191
|
+
</svg>
|
|
192
|
+
</button>
|
|
193
|
+
</div>
|
|
194
|
+
<APIPlayground
|
|
195
|
+
method={selectedMethod}
|
|
196
|
+
url={selectedPath}
|
|
197
|
+
servers={openAPIJson.servers}
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
</motion.div>
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
{Object.entries(paths).map(([path, methods]) => {
|
|
204
|
+
if (path !== selectedPath) {
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return (
|
|
209
|
+
<div key={path} className="my-8">
|
|
210
|
+
{Object.entries(methods).map(([method, details]) => {
|
|
211
|
+
const { description, parameters, requestBody, responses } = details;
|
|
212
|
+
const methodUpper = method.toUpperCase();
|
|
213
|
+
|
|
214
|
+
if (methodUpper !== selectedMethod) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return (
|
|
219
|
+
<Row key={`${method}-${path}`} cols={2}>
|
|
220
|
+
<Col>
|
|
221
|
+
<h2 className="flex items-center mt-4">
|
|
222
|
+
<Tag variant="medium" className="mr-2 py-1 px-4 rounded-lg">{methodUpper}</Tag>
|
|
223
|
+
<span className="ml-2 font-mono">{path}</span>
|
|
224
|
+
</h2>
|
|
225
|
+
|
|
226
|
+
{description && <p>{description}</p>}
|
|
227
|
+
|
|
228
|
+
{parameters && parameters.length > 0 && (
|
|
229
|
+
<div className="mt-4">
|
|
230
|
+
<h3>Parameters</h3>
|
|
231
|
+
<Properties>
|
|
232
|
+
{parameters.map((param) => (
|
|
233
|
+
<ParamField
|
|
234
|
+
key={param.name}
|
|
235
|
+
body={param.name}
|
|
236
|
+
type={param.schema?.type ?? 'string'}
|
|
237
|
+
required={param.required}
|
|
238
|
+
default={param.schema?.default}
|
|
239
|
+
>
|
|
240
|
+
{param.description}
|
|
241
|
+
</ParamField>
|
|
242
|
+
))}
|
|
243
|
+
</Properties>
|
|
244
|
+
</div>
|
|
245
|
+
)}
|
|
246
|
+
{requestBody && (
|
|
247
|
+
<div className="mt-4">
|
|
248
|
+
<h3>Request Body</h3>
|
|
249
|
+
<p>{requestBody.description}</p>
|
|
250
|
+
{requestBody.content?.['application/json']?.schema && (
|
|
251
|
+
(() => {
|
|
252
|
+
const resolvedSchema = resolveSchema(requestBody.content['application/json'].schema, components);
|
|
253
|
+
return (
|
|
254
|
+
<Properties>
|
|
255
|
+
{Object.entries(resolvedSchema.properties || {}).map(([propName, prop]) => (
|
|
256
|
+
<ParamField
|
|
257
|
+
key={propName}
|
|
258
|
+
body={propName}
|
|
259
|
+
type={prop.type ?? 'string'}
|
|
260
|
+
required={prop.required}
|
|
261
|
+
default={prop.default}
|
|
262
|
+
>
|
|
263
|
+
{prop.description}
|
|
264
|
+
</ParamField>
|
|
265
|
+
))}
|
|
266
|
+
</Properties>
|
|
267
|
+
);
|
|
268
|
+
})()
|
|
269
|
+
)}
|
|
270
|
+
</div>
|
|
271
|
+
)}
|
|
272
|
+
{components?.schemas && (
|
|
273
|
+
<div>
|
|
274
|
+
<h3>Schemas</h3>
|
|
275
|
+
{Object.entries(components.schemas).filter(([, schema]) => schema.properties).map(([name, schema]) => (
|
|
276
|
+
<div key={name} className="mt-4">
|
|
277
|
+
<h4>{name}</h4>
|
|
278
|
+
<Properties>
|
|
279
|
+
{Object.entries(schema.properties || {}).map(([propName, prop]) => (
|
|
280
|
+
<ResponseField
|
|
281
|
+
key={propName}
|
|
282
|
+
name={propName}
|
|
283
|
+
type={prop.type ?? 'string'}
|
|
284
|
+
required={prop.required}
|
|
285
|
+
>
|
|
286
|
+
{prop.description}
|
|
287
|
+
</ResponseField>
|
|
288
|
+
))}
|
|
289
|
+
</Properties>
|
|
290
|
+
</div>
|
|
291
|
+
))}
|
|
292
|
+
</div>
|
|
293
|
+
)}
|
|
294
|
+
</Col>
|
|
295
|
+
<Col sticky>
|
|
296
|
+
<button
|
|
297
|
+
onClick={handleShowPlayground}
|
|
298
|
+
className='ml-auto mt-3 flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium transition bg-sky-600 text-white hover:bg-sky-700'>
|
|
299
|
+
Try
|
|
300
|
+
<PlayButton className="h-4 w-4" />
|
|
301
|
+
</button>
|
|
302
|
+
<APIGroup title="Request" tag={methodUpper} label={path}>
|
|
303
|
+
{Object.entries(responses).map(([code, response]) => (
|
|
304
|
+
<div key={code} title={code}>
|
|
305
|
+
{response.content?.['application/json']?.schema && (() => {
|
|
306
|
+
const resolvedSchema = resolveSchema(response.content['application/json'].schema, components);
|
|
307
|
+
return (
|
|
308
|
+
<Fence language="json">
|
|
309
|
+
{JSON.stringify(resolvedSchema, null, 2)}
|
|
310
|
+
</Fence>
|
|
311
|
+
);
|
|
312
|
+
})()}
|
|
313
|
+
</div>
|
|
314
|
+
))}
|
|
315
|
+
</APIGroup>
|
|
316
|
+
</Col>
|
|
317
|
+
</Row>
|
|
318
|
+
)
|
|
319
|
+
})}
|
|
320
|
+
</div>
|
|
321
|
+
)
|
|
322
|
+
})}
|
|
323
|
+
</div>
|
|
324
|
+
)
|
|
325
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
type PathRange = {
|
|
2
|
+
path: string;
|
|
3
|
+
range: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
type SourceProps = {
|
|
7
|
+
url: string;
|
|
8
|
+
branch?: string;
|
|
9
|
+
paths: PathRange[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const Source = ({ url, branch = "main", paths }: SourceProps) => {
|
|
13
|
+
const createSourceUrl = (path: string, range: string) => {
|
|
14
|
+
const [start, end] = range.split('-');
|
|
15
|
+
|
|
16
|
+
if (url.includes('github.com')) {
|
|
17
|
+
return `${url}/blob/${branch}/${path}#L${start}${end ? `-L${end}` : ''}`;
|
|
18
|
+
} else if (url.includes('bitbucket.org')) {
|
|
19
|
+
return `${url}/src/${branch}/${path}#lines-${start}${end ? `:${end}` : ''}`;
|
|
20
|
+
} else if (url.includes('gitlab.com')) {
|
|
21
|
+
return `${url}/-/blob/${branch}/${path}#L${range.replace('-', '-')}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return url;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div>
|
|
29
|
+
<p className="text-sm text-slate-900 dark:text-white">Sources:</p>
|
|
30
|
+
<ul className="list-none pl-0 flex flex-wrap gap-2 mt-2">
|
|
31
|
+
{paths.map(({ path, range }) => (
|
|
32
|
+
<li key={path + range}>
|
|
33
|
+
<a
|
|
34
|
+
href={createSourceUrl(path, range)}
|
|
35
|
+
target="_blank"
|
|
36
|
+
rel="noopener noreferrer"
|
|
37
|
+
className="rounded px-3 py-1 font-mono text-sm text-slate-700 dark:text-slate-400 hover:opacity-80 transition-colors border border-slate-200 dark:border-slate-700"
|
|
38
|
+
>
|
|
39
|
+
{path}
|
|
40
|
+
<span className="ml-2 opacity-70">{range}</span>
|
|
41
|
+
</a>
|
|
42
|
+
</li>
|
|
43
|
+
))}
|
|
44
|
+
</ul>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
};
|
package/src/mdx/step.tsx
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import classNames from "classnames"
|
|
2
|
+
import { Children } from "preact/compat"
|
|
3
|
+
|
|
4
|
+
export function Steps({ children }: { children: preact.ComponentChildren }) {
|
|
5
|
+
const steps = Children.toArray(children) as preact.ComponentChildren[];
|
|
6
|
+
return (
|
|
7
|
+
<nav aria-label="Progress" className="py-16">
|
|
8
|
+
<div className="overflow-hidden">
|
|
9
|
+
{steps.map((step, stepIdx) => {
|
|
10
|
+
const stepElement = Children.toArray(step)[0] as preact.JSX.Element;
|
|
11
|
+
return (
|
|
12
|
+
<div key={stepIdx} className={classNames(
|
|
13
|
+
{
|
|
14
|
+
"pb-10": stepIdx !== steps.length - 1,
|
|
15
|
+
"pb-2": stepIdx === steps.length - 1,
|
|
16
|
+
},
|
|
17
|
+
'relative'
|
|
18
|
+
)}>
|
|
19
|
+
<div aria-hidden="true" className="absolute top-10 left-4 h-full w-[0.5px] bg-gray-300/50 dark:bg-gray-600/50" style={{ top: '40px', height: 'calc(100% - 44px)' }} />
|
|
20
|
+
<div className="group relative flex items-start">
|
|
21
|
+
<span className="flex h-9 items-center">
|
|
22
|
+
<span className="relative z-10 flex size-8 items-center justify-center rounded-full bg-white dark:bg-gray-800 group-hover:border-gray-400">
|
|
23
|
+
<span className="text-sm font-medium text-gray-500 dark:text-white">
|
|
24
|
+
{stepIdx + 1}
|
|
25
|
+
</span>
|
|
26
|
+
</span>
|
|
27
|
+
</span>
|
|
28
|
+
<span className="ml-4 flex min-w-0 flex-col">
|
|
29
|
+
<p className="text-lg font-medium text-inherit">{stepElement.props.title}</p>
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
<div className="ml-12 not-prose">
|
|
33
|
+
{stepElement.props.children}
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
)
|
|
37
|
+
})}
|
|
38
|
+
</div>
|
|
39
|
+
</nav>
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function Step({
|
|
44
|
+
children
|
|
45
|
+
}: {
|
|
46
|
+
children: preact.ComponentChildren
|
|
47
|
+
}) {
|
|
48
|
+
return <p className='text-sm'>{children}</p>
|
|
49
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { JSX } from 'preact/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
export const Table = (props: JSX.IntrinsicElements['table']) => (
|
|
4
|
+
<div className="overflow-x-auto rounded-lg my-8">
|
|
5
|
+
<table className="border-collapse w-full border border-gray-300/10 rounded-lg" {...props} />
|
|
6
|
+
</div>
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export const Th = (props: JSX.IntrinsicElements['th']) => (
|
|
10
|
+
<th className="border border-gray-300/10 p-2 bg-gray-100/25 text-left first:rounded-tl-lg last:rounded-tr-lg" {...props} />
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
export const Td = (props: JSX.IntrinsicElements['td']) => (
|
|
14
|
+
<td className="border border-gray-300/10 p-2 text-left last-row:first:rounded-bl-lg last-row:last:rounded-br-lg" {...props} />
|
|
15
|
+
);
|
package/src/mdx/tag.tsx
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import classNames from 'classnames'
|
|
2
|
+
|
|
3
|
+
const variantStyles = {
|
|
4
|
+
small: '',
|
|
5
|
+
medium: 'rounded-lg px-1.5 ring-1 ring-inset',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const colorStyles = {
|
|
9
|
+
emerald: {
|
|
10
|
+
small: 'text-emerald-500 dark:text-emerald-400',
|
|
11
|
+
medium:
|
|
12
|
+
'ring-emerald-300 dark:ring-emerald-400/30 bg-emerald-400/10 text-emerald-500 dark:text-emerald-400',
|
|
13
|
+
},
|
|
14
|
+
sky: {
|
|
15
|
+
small: 'text-sky-500',
|
|
16
|
+
medium:
|
|
17
|
+
'ring-sky-300 bg-sky-400/10 text-sky-500 dark:ring-sky-400/30 dark:bg-sky-400/10 dark:text-sky-400',
|
|
18
|
+
},
|
|
19
|
+
amber: {
|
|
20
|
+
small: 'text-amber-500',
|
|
21
|
+
medium:
|
|
22
|
+
'ring-amber-300 bg-amber-400/10 text-amber-500 dark:ring-amber-400/30 dark:bg-amber-400/10 dark:text-amber-400',
|
|
23
|
+
},
|
|
24
|
+
rose: {
|
|
25
|
+
small: 'text-red-500 dark:text-rose-500',
|
|
26
|
+
medium:
|
|
27
|
+
'ring-rose-200 bg-rose-50 text-red-500 dark:ring-rose-500/20 dark:bg-rose-400/10 dark:text-rose-400',
|
|
28
|
+
},
|
|
29
|
+
zinc: {
|
|
30
|
+
small: 'text-zinc-400 dark:text-zinc-500',
|
|
31
|
+
medium:
|
|
32
|
+
'ring-zinc-200 bg-zinc-50 text-zinc-500 dark:ring-zinc-500/20 dark:bg-zinc-400/10 dark:text-zinc-400',
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const valueColorMap = {
|
|
37
|
+
GET: 'emerald',
|
|
38
|
+
POST: 'sky',
|
|
39
|
+
PUT: 'amber',
|
|
40
|
+
DELETE: 'rose',
|
|
41
|
+
} as Record<string, keyof typeof colorStyles>
|
|
42
|
+
|
|
43
|
+
export function Tag({
|
|
44
|
+
children,
|
|
45
|
+
variant = 'medium',
|
|
46
|
+
color = valueColorMap[children] ?? 'zinc',
|
|
47
|
+
className,
|
|
48
|
+
}: {
|
|
49
|
+
children: keyof typeof valueColorMap & (string)
|
|
50
|
+
variant?: keyof typeof variantStyles
|
|
51
|
+
color?: keyof typeof colorStyles
|
|
52
|
+
className?: string
|
|
53
|
+
}) {
|
|
54
|
+
return (
|
|
55
|
+
<span
|
|
56
|
+
className={classNames(
|
|
57
|
+
'font-mono text-[0.625rem]/6 font-semibold',
|
|
58
|
+
variantStyles[variant],
|
|
59
|
+
colorStyles[color][variant],
|
|
60
|
+
className,
|
|
61
|
+
)}
|
|
62
|
+
>
|
|
63
|
+
{children}
|
|
64
|
+
</span>
|
|
65
|
+
)
|
|
66
|
+
}
|
package/src/mdx/text.tsx
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import classNames from "classnames"
|
|
2
|
+
import { useState } from "preact/hooks"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const h1 = function H1(props: preact.JSX.HTMLAttributes<HTMLHeadingElement>) {
|
|
6
|
+
return <h1 className="text-4xl font-bold mb-4 mt-12" {...props} />
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const h2 = function H2(props: preact.JSX.HTMLAttributes<HTMLHeadingElement>) {
|
|
10
|
+
return <h2 className="text-3xl font-bold mb-3 mt-10" {...props} />
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const h3 = function H3(props: preact.JSX.HTMLAttributes<HTMLHeadingElement>) {
|
|
14
|
+
return <h3 className="text-2xl font-bold mb-2 mt-8" {...props} />
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const h4 = function H4(props: preact.JSX.HTMLAttributes<HTMLHeadingElement>) {
|
|
18
|
+
return <h4 className="text-xl font-bold mb-2 mt-6" {...props} />
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const h5 = function H5(props: preact.JSX.HTMLAttributes<HTMLHeadingElement>) {
|
|
22
|
+
return <h5 className="text-lg font-bold mb-2" {...props} />
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const h6 = function H6(props: preact.JSX.HTMLAttributes<HTMLHeadingElement>) {
|
|
26
|
+
return <h6 className="text-base font-bold mb-2" {...props} />
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const p = function P(props: preact.JSX.HTMLAttributes<HTMLParagraphElement>) {
|
|
30
|
+
return <p className="mb-2 inline-block" {...props} />
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function Row({ children, cols = 1 }: { children: preact.ComponentChildren, cols?: number }) {
|
|
34
|
+
return (
|
|
35
|
+
<div className={`grid grid-cols-1 items-start gap-x-16 gap-y-10 xl:max-w-none`} style={{ gridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))` }}>
|
|
36
|
+
{children}
|
|
37
|
+
</div>
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function Col({
|
|
42
|
+
children,
|
|
43
|
+
sticky = false,
|
|
44
|
+
rows = 1,
|
|
45
|
+
gap = 4
|
|
46
|
+
}: {
|
|
47
|
+
children: preact.ComponentChildren
|
|
48
|
+
sticky?: boolean
|
|
49
|
+
rows?: number
|
|
50
|
+
gap?: number
|
|
51
|
+
}) {
|
|
52
|
+
return (
|
|
53
|
+
<div
|
|
54
|
+
className={classNames("[&>:first-child]:mt-0 [&>:last-child]:mb-0", {
|
|
55
|
+
'xl:sticky xl:top-24': sticky,
|
|
56
|
+
})}
|
|
57
|
+
style={{
|
|
58
|
+
display: 'grid',
|
|
59
|
+
gridTemplateRows: `repeat(${rows}, minmax(0, 1fr))`,
|
|
60
|
+
gap: `${gap * 0.25}rem`
|
|
61
|
+
}}
|
|
62
|
+
>
|
|
63
|
+
{children}
|
|
64
|
+
</div>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
export function Anchor({ children, href }: { children: preact.ComponentChildren, href: string }) {
|
|
70
|
+
return <a href={href} className="text-blue-500 hover:text-blue-600">{children}</a>
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function Image({ src, alt }: { src: string, alt: string }) {
|
|
74
|
+
const [isExpanded, setIsExpanded] = useState(false);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<>
|
|
78
|
+
<img
|
|
79
|
+
src={src}
|
|
80
|
+
alt={alt}
|
|
81
|
+
className="w-full h-auto cursor-pointer"
|
|
82
|
+
onClick={() => setIsExpanded(true)}
|
|
83
|
+
/>
|
|
84
|
+
{isExpanded && (
|
|
85
|
+
<div
|
|
86
|
+
className="fixed inset-0 bg-black bg-opacity-90 z-50 flex items-center justify-center"
|
|
87
|
+
onClick={() => setIsExpanded(false)}
|
|
88
|
+
>
|
|
89
|
+
<img
|
|
90
|
+
src={src}
|
|
91
|
+
alt={alt}
|
|
92
|
+
className="max-h-[90vh] max-w-[90vw] object-contain"
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
)}
|
|
96
|
+
</>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { visit } from 'unist-util-visit';
|
|
2
|
+
|
|
3
|
+
export const remarkSafeVars = () => {
|
|
4
|
+
return (tree: any) => {
|
|
5
|
+
visit(tree, 'mdxTextExpression', (node: any, index: number | undefined, parent: any) => {
|
|
6
|
+
if (parent && typeof index === 'number') {
|
|
7
|
+
// Replace mdxTextExpression with inlineCode node for code formatting
|
|
8
|
+
parent.children[index] = {
|
|
9
|
+
type: 'inlineCode',
|
|
10
|
+
value: node.value
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
};
|