handoff-app 1.2.2-7 → 2.0.0-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/Changelog.md +37 -15
- package/README.md +372 -118
- package/dist/app-builder/build.d.ts +41 -2
- package/dist/app-builder/build.js +455 -18
- package/dist/app-builder/client-config.d.ts +15 -2
- package/dist/app-builder/client-config.js +43 -4
- package/dist/app-builder/config-diff/snapshot.d.ts +1 -6
- package/dist/app-builder/config-diff/snapshot.js +2 -9
- package/dist/app-builder/index.d.ts +1 -1
- package/dist/app-builder/index.js +3 -1
- package/dist/app-builder/nav-shell.d.ts +23 -0
- package/dist/app-builder/nav-shell.js +80 -0
- package/dist/app-builder/static-export.d.ts +17 -0
- package/dist/app-builder/static-export.js +181 -0
- package/dist/app-builder/vercel-output.d.ts +39 -0
- package/dist/app-builder/vercel-output.js +259 -0
- package/dist/app-builder/watchers/utils.d.ts +2 -0
- package/dist/app-builder/watchers.d.ts +14 -4
- package/dist/app-builder/watchers.js +123 -28
- package/dist/app-builder/websocket.js +1 -1
- package/dist/artifacts/index.d.ts +2 -0
- package/dist/artifacts/index.js +13 -0
- package/dist/artifacts/types.d.ts +136 -0
- package/dist/artifacts/types.js +24 -0
- package/dist/artifacts/url.d.ts +49 -0
- package/dist/artifacts/url.js +86 -0
- package/dist/cache/build-cache.js +48 -4
- package/dist/cli.js +0 -0
- package/dist/commands/build/app.js +1 -2
- package/dist/commands/build/index.d.ts +17 -0
- package/dist/commands/build/index.js +66 -0
- package/dist/commands/checkout/index.d.ts +24 -0
- package/dist/commands/checkout/index.js +71 -0
- package/dist/commands/db/migrate.d.ts +11 -0
- package/dist/commands/db/migrate.js +33 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/publish/index.d.ts +21 -0
- package/dist/commands/publish/index.js +68 -0
- package/dist/config/defaults.js +15 -1
- package/dist/config/loader.js +6 -1
- package/dist/config/normalizers/declaration.js +4 -1
- package/dist/config/normalizers/page.d.ts +18 -0
- package/dist/config/normalizers/page.js +34 -0
- package/dist/config/normalizers/pattern.js +7 -1
- package/dist/config/runtime.d.ts +4 -0
- package/dist/config/runtime.js +53 -5
- package/dist/index.d.ts +65 -1
- package/dist/index.js +123 -3
- package/dist/nav/index.d.ts +83 -0
- package/dist/nav/index.js +9 -0
- package/dist/nav/registry.d.ts +15 -0
- package/dist/nav/registry.js +42 -0
- package/dist/nav/resolver.d.ts +8 -0
- package/dist/nav/resolver.js +192 -0
- package/dist/nav/workspace.d.ts +18 -0
- package/dist/nav/workspace.js +103 -0
- package/dist/pipeline/styles.js +7 -35
- package/dist/pipeline/token-transformers.d.ts +45 -0
- package/dist/pipeline/token-transformers.js +71 -0
- package/dist/registry/asset-storage/adapters/vercel-blob.d.ts +17 -0
- package/dist/registry/asset-storage/adapters/vercel-blob.js +87 -0
- package/dist/registry/asset-storage/define.d.ts +10 -0
- package/dist/registry/asset-storage/define.js +13 -0
- package/dist/registry/asset-storage/resolve.d.ts +45 -0
- package/dist/registry/asset-storage/resolve.js +36 -0
- package/dist/registry/asset-storage/types.d.ts +51 -0
- package/dist/registry/asset-storage/types.js +9 -0
- package/dist/registry/assets/layout.d.ts +22 -0
- package/dist/registry/assets/layout.js +30 -0
- package/dist/registry/assets/sets.d.ts +18 -0
- package/dist/registry/assets/sets.js +44 -0
- package/dist/registry/assets/transfer.d.ts +45 -0
- package/dist/registry/assets/transfer.js +11 -0
- package/dist/registry/checkout/assets.d.ts +16 -0
- package/dist/registry/checkout/assets.js +150 -0
- package/dist/registry/checkout/index.d.ts +33 -0
- package/dist/registry/checkout/index.js +610 -0
- package/dist/registry/checkout/tokens.d.ts +15 -0
- package/dist/registry/checkout/tokens.js +171 -0
- package/dist/registry/client.d.ts +61 -0
- package/dist/registry/client.js +211 -0
- package/dist/registry/connection.d.ts +30 -0
- package/dist/registry/connection.js +36 -0
- package/dist/registry/db/adapter.d.ts +43 -0
- package/dist/registry/db/adapter.js +59 -0
- package/dist/registry/db/client.d.ts +35 -0
- package/dist/registry/db/client.js +94 -0
- package/dist/registry/db/index.d.ts +5 -0
- package/dist/registry/db/index.js +24 -0
- package/dist/registry/db/migrate.d.ts +23 -0
- package/dist/registry/db/migrate.js +64 -0
- package/dist/registry/db/schema.d.ts +4869 -0
- package/dist/registry/db/schema.js +347 -0
- package/dist/registry/path.d.ts +4 -0
- package/dist/registry/path.js +31 -0
- package/dist/registry/publish/artifacts.d.ts +16 -0
- package/dist/registry/publish/artifacts.js +132 -0
- package/dist/registry/publish/assets.d.ts +16 -0
- package/dist/registry/publish/assets.js +129 -0
- package/dist/registry/publish/errors.d.ts +5 -0
- package/dist/registry/publish/errors.js +26 -0
- package/dist/registry/publish/index.d.ts +27 -0
- package/dist/registry/publish/index.js +126 -0
- package/dist/registry/publish/package.d.ts +27 -0
- package/dist/registry/publish/package.js +257 -0
- package/dist/registry/publish/publish-build.d.ts +12 -0
- package/dist/registry/publish/publish-build.js +43 -0
- package/dist/registry/publish/tokens.d.ts +18 -0
- package/dist/registry/publish/tokens.js +112 -0
- package/dist/registry/tokens/sets.d.ts +59 -0
- package/dist/registry/tokens/sets.js +109 -0
- package/dist/registry/tokens/transfer.d.ts +48 -0
- package/dist/registry/tokens/transfer.js +10 -0
- package/dist/registry/transfer.d.ts +75 -0
- package/dist/registry/transfer.js +11 -0
- package/dist/store/filesystem-assets.d.ts +17 -0
- package/dist/store/filesystem-assets.js +147 -0
- package/dist/store/filesystem.d.ts +76 -0
- package/dist/store/filesystem.js +208 -0
- package/dist/store/index.d.ts +20 -0
- package/dist/store/index.js +38 -0
- package/dist/store/registry.d.ts +77 -0
- package/dist/store/registry.js +350 -0
- package/dist/store/source-files.d.ts +24 -0
- package/dist/store/source-files.js +147 -0
- package/dist/store/types.d.ts +185 -0
- package/dist/store/types.js +12 -0
- package/dist/transformers/plugins/csf-render.js +17 -8
- package/dist/transformers/plugins/handlebars-previews.js +10 -3
- package/dist/transformers/plugins/ssr-render.js +116 -49
- package/dist/transformers/preview/component/api.js +3 -1
- package/dist/transformers/preview/component/artifacts.js +8 -1
- package/dist/transformers/preview/component/builder.js +13 -5
- package/dist/transformers/preview/component/css.js +9 -1
- package/dist/transformers/preview/component/javascript.d.ts +9 -3
- package/dist/transformers/preview/component/javascript.js +45 -17
- package/dist/transformers/preview/component/shared-artifacts.d.ts +83 -0
- package/dist/transformers/preview/component/shared-artifacts.js +92 -0
- package/dist/transformers/preview/component.js +5 -2
- package/dist/transformers/preview/pattern/builder.js +28 -9
- package/dist/transformers/preview/pattern/html.d.ts +13 -10
- package/dist/transformers/preview/pattern/html.js +62 -27
- package/dist/transformers/preview/types.d.ts +38 -0
- package/dist/transformers/utils/handlebars.d.ts +3 -0
- package/dist/transformers/utils/handlebars.js +19 -5
- package/dist/types/config.d.ts +118 -25
- package/dist/utils/menu-shell.d.ts +60 -0
- package/dist/utils/menu-shell.js +221 -0
- package/dist/utils/stable-stringify.d.ts +2 -0
- package/dist/utils/stable-stringify.js +8 -0
- package/docs/cli.md +4 -2
- package/drizzle/0000_init_registry_storage.sql +95 -0
- package/drizzle/0001_add_review_metadata.sql +2 -0
- package/drizzle/0002_add_pages.sql +28 -0
- package/drizzle/0003_add_tokens.sql +29 -0
- package/drizzle/0004_add_assets.sql +37 -0
- package/drizzle/meta/0000_snapshot.json +642 -0
- package/drizzle/meta/0001_snapshot.json +654 -0
- package/drizzle/meta/0002_snapshot.json +835 -0
- package/drizzle/meta/0003_snapshot.json +1023 -0
- package/drizzle/meta/0004_snapshot.json +1252 -0
- package/drizzle/meta/_journal.json +41 -0
- package/drizzle.config.ts +16 -0
- package/package.json +10 -1
- package/src/app/components/Component/Preview.tsx +3 -2
- package/src/app/components/Component/RegistryActions.tsx +150 -0
- package/src/app/components/Foundations/DisplayLogo.tsx +5 -3
- package/src/app/components/Layout/Header.tsx +21 -3
- package/src/app/components/Layout/Main.tsx +11 -3
- package/src/app/components/Navigation/MainNav.tsx +4 -2
- package/src/app/components/Navigation/MobileNav.tsx +4 -2
- package/src/app/components/Navigation/SideNav.tsx +46 -11
- package/src/app/components/NotFound.tsx +24 -0
- package/src/app/components/context/NavProvider.tsx +71 -0
- package/src/app/components/old/Header.tsx +3 -3
- package/src/app/components/util/index.ts +203 -380
- package/src/app/components/util/useCollectionAssets.ts +125 -0
- package/src/app/components/util/useFoundationTokens.ts +67 -0
- package/src/app/generated/default-pages.json +1 -0
- package/src/app/generated/nav-shell.json +1 -0
- package/src/app/lib/api/query.ts +6 -0
- package/src/app/lib/api/redact.ts +46 -0
- package/src/app/lib/asset-storage.ts +81 -0
- package/src/app/lib/docs-api/artifacts.ts +116 -0
- package/src/app/lib/docs-api/backend.ts +151 -0
- package/src/app/lib/docs-api/errors.ts +52 -0
- package/src/app/lib/docs-api/handler.ts +34 -0
- package/src/app/lib/docs-api/index.ts +7 -0
- package/src/app/lib/docs-api/records.ts +189 -0
- package/src/app/lib/docs-api/registry.ts +130 -0
- package/src/app/lib/docs-api/runtime-config.ts +173 -0
- package/src/app/lib/docs-api/serve.ts +37 -0
- package/src/app/lib/docs-api/token-detail.ts +19 -0
- package/src/app/lib/registry-api/allowlist.ts +163 -0
- package/src/app/lib/registry-api/asset-transfer.ts +363 -0
- package/src/app/lib/registry-api/auth.ts +68 -0
- package/src/app/lib/registry-api/entity-routes.ts +197 -0
- package/src/app/lib/registry-api/errors.ts +51 -0
- package/src/app/lib/registry-api/files.ts +135 -0
- package/src/app/lib/registry-api/handler.ts +96 -0
- package/src/app/lib/registry-api/index.ts +4 -0
- package/src/app/lib/registry-api/meta.ts +87 -0
- package/src/app/lib/registry-api/revalidate.ts +36 -0
- package/src/app/lib/registry-api/store.ts +348 -0
- package/src/app/lib/registry-api/token-transfer.ts +231 -0
- package/src/app/lib/registry-api/transfer.ts +513 -0
- package/src/app/lib/registry-api/validation.ts +74 -0
- package/src/app/lib/registry-connection.ts +58 -0
- package/src/app/lib/utils.ts +14 -0
- package/src/app/next.config.mjs +72 -13
- package/src/app/pages/[...slug]/index.tsx +74 -20
- package/src/app/pages/_app.tsx +5 -2
- package/src/app/pages/api/docs/artifacts/[...artifactPath].ts +16 -0
- package/src/app/pages/api/docs/assets/[collection]/[...path].ts +50 -0
- package/src/app/pages/api/docs/assets/[collection]/index.ts +22 -0
- package/src/app/pages/api/docs/components/[id]/assets/[asset].ts +33 -0
- package/src/app/pages/api/docs/components/[id]/inspect/[previewId].ts +20 -0
- package/src/app/pages/api/docs/components/[id]/previews/[previewId].ts +21 -0
- package/src/app/pages/api/docs/components/[id].ts +24 -0
- package/src/app/pages/api/docs/components.json.ts +12 -0
- package/src/app/pages/api/docs/nav.json.ts +48 -0
- package/src/app/pages/api/docs/patterns/[id]/preview.ts +19 -0
- package/src/app/pages/api/docs/patterns/[id].ts +24 -0
- package/src/app/pages/api/docs/patterns.json.ts +12 -0
- package/src/app/pages/api/docs/tokens/components/[id].ts +30 -0
- package/src/app/pages/api/docs/tokens/foundations/[type].ts +32 -0
- package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +19 -0
- package/src/app/pages/api/registry/components/[id]/files/index.ts +19 -0
- package/src/app/pages/api/registry/components/[id].ts +20 -0
- package/src/app/pages/api/registry/components/index.ts +19 -0
- package/src/app/pages/api/registry/health.ts +20 -0
- package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +19 -0
- package/src/app/pages/api/registry/patterns/[id]/files/index.ts +19 -0
- package/src/app/pages/api/registry/patterns/[id].ts +20 -0
- package/src/app/pages/api/registry/patterns/index.ts +19 -0
- package/src/app/pages/api/registry/transfer/[kind]/[id].ts +39 -0
- package/src/app/pages/api/registry/transfer/assets/[collection].ts +24 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/[hash].ts +23 -0
- package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +11 -0
- package/src/app/pages/api/registry/transfer/assets/index.ts +10 -0
- package/src/app/pages/api/registry/transfer/tokens/[...setId].ts +26 -0
- package/src/app/pages/api/registry/transfer/tokens/index.ts +11 -0
- package/src/app/pages/assets/fonts.tsx +41 -17
- package/src/app/pages/assets/index.tsx +2 -2
- package/src/app/pages/assets/logos.tsx +2 -2
- package/src/app/pages/foundations/colors.tsx +18 -8
- package/src/app/pages/foundations/effects.tsx +18 -8
- package/src/app/pages/foundations/icons/[name]/index.tsx +26 -14
- package/src/app/pages/foundations/icons/index.tsx +13 -9
- package/src/app/pages/foundations/index.tsx +1 -1
- package/src/app/pages/foundations/logo.tsx +7 -4
- package/src/app/pages/foundations/typography.tsx +19 -9
- package/src/app/pages/index.tsx +1 -1
- package/src/app/pages/system/component/[component]/index.tsx +87 -17
- package/src/app/pages/system/index.tsx +13 -4
- package/src/app/pages/system/pattern/[pattern]/index.tsx +70 -14
- package/src/app/pages/system/tokens/components/[component]/index.tsx +42 -14
- package/src/app/pages/system/tokens/foundations/colors.tsx +7 -5
- package/src/app/pages/system/tokens/foundations/effects.tsx +7 -5
- package/src/app/pages/system/tokens/foundations/typography.tsx +8 -4
- package/src/app/tsconfig.json +2 -3
- package/src/app-builder/build.ts +555 -11
- package/src/app-builder/client-config.ts +61 -4
- package/src/app-builder/config-diff/snapshot.ts +1 -11
- package/src/app-builder/index.ts +1 -1
- package/src/app-builder/nav-shell.ts +74 -0
- package/src/app-builder/static-export.ts +215 -0
- package/src/app-builder/vercel-output.ts +297 -0
- package/src/app-builder/watchers/utils.ts +2 -0
- package/src/app-builder/watchers.ts +149 -25
- package/src/app-builder/websocket.ts +2 -2
- package/src/artifacts/README.md +14 -0
- package/src/artifacts/index.ts +17 -0
- package/src/artifacts/types.ts +146 -0
- package/src/artifacts/url.ts +90 -0
- package/src/cache/build-cache.ts +47 -2
- package/src/commands/build/app.ts +1 -2
- package/src/commands/build/index.ts +61 -0
- package/src/commands/checkout/index.ts +66 -0
- package/src/commands/db/migrate.ts +25 -0
- package/src/commands/index.ts +8 -0
- package/src/commands/publish/index.ts +63 -0
- package/src/config/defaults.ts +15 -0
- package/src/config/loader.ts +10 -1
- package/src/config/normalizers/declaration.ts +3 -0
- package/src/config/normalizers/page.ts +45 -0
- package/src/config/normalizers/pattern.ts +4 -1
- package/src/config/runtime.ts +48 -2
- package/src/index.ts +126 -3
- package/src/nav/index.ts +94 -0
- package/src/nav/registry.ts +54 -0
- package/src/nav/resolver.ts +217 -0
- package/src/nav/workspace.ts +87 -0
- package/src/pipeline/styles.ts +4 -35
- package/src/pipeline/token-transformers.ts +97 -0
- package/src/registry/asset-storage/adapters/vercel-blob.ts +51 -0
- package/src/registry/asset-storage/define.ts +15 -0
- package/src/registry/asset-storage/resolve.ts +72 -0
- package/src/registry/asset-storage/types.ts +46 -0
- package/src/registry/assets/layout.ts +38 -0
- package/src/registry/assets/sets.ts +48 -0
- package/src/registry/assets/transfer.ts +50 -0
- package/src/registry/checkout/assets.ts +126 -0
- package/src/registry/checkout/index.ts +596 -0
- package/src/registry/checkout/tokens.ts +152 -0
- package/src/registry/client.ts +234 -0
- package/src/registry/connection.ts +50 -0
- package/src/registry/db/adapter.ts +74 -0
- package/src/registry/db/client.ts +88 -0
- package/src/registry/db/index.ts +35 -0
- package/src/registry/db/migrate.ts +56 -0
- package/src/registry/db/schema.ts +444 -0
- package/src/registry/path.ts +26 -0
- package/src/registry/publish/artifacts.ts +147 -0
- package/src/registry/publish/assets.ts +129 -0
- package/src/registry/publish/errors.ts +34 -0
- package/src/registry/publish/index.ts +128 -0
- package/src/registry/publish/package.ts +272 -0
- package/src/registry/publish/publish-build.ts +51 -0
- package/src/registry/publish/tokens.ts +119 -0
- package/src/registry/tokens/sets.ts +132 -0
- package/src/registry/tokens/transfer.ts +53 -0
- package/src/registry/transfer.ts +82 -0
- package/src/store/filesystem-assets.ts +152 -0
- package/src/store/filesystem.ts +237 -0
- package/src/store/index.ts +62 -0
- package/src/store/registry.ts +334 -0
- package/src/store/source-files.ts +155 -0
- package/src/store/types.ts +210 -0
- package/src/transformers/plugins/csf-render.ts +31 -7
- package/src/transformers/plugins/handlebars-previews.ts +22 -3
- package/src/transformers/plugins/ssr-render.ts +145 -57
- package/src/transformers/preview/component/api.ts +2 -1
- package/src/transformers/preview/component/artifacts.ts +10 -1
- package/src/transformers/preview/component/builder.ts +9 -2
- package/src/transformers/preview/component/css.ts +10 -1
- package/src/transformers/preview/component/javascript.ts +55 -20
- package/src/transformers/preview/component/shared-artifacts.ts +146 -0
- package/src/transformers/preview/component.ts +5 -2
- package/src/transformers/preview/pattern/builder.ts +33 -7
- package/src/transformers/preview/pattern/html.ts +71 -27
- package/src/transformers/preview/types.ts +42 -0
- package/src/transformers/utils/handlebars.ts +31 -5
- package/src/types/config.ts +123 -25
- package/src/utils/menu-shell.ts +241 -0
- package/src/utils/stable-stringify.ts +7 -0
- package/templates/default/package.json.tpl +1 -1
- package/handoff.config.js +0 -90
- package/src/app/components/ComponentSearch.tsx +0 -93
|
@@ -226,3 +226,41 @@ export type PatternListObject = {
|
|
|
226
226
|
id: string;
|
|
227
227
|
path: string;
|
|
228
228
|
} & PatternObject;
|
|
229
|
+
/**
|
|
230
|
+
* A documentation page authored as markdown. The frontmatter is parsed into these fields and the
|
|
231
|
+
* markdown body is the rendered content. Pages are workspace-authored under `<workingPath>/pages/`
|
|
232
|
+
* and are first-class registry entities (publish/checkout) alongside components and patterns. Unlike
|
|
233
|
+
* components/patterns there is no rendered-artifact pipeline: the raw markdown is stored and rendered
|
|
234
|
+
* at runtime.
|
|
235
|
+
*/
|
|
236
|
+
export type PageObject = {
|
|
237
|
+
title: string;
|
|
238
|
+
description?: string;
|
|
239
|
+
group?: string;
|
|
240
|
+
/** Sort weight within the nav section (lower first). */
|
|
241
|
+
weight?: number;
|
|
242
|
+
/** Alternative title used in navigation. */
|
|
243
|
+
menuTitle?: string;
|
|
244
|
+
/** SEO overrides. */
|
|
245
|
+
metaTitle?: string;
|
|
246
|
+
metaDescription?: string;
|
|
247
|
+
/** When `false`, the page is hidden from navigation. */
|
|
248
|
+
enabled?: boolean;
|
|
249
|
+
/** External link target — a URL/path string, or `true` to flag the section as external. */
|
|
250
|
+
external?: string | boolean;
|
|
251
|
+
/** Optional declarative submenu structure (mirrors the markdown frontmatter `menu`). */
|
|
252
|
+
menu?: {
|
|
253
|
+
[key: string]: any;
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
export type PageListObject = {
|
|
257
|
+
/** Stable page id — its slug path (e.g. `guides/setup`), derived from the file location (id ≡ route). */
|
|
258
|
+
id: string;
|
|
259
|
+
/** Logical route the page is served at (e.g. `/guides/setup`). */
|
|
260
|
+
path: string;
|
|
261
|
+
/**
|
|
262
|
+
* Absolute filesystem path of the source `.md` (workspace store only). Workspace-only and stripped
|
|
263
|
+
* from the published transfer item — never persisted to or served from the registry.
|
|
264
|
+
*/
|
|
265
|
+
sourcePath?: string;
|
|
266
|
+
} & PageObject;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RegisterHandlebarsHelpersContext } from '../../types/config';
|
|
2
2
|
import { SlotMetadata } from '../preview/component';
|
|
3
|
+
import { type ComponentArtifactPresence, type SharedArtifactPresence } from '../preview/component/shared-artifacts';
|
|
3
4
|
import { HandlebarsContext } from '../types';
|
|
4
5
|
/**
|
|
5
6
|
* Registers common Handlebars helpers, then runs optional `hooks.registerHandlebarsHelpers`.
|
|
@@ -29,4 +30,6 @@ export declare const createHandlebarsContext: (data: {
|
|
|
29
30
|
values?: any;
|
|
30
31
|
}, options?: {
|
|
31
32
|
includeSharedStyles?: boolean;
|
|
33
|
+
sharedArtifacts?: SharedArtifactPresence;
|
|
34
|
+
componentArtifacts?: ComponentArtifactPresence;
|
|
32
35
|
}) => HandlebarsContext;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.createHandlebarsContext = exports.registerHandlebarsHelpers = void 0;
|
|
7
7
|
const handlebars_1 = __importDefault(require("handlebars"));
|
|
8
8
|
const logger_1 = require("../../utils/logger");
|
|
9
|
+
const shared_artifacts_1 = require("../preview/component/shared-artifacts");
|
|
9
10
|
/**
|
|
10
11
|
* Registers common Handlebars helpers, then runs optional `hooks.registerHandlebarsHelpers`.
|
|
11
12
|
* @param data - Component data containing properties
|
|
@@ -66,14 +67,27 @@ exports.registerHandlebarsHelpers = registerHandlebarsHelpers;
|
|
|
66
67
|
* @returns Handlebars context object
|
|
67
68
|
*/
|
|
68
69
|
const createHandlebarsContext = (data, previewData, options) => {
|
|
69
|
-
var _a;
|
|
70
|
+
var _a, _b, _c;
|
|
70
71
|
const basePath = (_a = process.env.HANDOFF_APP_BASE_PATH) !== null && _a !== void 0 ? _a : '';
|
|
71
|
-
|
|
72
|
+
// Shared/global artifacts (`component/shared.css`, `component/main.css`, `component/main.js`) and
|
|
73
|
+
// the component's own css/js are referenced only when present, so a failed/absent build never
|
|
74
|
+
// produces a dangling reference. Absent presence info conservatively omits the artifacts.
|
|
75
|
+
const presence = (_b = options === null || options === void 0 ? void 0 : options.sharedArtifacts) !== null && _b !== void 0 ? _b : { mainJs: false, mainCss: false, sharedCss: false };
|
|
76
|
+
const componentPresence = (_c = options === null || options === void 0 ? void 0 : options.componentArtifacts) !== null && _c !== void 0 ? _c : { css: false, js: false };
|
|
77
|
+
const sharedStyleLinks = (0, shared_artifacts_1.renderSharedStyleLinks)(presence, basePath, {
|
|
78
|
+
includeSharedStyles: options === null || options === void 0 ? void 0 : options.includeSharedStyles,
|
|
79
|
+
});
|
|
80
|
+
const componentStyleLink = (0, shared_artifacts_1.renderComponentStyleLink)(componentPresence, data.id, basePath);
|
|
81
|
+
// The global script loads before the component-specific script so global side effects run first.
|
|
82
|
+
const globalScriptTag = (0, shared_artifacts_1.renderGlobalScriptTag)(presence, basePath);
|
|
83
|
+
const componentScriptTag = (0, shared_artifacts_1.renderComponentScriptTag)(componentPresence, data.id, basePath);
|
|
72
84
|
return {
|
|
73
|
-
style: `${
|
|
74
|
-
|
|
85
|
+
style: `${sharedStyleLinks ? `${sharedStyleLinks}\n` : ''}` +
|
|
86
|
+
`${componentStyleLink ? `${componentStyleLink}\n` : ''}` +
|
|
75
87
|
`<link rel="stylesheet" href="${basePath}/assets/css/preview.css">`,
|
|
76
|
-
script:
|
|
88
|
+
script: `${globalScriptTag ? `${globalScriptTag}\n` : ''}` +
|
|
89
|
+
`${componentScriptTag ? `${componentScriptTag}\n` : ''}` +
|
|
90
|
+
`<script src="${basePath}/assets/js/preview.js"></script><script>var fields = ${JSON.stringify(data.properties)};</script>`,
|
|
77
91
|
properties: previewData.values || {},
|
|
78
92
|
fields: data.properties,
|
|
79
93
|
title: data.title,
|
package/dist/types/config.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type Handlebars from 'handlebars';
|
|
|
3
3
|
import { Types as HandoffTypes } from 'handoff-core';
|
|
4
4
|
import { InlineConfig } from 'vite';
|
|
5
5
|
import { SlotMetadata } from '../transformers/preview/component';
|
|
6
|
-
import { ComponentListObject, PatternListObject, TransformComponentTokensResult } from '../transformers/preview/types';
|
|
6
|
+
import { ComponentListObject, PageListObject, PatternListObject, TransformComponentTokensResult } from '../transformers/preview/types';
|
|
7
7
|
import { ValidationResult } from './preview';
|
|
8
8
|
export interface ImageStyle {
|
|
9
9
|
name: string;
|
|
@@ -84,6 +84,98 @@ export interface NextAppConfig {
|
|
|
84
84
|
websocket: number;
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Configuration for entry points to assets and components that will be built.
|
|
89
|
+
*/
|
|
90
|
+
export interface ConfigEntries {
|
|
91
|
+
/**
|
|
92
|
+
* Path to the main SCSS entry file
|
|
93
|
+
* @example "styles/main.scss"
|
|
94
|
+
*/
|
|
95
|
+
scss?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Path to the main JavaScript entry file
|
|
98
|
+
* @example "scripts/main.js"
|
|
99
|
+
*/
|
|
100
|
+
js?: string;
|
|
101
|
+
/**
|
|
102
|
+
* Array of component paths to be included in the build
|
|
103
|
+
* @example ["components/button", "components/input"]
|
|
104
|
+
*/
|
|
105
|
+
components?: string[];
|
|
106
|
+
/**
|
|
107
|
+
* Array of pattern paths to be included in the build.
|
|
108
|
+
* Patterns compose multiple component previews into single-page views.
|
|
109
|
+
* @example ["patterns/hero-section", "patterns"]
|
|
110
|
+
*/
|
|
111
|
+
patterns?: string[];
|
|
112
|
+
}
|
|
113
|
+
/** Runtime mode. Resolved solely from `runtime.mode`; never inferred from env vars or connection settings. */
|
|
114
|
+
export type RuntimeMode = 'workspace' | 'registry';
|
|
115
|
+
/** Format used when synthesizing local workspace declarations. */
|
|
116
|
+
export type DeclarationFormat = 'ts' | 'js' | 'cjs' | 'json';
|
|
117
|
+
/**
|
|
118
|
+
* User-facing `runtime` configuration block. A single optional block that selects the runtime
|
|
119
|
+
* mode and carries mode-specific host/connection settings.
|
|
120
|
+
*
|
|
121
|
+
* Note: this is the authored shape. {@link RuntimeConfig} is the separate, resolved post-discovery
|
|
122
|
+
* shape used internally by the build/runtime.
|
|
123
|
+
*/
|
|
124
|
+
export interface HandoffRuntimeConfig {
|
|
125
|
+
/**
|
|
126
|
+
* The sole determinant of runtime mode. Defaults to `'workspace'` when omitted.
|
|
127
|
+
* Mode is never inferred from environment variables, database settings, or token presence.
|
|
128
|
+
*/
|
|
129
|
+
mode?: RuntimeMode;
|
|
130
|
+
/** Workspace-mode settings. */
|
|
131
|
+
workspace?: {
|
|
132
|
+
entries?: ConfigEntries;
|
|
133
|
+
declarationFormat?: DeclarationFormat;
|
|
134
|
+
};
|
|
135
|
+
/** Registry-mode host settings. Env-var values are stored as names, never as secrets. */
|
|
136
|
+
registry?: {
|
|
137
|
+
/** Name of the env var holding the database URL. @default "DATABASE_URL" */
|
|
138
|
+
databaseUrlEnv?: string;
|
|
139
|
+
/** Name of the env var holding the registry API token. @default "HANDOFF_REGISTRY_API_TOKEN" */
|
|
140
|
+
apiTokenEnv?: string;
|
|
141
|
+
database?: {
|
|
142
|
+
/** @default "pg" */
|
|
143
|
+
adapter?: 'pg' | 'neon';
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Where published asset blobs (icons/logos/fonts/sprites/archives) are stored. Defaults to the
|
|
147
|
+
* built-in PostgreSQL `bytea` store when omitted. Secrets are never persisted here - only the
|
|
148
|
+
* *names* of the env vars their values are read from at request time.
|
|
149
|
+
*/
|
|
150
|
+
assetStorage?: {
|
|
151
|
+
/**
|
|
152
|
+
* Active storage provider for new uploads. `database` keeps bytes inline in Postgres; use the
|
|
153
|
+
* pre-packaged `vercel-blob` adapter or a `custom` module for object storage.
|
|
154
|
+
* @default "database"
|
|
155
|
+
*/
|
|
156
|
+
adapter?: 'database' | 'vercel-blob' | 'custom';
|
|
157
|
+
/** For `adapter: "custom"` - server-only module path default-exporting a `defineAssetStorage` adapter. */
|
|
158
|
+
module?: string;
|
|
159
|
+
/** For `adapter: "vercel-blob"` - env var name holding the Blob read/write token. @default "BLOB_READ_WRITE_TOKEN" */
|
|
160
|
+
tokenEnv?: string;
|
|
161
|
+
/** Max bytes kept inline in the database `bytea` column (larger uploads are rejected). @default 4194304 */
|
|
162
|
+
maxInlineBytes?: number;
|
|
163
|
+
/** Non-secret adapter options (bucket env-var names, region, a custom `providerId`, …). */
|
|
164
|
+
options?: Record<string, unknown>;
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Connected-workspace settings pointing at a remote registry. A connected workspace is
|
|
169
|
+
* `mode: 'workspace'` plus this block — it is not a third runtime mode.
|
|
170
|
+
*/
|
|
171
|
+
registryConnection?: {
|
|
172
|
+
url?: string;
|
|
173
|
+
/** @default "HANDOFF_REGISTRY_URL" */
|
|
174
|
+
urlEnv?: string;
|
|
175
|
+
/** @default "HANDOFF_REGISTRY_ACCESS_TOKEN" */
|
|
176
|
+
accessTokenEnv?: string;
|
|
177
|
+
};
|
|
178
|
+
}
|
|
87
179
|
export interface Config {
|
|
88
180
|
dev_access_token?: string | null | undefined;
|
|
89
181
|
devAccessToken?: string | null | undefined;
|
|
@@ -112,32 +204,15 @@ export interface Config {
|
|
|
112
204
|
* Configuration for the build pipeline
|
|
113
205
|
*/
|
|
114
206
|
pipeline?: PipelineConfig;
|
|
207
|
+
/**
|
|
208
|
+
* Runtime configuration. `runtime.mode` is the sole determinant of runtime mode
|
|
209
|
+
* (`workspace` | `registry`), defaulting to `workspace` when omitted.
|
|
210
|
+
*/
|
|
211
|
+
runtime?: HandoffRuntimeConfig;
|
|
115
212
|
/**
|
|
116
213
|
* Configuration for entry points to assets and components that will be built
|
|
117
214
|
*/
|
|
118
|
-
entries?:
|
|
119
|
-
/**
|
|
120
|
-
* Path to the main SCSS entry file
|
|
121
|
-
* @example "styles/main.scss"
|
|
122
|
-
*/
|
|
123
|
-
scss?: string;
|
|
124
|
-
/**
|
|
125
|
-
* Path to the main JavaScript entry file
|
|
126
|
-
* @example "scripts/main.js"
|
|
127
|
-
*/
|
|
128
|
-
js?: string;
|
|
129
|
-
/**
|
|
130
|
-
* Array of component paths to be included in the build
|
|
131
|
-
* @example ["components/button", "components/input"]
|
|
132
|
-
*/
|
|
133
|
-
components?: string[];
|
|
134
|
-
/**
|
|
135
|
-
* Array of pattern paths to be included in the build.
|
|
136
|
-
* Patterns compose multiple component previews into single-page views.
|
|
137
|
-
* @example ["patterns/hero-section", "patterns"]
|
|
138
|
-
*/
|
|
139
|
-
patterns?: string[];
|
|
140
|
-
};
|
|
215
|
+
entries?: ConfigEntries;
|
|
141
216
|
/**
|
|
142
217
|
* Configuration for asset zip file download links
|
|
143
218
|
* @default { icons: "/icons.zip", logos: "/logos.zip" }
|
|
@@ -283,7 +358,22 @@ export interface Config {
|
|
|
283
358
|
registerHandlebarsHelpers?: (context: RegisterHandlebarsHelpersContext) => void;
|
|
284
359
|
};
|
|
285
360
|
}
|
|
286
|
-
|
|
361
|
+
/**
|
|
362
|
+
* Non-secret runtime values projected to the browser. Only the resolved {@link RuntimeMode}
|
|
363
|
+
* crosses to the client; secrets and connection values never do.
|
|
364
|
+
*/
|
|
365
|
+
export interface ClientRuntimeConfig {
|
|
366
|
+
mode: RuntimeMode;
|
|
367
|
+
/**
|
|
368
|
+
* True when the runtime is a connected workspace (`mode: 'workspace'` plus a resolvable
|
|
369
|
+
* `registryConnection` URL). Non-secret: it never carries the URL or token value, only whether a
|
|
370
|
+
* connection is configured. Drives the workspace-only publish affordance in the docs UI.
|
|
371
|
+
*/
|
|
372
|
+
connected: boolean;
|
|
373
|
+
}
|
|
374
|
+
export type ClientConfig = Pick<Config, 'app' | 'exportsOutputDirectory' | 'sitesOutputDirectory' | 'assets_zip_links' | 'useVariables'> & {
|
|
375
|
+
runtime: ClientRuntimeConfig;
|
|
376
|
+
};
|
|
287
377
|
export interface RuntimeConfigComponentOptions {
|
|
288
378
|
cssRootClass?: string;
|
|
289
379
|
tokenNameSegments?: string[];
|
|
@@ -311,6 +401,9 @@ export interface RuntimeConfig {
|
|
|
311
401
|
patterns: {
|
|
312
402
|
[id: string]: PatternListObject;
|
|
313
403
|
};
|
|
404
|
+
pages: {
|
|
405
|
+
[id: string]: PageListObject;
|
|
406
|
+
};
|
|
314
407
|
};
|
|
315
408
|
options: {
|
|
316
409
|
[key: string]: RuntimeConfigComponentOptions;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { NavMenuItem, NavSubSection, SectionLink } from '../nav';
|
|
2
|
+
/**
|
|
3
|
+
* Build-time menu *shell* builder.
|
|
4
|
+
*
|
|
5
|
+
* The docs navigation is two things: a SHELL (which sections exist, their order/titles, and which
|
|
6
|
+
* submenu slots are filled at runtime from the registry) and the runtime ENTITY lists
|
|
7
|
+
* (components/patterns/token sets) that the resolver splices into those slots. The shell is
|
|
8
|
+
* markdown-driven and therefore static per build; the entities are mutable at runtime and the
|
|
9
|
+
* resolved tree is served by `/api/docs/nav.json`.
|
|
10
|
+
*
|
|
11
|
+
* On Vercel the registry function cannot read `config/docs` markdown at request time — those reads
|
|
12
|
+
* use absolute build-machine paths (`HANDOFF_MODULE_PATH/...`) that do not exist on the deploy host
|
|
13
|
+
* and that nft cannot trace. So the shell is frozen here at build time (where the markdown is
|
|
14
|
+
* present) into `generated/nav-shell.json`, which the API route imports statically (bundled, path
|
|
15
|
+
* independent). The resolver combines it with runtime-variable records before the client renders it.
|
|
16
|
+
*
|
|
17
|
+
* This module is intentionally dependency-light and PURE (fs + gray-matter, no DB, no React, no
|
|
18
|
+
* `@handoff` aliases) so the compiled build pipeline (`dist/`) can import it — `src/app` is excluded
|
|
19
|
+
* from `tsc` and is not importable from the builder.
|
|
20
|
+
*
|
|
21
|
+
* It emits the canonical section structure with empty entity lists and `dynamic` splice markers.
|
|
22
|
+
* `src/nav/resolver.ts` is the sole place that fills those markers in every runtime mode.
|
|
23
|
+
*/
|
|
24
|
+
/** Back-compatible shell-builder names reconciled to the canonical navigation contract. */
|
|
25
|
+
export type MenuShellSubItem = NavMenuItem;
|
|
26
|
+
export type MenuShellSubSection = NavSubSection;
|
|
27
|
+
export type MenuShellSection = SectionLink;
|
|
28
|
+
export interface BuildMenuShellOptions {
|
|
29
|
+
/** Absolute path to the package docs root (`<modulePath>/config/docs`). */
|
|
30
|
+
docRoot: string;
|
|
31
|
+
/** Absolute path to the working-project page overrides (`<workingPath>/pages`), optional. */
|
|
32
|
+
workingPagesDir?: string;
|
|
33
|
+
/** Resolved app base path (e.g. `"foundations"` → no leading/trailing slash), optional. */
|
|
34
|
+
basePath?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Paths that have dedicated route files and are therefore excluded from auto-scanned submenus.
|
|
38
|
+
* Single source of truth — the docs app imports this (re-exported there as `knownPaths`).
|
|
39
|
+
*/
|
|
40
|
+
export declare const KNOWN_PATHS: string[];
|
|
41
|
+
/**
|
|
42
|
+
* The static Tokens submenu (Foundations only). Component token sets are mode-resolved runtime
|
|
43
|
+
* records, so the shell bakes only the deterministic Foundations entries. The resolver appends the
|
|
44
|
+
* component token-set records when it fills the dynamic slot. `basePath` must already be
|
|
45
|
+
* `"prefix/"`-normalized.
|
|
46
|
+
*/
|
|
47
|
+
export declare const buildTokensFoundationsMenu: (basePath: string) => MenuShellSubItem[];
|
|
48
|
+
/**
|
|
49
|
+
* Recursively build menu entries from .md files in a directory (auto-scan for sections that do not
|
|
50
|
+
* declare a `menu` in frontmatter). Shared with the app — single source of truth for the auto-scan.
|
|
51
|
+
*/
|
|
52
|
+
export declare const buildMenuFromDirectory: (dirPath: string, urlPrefix: string) => MenuShellSubItem[];
|
|
53
|
+
/**
|
|
54
|
+
* Build the full navigation shell from the docs markdown, with all registry entity slots
|
|
55
|
+
* (components/patterns/token sets) emitted empty and tagged `dynamic` for the resolver to fill.
|
|
56
|
+
*
|
|
57
|
+
* Returns the top-level `MenuShellSection[]` sorted by weight — the same shape the docs app's
|
|
58
|
+
* `SectionLink[]` uses, so it serializes directly into `generated/nav-shell.json`.
|
|
59
|
+
*/
|
|
60
|
+
export declare const buildMenuShell: (options: BuildMenuShellOptions) => MenuShellSection[];
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.buildMenuShell = exports.buildMenuFromDirectory = exports.buildTokensFoundationsMenu = exports.KNOWN_PATHS = void 0;
|
|
30
|
+
const fs = __importStar(require("fs"));
|
|
31
|
+
const gray_matter_1 = __importDefault(require("gray-matter"));
|
|
32
|
+
const lodash_1 = require("lodash");
|
|
33
|
+
const path_1 = __importDefault(require("path"));
|
|
34
|
+
/**
|
|
35
|
+
* Paths that have dedicated route files and are therefore excluded from auto-scanned submenus.
|
|
36
|
+
* Single source of truth — the docs app imports this (re-exported there as `knownPaths`).
|
|
37
|
+
*/
|
|
38
|
+
exports.KNOWN_PATHS = [
|
|
39
|
+
'assets',
|
|
40
|
+
'assets/fonts',
|
|
41
|
+
'assets/icons',
|
|
42
|
+
'assets/logos',
|
|
43
|
+
'foundations',
|
|
44
|
+
'foundations/colors',
|
|
45
|
+
'foundations/icons',
|
|
46
|
+
'foundations/effects',
|
|
47
|
+
'foundations/logos',
|
|
48
|
+
'foundations/logo',
|
|
49
|
+
'foundations/typography',
|
|
50
|
+
'system',
|
|
51
|
+
'system/component',
|
|
52
|
+
'system/tokens',
|
|
53
|
+
'system/tokens/foundations',
|
|
54
|
+
'system/tokens/foundations/colors',
|
|
55
|
+
'system/tokens/foundations/effects',
|
|
56
|
+
'system/tokens/foundations/typography',
|
|
57
|
+
'system/tokens/components',
|
|
58
|
+
'system/pattern',
|
|
59
|
+
];
|
|
60
|
+
/** Normalize the base path to the resolver's `"prefix/"` form (or `""`). */
|
|
61
|
+
const normalizeBasePath = (basePath) => {
|
|
62
|
+
if (!basePath) {
|
|
63
|
+
return '';
|
|
64
|
+
}
|
|
65
|
+
return basePath.replace(/^\/+|\/+$/g, '') + '/';
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* The static Tokens submenu (Foundations only). Component token sets are mode-resolved runtime
|
|
69
|
+
* records, so the shell bakes only the deterministic Foundations entries. The resolver appends the
|
|
70
|
+
* component token-set records when it fills the dynamic slot. `basePath` must already be
|
|
71
|
+
* `"prefix/"`-normalized.
|
|
72
|
+
*/
|
|
73
|
+
const buildTokensFoundationsMenu = (basePath) => [
|
|
74
|
+
{
|
|
75
|
+
title: 'Foundations',
|
|
76
|
+
path: `${basePath}system/tokens/foundations`,
|
|
77
|
+
menu: [
|
|
78
|
+
{ title: 'Colors', path: `${basePath}system/tokens/foundations/colors` },
|
|
79
|
+
{ title: 'Effects', path: `${basePath}system/tokens/foundations/effects` },
|
|
80
|
+
{ title: 'Typography', path: `${basePath}system/tokens/foundations/typography` },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
exports.buildTokensFoundationsMenu = buildTokensFoundationsMenu;
|
|
85
|
+
/**
|
|
86
|
+
* Recursively build menu entries from .md files in a directory (auto-scan for sections that do not
|
|
87
|
+
* declare a `menu` in frontmatter). Shared with the app — single source of truth for the auto-scan.
|
|
88
|
+
*/
|
|
89
|
+
const buildMenuFromDirectory = (dirPath, urlPrefix) => {
|
|
90
|
+
var _a, _b, _c;
|
|
91
|
+
if (!fs.existsSync(dirPath))
|
|
92
|
+
return [];
|
|
93
|
+
const entries = fs.readdirSync(dirPath);
|
|
94
|
+
const items = [];
|
|
95
|
+
for (const entry of entries) {
|
|
96
|
+
const fullPath = path_1.default.join(dirPath, entry);
|
|
97
|
+
if (fs.lstatSync(fullPath).isDirectory()) {
|
|
98
|
+
const nestedItems = (0, exports.buildMenuFromDirectory)(fullPath, `${urlPrefix}/${entry}`);
|
|
99
|
+
if (nestedItems.length > 0) {
|
|
100
|
+
items.push({ title: (0, lodash_1.startCase)(entry), path: `${urlPrefix}/${entry}`, menu: nestedItems });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (entry.endsWith('.md') && entry !== 'index.md') {
|
|
104
|
+
const slug = entry.replace('.md', '');
|
|
105
|
+
const fullSlugPath = `${urlPrefix}/${slug}`.replace(/^\/+/, '');
|
|
106
|
+
if (exports.KNOWN_PATHS.indexOf(fullSlugPath) >= 0)
|
|
107
|
+
continue;
|
|
108
|
+
const contents = fs.readFileSync(fullPath, 'utf-8');
|
|
109
|
+
const { data: metadata } = (0, gray_matter_1.default)(contents);
|
|
110
|
+
if (metadata.enabled === false)
|
|
111
|
+
continue;
|
|
112
|
+
items.push({
|
|
113
|
+
title: (_b = (_a = metadata.menuTitle) !== null && _a !== void 0 ? _a : metadata.title) !== null && _b !== void 0 ? _b : (0, lodash_1.startCase)(slug),
|
|
114
|
+
path: `/${fullSlugPath}`,
|
|
115
|
+
weight: (_c = metadata.weight) !== null && _c !== void 0 ? _c : 0,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return items.sort((a, b) => { var _a, _b; return ((_a = a.weight) !== null && _a !== void 0 ? _a : 0) - ((_b = b.weight) !== null && _b !== void 0 ? _b : 0); });
|
|
120
|
+
};
|
|
121
|
+
exports.buildMenuFromDirectory = buildMenuFromDirectory;
|
|
122
|
+
/**
|
|
123
|
+
* Build the full navigation shell from the docs markdown, with all registry entity slots
|
|
124
|
+
* (components/patterns/token sets) emitted empty and tagged `dynamic` for the resolver to fill.
|
|
125
|
+
*
|
|
126
|
+
* Returns the top-level `MenuShellSection[]` sorted by weight — the same shape the docs app's
|
|
127
|
+
* `SectionLink[]` uses, so it serializes directly into `generated/nav-shell.json`.
|
|
128
|
+
*/
|
|
129
|
+
const buildMenuShell = (options) => {
|
|
130
|
+
var _a, _b, _c;
|
|
131
|
+
const { docRoot, workingPagesDir } = options;
|
|
132
|
+
const basePath = normalizeBasePath(options.basePath);
|
|
133
|
+
if (!fs.existsSync(docRoot)) {
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
const docFiles = fs.readdirSync(docRoot);
|
|
137
|
+
let pageFiles = [];
|
|
138
|
+
if (workingPagesDir && fs.existsSync(workingPagesDir)) {
|
|
139
|
+
pageFiles = fs.readdirSync(workingPagesDir);
|
|
140
|
+
}
|
|
141
|
+
// De-duplicate; working-project pages win over package docs (same as the app).
|
|
142
|
+
const list = Array.from(new Set([...docFiles, ...pageFiles]));
|
|
143
|
+
const sections = [];
|
|
144
|
+
for (const fileName of list) {
|
|
145
|
+
const fromPages = pageFiles.includes(fileName);
|
|
146
|
+
const search = fromPages ? path_1.default.resolve(workingPagesDir, fileName) : path_1.default.resolve(docRoot, fileName);
|
|
147
|
+
if (fs.lstatSync(search).isDirectory() ||
|
|
148
|
+
search === path_1.default.resolve(docRoot, 'index.md') ||
|
|
149
|
+
(workingPagesDir && search === path_1.default.resolve(workingPagesDir, 'index.md')) ||
|
|
150
|
+
!fileName.endsWith('md')) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const contents = fs.readFileSync(search, 'utf-8');
|
|
154
|
+
const { data: metadata } = (0, gray_matter_1.default)(contents);
|
|
155
|
+
if (metadata.enabled === false) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const filepath = `/${fileName.replace('.md', '')}`;
|
|
159
|
+
const subSections = [];
|
|
160
|
+
if (metadata.menu) {
|
|
161
|
+
for (const key of Object.keys(metadata.menu)) {
|
|
162
|
+
const sub = metadata.menu[key];
|
|
163
|
+
if (sub.components) {
|
|
164
|
+
// Omit `type` entirely when there is no filter (`undefined` is not JSON-serializable).
|
|
165
|
+
const dynamic = typeof sub.components === 'string'
|
|
166
|
+
? { kind: 'components', type: sub.components }
|
|
167
|
+
: { kind: 'components' };
|
|
168
|
+
subSections.push({ title: sub.title, menu: [], dynamic });
|
|
169
|
+
}
|
|
170
|
+
else if (sub.tokens) {
|
|
171
|
+
// Foundations are baked (deterministic); the resolver appends published component token
|
|
172
|
+
// sets into this slot when it builds the refreshed registry tree.
|
|
173
|
+
subSections.push({ title: 'Tokens', menu: (0, exports.buildTokensFoundationsMenu)(basePath), dynamic: { kind: 'token-components' } });
|
|
174
|
+
}
|
|
175
|
+
else if (sub.patterns) {
|
|
176
|
+
// Always keep the empty patterns slot in the shell for the resolver to fill on refresh.
|
|
177
|
+
subSections.push({ title: sub.title || 'Patterns', menu: [], dynamic: { kind: 'patterns' } });
|
|
178
|
+
}
|
|
179
|
+
else if (sub.enabled !== false) {
|
|
180
|
+
subSections.push(sub);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
// No frontmatter menu: auto-scan the matching directory (working pages win over docs).
|
|
186
|
+
const dirName = fileName.replace('.md', '');
|
|
187
|
+
const nestedFromDocs = (0, exports.buildMenuFromDirectory)(path_1.default.resolve(docRoot, dirName), `/${dirName}`);
|
|
188
|
+
const nestedFromPages = workingPagesDir
|
|
189
|
+
? (0, exports.buildMenuFromDirectory)(path_1.default.resolve(workingPagesDir, dirName), `/${dirName}`)
|
|
190
|
+
: [];
|
|
191
|
+
const seenPaths = new Set();
|
|
192
|
+
const children = [];
|
|
193
|
+
for (const item of [...nestedFromPages, ...nestedFromDocs]) {
|
|
194
|
+
if (item.path && !seenPaths.has(item.path)) {
|
|
195
|
+
seenPaths.add(item.path);
|
|
196
|
+
children.push(item);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Wrap the scanned children under one labeled group (no `path`) so the side nav renders them as
|
|
200
|
+
// links — a flat subsection carrying a `path` but no `menu` renders nothing. This matches the
|
|
201
|
+
// record-backed nesting produced by the resolver so all modes remain structurally identical.
|
|
202
|
+
if (children.length > 0) {
|
|
203
|
+
subSections.push({ title: (_a = metadata.menuTitle) !== null && _a !== void 0 ? _a : metadata.title, menu: children });
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
let external = false;
|
|
207
|
+
if (typeof metadata.external === 'string' &&
|
|
208
|
+
(metadata.external.startsWith('http://') || metadata.external.startsWith('https://') || metadata.external.startsWith('/'))) {
|
|
209
|
+
external = metadata.external;
|
|
210
|
+
}
|
|
211
|
+
sections.push({
|
|
212
|
+
title: (_b = metadata.menuTitle) !== null && _b !== void 0 ? _b : metadata.title,
|
|
213
|
+
external,
|
|
214
|
+
weight: (_c = metadata.weight) !== null && _c !== void 0 ? _c : 0,
|
|
215
|
+
path: filepath,
|
|
216
|
+
subSections,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
return sections.sort((a, b) => a.weight - b.weight);
|
|
220
|
+
};
|
|
221
|
+
exports.buildMenuShell = buildMenuShell;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stableStringify = void 0;
|
|
4
|
+
/** Serialize a value with object keys sorted at every nesting level. */
|
|
5
|
+
const stableStringify = (value) => JSON.stringify(value, (_, nestedValue) => nestedValue && typeof nestedValue === 'object' && !Array.isArray(nestedValue)
|
|
6
|
+
? Object.fromEntries(Object.entries(nestedValue).sort(([left], [right]) => left.localeCompare(right)))
|
|
7
|
+
: nestedValue);
|
|
8
|
+
exports.stableStringify = stableStringify;
|
package/docs/cli.md
CHANGED
|
@@ -51,11 +51,13 @@ Usage: handoff-app <cmd> <opts>
|
|
|
51
51
|
Commands:
|
|
52
52
|
fetch [opts] - Fetches the design tokens from the design system
|
|
53
53
|
|
|
54
|
-
build -
|
|
55
|
-
build:app [opts] - Builds the design system static application
|
|
54
|
+
build [--target static|registry] [opts] - Builds the design system for the target (default: static export)
|
|
55
|
+
build:app [opts] - Builds the design system static application (alias of `build --target static`)
|
|
56
56
|
|
|
57
57
|
start [opts] - Starts the design system in development mode
|
|
58
58
|
|
|
59
|
+
db:migrate [opts] - Runs registry database migrations (Drizzle / PostgreSQL). Reads the project config and database env vars, applies the package-owned migration set, and runs independently of `build`.
|
|
60
|
+
|
|
59
61
|
make
|
|
60
62
|
make:template <component> <state> [opts] - Creates a new template
|
|
61
63
|
make:page <component> <state> [opts] - Creates a new page
|