@veluai/velu 0.2.35 → 0.2.37
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 +56 -0
- package/dist/cli.js +129 -54
- package/docs/mintlify-migration.md +159 -0
- package/docs/vepa.md +96 -0
- package/package.json +8 -2
- package/runtime/velu-ui/components/Accordion.jsx +3 -3
- package/runtime/velu-ui/components/ApiClient.jsx +4 -2
- package/runtime/velu-ui/components/ApiReferencePage.jsx +23 -15
- package/runtime/velu-ui/components/ApiSamples.jsx +9 -4
- package/runtime/velu-ui/components/AskBar.jsx +3 -2
- package/runtime/velu-ui/components/Callout.jsx +11 -26
- package/runtime/velu-ui/components/Card.jsx +16 -12
- package/runtime/velu-ui/components/ChangelogFilters.jsx +2 -1
- package/runtime/velu-ui/components/Chatbot.jsx +20 -9
- package/runtime/velu-ui/components/CodeBlock.jsx +7 -6
- package/runtime/velu-ui/components/Columns.jsx +2 -0
- package/runtime/velu-ui/components/ContextMenu.jsx +3 -2
- package/runtime/velu-ui/components/Field.jsx +2 -2
- package/runtime/velu-ui/components/Icon.jsx +1 -0
- package/runtime/velu-ui/components/Image.jsx +2 -2
- package/runtime/velu-ui/components/MethodBadge.jsx +2 -2
- package/runtime/velu-ui/components/NavSelect.jsx +22 -4
- package/runtime/velu-ui/components/NotFound.jsx +7 -7
- package/runtime/velu-ui/components/PageFeedback.jsx +13 -3
- package/runtime/velu-ui/components/PageFooter.jsx +3 -0
- package/runtime/velu-ui/components/PageHeader.jsx +37 -15
- package/runtime/velu-ui/components/PageNav.jsx +2 -1
- package/runtime/velu-ui/components/Prompt.jsx +2 -2
- package/runtime/velu-ui/components/Search.jsx +1 -0
- package/runtime/velu-ui/components/Sidebar.jsx +18 -6
- package/runtime/velu-ui/components/Steps.jsx +4 -4
- package/runtime/velu-ui/components/ThemePreferenceMenu.jsx +57 -0
- package/runtime/velu-ui/components/ThemeToggle.jsx +4 -1
- package/runtime/velu-ui/components/Toc.jsx +6 -4
- package/runtime/velu-ui/components/Tree.jsx +6 -5
- package/runtime/velu-ui/components/TryItBar.jsx +1 -0
- package/runtime/velu-ui/components/Update.jsx +2 -2
- package/runtime/velu-ui/components/VepaFooter.jsx +40 -0
- package/runtime/velu-ui/components/callout.css +28 -0
- package/runtime/velu-ui/components/card.css +9 -0
- package/runtime/velu-ui/components/chatbot.css +42 -0
- package/runtime/velu-ui/components/docs-layout.css +80 -0
- package/runtime/velu-ui/components/page-header.css +6 -0
- package/runtime/velu-ui/components/sidebar.css +5 -5
- package/runtime/velu-ui/element-selectors.css +66 -0
- package/runtime/velu-ui/primitives/Cluster.jsx +12 -0
- package/runtime/velu-ui/primitives/Stack.jsx +12 -0
- package/runtime/velu-ui/primitives/Switcher.jsx +11 -1
- package/runtime/velu-ui/styles.css +52 -35
- package/runtime/velu-ui/themes/vepa.css +264 -0
- package/schema/velu.schema.json +5 -0
- package/src/navigation.js +3 -2
- package/src/runtime/App.jsx +144 -52
- package/src/runtime/VepaToc.jsx +12 -0
- package/src/runtime/client-entry.jsx +23 -0
- package/src/runtime/dev-warnings.js +16 -0
- package/src/runtime/page-mode.js +54 -0
- package/src/runtime/server-entry.jsx +1 -0
- package/templates/starter/essentials/settings.mdx +15 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# Migrate Mintlify documentation to Velu
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
velu migrate mintlify ./mintlify-docs --out ./velu-docs --dry-run
|
|
5
|
+
velu migrate mintlify ./mintlify-docs --out ./velu-docs
|
|
6
|
+
cd velu-docs
|
|
7
|
+
velu validate .
|
|
8
|
+
velu dev .
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
From this repository, replace `velu` with `node packages/velu-cli/bin/cli.js`.
|
|
12
|
+
The command is included in the bundled public CLI. It has not been published
|
|
13
|
+
until a package release is made.
|
|
14
|
+
|
|
15
|
+
The source is a local repository/content directory containing `docs.json` or
|
|
16
|
+
legacy `mint.json`. The command creates a **new directory** and leaves the source
|
|
17
|
+
untouched. Without `--out`, it creates a sibling named `<source>-velu`. Existing
|
|
18
|
+
destinations, destinations inside the source, and filename collisions are rejected.
|
|
19
|
+
Files are staged before the completed directory is moved into place.
|
|
20
|
+
|
|
21
|
+
`docs.json` takes precedence if both configs exist. Use `--config mint.json` to
|
|
22
|
+
select the legacy file. JSON comments/trailing commas and local JSON/YAML config
|
|
23
|
+
`$ref` files are supported. Config references cannot escape the source directory;
|
|
24
|
+
remote references, fragments, and cycles fail with an explicit error.
|
|
25
|
+
|
|
26
|
+
## Preview and CI
|
|
27
|
+
|
|
28
|
+
| Option | Behavior |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `--dry-run` | Runs analysis, transformations, and MDX compilation in memory; writes nothing |
|
|
31
|
+
| `--json` | Prints only the machine-readable report |
|
|
32
|
+
| `--strict` | Refuses to write output if there are warnings or errors |
|
|
33
|
+
| `--out <directory>` | Sets the new destination |
|
|
34
|
+
| `--config docs.json\|mint.json` | Selects the source configuration |
|
|
35
|
+
| `--help` | Prints usage |
|
|
36
|
+
|
|
37
|
+
Exit codes are `0` for completion without compatibility errors, `1` for invocation
|
|
38
|
+
or filesystem failures, `2` for compatibility errors, and `3` when strict mode
|
|
39
|
+
requires review. **Normal mode writes a reviewable migration even with code 2.**
|
|
40
|
+
Warnings alone return 0 unless strict mode is enabled. The report still labels
|
|
41
|
+
any migration with findings `needs-review`.
|
|
42
|
+
|
|
43
|
+
Every migration writes `VELU-MIGRATION.md` and `velu-migration-report.json`.
|
|
44
|
+
It also archives the fully resolved original config in
|
|
45
|
+
`.velu-migration/source-config.json`, outside the publicly served assets.
|
|
46
|
+
The JSON report includes per-file actions and SHA-256 output hashes, script
|
|
47
|
+
conversions, skipped paths, and findings with source locations. Reports do not
|
|
48
|
+
contain source script bodies or unsupported config values. They can contain
|
|
49
|
+
filenames, endpoint paths, and diagnostic text; review before sharing.
|
|
50
|
+
|
|
51
|
+
## Coverage
|
|
52
|
+
|
|
53
|
+
| Area | Migration behavior |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| Config | Projects supported values against the shipped Velu schema; reports unsupported nested fields individually and preserves the original source config |
|
|
56
|
+
| Legacy config | Converts navigation arrays, prefix-based tabs, anchors, topbar links/CTA, footer socials, and API base URL/example languages |
|
|
57
|
+
| Navigation | Retains groups, tabs, products, versions, languages, root pages, and supported OpenAPI references; maps simple dropdown containers to tabs and merges global anchors/tabs with a review finding |
|
|
58
|
+
| Branding | Copies logos/favicons, colors, navbar/footer, contextual menu and SEO; maps `description` to SEO metadata, body font family to `font`, and a dual favicon to one local variant |
|
|
59
|
+
| Content | Converts content `.md` to `.mdx`; preserves frontmatter, prose, fenced examples, MDX expressions, and local components; compiles every migrated MDX file |
|
|
60
|
+
| Components | Maps Note/Tip/Warning/Info/Check/Danger to Callout, ParamField/ResponseField to Field, Expandable to Accordion, CardGroup `cols` to `limit`, and Accordion `default-open` to `defaultOpen` |
|
|
61
|
+
| React adapters | Adds an editable `snippets/velu-mintlify-compat.jsx` for Tabs/Tab, Frame, Tooltip, Badge, Button, and Panel; imports only used adapters into each MDX page |
|
|
62
|
+
| Snippets | Preserves JSX/TSX modules; converts snippet-directory `.js` files to `.jsx` to avoid global execution; updates MDX and JS/TS module imports, including root-relative and extensionless imports |
|
|
63
|
+
| Custom JavaScript | Preserves browser `.js` files byte-for-byte and inventories their execution risks; Velu loads them after hydration, once per full page load, in path order |
|
|
64
|
+
| Custom CSS | Preserves styles; parses declarations to rewrite relative `url(...)` asset references to site-root paths; reports selectors/imports needing review |
|
|
65
|
+
| Assets | Copies files and mirrors ordinary images, fonts, media, downloads, CSS/JS, and explicitly linked data into `public/` for existing URLs; retains originals for branding and local imports |
|
|
66
|
+
| OpenAPI navigation | Preserves specs and references, reports missing/remote sources and the need to compare generated routes |
|
|
67
|
+
| OpenAPI MDX pages | Materializes `openapi: spec.json GET /path`, or `GET /path` with a root spec reference, into an editable API playground snapshot without changing the page path or removing its body; supports single local specs with internal references |
|
|
68
|
+
| npm scripts | Rewrites exact `mint`/`mintlify` dev, validate, version/v, and update invocations, including common package-manager launchers; adds the running Velu version as a dev dependency when Mintlify usage is found |
|
|
69
|
+
| Ignore rules | Honors `.mintignore` using gitignore semantics, including negation; excludes dependencies, build caches, environment files, and known tooling directories |
|
|
70
|
+
| Project tooling | Preserves shell scripts, package manifests, lockfiles, and CI workflows; flags Mintlify commands requiring manual replacement |
|
|
71
|
+
|
|
72
|
+
## Custom scripts and remaining work
|
|
73
|
+
|
|
74
|
+
Migration never executes project scripts, installs dependencies, or downloads
|
|
75
|
+
remote assets/specs. Run your package manager afterward when `package.json` has
|
|
76
|
+
changed; lockfiles and Mintlify dependencies are retained for review.
|
|
77
|
+
|
|
78
|
+
Mintlify and Velu share many DOM selectors, but arbitrary JavaScript cannot be
|
|
79
|
+
translated reliably without understanding its behavior. The report identifies
|
|
80
|
+
Mintlify browser APIs (`window.mintlify`, user events), Next.js internals,
|
|
81
|
+
DOMContentLoaded/load timing, module syntax in classic scripts, Node.js code in
|
|
82
|
+
globally loaded `.js` files, and DOM-dependent code. These checks are static
|
|
83
|
+
heuristics, not proof of complete runtime parity. For DOM-ready callbacks, check
|
|
84
|
+
`document.readyState` and initialize immediately when the event has already fired.
|
|
85
|
+
Verify behavior after client-side navigation as well as a full refresh.
|
|
86
|
+
|
|
87
|
+
The `css-dom` finding flags styles aimed at shared chrome IDs such as `#content`,
|
|
88
|
+
`#sidebar-content`, and `#footer`. Vepa aligns these common hooks with Sequoia,
|
|
89
|
+
including a content-body-only `#content` and route-specific body remounting, but
|
|
90
|
+
a shared ID does not guarantee identical nesting or dimensions for every component.
|
|
91
|
+
Selectors are preserved for review,
|
|
92
|
+
not automatically rewritten. Compare desktop and mobile pages with custom CSS
|
|
93
|
+
enabled; successful asset copying is not a visual parity score.
|
|
94
|
+
|
|
95
|
+
Endpoint snapshots are exported as `veluApi` metadata in MDX. Velu uses this
|
|
96
|
+
metadata for API layout, request/response samples, and sidebar method badges;
|
|
97
|
+
the original MDX body appears between the Try It bar and schema fields. Keep
|
|
98
|
+
the export when editing a migrated endpoint. Re-migrate after OpenAPI changes
|
|
99
|
+
to regenerate the snapshot.
|
|
100
|
+
|
|
101
|
+
Files under `public/` and dot directories are not automatically loaded by Velu;
|
|
102
|
+
their inclusion needs review. Root `.js` files are deliberately not rewritten
|
|
103
|
+
because blindly changing lifecycle logic, globals, or selectors can alter behavior.
|
|
104
|
+
Place Node tooling outside the docs content root or use `.cjs`/`.mjs` so it is not
|
|
105
|
+
loaded as a browser script.
|
|
106
|
+
|
|
107
|
+
The React adapters preserve basic interactions, not every Mintlify prop or exact
|
|
108
|
+
appearance. Panel renders inline, Tooltip uses a text-only native tooltip, and
|
|
109
|
+
Tabs supports keyboard navigation but does not synchronize selections across
|
|
110
|
+
separate tab groups. Unknown components are reported as errors instead of being
|
|
111
|
+
replaced with empty placeholders. Font Awesome/Tabler icon names may need Lucide
|
|
112
|
+
equivalents. Original references in code examples and prose remain unchanged.
|
|
113
|
+
|
|
114
|
+
Mintlify's `theme: "sequoia"` is converted to `theme: "vepa"` and activates the [Vepa preset](vepa.md).
|
|
115
|
+
The preset is not a certification of pixel equality for every component or custom script.
|
|
116
|
+
|
|
117
|
+
Features without full Velu equivalents require review: other Mintlify themes, advanced
|
|
118
|
+
fonts and styling, redirects, analytics/support integrations, hosting settings,
|
|
119
|
+
authentication, personalization, hidden-page routing, legacy version filtering,
|
|
120
|
+
complex dropdown/global navigation, AsyncAPI, manually authored `api:` pages,
|
|
121
|
+
multi-file/remote endpoint snapshots, OpenAPI overlays and `x-mint` extensions.
|
|
122
|
+
Access/visibility settings are reported as errors; they must be migrated before
|
|
123
|
+
publishing. Unlisted content is copied but Velu currently renders navigation
|
|
124
|
+
pages only. Snapshot API pages must be regenerated or edited when their specs
|
|
125
|
+
change. Existing generated robots/sitemap/LLM files can still contain old domains.
|
|
126
|
+
|
|
127
|
+
`mint broken-links`, `mint a11y`, `mint export`, cloud/account commands, compound
|
|
128
|
+
shell commands, and CLI flags have no automatically assumed equivalent. These
|
|
129
|
+
scripts and workflows are retained with findings. In particular, `velu validate`
|
|
130
|
+
is not a complete replacement for Mintlify's separate broken-link/a11y tools,
|
|
131
|
+
and the public Velu package does not expose the internal static build command.
|
|
132
|
+
|
|
133
|
+
## Parity research
|
|
134
|
+
|
|
135
|
+
Inspected on 2026-09-08:
|
|
136
|
+
|
|
137
|
+
- Published [`@mintlify/cli@4.0.1479`](https://www.npmjs.com/package/@mintlify/cli/v/4.0.1479): command dispatch/options in `bin/cli.js`; starter source in `bin/init.js`.
|
|
138
|
+
- Published [`@mintlify/common@1.0.1132`](https://www.npmjs.com/package/@mintlify/common/v/1.0.1132): content/snippet categories and `.mintignore` semantics in `dist/getFileCategory.js` and `dist/mintIgnore.js`.
|
|
139
|
+
- Published [`@mintlify/prebuild@1.0.1286`](https://www.npmjs.com/package/@mintlify/prebuild/v/1.0.1286): split config references and config loading.
|
|
140
|
+
- [`docs.json` schema](https://www.mintlify.com/docs.json), [custom scripts documentation](https://www.mintlify.com/docs/customize/custom-scripts), and [official starter](https://github.com/mintlify/starter).
|
|
141
|
+
|
|
142
|
+
The current `@mintlify/validation@0.1.849` tarball was also retrieved, but it did
|
|
143
|
+
not contain its declared `dist/` implementation. Legacy conversion is implemented
|
|
144
|
+
locally; it does not depend on executing Mintlify's upgrade code. No Mintlify
|
|
145
|
+
implementation code or package is vendored as a runtime dependency.
|
|
146
|
+
|
|
147
|
+
## Verification
|
|
148
|
+
|
|
149
|
+
```sh
|
|
150
|
+
node --test packages/velu-cli/test/migrate.test.mjs
|
|
151
|
+
node --test packages/velu-cli/test/*.test.mjs
|
|
152
|
+
node packages/velu-cli/scripts/build.mjs
|
|
153
|
+
node packages/velu-cli/dist/cli.js migrate --help
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Tests cover clean and review-required outputs, source immutability, JSONC/YAML
|
|
157
|
+
references, ignore negation, collisions/junctions, script preservation, AST
|
|
158
|
+
rewrites, assets, endpoint snapshots, generated-project validation, and CLI exit
|
|
159
|
+
codes. No network is needed for the migration tests.
|
package/docs/vepa.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Vepa (வேப்பம்) compatibility
|
|
2
|
+
|
|
3
|
+
Enable the preset in `velu.json`:
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"name": "Documentation",
|
|
8
|
+
"theme": "vepa",
|
|
9
|
+
"colors": { "primary": "#16A34A", "light": "#07C983" },
|
|
10
|
+
"navigation": { "groups": [{ "group": "Guide", "pages": ["index"] }] }
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Mintlify migration converts `theme: "sequoia"` to `theme: "vepa"`. The normal Velu appearance is
|
|
15
|
+
still the default when `theme` is omitted. The visual preset is separate from
|
|
16
|
+
the reader's Light / Dark / System preference.
|
|
17
|
+
|
|
18
|
+
For Vepa, `colors.primary` is the light-mode accent and `colors.light` is the
|
|
19
|
+
dark-mode accent, matching Mintlify. The primary color also tints the gray ramp.
|
|
20
|
+
`font.family` overrides Inter. Development, prerendered builds, and the browser
|
|
21
|
+
preview share these normalizers.
|
|
22
|
+
|
|
23
|
+
## Reference inspected
|
|
24
|
+
|
|
25
|
+
The npm CLI does not ship the renderer inside its own package. Its previewing
|
|
26
|
+
dependency retrieves a separately versioned client from Mintlify's release host.
|
|
27
|
+
Research was pinned on 2026-09-08 to:
|
|
28
|
+
|
|
29
|
+
- [`@mintlify/cli@4.0.1479`](https://www.npmjs.com/package/@mintlify/cli/v/4.0.1479)
|
|
30
|
+
- [`@mintlify/previewing@4.0.1358`](https://www.npmjs.com/package/@mintlify/previewing/v/4.0.1358), `dist/constants.js`, `dist/util.js`, and `dist/local-preview/client.js`
|
|
31
|
+
- [Client 0.0.3566](https://releases.mintlify.com/mint-0.0.3566.tar.gz), compiled Sequoia topbar, sidebar, page-header, and TOC modules
|
|
32
|
+
- [`@mintlify/common@1.0.1132`](https://www.npmjs.com/package/@mintlify/common/v/1.0.1132), color composition
|
|
33
|
+
|
|
34
|
+
Client archive SHA-256:
|
|
35
|
+
`a2b758fd67159a066e14fa7e78599047b0fd7f5ae78477e7364efdc232ef7ee5`
|
|
36
|
+
|
|
37
|
+
The downloaded client is research material only. It is not included in Velu's
|
|
38
|
+
published package or used at runtime.
|
|
39
|
+
|
|
40
|
+
## Measured geometry
|
|
41
|
+
|
|
42
|
+
| Region | Vepa preset |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| Desktop topbar | 48 px; navigation tabs add 48 px |
|
|
45
|
+
| Logo | 22 px high |
|
|
46
|
+
| Desktop search trigger | 256 × 32 px |
|
|
47
|
+
| Left sidebar | 288 px |
|
|
48
|
+
| Default article at 1440 px viewport | 648 px; left edge 396 px |
|
|
49
|
+
| Table of contents | 288 px rail with 32 px side padding |
|
|
50
|
+
| API examples | 472 px rail including a 24 px outer gutter; 448 px sample cards |
|
|
51
|
+
| API rail breakpoint | Hidden below 1280 px; article reclaims its space |
|
|
52
|
+
| Mobile navigation | Below 1024 px; 48 px topbar and 56 px breadcrumb strip |
|
|
53
|
+
| Title | Inter, 500 weight, 36/40 px; 30/36 px below 640 px |
|
|
54
|
+
|
|
55
|
+
The API rail deliberately has its own width and padding. Applying the normal
|
|
56
|
+
TOC's width leaves too little room for request tabs and response examples. Long
|
|
57
|
+
code lines scroll inside their code panel instead of widening the page.
|
|
58
|
+
|
|
59
|
+
The preset includes a plain TOC, tinted light/dark surfaces, a three-way theme
|
|
60
|
+
menu, responsive columns, and mode-specific content widths. Card links retain
|
|
61
|
+
their destinations, and navigation uses `sidebarTitle` when supplied.
|
|
62
|
+
|
|
63
|
+
For custom styles, Vepa exposes `#page-title` on the title, `#content` on the
|
|
64
|
+
ordinary MDX body (excluding the header), and `#sidebar-content` on the sidebar.
|
|
65
|
+
The MDX body remounts on route changes so DOM decorations do not leak into the
|
|
66
|
+
next page. Body font overrides inherit into prose; component headings retain
|
|
67
|
+
their own typography. API pages use their own content structure.
|
|
68
|
+
|
|
69
|
+
Migrated endpoint MDX exports a `veluApi` snapshot containing the operation,
|
|
70
|
+
samples, and API settings. Both runtimes use it to activate the API layout and
|
|
71
|
+
navigation method badges. Author imports and exports stay at module scope;
|
|
72
|
+
custom content renders after the Try It bar and before the schema fields.
|
|
73
|
+
|
|
74
|
+
## Verification and limits
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
node --test packages/velu-cli/test/vepa.test.mjs
|
|
78
|
+
node packages/velu-cli/scripts/check-vepa-layout.mjs http://localhost:8358 /api-reference/products/listproducts /api-reference/products/addproduct
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The browser check covers GET/POST pages at 1440, 1280, 1100, 768, and 390 px in
|
|
82
|
+
light/dark mode. It checks rail size, sample width, column overlap, document
|
|
83
|
+
overflow, closed drawers, language tabs, system preference changes, and runtime
|
|
84
|
+
errors. Supply routes from your own running site.
|
|
85
|
+
|
|
86
|
+
This is a source-informed compatibility preset, **not yet verified pixel-for-pixel
|
|
87
|
+
across Mintlify's complete component/state matrix**. Velu still uses its own
|
|
88
|
+
search, API playground, syntax highlighting, icons, feedback, and content
|
|
89
|
+
components. Font availability can also affect screenshots. Hosted Mintlify
|
|
90
|
+
services are not reproduced by copying theme settings. Custom scripts and CSS
|
|
91
|
+
that depend on Mintlify's exact DOM, globals, lifecycle, or unsupported components
|
|
92
|
+
need testing on the migrated site.
|
|
93
|
+
|
|
94
|
+
Below the API rail breakpoint, samples move inline after the Try It bar and
|
|
95
|
+
before custom content. Inline and desktop samples use distinct IDs. This
|
|
96
|
+
document records the current scope rather than asserting complete parity.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@veluai/velu",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": "./dist/cli.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"src/lib/known-components.js",
|
|
17
17
|
"runtime/velu-ui/**",
|
|
18
18
|
"schema/**",
|
|
19
|
-
"templates/**"
|
|
19
|
+
"templates/**",
|
|
20
|
+
"docs/mintlify-migration.md",
|
|
21
|
+
"docs/vepa.md"
|
|
20
22
|
],
|
|
21
23
|
"scripts": {
|
|
22
24
|
"build": "node scripts/build.mjs",
|
|
@@ -26,6 +28,7 @@
|
|
|
26
28
|
},
|
|
27
29
|
"dependencies": {
|
|
28
30
|
"@apidevtools/swagger-parser": "^10.1.0",
|
|
31
|
+
"@babel/parser": "7.28.0",
|
|
29
32
|
"@icons-pack/react-simple-icons": ">=13.0.0 <13.13.0",
|
|
30
33
|
"@mdx-js/mdx": "^3.1.1",
|
|
31
34
|
"@mdx-js/react": "^3.1.1",
|
|
@@ -36,10 +39,13 @@
|
|
|
36
39
|
"estree-util-value-to-estree": "^3.5.0",
|
|
37
40
|
"express": "^4.21.1",
|
|
38
41
|
"github-slugger": "^2.0.0",
|
|
42
|
+
"ignore": "7.0.5",
|
|
39
43
|
"iso-639-1": "^3.1.5",
|
|
40
44
|
"js-yaml": "^4.1.0",
|
|
45
|
+
"jsonc-parser": "3.3.1",
|
|
41
46
|
"lucide-react": "^0.460.0",
|
|
42
47
|
"mdast-util-to-string": "^4.0.0",
|
|
48
|
+
"postcss": "8.5.0",
|
|
43
49
|
"prism-react-renderer": "^2.4.0",
|
|
44
50
|
"prismjs": "^1.29.0",
|
|
45
51
|
"react": "^18.3.1",
|
|
@@ -39,7 +39,7 @@ export function Accordion({
|
|
|
39
39
|
.join(' ');
|
|
40
40
|
|
|
41
41
|
return (
|
|
42
|
-
<details className={cls} open={defaultOpen || undefined} {...rest}>
|
|
42
|
+
<details className={cls} data-component="accordion" open={defaultOpen || undefined} {...rest}>
|
|
43
43
|
<summary className="velu-accordion__summary">
|
|
44
44
|
<span className="velu-accordion__chevron" aria-hidden="true">
|
|
45
45
|
{resolveIcon('chevron-right', { size: '1em' })}
|
|
@@ -54,9 +54,9 @@ export function Accordion({
|
|
|
54
54
|
export function AccordionGroup({ children, className = '', ...rest }) {
|
|
55
55
|
return (
|
|
56
56
|
<GroupCtx.Provider value={true}>
|
|
57
|
-
<
|
|
57
|
+
<accordion-group class={`velu-accordion-group ${className}`.trim()} {...rest}>
|
|
58
58
|
{children}
|
|
59
|
-
</
|
|
59
|
+
</accordion-group>
|
|
60
60
|
</GroupCtx.Provider>
|
|
61
61
|
);
|
|
62
62
|
}
|
|
@@ -110,10 +110,11 @@ export default function ApiClient({
|
|
|
110
110
|
align="flex-start"
|
|
111
111
|
className="velu-api-client__head"
|
|
112
112
|
>
|
|
113
|
-
<
|
|
113
|
+
<option-dropdown class="velu-api-client__op" ref={opRef}>
|
|
114
114
|
{canSwitch ? (
|
|
115
115
|
<button
|
|
116
116
|
type="button"
|
|
117
|
+
id="endpoints-menu-trigger"
|
|
117
118
|
className="velu-api-client__op-btn"
|
|
118
119
|
onClick={() => setMenuOpen((v) => !v)}
|
|
119
120
|
aria-haspopup="listbox"
|
|
@@ -166,7 +167,7 @@ export default function ApiClient({
|
|
|
166
167
|
))}
|
|
167
168
|
</ul>
|
|
168
169
|
)}
|
|
169
|
-
</
|
|
170
|
+
</option-dropdown>
|
|
170
171
|
<TryItBar
|
|
171
172
|
method={method}
|
|
172
173
|
path={path}
|
|
@@ -183,6 +184,7 @@ export default function ApiClient({
|
|
|
183
184
|
visible without scrolling past the inputs; the form and code samples
|
|
184
185
|
follow. See api.css. */}
|
|
185
186
|
<div
|
|
187
|
+
id="api-playground-input"
|
|
186
188
|
className="velu-api-client__body"
|
|
187
189
|
data-has-response={response != null ? 'true' : undefined}
|
|
188
190
|
>
|
|
@@ -27,7 +27,7 @@ import { sendApiRequest } from '../lib/api-send.js';
|
|
|
27
27
|
*/
|
|
28
28
|
const LOCATION_LABEL = { path: 'Path Parameters', query: 'Query Parameters', header: 'Header Parameters' };
|
|
29
29
|
|
|
30
|
-
export default function ApiReferencePage({ operation, samples = [], apiOperations = [], api = {} }) {
|
|
30
|
+
export default function ApiReferencePage({ operation, samples = [], apiOperations = [], api = {}, children, preset }) {
|
|
31
31
|
const [open, setOpen] = useState(false);
|
|
32
32
|
// Which operation the playground is currently showing. Defaults to this
|
|
33
33
|
// page's own operation; the dropdown can switch it to any sibling.
|
|
@@ -78,16 +78,19 @@ export default function ApiReferencePage({ operation, samples = [], apiOperation
|
|
|
78
78
|
className="velu-api-page__tryit"
|
|
79
79
|
/>
|
|
80
80
|
|
|
81
|
+
{preset === 'vepa' && <div className="velu-api-page__inline-samples"><ApiSamples idPrefix="inline-" samples={samples} responses={operation.responses} preset={preset} title={operation.title} /></div>}
|
|
82
|
+
{children && <div className="velu-api-page__custom-content">{children}</div>}
|
|
83
|
+
|
|
81
84
|
{/* Authorizations */}
|
|
82
85
|
{operation.auth?.length > 0 && (
|
|
83
|
-
<section
|
|
84
|
-
<h2>Authorizations</h2>
|
|
86
|
+
<api-section class="velu-api-page__section">
|
|
87
|
+
<h2 data-component="api-section-heading">Authorizations</h2>
|
|
85
88
|
{operation.auth.map((a, i) => (
|
|
86
89
|
<Field key={i} name={a.name} pre={a.prefix} type={a.type} required={a.required} post={a.in}>
|
|
87
90
|
{a.description}
|
|
88
91
|
</Field>
|
|
89
92
|
))}
|
|
90
|
-
</section>
|
|
93
|
+
</api-section>
|
|
91
94
|
)}
|
|
92
95
|
|
|
93
96
|
{/* Parameters, by location */}
|
|
@@ -95,37 +98,37 @@ export default function ApiReferencePage({ operation, samples = [], apiOperation
|
|
|
95
98
|
const rows = operation.parameters?.[loc] || [];
|
|
96
99
|
if (!rows.length) return null;
|
|
97
100
|
return (
|
|
98
|
-
<section key={loc}
|
|
99
|
-
<h2>{LOCATION_LABEL[loc]}</h2>
|
|
101
|
+
<api-section key={loc} class="velu-api-page__section">
|
|
102
|
+
<h2 data-component="api-section-heading">{LOCATION_LABEL[loc]}</h2>
|
|
100
103
|
{rows.map((p, i) => (
|
|
101
104
|
<Field key={i} name={p.name} type={p.type} required={p.required}>
|
|
102
105
|
{p.description}
|
|
103
106
|
{p.enum && <EnumHint values={p.enum} />}
|
|
104
107
|
</Field>
|
|
105
108
|
))}
|
|
106
|
-
</section>
|
|
109
|
+
</api-section>
|
|
107
110
|
);
|
|
108
111
|
})}
|
|
109
112
|
|
|
110
113
|
{/* Request body */}
|
|
111
114
|
{operation.body?.fields?.length > 0 && (
|
|
112
|
-
<section
|
|
113
|
-
<h2>Body</h2>
|
|
115
|
+
<api-section class="velu-api-page__section">
|
|
116
|
+
<h2 data-component="api-section-heading">Body</h2>
|
|
114
117
|
{operation.body.fields.map((f, i) => (
|
|
115
118
|
<Field key={i} name={f.name} type={f.type} required={f.required}>
|
|
116
119
|
{f.description}
|
|
117
120
|
{f.enum && <EnumHint values={f.enum} />}
|
|
118
121
|
</Field>
|
|
119
122
|
))}
|
|
120
|
-
</section>
|
|
123
|
+
</api-section>
|
|
121
124
|
)}
|
|
122
125
|
|
|
123
126
|
{/* Responses */}
|
|
124
127
|
{operation.responses?.length > 0 && (
|
|
125
|
-
<section
|
|
126
|
-
<h2>Response</h2>
|
|
127
|
-
<ResponseSections responses={operation.responses} />
|
|
128
|
-
</section>
|
|
128
|
+
<api-section class="velu-api-page__section">
|
|
129
|
+
<h2 data-component="api-section-heading">Response</h2>
|
|
130
|
+
<ResponseSections responses={operation.responses} preset={preset} />
|
|
131
|
+
</api-section>
|
|
129
132
|
)}
|
|
130
133
|
|
|
131
134
|
{/* Try-It playground — rendered as an overlay above the page, with a
|
|
@@ -175,7 +178,12 @@ function EnumHint({ values }) {
|
|
|
175
178
|
);
|
|
176
179
|
}
|
|
177
180
|
|
|
178
|
-
function ResponseSections({ responses }) {
|
|
181
|
+
function ResponseSections({ responses, preset }) {
|
|
182
|
+
if (preset === 'vepa') return <div className="velu-vepa-responses">{responses.map((r, i) => <section key={i}>
|
|
183
|
+
<div className="velu-vepa-responses__status">{r.status}{r.contentType && ` · ${r.contentType}`}</div>
|
|
184
|
+
{r.description && <p>{r.description}</p>}
|
|
185
|
+
{r.fields?.map((f, j) => <Field key={j} name={f.name} type={f.type} required={f.required}>{f.description}</Field>)}
|
|
186
|
+
</section>)}</div>;
|
|
179
187
|
return (
|
|
180
188
|
<AccordionGroup className="velu-api-resp">
|
|
181
189
|
{responses.map((r, i) => {
|
|
@@ -9,12 +9,17 @@ import CodeBlock, { CodeGroup } from './CodeBlock.jsx';
|
|
|
9
9
|
*
|
|
10
10
|
* @param {{ samples: {key,label,language,code}[], responses: object[] }} props
|
|
11
11
|
*/
|
|
12
|
-
export default function ApiSamples({ samples = [], responses = [] }) {
|
|
12
|
+
export default function ApiSamples({ samples = [], responses = [], preset, title, idPrefix = '' }) {
|
|
13
|
+
const [selected, setSelected] = React.useState('');
|
|
14
|
+
const sample = samples.find((s) => s.key === selected) || samples[0];
|
|
13
15
|
const withExample = responses.filter((r) => r.example != null);
|
|
14
16
|
return (
|
|
15
17
|
<div className="velu-api-samples">
|
|
16
|
-
{
|
|
17
|
-
<
|
|
18
|
+
{sample && preset === 'vepa' ? <section id={idPrefix + 'request-example'} className="velu-vepa-request">
|
|
19
|
+
<div className="velu-vepa-request__header"><span>{title}</span><select aria-label="Request example language" value={sample.key} onChange={(e) => setSelected(e.target.value)}>{samples.map((s) => <option key={s.key} value={s.key}>{s.label}</option>)}</select></div>
|
|
20
|
+
<CodeBlock language={sample.language}>{sample.code}</CodeBlock>
|
|
21
|
+
</section> : samples.length > 0 && (
|
|
22
|
+
<CodeGroup id={idPrefix + 'request-example'} className="velu-api-samples__req">
|
|
18
23
|
{samples.map((s) => (
|
|
19
24
|
<CodeBlock key={s.key} title={s.label} language={s.language}>
|
|
20
25
|
{s.code}
|
|
@@ -23,7 +28,7 @@ export default function ApiSamples({ samples = [], responses = [] }) {
|
|
|
23
28
|
</CodeGroup>
|
|
24
29
|
)}
|
|
25
30
|
{withExample.length > 0 && (
|
|
26
|
-
<CodeGroup className="velu-api-samples__res">
|
|
31
|
+
<CodeGroup id={idPrefix + 'response-example'} className="velu-api-samples__res">
|
|
27
32
|
{withExample.map((r) => (
|
|
28
33
|
<CodeBlock key={r.status} title={r.status} language="json">
|
|
29
34
|
{JSON.stringify(r.example, null, 2)}
|
|
@@ -48,7 +48,7 @@ export default function AskBar({
|
|
|
48
48
|
const isEmpty = value.trim().length === 0;
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
|
-
<
|
|
51
|
+
<chat-assistant-floating-input class={`velu-ask-bar ${className}`.trim()} {...rest}>
|
|
52
52
|
<textarea
|
|
53
53
|
className="velu-ask-bar__input"
|
|
54
54
|
placeholder={placeholder}
|
|
@@ -59,6 +59,7 @@ export default function AskBar({
|
|
|
59
59
|
/>
|
|
60
60
|
<button
|
|
61
61
|
type="button"
|
|
62
|
+
data-component="chat-assistant-send-button"
|
|
62
63
|
className="velu-ask-bar__send"
|
|
63
64
|
onClick={submit}
|
|
64
65
|
disabled={isEmpty}
|
|
@@ -66,6 +67,6 @@ export default function AskBar({
|
|
|
66
67
|
>
|
|
67
68
|
{resolveIcon('arrow-up', { size: '1em' })}
|
|
68
69
|
</button>
|
|
69
|
-
</
|
|
70
|
+
</chat-assistant-floating-input>
|
|
70
71
|
);
|
|
71
72
|
}
|
|
@@ -73,42 +73,27 @@ export default function Callout({
|
|
|
73
73
|
// (.lucide rule in base.css), not set per-icon.
|
|
74
74
|
const iconNode = resolveIcon(icon ?? v.icon, { size: '1em' });
|
|
75
75
|
|
|
76
|
+
// Static styles live in callout.css so a project's custom CSS can override
|
|
77
|
+
// them with a plain `callout { ... }` element selector (inline styles would
|
|
78
|
+
// beat any stylesheet). Only the per-instance colours are inline, as custom
|
|
79
|
+
// properties the stylesheet reads.
|
|
76
80
|
return (
|
|
77
|
-
<
|
|
78
|
-
className={className}
|
|
81
|
+
<callout
|
|
82
|
+
className={`velu-callout ${className}`.trim()}
|
|
83
|
+
data-type={type}
|
|
79
84
|
style={{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
background: bgColor,
|
|
83
|
-
border: `var(--border-width) solid ${strokeColor}`,
|
|
84
|
-
borderRadius: 'var(--radius-sm)',
|
|
85
|
-
color: 'var(--text-color)',
|
|
86
|
-
fontSize: 'var(--f-body)',
|
|
87
|
-
lineHeight: 'var(--lh-body)',
|
|
85
|
+
'--velu-callout-bg': bgColor,
|
|
86
|
+
'--velu-callout-stroke': strokeColor,
|
|
88
87
|
...style,
|
|
89
88
|
}}
|
|
90
89
|
{...rest}
|
|
91
90
|
>
|
|
92
91
|
{iconNode && (
|
|
93
|
-
<span
|
|
94
|
-
aria-hidden="true"
|
|
95
|
-
style={{
|
|
96
|
-
float: 'left',
|
|
97
|
-
display: 'inline-flex',
|
|
98
|
-
alignItems: 'center',
|
|
99
|
-
// one line-box tall (body font-size × body line-height token) so
|
|
100
|
-
// the icon is centered on the FIRST line; text wraps beside it
|
|
101
|
-
// then flows back under it (no hanging indent).
|
|
102
|
-
blockSize: 'calc(var(--f-body) * var(--lh-body))',
|
|
103
|
-
marginInlineEnd: 'var(--s-1)',
|
|
104
|
-
color: strokeColor,
|
|
105
|
-
fontSize: 'var(--f-body)',
|
|
106
|
-
}}
|
|
107
|
-
>
|
|
92
|
+
<span className="velu-callout__icon" aria-hidden="true">
|
|
108
93
|
{iconNode}
|
|
109
94
|
</span>
|
|
110
95
|
)}
|
|
111
96
|
{children}
|
|
112
|
-
</
|
|
97
|
+
</callout>
|
|
113
98
|
);
|
|
114
99
|
}
|
|
@@ -5,9 +5,9 @@ import Switcher from '../primitives/Switcher.jsx';
|
|
|
5
5
|
/**
|
|
6
6
|
* Card + CardGroup — content / horizontal / image / CTA cards.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* single "Click Here ›"
|
|
8
|
+
* Pass `href` (without `cta`) to make the whole card a stretched link.
|
|
9
|
+
* Nested links/buttons inside the card stay clickable above that overlay.
|
|
10
|
+
* Pass `cta={{ label, href }}` for a single "Click Here ›" control instead.
|
|
11
11
|
*
|
|
12
12
|
* Fully tokenized (border-width, border-color, radius scale, spacing, type,
|
|
13
13
|
* line-height, accent, icon-stroke) → light/dark automatic via [data-theme].
|
|
@@ -22,7 +22,7 @@ import Switcher from '../primitives/Switcher.jsx';
|
|
|
22
22
|
* `icon` is a lucide id string (shared resolveIcon).
|
|
23
23
|
*
|
|
24
24
|
* @param {{ title?: React.ReactNode, icon?: string, horizontal?: boolean,
|
|
25
|
-
* img?: string, imgAlt?: string,
|
|
25
|
+
* img?: string, imgAlt?: string, href?: string,
|
|
26
26
|
* cta?: {label: React.ReactNode, href: string},
|
|
27
27
|
* children?: React.ReactNode, className?: string }} props
|
|
28
28
|
*/
|
|
@@ -34,6 +34,7 @@ export function Card({
|
|
|
34
34
|
img,
|
|
35
35
|
imgAlt = '',
|
|
36
36
|
cta,
|
|
37
|
+
href,
|
|
37
38
|
children,
|
|
38
39
|
className = '',
|
|
39
40
|
...rest
|
|
@@ -49,13 +50,13 @@ export function Card({
|
|
|
49
50
|
.join(' ');
|
|
50
51
|
|
|
51
52
|
const iconEl = icon ? (
|
|
52
|
-
<span className="velu-card__icon" aria-hidden="true">
|
|
53
|
+
<span className="velu-card__icon" data-component-part="card-icon" aria-hidden="true">
|
|
53
54
|
{resolveIcon(icon, { size: '1em' })}
|
|
54
55
|
</span>
|
|
55
56
|
) : null;
|
|
56
57
|
|
|
57
58
|
const ctaEl = cta ? (
|
|
58
|
-
<a className="velu-card__cta" href={cta.href}>
|
|
59
|
+
<a className="velu-card__cta" data-component-part="card-cta" href={cta.href}>
|
|
59
60
|
{cta.label}
|
|
60
61
|
<span className="velu-card__cta-icon" aria-hidden="true">
|
|
61
62
|
{resolveIcon('chevron-right', { size: '1em' })}
|
|
@@ -64,21 +65,22 @@ export function Card({
|
|
|
64
65
|
) : null;
|
|
65
66
|
|
|
66
67
|
const titleEl = title ? (
|
|
67
|
-
<div className="velu-card__title">{title}</div>
|
|
68
|
+
<div className="velu-card__title" data-component-part="card-title">{title}</div>
|
|
68
69
|
) : null;
|
|
69
70
|
const textEl = children ? (
|
|
70
|
-
<div className="velu-card__text">{children}</div>
|
|
71
|
+
<div className="velu-card__text" data-component-part="card-content">{children}</div>
|
|
71
72
|
) : null;
|
|
72
73
|
|
|
73
74
|
return (
|
|
74
|
-
<
|
|
75
|
+
<card className={cls} {...rest}>
|
|
76
|
+
{href && !cta && <a className="velu-card__link" href={href} aria-label={typeof title === 'string' ? title : 'Read more'} />}
|
|
75
77
|
{img && (
|
|
76
|
-
<div className="velu-card__media">
|
|
78
|
+
<div className="velu-card__media" data-component-part="card-image">
|
|
77
79
|
<img src={img} alt={imgAlt} loading="lazy" />
|
|
78
80
|
</div>
|
|
79
81
|
)}
|
|
80
82
|
|
|
81
|
-
<div className="velu-card__body">
|
|
83
|
+
<div className="velu-card__body" data-component-part="card-content-container">
|
|
82
84
|
{horizontal ? (
|
|
83
85
|
<>
|
|
84
86
|
{iconEl}
|
|
@@ -97,7 +99,7 @@ export function Card({
|
|
|
97
99
|
</>
|
|
98
100
|
)}
|
|
99
101
|
</div>
|
|
100
|
-
</
|
|
102
|
+
</card>
|
|
101
103
|
);
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -117,10 +119,12 @@ export function CardGroup({
|
|
|
117
119
|
}) {
|
|
118
120
|
return (
|
|
119
121
|
<Switcher
|
|
122
|
+
as="card-group"
|
|
120
123
|
className={`velu-card-group ${className}`.trim()}
|
|
121
124
|
space={space}
|
|
122
125
|
min={min}
|
|
123
126
|
limit={limit}
|
|
127
|
+
style={{ '--vepa-columns': Math.max(1, Math.min(4, Number(limit) || 2)) }}
|
|
124
128
|
{...rest}
|
|
125
129
|
>
|
|
126
130
|
{children}
|