@storyshelf/core 0.1.3 → 0.3.2
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 +50 -46
- package/dist/adapter/auth.d.mts +4 -4
- package/dist/adapter/auth.mjs.map +1 -1
- package/dist/{adapters → adapter}/capture-queue.d.mts +4 -4
- package/dist/adapter/capture-queue.mjs +4 -0
- package/dist/adapter/capture-runner.d.mts +7 -7
- package/dist/adapter/database.d.mts +20 -9
- package/dist/adapter/database.mjs +60 -1
- package/dist/adapter/database.mjs.map +1 -0
- package/dist/adapter/git-host/comments.d.mts +41 -0
- package/dist/adapter/git-host/comments.mjs +54 -0
- package/dist/adapter/git-host/comments.mjs.map +1 -0
- package/dist/adapter/git-host.d.mts +3 -7
- package/dist/adapter/init.d.mts +58 -0
- package/dist/adapter/init.mjs +93 -0
- package/dist/adapter/init.mjs.map +1 -0
- package/dist/adapter/metadata.d.mts +83 -0
- package/dist/adapter/metadata.mjs +4 -0
- package/dist/adapter/storage.d.mts +15 -4
- package/dist/adapters/webhook-events.mjs +12 -4
- package/dist/adapters/webhook-events.mjs.map +1 -1
- package/dist/capture/adapter.d.mts +5 -1
- package/dist/capture/dispatch.mjs +150 -0
- package/dist/capture/dispatch.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +2 -0
- package/dist/capture/orchestrator.mjs +5 -44
- package/dist/capture/orchestrator.mjs.map +1 -1
- package/dist/capture/pipeline.d.mts +4 -1
- package/dist/capture/pipeline.mjs +6 -6
- package/dist/capture/pipeline.mjs.map +1 -1
- package/dist/capture/queue.d.mts +2 -1
- package/dist/capture/queue.mjs +2 -1
- package/dist/capture/queue.mjs.map +1 -1
- package/dist/capture/skip-checks.mjs +76 -0
- package/dist/capture/skip-checks.mjs.map +1 -0
- package/dist/capture/statics.mjs +124 -0
- package/dist/capture/statics.mjs.map +1 -0
- package/dist/capture/status-fanout.mjs.map +1 -1
- package/dist/capture/storybook.mjs.map +1 -1
- package/dist/capture.d.mts +8 -0
- package/dist/capture.mjs +9 -0
- package/dist/config.d.mts +10 -2
- package/dist/config.mjs +14 -2
- package/dist/config.mjs.map +1 -1
- package/dist/ddl.d.mts +1 -1
- package/dist/ddl.mjs +1 -1
- package/dist/ddl.mjs.map +1 -1
- package/dist/diff/engine.mjs.map +1 -1
- package/dist/diff/options.d.mts +3 -1
- package/dist/diff.d.mts +5 -0
- package/dist/diff.mjs +6 -0
- package/dist/index.d.mts +32 -25
- package/dist/index.mjs +207 -253
- package/dist/index.mjs.map +1 -1
- package/dist/logger.d.mts +3 -3
- package/dist/middleware/auth-gate.mjs +36 -0
- package/dist/middleware/auth-gate.mjs.map +1 -0
- package/dist/middleware/csrf.mjs.map +1 -1
- package/dist/middleware/request-log.mjs +28 -0
- package/dist/middleware/request-log.mjs.map +1 -0
- package/dist/middleware/store-scope.mjs +29 -0
- package/dist/middleware/store-scope.mjs.map +1 -0
- package/dist/models/baseline.mjs +7 -5
- package/dist/models/baseline.mjs.map +1 -1
- package/dist/models/build.mjs +3 -1
- package/dist/models/build.mjs.map +1 -1
- package/dist/models/comment.mjs +2 -1
- package/dist/models/comment.mjs.map +1 -1
- package/dist/models/label.mjs +2 -1
- package/dist/models/label.mjs.map +1 -1
- package/dist/models/member.mjs +1 -1
- package/dist/models/member.mjs.map +1 -1
- package/dist/models/project.mjs +1 -1
- package/dist/models/project.mjs.map +1 -1
- package/dist/models/snapshot.mjs +1 -1
- package/dist/models/snapshot.mjs.map +1 -1
- package/dist/models/status-config.mjs +1 -1
- package/dist/models/status-config.mjs.map +1 -1
- package/dist/models/token.mjs +1 -1
- package/dist/models/token.mjs.map +1 -1
- package/dist/models/webhook.mjs +11 -3
- package/dist/models/webhook.mjs.map +1 -1
- package/dist/pages/build-detail.mjs +9 -4
- package/dist/pages/build-detail.mjs.map +1 -1
- package/dist/pages/build-diff-comments.mjs +113 -0
- package/dist/pages/build-diff-comments.mjs.map +1 -0
- package/dist/pages/build-diff-header.mjs +163 -0
- package/dist/pages/build-diff-header.mjs.map +1 -0
- package/dist/pages/build-diff-nav.mjs +66 -0
- package/dist/pages/build-diff-nav.mjs.map +1 -0
- package/dist/pages/build-diff-viewer.mjs +197 -0
- package/dist/pages/build-diff-viewer.mjs.map +1 -0
- package/dist/pages/build-diff.mjs +65 -413
- package/dist/pages/build-diff.mjs.map +1 -1
- package/dist/pages/compute-jobs.mjs +1 -1
- package/dist/pages/compute-jobs.mjs.map +1 -1
- package/dist/pages/label-detail.mjs +4 -3
- package/dist/pages/label-detail.mjs.map +1 -1
- package/dist/pages/login.mjs.map +1 -1
- package/dist/pages/project-builds.mjs +5 -3
- package/dist/pages/project-builds.mjs.map +1 -1
- package/dist/pages/project-create.mjs.map +1 -1
- package/dist/pages/project-settings.mjs.map +1 -1
- package/dist/pages/projects.mjs +11 -6
- package/dist/pages/projects.mjs.map +1 -1
- package/dist/pages/root.mjs +6 -3
- package/dist/pages/root.mjs.map +1 -1
- package/dist/pages/settings-general.mjs.map +1 -1
- package/dist/pages/settings-labels.mjs +1 -1
- package/dist/pages/settings-labels.mjs.map +1 -1
- package/dist/pages/settings-members.mjs +1 -1
- package/dist/pages/settings-members.mjs.map +1 -1
- package/dist/pages/settings-status.mjs +2 -1
- package/dist/pages/settings-status.mjs.map +1 -1
- package/dist/pages/settings-tests.mjs +3 -3
- package/dist/pages/settings-tests.mjs.map +1 -1
- package/dist/pages/settings-tokens.mjs.map +1 -1
- package/dist/pages/settings-webhooks.mjs.map +1 -1
- package/dist/pages/storybook.mjs +38 -1
- package/dist/pages/storybook.mjs.map +1 -1
- package/dist/paths.mjs.map +1 -0
- package/dist/retention/purge.mjs +6 -3
- package/dist/retention/purge.mjs.map +1 -1
- package/dist/routers/admin.mjs +1 -1
- package/dist/routers/admin.mjs.map +1 -1
- package/dist/routers/assets.mjs.map +1 -1
- package/dist/routers/auth.mjs.map +1 -1
- package/dist/routers/builds.handlers.mjs +106 -21
- package/dist/routers/builds.handlers.mjs.map +1 -1
- package/dist/routers/builds.mjs +54 -34
- package/dist/routers/builds.mjs.map +1 -1
- package/dist/routers/comments.mjs.map +1 -1
- package/dist/routers/health.mjs +137 -0
- package/dist/routers/health.mjs.map +1 -0
- package/dist/routers/helpers.mjs +2 -2
- package/dist/routers/helpers.mjs.map +1 -1
- package/dist/routers/htmx.mjs.map +1 -1
- package/dist/routers/labels.mjs +1 -1
- package/dist/routers/labels.mjs.map +1 -1
- package/dist/routers/media.mjs +2 -2
- package/dist/routers/media.mjs.map +1 -1
- package/dist/routers/members.mjs.map +1 -1
- package/dist/routers/projects.mjs +1 -1
- package/dist/routers/projects.mjs.map +1 -1
- package/dist/routers/schemas.mjs.map +1 -1
- package/dist/routers/settings-general.mjs +95 -0
- package/dist/routers/settings-general.mjs.map +1 -0
- package/dist/routers/settings-labels.mjs +49 -0
- package/dist/routers/settings-labels.mjs.map +1 -0
- package/dist/routers/settings-members.mjs +30 -0
- package/dist/routers/settings-members.mjs.map +1 -0
- package/dist/routers/settings-status.mjs +73 -0
- package/dist/routers/settings-status.mjs.map +1 -0
- package/dist/routers/settings-tokens.mjs +40 -0
- package/dist/routers/settings-tokens.mjs.map +1 -0
- package/dist/routers/settings-webhooks.mjs +63 -0
- package/dist/routers/settings-webhooks.mjs.map +1 -0
- package/dist/routers/settings.handlers.mjs +93 -0
- package/dist/routers/settings.handlers.mjs.map +1 -0
- package/dist/routers/settings.mjs +13 -247
- package/dist/routers/settings.mjs.map +1 -1
- package/dist/routers/snapshots.mjs +1 -1
- package/dist/routers/snapshots.mjs.map +1 -1
- package/dist/routers/status-configs.mjs +1 -1
- package/dist/routers/status-configs.mjs.map +1 -1
- package/dist/routers/storybook.mjs +11 -4
- package/dist/routers/storybook.mjs.map +1 -1
- package/dist/routers/tokens.mjs +1 -1
- package/dist/routers/tokens.mjs.map +1 -1
- package/dist/routers/ui.mjs +4 -4
- package/dist/routers/ui.mjs.map +1 -1
- package/dist/routers/webhooks.mjs +6 -6
- package/dist/routers/webhooks.mjs.map +1 -1
- package/dist/schema/baseline.d.mts +18 -0
- package/dist/schema/baseline.mjs +22 -0
- package/dist/schema/baseline.mjs.map +1 -0
- package/dist/schema/build.d.mts +26 -0
- package/dist/schema/build.mjs +29 -0
- package/dist/schema/build.mjs.map +1 -0
- package/dist/schema/comment.d.mts +19 -0
- package/dist/schema/comment.mjs +26 -0
- package/dist/schema/comment.mjs.map +1 -0
- package/dist/schema/label.d.mts +25 -0
- package/dist/schema/label.mjs +30 -0
- package/dist/schema/label.mjs.map +1 -0
- package/dist/schema/member.d.mts +15 -0
- package/dist/schema/member.mjs +19 -0
- package/dist/schema/member.mjs.map +1 -0
- package/dist/schema/project.d.mts +34 -0
- package/dist/schema/project.mjs +25 -0
- package/dist/schema/project.mjs.map +1 -0
- package/dist/schema/snapshot.d.mts +30 -0
- package/dist/schema/snapshot.mjs +34 -0
- package/dist/schema/snapshot.mjs.map +1 -0
- package/dist/schema/status-config.d.mts +16 -0
- package/dist/schema/status-config.mjs +20 -0
- package/dist/schema/status-config.mjs.map +1 -0
- package/dist/schema/token.d.mts +15 -0
- package/dist/schema/token.mjs +19 -0
- package/dist/schema/token.mjs.map +1 -0
- package/dist/schema/user.d.mts +17 -0
- package/dist/schema/user.mjs +19 -0
- package/dist/schema/user.mjs.map +1 -0
- package/dist/schema/webhook.d.mts +16 -0
- package/dist/schema/webhook.mjs +20 -0
- package/dist/schema/webhook.mjs.map +1 -0
- package/dist/schema.d.mts +13 -168
- package/dist/schema.mjs +12 -2
- package/dist/schema.mjs.map +1 -1
- package/dist/store.mjs.map +1 -1
- package/dist/types.d.mts +1 -2
- package/dist/types.mjs.map +1 -1
- package/dist/ui/document.mjs.map +1 -1
- package/dist/ui/feedback.mjs +24 -0
- package/dist/ui/feedback.mjs.map +1 -0
- package/dist/ui/{components.mjs → forms.mjs} +3 -18
- package/dist/ui/forms.mjs.map +1 -0
- package/dist/ui/styles.mjs.map +1 -1
- package/dist/urls.mjs.map +1 -1
- package/package.json +47 -45
- package/dist/adapters/metadata.d.mts +0 -24
- package/dist/models/baseline.d.mts +0 -21
- package/dist/models/build.d.mts +0 -53
- package/dist/models/comment.d.mts +0 -22
- package/dist/models/label.d.mts +0 -49
- package/dist/models/member.d.mts +0 -27
- package/dist/models/project.d.mts +0 -43
- package/dist/models/snapshot.d.mts +0 -47
- package/dist/models/token.d.mts +0 -33
- package/dist/models/webhook.d.mts +0 -38
- package/dist/retention/purge.d.mts +0 -31
- package/dist/schema-tables.mjs +0 -166
- package/dist/schema-tables.mjs.map +0 -1
- package/dist/ui/components.mjs.map +0 -1
- package/dist/ui/document.d.mts +0 -9
- package/dist/utils/paths.mjs.map +0 -1
- package/dist/utils/ulid.d.mts +0 -10
- /package/dist/{utils/paths.d.mts → paths.d.mts} +0 -0
- /package/dist/{utils/paths.mjs → paths.mjs} +0 -0
package/dist/schema.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","names":["projectsTable","projectStatusConfigsTable","buildsTable","snapshotsTable","baselinesTable","commentsTable","labelTypesTable","buildLabelsTable","tokensTable","webhooksTable","usersTable","projectMembersTable"],"sources":["../src/schema.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":["projectsTable","projectStatusConfigsTable","buildsTable","snapshotsTable","baselinesTable","commentsTable","labelTypesTable","buildLabelsTable","tokensTable","webhooksTable","usersTable","projectMembersTable"],"sources":["../src/schema/index.ts"],"sourcesContent":["/**\n * Database schema: table handles, row types, and the schema object passed\n * to the database client.\n */\nimport type { AnySQLiteTable } from \"drizzle-orm/sqlite-core\";\n\nimport { baselines as baselinesTable } from \"./baseline.ts\";\nimport { buildLabels as buildLabelsTable, labelTypes as labelTypesTable } from \"./label.ts\";\nimport { builds as buildsTable } from \"./build.ts\";\nimport { comments as commentsTable } from \"./comment.ts\";\nimport { projectMembers as projectMembersTable } from \"./member.ts\";\nimport { projects as projectsTable } from \"./project.ts\";\nimport { projectStatusConfigs as projectStatusConfigsTable } from \"./status-config.ts\";\nimport { snapshots as snapshotsTable } from \"./snapshot.ts\";\nimport { tokens as tokensTable } from \"./token.ts\";\nimport { users as usersTable } from \"./user.ts\";\nimport { webhooks as webhooksTable } from \"./webhook.ts\";\n\n/**\n * Database schema: table handles, row types, and the schema object passed\n * to the database client.\n *\n * Table handles are explicitly typed (JSR fast-check); exact column types\n * live on the narrow per-entity definitions, and the row interfaces are\n * pinned to them by `schema-types.test.ts`.\n */\nexport type { Baseline } from \"./baseline.ts\";\nexport type { Build } from \"./build.ts\";\nexport type { Comment } from \"./comment.ts\";\nexport type { BuildLabel, LabelType } from \"./label.ts\";\nexport type { ProjectMember } from \"./member.ts\";\nexport type { Project, StorybookMeta } from \"./project.ts\";\nexport type { ProjectStatusConfig } from \"./status-config.ts\";\nexport type { Snapshot } from \"./snapshot.ts\";\nexport type { Token } from \"./token.ts\";\nexport type { User } from \"./user.ts\";\nexport type { Webhook } from \"./webhook.ts\";\n\n/** Projects table (one row per Storybook project). */\nexport const projects: AnySQLiteTable = projectsTable;\n/** Project status-configs table (merge-gate configurations). */\nexport const projectStatusConfigs: AnySQLiteTable = projectStatusConfigsTable;\n/** Builds table (one row per uploaded Storybook build). */\nexport const builds: AnySQLiteTable = buildsTable;\n/** Snapshots table (one row per captured story screenshot). */\nexport const snapshots: AnySQLiteTable = snapshotsTable;\n/** Baselines table (accepted reference snapshots per branch). */\nexport const baselines: AnySQLiteTable = baselinesTable;\n/** Comments table (review comments on snapshots). */\nexport const comments: AnySQLiteTable = commentsTable;\n/** Label-types table (project-defined build label vocabularies). */\nexport const labelTypes: AnySQLiteTable = labelTypesTable;\n/** Build-labels table (labels attached to builds). */\nexport const buildLabels: AnySQLiteTable = buildLabelsTable;\n/** Tokens table (CI token hashes per project). */\nexport const tokens: AnySQLiteTable = tokensTable;\n/** Webhooks table (outgoing build-event subscriptions). */\nexport const webhooks: AnySQLiteTable = webhooksTable;\n/** Users table (dashboard members). */\nexport const users: AnySQLiteTable = usersTable;\n/** Project-members table (per-project memberships and roles). */\nexport const projectMembers: AnySQLiteTable = projectMembersTable;\n\n/** Full Drizzle schema object passed to the database client. */\nexport const schema = {\n projects,\n projectStatusConfigs,\n builds,\n snapshots,\n baselines,\n comments,\n labelTypes,\n buildLabels,\n tokens,\n webhooks,\n users,\n projectMembers,\n};\n\n/** The full database schema type. */\nexport type Schema = typeof schema;\n"],"mappings":";;;;;;;;;;;;;;;;AAuCA,MAAa,WAA2BA;;AAExC,MAAa,uBAAuCC;;AAEpD,MAAa,SAAyBC;;AAEtC,MAAa,YAA4BC;;AAEzC,MAAa,YAA4BC;;AAEzC,MAAa,WAA2BC;;AAExC,MAAa,aAA6BC;;AAE1C,MAAa,cAA8BC;;AAE3C,MAAa,SAAyBC;;AAEtC,MAAa,WAA2BC;;AAExC,MAAa,QAAwBC;;AAErC,MAAa,iBAAiCC;;AAG9C,MAAa,SAAS;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|
package/dist/store.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.mjs","names":[],"sources":["../src/store.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\
|
|
1
|
+
{"version":3,"file":"store.mjs","names":[],"sources":["../src/store.ts"],"sourcesContent":["import { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { Logger } from \"pino\";\nimport type { AuthUser } from \"./adapters/auth.ts\";\nimport type { CaptureQueue } from \"./adapters/capture-queue.ts\";\nimport type { DatabaseAdapter } from \"./adapters/database.ts\";\nimport type { GitHostProvider } from \"./adapters/git-host/index.ts\";\nimport type { StorageAdapter } from \"./adapters/storage.ts\";\nimport type { ShelfConfig, UIConfig } from \"./config.ts\";\n\n/** Request-scoped dependencies and session state. */\nexport interface Store {\n db: DatabaseAdapter;\n storage: StorageAdapter;\n config: ShelfConfig;\n ui: UIConfig;\n logger: Logger;\n user: AuthUser | null;\n authEnabled: boolean;\n enqueueCapture?: (buildId: string, reqId?: string) => Promise<void>;\n captureQueue?: CaptureQueue | null;\n gitHosts: GitHostProvider[];\n}\n\nconst storage = new AsyncLocalStorage<Store>();\n\n/** Run a function with the given request store in scope. */\nexport function runWithStore<T>(store: Store, fn: () => T): T {\n return storage.run(store, fn);\n}\n\n/** Return the current request store, throwing outside a request scope. */\nexport function getStore(): Store {\n const store = storage.getStore();\n if (!store) {\n throw new Error(\"Store not available. Use runWithStore().\");\n }\n return store;\n}\n"],"mappings":";;;;;AAuBA,MAAM,UAAU,IAAI,kBAAyB;;AAG7C,SAAgB,aAAgB,OAAc,IAAgB;CAC5D,OAAO,QAAQ,IAAI,OAAO,EAAE;AAC9B;;AAGA,SAAgB,WAAkB;CAChC,MAAM,QAAQ,QAAQ,SAAS;CAC/B,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,0CAA0C;CAE5D,OAAO;AACT"}
|
package/dist/types.d.mts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import __tsdown_shims_path from 'node:path';
|
|
2
2
|
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { Logger } from "./logger.mjs";
|
|
4
3
|
//#region src/types.d.ts
|
|
5
4
|
/** All lifecycle statuses a build can carry. */
|
|
6
5
|
declare const BUILD_STATUSES: readonly ["pending", "capturing", "comparing", "reviewing", "approved", "rejected", "failed"];
|
|
@@ -27,5 +26,5 @@ declare const RESERVED_LABEL_KEYS: readonly ["build"];
|
|
|
27
26
|
/** Label key marking a build as exempt from retention purging. */
|
|
28
27
|
declare const PERSISTENT_LABEL_KEY = "persistent";
|
|
29
28
|
//#endregion
|
|
30
|
-
export { BUILD_STATUSES, BuildStatus,
|
|
29
|
+
export { BUILD_STATUSES, BuildStatus, PERSISTENT_LABEL_KEY, PROJECT_ROLES, ProjectRole, RESERVED_LABEL_KEYS, SEEDED_LABEL_KEYS, SITE_ROLES, SNAPSHOT_STATUSES, SiteRole, SnapshotStatus, TERMINAL_BUILD_STATUSES };
|
|
31
30
|
//# sourceMappingURL=types.d.mts.map
|
package/dist/types.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["/** All lifecycle statuses a build can carry. */\nexport const BUILD_STATUSES = [\n \"pending\",\n \"capturing\",\n \"comparing\",\n \"reviewing\",\n \"approved\",\n \"rejected\",\n \"failed\",\n] as const;\n\n/** Lifecycle status of a build. */\nexport type BuildStatus = (typeof BUILD_STATUSES)[number];\n\n/** All review statuses a snapshot can carry. */\nexport const SNAPSHOT_STATUSES = [\"pending\"
|
|
1
|
+
{"version":3,"file":"types.mjs","names":[],"sources":["../src/types.ts"],"sourcesContent":["/** All lifecycle statuses a build can carry. */\nexport const BUILD_STATUSES = [\n \"pending\",\n \"capturing\",\n \"comparing\",\n \"reviewing\",\n \"approved\",\n \"rejected\",\n \"failed\",\n] as const;\n\n/** Lifecycle status of a build. */\nexport type BuildStatus = (typeof BUILD_STATUSES)[number];\n\n/** All review statuses a snapshot can carry. */\nexport const SNAPSHOT_STATUSES = [\n \"pending\",\n \"new\",\n \"unchanged\",\n \"changed\",\n \"approved\",\n \"rejected\",\n] as const;\n\n/** Review status of a snapshot. */\nexport type SnapshotStatus = (typeof SNAPSHOT_STATUSES)[number];\n\n/** Build statuses eligible for retention purging. */\nexport const TERMINAL_BUILD_STATUSES: readonly BuildStatus[] = [\"approved\", \"rejected\", \"failed\"];\n\n/** All site-wide user roles. */\nexport const SITE_ROLES = [\"admin\", \"member\"] as const;\n\n/** Site-wide role of a user. */\nexport type SiteRole = (typeof SITE_ROLES)[number];\n\n/** All per-project membership roles. */\nexport const PROJECT_ROLES = [\"admin\", \"approver\", \"developer\", \"viewer\"] as const;\n\n/** Per-project role of a member. */\nexport type ProjectRole = (typeof PROJECT_ROLES)[number];\n\n/** Label type keys seeded for every new project. */\nexport const SEEDED_LABEL_KEYS = [\n \"branch\",\n \"persistent\",\n \"pr\",\n \"mr\",\n \"jira\",\n \"linear\",\n \"figma\",\n \"custom\",\n] as const;\n\n/** Label type keys reserved for internal use. */\nexport const RESERVED_LABEL_KEYS = [\"build\"] as const;\n\n/** Label key marking a build as exempt from retention purging. */\nexport const PERSISTENT_LABEL_KEY = \"persistent\";\n"],"mappings":";;;;;AACA,MAAa,iBAAiB;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAMA,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;AACF;;AAMA,MAAa,0BAAkD;CAAC;CAAY;CAAY;AAAQ;;AAGhG,MAAa,aAAa,CAAC,SAAS,QAAQ;;AAM5C,MAAa,gBAAgB;CAAC;CAAS;CAAY;CAAa;AAAQ;;AAMxE,MAAa,oBAAoB;CAC/B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;AAGA,MAAa,sBAAsB,CAAC,OAAO;;AAG3C,MAAa,uBAAuB"}
|
package/dist/ui/document.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"document.mjs","names":[],"sources":["../../src/ui/document.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\n\nimport { getStore } from \"../store.ts\";\nimport { baseStyle } from \"./styles.ts\";\nimport { DARK_THEME, LIGHT_THEME } from \"./theme.ts\";\n\n/** Rendered HTML content returned by page components. */\nexport type RenderedContent = string | Promise<string>;\n\ninterface NavConfig {\n active?: string;\n projectSlug?: string;\n projectName?: string;\n}\n\n// Hono's JSX.Element is typed as `HtmlEscapedString | Promise<...>`, so JSX-returning\n// Functions can legitimately return a promise; the rule is a false positive here.\n/** Full HTML document shell with top bar, sidebar, theme, and HTMX. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const DocumentLayout: FC<{ title: string; nav?: NavConfig; children?: unknown }> = ({ title, nav, children }) => {\n const { ui } = getStore();\n const name = ui.name ?? \"StoryShelf\";\n const light = ui.lightTheme ?? LIGHT_THEME;\n const dark = ui.darkTheme ?? DARK_THEME;\n\n return (\n <html lang=\"en\" data-theme=\"system\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"color-scheme\" content=\"light dark\" />\n {ui.favicon ? <link rel=\"icon\" href={ui.favicon} /> : null}\n <title>\n {title} · {name}\n </title>\n <style>{baseStyle(light, dark)}</style>\n <script dangerouslySetInnerHTML={{ __html: themeScript() }} />\n </head>\n <body>\n <a class=\"skip-link\" href=\"#main-content\">\n Skip to content\n </a>\n <TopBar name={name} logo={ui.logo} nav={nav} />\n <div class=\"shell\">\n <Sidebar nav={nav} />\n <main id=\"main-content\" class=\"content\" tabindex={-1}>\n {children}\n </main>\n </div>\n <script src=\"/assets/htmx.js\" />\n <script dangerouslySetInnerHTML={{ __html: clientScript() }} />\n </body>\n </html>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst TopBar: FC<{ name: string; logo?: string; nav?: NavConfig }> = ({ name, logo, nav }) => {\n return (\n <header class=\"topbar\" role=\"banner\">\n <div class=\"topbar__inner\">\n <div class=\"topbar__left\">\n <button class=\"topbar__menu\" type=\"button\" aria-label=\"Toggle navigation\" aria-expanded=\"false\" aria-controls=\"sidebar\" data-sidebar-toggle>\n <span aria-hidden=\"true\">☰</span>\n </button>\n <a class=\"brand\" href=\"/\">\n {logo ? <img class=\"logo\" src={logo} alt={name} width=\"28\" height=\"28\" /> : <span class=\"brand__mark\" aria-hidden=\"true\">◆</span>}\n <span class=\"brand__name\">{name}</span>\n </a>\n {nav?.projectSlug ? (\n <nav class=\"project-crumb\" aria-label=\"Project\">\n <span class=\"project-crumb__sep\" aria-hidden=\"true\">\n /\n </span>\n <a href={`/projects/${nav.projectSlug}/builds`}>{nav.projectName ?? nav.projectSlug}</a>\n </nav>\n ) : null}\n </div>\n <div class=\"topbar__right\">\n <ThemeToggle />\n <AuthMenu />\n </div>\n </div>\n </header>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst ThemeToggle: FC = () => {\n return (\n <button class=\"topbar__theme\" type=\"button\" aria-label=\"Toggle theme\" data-theme-toggle>\n <span data-theme-icon=\"light\" aria-hidden=\"true\">\n ☀\n </span>\n <span data-theme-icon=\"dark\" aria-hidden=\"true\">\n ☾\n </span>\n <span data-theme-icon=\"system\" aria-hidden=\"true\">\n ◐\n </span>\n </button>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst AuthMenu: FC = () => {\n const { user, authEnabled } = getStore();\n if (!authEnabled) {\n return null;\n }\n if (!user) {\n return (\n <a class=\"topbar__login\" href=\"/auth/login\">\n Sign in\n </a>\n );\n }\n return (\n <div class=\"user-menu\">\n {user.avatarUrl ? (\n <img class=\"user-menu__avatar\" src={user.avatarUrl} alt=\"\" width=\"28\" height=\"28\" />\n ) : (\n <span class=\"user-menu__avatar user-menu__avatar--fallback\" aria-hidden=\"true\">\n {user.name.slice(0, 1).toUpperCase()}\n </span>\n )}\n <span class=\"user-menu__name\">{user.name}</span>\n <span class={`user-menu__role user-menu__role--${user.role}`}>{user.role}</span>\n <form method=\"post\" action=\"/auth/logout\">\n <button class=\"user-menu__logout\" type=\"submit\">\n Sign out\n </button>\n </form>\n </div>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst Sidebar: FC<{ nav?: NavConfig }> = ({ nav }) => {\n return (\n <aside id=\"sidebar\" class=\"sidebar\" aria-label=\"Primary\">\n <nav class=\"sidebar__nav\">\n <a class={`sidebar__link ${nav?.active === \"projects\" ? \"sidebar__link--active\" : \"\"}`} href=\"/projects\" aria-current={nav?.active === \"projects\" ? \"page\" : undefined}>\n <span aria-hidden=\"true\">▦</span> Projects\n </a>\n {nav?.projectSlug ? (\n <>\n <div class=\"sidebar__section\">Project</div>\n <a class={`sidebar__link ${nav.active === \"builds\" ? \"sidebar__link--active\" : \"\"}`} href={`/projects/${nav.projectSlug}/builds`} aria-current={nav.active === \"builds\" ? \"page\" : undefined}>\n <span aria-hidden=\"true\">◧</span> Builds\n </a>\n <a class={`sidebar__link ${nav.active === \"jobs\" ? \"sidebar__link--active\" : \"\"}`} href={`/projects/${nav.projectSlug}/jobs`} aria-current={nav.active === \"jobs\" ? \"page\" : undefined}>\n <span aria-hidden=\"true\">◫</span> Jobs\n </a>\n <a class={`sidebar__link ${nav.active === \"labels\" ? \"sidebar__link--active\" : \"\"}`} href={`/projects/${nav.projectSlug}/labels`} aria-current={nav.active === \"labels\" ? \"page\" : undefined}>\n <span aria-hidden=\"true\">⌗</span> Labels\n </a>\n <a class={`sidebar__link ${nav.active === \"settings\" ? \"sidebar__link--active\" : \"\"}`} href={`/projects/${nav.projectSlug}/settings`} aria-current={nav.active === \"settings\" ? \"page\" : undefined}>\n <span aria-hidden=\"true\">⚙</span> Settings\n </a>\n </>\n ) : null}\n <div class=\"sidebar__section\">Resources</div>\n <a class=\"sidebar__link\" href=\"/api/v1/projects\" aria-label=\"API (JSON)\">\n <span aria-hidden=\"true\">{\"{} \"}</span> API\n </a>\n </nav>\n </aside>\n );\n};\n\nfunction themeScript(): string {\n return `\n (function(){\n var cookieName='storyshelf_theme';\n function readCookie(n){\n var m=document.cookie.match(new RegExp('(?:^|; )'+n.replace(/([.$?*|{}\\\\[\\\\]\\\\\\\\/\\\\+^])/gu,'\\\\\\\\$1')+'=([^;]*)'));\n return m?decodeURIComponent(m[1]):null;\n }\n function writeCookie(n,v){\n document.cookie=n+'='+encodeURIComponent(v)+'; Path=/; Max-Age=31536000; SameSite=Lax';\n }\n function applyTheme(v){\n var html=document.documentElement;\n if(v==='light'||v==='dark'||v==='system'){ html.setAttribute('data-theme',v); }\n else { html.setAttribute('data-theme','system'); }\n }\n var initial=readCookie(cookieName);\n if(initial){ applyTheme(initial); }\n window.__storyshelfTheme={readCookie:readCookie,writeCookie:writeCookie,applyTheme:applyTheme,cookieName:cookieName};\n })();\n `.trim();\n}\n\nfunction clientScript(): string {\n return `\n (function(){\n var theme=window.__storyshelfTheme;\n var toggle=document.querySelector('[data-theme-toggle]');\n if(toggle&&theme){\n toggle.addEventListener('click',function(){\n var cur=document.documentElement.getAttribute('data-theme')||'system';\n var next=cur==='system'?'light':cur==='light'?'dark':'system';\n theme.applyTheme(next);\n theme.writeCookie(theme.cookieName,next);\n });\n }\n var menuBtn=document.querySelector('[data-sidebar-toggle]');\n var sidebar=document.getElementById('sidebar');\n if(menuBtn&&sidebar){\n menuBtn.addEventListener('click',function(){\n var open=sidebar.classList.toggle('sidebar--open');\n menuBtn.setAttribute('aria-expanded', open ? 'true' : 'false');\n });\n }\n document.addEventListener('keydown',function(e){\n if(e.key==='Escape'&&sidebar&&sidebar.classList.contains('sidebar--open')){\n sidebar.classList.remove('sidebar--open');\n if(menuBtn) menuBtn.setAttribute('aria-expanded','false');\n menuBtn && menuBtn.focus();\n }\n });\n // HTMX after swap focus management\n document.body.addEventListener('htmx:afterSwap',function(e){\n var target=e.detail && e.detail.target;\n if(target&&target.querySelector){\n var focusable=target.querySelector('[autofocus], input, select, textarea, button');\n if(focusable) try{ focusable.focus(); }catch(_){}\n }\n });\n // Diff keyboard shortcuts\n document.addEventListener('keydown',function(e){\n if(e.target instanceof HTMLElement && (e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA'||e.target.isContentEditable)) return;\n var diffRoot=document.querySelector('[data-diff-nav]');\n if(!diffRoot) return;\n if(e.key==='ArrowLeft' || e.key==='ArrowRight'){\n var links=Array.from(diffRoot.querySelectorAll('[data-snapshot-link]'));\n if(links.length===0) return;\n var active=document.activeElement;\n var idx=links.indexOf(active);\n if(idx===-1){\n var current=diffRoot.getAttribute('data-current');\n idx=links.findIndex(function(a){ return a.getAttribute('data-snapshot-id')===current; });\n }\n var nextIdx=e.key==='ArrowRight' ? Math.min(links.length-1, idx+1) : Math.max(0, idx-1);\n if(links[nextIdx]){ e.preventDefault(); links[nextIdx].focus(); links[nextIdx].click(); }\n }\n });\n })();\n `.trim();\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"document.mjs","names":[],"sources":["../../src/ui/document.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\nimport { getStore } from \"../store.ts\";\nimport { baseStyle } from \"./styles.ts\";\nimport { DARK_THEME, LIGHT_THEME } from \"./theme.ts\";\n\n/** Rendered HTML content returned by page components. */\nexport type RenderedContent = string | Promise<string>;\n\ninterface NavConfig {\n active?: string;\n projectSlug?: string;\n projectName?: string;\n}\n\n// Hono's JSX.Element is typed as `HtmlEscapedString | Promise<...>`, so JSX-returning\n// Functions can legitimately return a promise; the rule is a false positive here.\n/** Full HTML document shell with top bar, sidebar, theme, and HTMX. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const DocumentLayout: FC<{ title: string; nav?: NavConfig; children?: unknown }> = ({\n title,\n nav,\n children,\n}) => {\n const { ui } = getStore();\n const name = ui.name ?? \"StoryShelf\";\n const light = ui.lightTheme ?? LIGHT_THEME;\n const dark = ui.darkTheme ?? DARK_THEME;\n\n return (\n <html lang=\"en\" data-theme=\"system\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"color-scheme\" content=\"light dark\" />\n {ui.favicon ? <link rel=\"icon\" href={ui.favicon} /> : null}\n <title>\n {title} · {name}\n </title>\n <style>{baseStyle(light, dark)}</style>\n <script dangerouslySetInnerHTML={{ __html: themeScript() }} />\n </head>\n <body>\n <a class=\"skip-link\" href=\"#main-content\">\n Skip to content\n </a>\n <TopBar name={name} logo={ui.logo} nav={nav} />\n <div class=\"shell\">\n <Sidebar nav={nav} />\n <main id=\"main-content\" class=\"content\" tabindex={-1}>\n {children}\n </main>\n </div>\n <script src=\"/assets/htmx.js\" />\n <script dangerouslySetInnerHTML={{ __html: clientScript() }} />\n </body>\n </html>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst TopBar: FC<{ name: string; logo?: string; nav?: NavConfig }> = ({ name, logo, nav }) => {\n return (\n <header class=\"topbar\" role=\"banner\">\n <div class=\"topbar__inner\">\n <div class=\"topbar__left\">\n <button\n class=\"topbar__menu\"\n type=\"button\"\n aria-label=\"Toggle navigation\"\n aria-expanded=\"false\"\n aria-controls=\"sidebar\"\n data-sidebar-toggle\n >\n <span aria-hidden=\"true\">☰</span>\n </button>\n <a class=\"brand\" href=\"/\">\n {logo ? (\n <img class=\"logo\" src={logo} alt={name} width=\"28\" height=\"28\" />\n ) : (\n <span class=\"brand__mark\" aria-hidden=\"true\">\n ◆\n </span>\n )}\n <span class=\"brand__name\">{name}</span>\n </a>\n {nav?.projectSlug ? (\n <nav class=\"project-crumb\" aria-label=\"Project\">\n <span class=\"project-crumb__sep\" aria-hidden=\"true\">\n /\n </span>\n <a href={`/projects/${nav.projectSlug}/builds`}>\n {nav.projectName ?? nav.projectSlug}\n </a>\n </nav>\n ) : null}\n </div>\n <div class=\"topbar__right\">\n <ThemeToggle />\n <AuthMenu />\n </div>\n </div>\n </header>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst ThemeToggle: FC = () => {\n return (\n <button class=\"topbar__theme\" type=\"button\" aria-label=\"Toggle theme\" data-theme-toggle>\n <span data-theme-icon=\"light\" aria-hidden=\"true\">\n ☀\n </span>\n <span data-theme-icon=\"dark\" aria-hidden=\"true\">\n ☾\n </span>\n <span data-theme-icon=\"system\" aria-hidden=\"true\">\n ◐\n </span>\n </button>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst AuthMenu: FC = () => {\n const { user, authEnabled } = getStore();\n if (!authEnabled) {\n return null;\n }\n if (!user) {\n return (\n <a class=\"topbar__login\" href=\"/auth/login\">\n Sign in\n </a>\n );\n }\n return (\n <div class=\"user-menu\">\n {user.avatarUrl ? (\n <img class=\"user-menu__avatar\" src={user.avatarUrl} alt=\"\" width=\"28\" height=\"28\" />\n ) : (\n <span class=\"user-menu__avatar user-menu__avatar--fallback\" aria-hidden=\"true\">\n {user.name.slice(0, 1).toUpperCase()}\n </span>\n )}\n <span class=\"user-menu__name\">{user.name}</span>\n <span class={`user-menu__role user-menu__role--${user.role}`}>{user.role}</span>\n <form method=\"post\" action=\"/auth/logout\">\n <button class=\"user-menu__logout\" type=\"submit\">\n Sign out\n </button>\n </form>\n </div>\n );\n};\n\n// eslint-disable-next-line promise-function-async -- JSX component return type\nconst Sidebar: FC<{ nav?: NavConfig }> = ({ nav }) => {\n return (\n <aside id=\"sidebar\" class=\"sidebar\" aria-label=\"Primary\">\n <nav class=\"sidebar__nav\">\n <a\n class={`sidebar__link ${nav?.active === \"projects\" ? \"sidebar__link--active\" : \"\"}`}\n href=\"/projects\"\n aria-current={nav?.active === \"projects\" ? \"page\" : undefined}\n >\n <span aria-hidden=\"true\">▦</span> Projects\n </a>\n {nav?.projectSlug ? (\n <>\n <div class=\"sidebar__section\">Project</div>\n <a\n class={`sidebar__link ${nav.active === \"builds\" ? \"sidebar__link--active\" : \"\"}`}\n href={`/projects/${nav.projectSlug}/builds`}\n aria-current={nav.active === \"builds\" ? \"page\" : undefined}\n >\n <span aria-hidden=\"true\">◧</span> Builds\n </a>\n <a\n class={`sidebar__link ${nav.active === \"jobs\" ? \"sidebar__link--active\" : \"\"}`}\n href={`/projects/${nav.projectSlug}/jobs`}\n aria-current={nav.active === \"jobs\" ? \"page\" : undefined}\n >\n <span aria-hidden=\"true\">◫</span> Jobs\n </a>\n <a\n class={`sidebar__link ${nav.active === \"labels\" ? \"sidebar__link--active\" : \"\"}`}\n href={`/projects/${nav.projectSlug}/labels`}\n aria-current={nav.active === \"labels\" ? \"page\" : undefined}\n >\n <span aria-hidden=\"true\">⌗</span> Labels\n </a>\n <a\n class={`sidebar__link ${nav.active === \"settings\" ? \"sidebar__link--active\" : \"\"}`}\n href={`/projects/${nav.projectSlug}/settings`}\n aria-current={nav.active === \"settings\" ? \"page\" : undefined}\n >\n <span aria-hidden=\"true\">⚙</span> Settings\n </a>\n </>\n ) : null}\n <div class=\"sidebar__section\">Resources</div>\n <a class=\"sidebar__link\" href=\"/api/v1/projects\" aria-label=\"API (JSON)\">\n <span aria-hidden=\"true\">{\"{} \"}</span> API\n </a>\n </nav>\n </aside>\n );\n};\n\nfunction themeScript(): string {\n return `\n (function(){\n var cookieName='storyshelf_theme';\n function readCookie(n){\n var m=document.cookie.match(new RegExp('(?:^|; )'+n.replace(/([.$?*|{}\\\\[\\\\]\\\\\\\\/\\\\+^])/gu,'\\\\\\\\$1')+'=([^;]*)'));\n return m?decodeURIComponent(m[1]):null;\n }\n function writeCookie(n,v){\n document.cookie=n+'='+encodeURIComponent(v)+'; Path=/; Max-Age=31536000; SameSite=Lax';\n }\n function applyTheme(v){\n var html=document.documentElement;\n if(v==='light'||v==='dark'||v==='system'){ html.setAttribute('data-theme',v); }\n else { html.setAttribute('data-theme','system'); }\n }\n var initial=readCookie(cookieName);\n if(initial){ applyTheme(initial); }\n window.__storyshelfTheme={readCookie:readCookie,writeCookie:writeCookie,applyTheme:applyTheme,cookieName:cookieName};\n })();\n `.trim();\n}\n\nfunction clientScript(): string {\n return `\n (function(){\n var theme=window.__storyshelfTheme;\n var toggle=document.querySelector('[data-theme-toggle]');\n if(toggle&&theme){\n toggle.addEventListener('click',function(){\n var cur=document.documentElement.getAttribute('data-theme')||'system';\n var next=cur==='system'?'light':cur==='light'?'dark':'system';\n theme.applyTheme(next);\n theme.writeCookie(theme.cookieName,next);\n });\n }\n var menuBtn=document.querySelector('[data-sidebar-toggle]');\n var sidebar=document.getElementById('sidebar');\n if(menuBtn&&sidebar){\n menuBtn.addEventListener('click',function(){\n var open=sidebar.classList.toggle('sidebar--open');\n menuBtn.setAttribute('aria-expanded', open ? 'true' : 'false');\n });\n }\n document.addEventListener('keydown',function(e){\n if(e.key==='Escape'&&sidebar&&sidebar.classList.contains('sidebar--open')){\n sidebar.classList.remove('sidebar--open');\n if(menuBtn) menuBtn.setAttribute('aria-expanded','false');\n menuBtn && menuBtn.focus();\n }\n });\n // HTMX after swap focus management\n document.body.addEventListener('htmx:afterSwap',function(e){\n var target=e.detail && e.detail.target;\n if(target&&target.querySelector){\n var focusable=target.querySelector('[autofocus], input, select, textarea, button');\n if(focusable) try{ focusable.focus(); }catch(_){}\n }\n });\n // Diff keyboard shortcuts\n document.addEventListener('keydown',function(e){\n if(e.target instanceof HTMLElement && (e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA'||e.target.isContentEditable)) return;\n var diffRoot=document.querySelector('[data-diff-nav]');\n if(!diffRoot) return;\n if(e.key==='ArrowLeft' || e.key==='ArrowRight'){\n var links=Array.from(diffRoot.querySelectorAll('[data-snapshot-link]'));\n if(links.length===0) return;\n var active=document.activeElement;\n var idx=links.indexOf(active);\n if(idx===-1){\n var current=diffRoot.getAttribute('data-current');\n idx=links.findIndex(function(a){ return a.getAttribute('data-snapshot-id')===current; });\n }\n var nextIdx=e.key==='ArrowRight' ? Math.min(links.length-1, idx+1) : Math.max(0, idx-1);\n if(links[nextIdx]){ e.preventDefault(); links[nextIdx].focus(); links[nextIdx].click(); }\n }\n });\n })();\n `.trim();\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { jsx } from "hono/jsx/jsx-runtime";
|
|
5
|
+
//#region src/ui/feedback.tsx
|
|
6
|
+
/** Small status pill with a color tone. */
|
|
7
|
+
const Badge = ({ tone = "neutral", children }) => {
|
|
8
|
+
return /* @__PURE__ */ jsx("span", {
|
|
9
|
+
class: `badge badge--${tone}`,
|
|
10
|
+
children
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
/** Map a build or snapshot status string to its badge tone. */
|
|
14
|
+
function statusTone(status) {
|
|
15
|
+
if (status === "approved" || status === "unchanged") return "success";
|
|
16
|
+
if (status === "rejected" || status === "failed") return "danger";
|
|
17
|
+
if (status === "changed" || status === "new" || status === "reviewing") return "warning";
|
|
18
|
+
if (status === "capturing" || status === "comparing" || status === "pending") return "info";
|
|
19
|
+
return "neutral";
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { Badge, statusTone };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=feedback.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feedback.mjs","names":[],"sources":["../../src/ui/feedback.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\ntype BadgeTone = \"neutral\" | \"success\" | \"warning\" | \"danger\" | \"info\";\n\n/** Small status pill with a color tone. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const Badge: FC<{ tone?: BadgeTone; children?: unknown }> = ({\n tone = \"neutral\",\n children,\n}) => {\n return <span class={`badge badge--${tone}`}>{children}</span>;\n};\n\n/** Map a build or snapshot status string to its badge tone. */\nexport function statusTone(status: string): BadgeTone {\n if (status === \"approved\" || status === \"unchanged\") {\n return \"success\";\n }\n if (status === \"rejected\" || status === \"failed\") {\n return \"danger\";\n }\n if (status === \"changed\" || status === \"new\" || status === \"reviewing\") {\n return \"warning\";\n }\n if (status === \"capturing\" || status === \"comparing\" || status === \"pending\") {\n return \"info\";\n }\n return \"neutral\";\n}\n\n/** Alert banner with an optional title. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const Alert: FC<{ tone?: BadgeTone; title?: string; children?: unknown }> = ({\n tone = \"info\",\n title,\n children,\n}) => {\n return (\n <div class={`alert alert--${tone}`} role=\"alert\">\n {title ? <strong class=\"alert__title\">{title}</strong> : null}\n <div class=\"alert__body\">{children}</div>\n </div>\n );\n};\n\n/** Centered empty state with an optional call-to-action. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const EmptyState: FC<{ title: string; description?: string; action?: unknown }> = ({\n title,\n description,\n action,\n}) => {\n return (\n <div class=\"empty\">\n <h2 class=\"empty__title\">{title}</h2>\n {description ? <p class=\"empty__desc\">{description}</p> : null}\n {action ? <div class=\"empty__action\">{action}</div> : null}\n </div>\n );\n};\n\n/** Centered statistic value with a label. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const Stat: FC<{ label: string; value: string | number }> = ({ label, value }) => {\n return (\n <div class=\"stat\">\n <div class=\"stat__value\">{String(value)}</div>\n <div class=\"stat__label\">{label}</div>\n </div>\n );\n};\n"],"mappings":";;;;;;AAQA,MAAa,SAAuD,EAClE,OAAO,WACP,eACI;CACJ,OAAO,oBAAC,QAAD;EAAM,OAAO,gBAAgB;EAAS;CAAe,CAAA;AAC9D;;AAGA,SAAgB,WAAW,QAA2B;CACpD,IAAI,WAAW,cAAc,WAAW,aACtC,OAAO;CAET,IAAI,WAAW,cAAc,WAAW,UACtC,OAAO;CAET,IAAI,WAAW,aAAa,WAAW,SAAS,WAAW,aACzD,OAAO;CAET,IAAI,WAAW,eAAe,WAAW,eAAe,WAAW,WACjE,OAAO;CAET,OAAO;AACT"}
|
|
@@ -2,22 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
5
|
-
//#region src/ui/
|
|
6
|
-
/** Small status pill with a color tone. */
|
|
7
|
-
const Badge = ({ tone = "neutral", children }) => {
|
|
8
|
-
return /* @__PURE__ */ jsx("span", {
|
|
9
|
-
class: `badge badge--${tone}`,
|
|
10
|
-
children
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
/** Map a build or snapshot status string to its badge tone. */
|
|
14
|
-
function statusTone(status) {
|
|
15
|
-
if (status === "approved" || status === "unchanged") return "success";
|
|
16
|
-
if (status === "rejected" || status === "failed") return "danger";
|
|
17
|
-
if (status === "changed" || status === "new" || status === "reviewing") return "warning";
|
|
18
|
-
if (status === "capturing" || status === "comparing" || status === "pending") return "info";
|
|
19
|
-
return "neutral";
|
|
20
|
-
}
|
|
5
|
+
//#region src/ui/forms.tsx
|
|
21
6
|
const FieldAssistant = ({ name, error, hint }) => {
|
|
22
7
|
if (error) return /* @__PURE__ */ jsx("p", {
|
|
23
8
|
class: "field__error",
|
|
@@ -127,6 +112,6 @@ const SelectField = ({ label, name, value, options, hint }) => {
|
|
|
127
112
|
});
|
|
128
113
|
};
|
|
129
114
|
//#endregion
|
|
130
|
-
export {
|
|
115
|
+
export { Field, SelectField, TextareaField };
|
|
131
116
|
|
|
132
|
-
//# sourceMappingURL=
|
|
117
|
+
//# sourceMappingURL=forms.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"forms.mjs","names":[],"sources":["../../src/ui/forms.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n// eslint-disable-next-line promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString>\nconst FieldAssistant: FC<{ name: string; error: string | undefined; hint: string | undefined }> = ({\n name,\n error,\n hint,\n}) => {\n if (error) {\n return (\n <p class=\"field__error\" id={`${name}-error`} role=\"alert\">\n {error}\n </p>\n );\n }\n if (hint) {\n return (\n <p class=\"field__hint\" id={`${name}-hint`}>\n {hint}\n </p>\n );\n }\n return null;\n};\n\nfunction fieldDescribedBy(\n name: string,\n error: string | undefined,\n hint: string | undefined,\n): string | undefined {\n if (error) {\n return `${name}-error`;\n }\n if (hint) {\n return `${name}-hint`;\n }\n return undefined;\n}\n\n/** Labeled text input with error and hint states. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const Field: FC<{\n label: string;\n name: string;\n type?: string;\n value?: string;\n placeholder?: string;\n required?: boolean;\n error?: string;\n hint?: string;\n autocomplete?: string;\n}> = ({ label, name, type = \"text\", value, placeholder, required, error, hint, autocomplete }) => {\n return (\n <div class=\"field\">\n <label class=\"field__label\" for={name}>\n {label}\n {required ? <span aria-hidden=\"true\"> *</span> : null}\n </label>\n <input\n class={`field__input ${error ? \"field__input--error\" : \"\"}`}\n id={name}\n name={name}\n type={type}\n value={value}\n placeholder={placeholder}\n required={required}\n aria-invalid={error ? \"true\" : undefined}\n aria-describedby={fieldDescribedBy(name, error, hint)}\n autocomplete={autocomplete}\n />\n <FieldAssistant name={name} error={error} hint={hint} />\n </div>\n );\n};\n\n/** Labeled textarea with error and hint states. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const TextareaField: FC<{\n label: string;\n name: string;\n value?: string;\n placeholder?: string;\n rows?: number;\n hint?: string;\n error?: string;\n}> = ({ label, name, value, placeholder, rows = 3, hint, error }) => {\n return (\n <div class=\"field\">\n <label class=\"field__label\" for={name}>\n {label}\n </label>\n <textarea\n class={`field__input field__input--textarea ${error ? \"field__input--error\" : \"\"}`}\n id={name}\n name={name}\n placeholder={placeholder}\n rows={rows}\n aria-invalid={error ? \"true\" : undefined}\n aria-describedby={fieldDescribedBy(name, error, hint)}\n >\n {value}\n </textarea>\n <FieldAssistant name={name} error={error} hint={hint} />\n </div>\n );\n};\n\n/** Labeled select dropdown with an optional hint. */\n// eslint-disable-next-line promise-function-async -- JSX component return type\nexport const SelectField: FC<{\n label: string;\n name: string;\n value?: string;\n options: { value: string; label: string }[];\n hint?: string;\n}> = ({ label, name, value, options, hint }) => {\n return (\n <div class=\"field\">\n <label class=\"field__label\" for={name}>\n {label}\n </label>\n <select\n class=\"field__input\"\n id={name}\n name={name}\n aria-describedby={hint ? `${name}-hint` : undefined}\n >\n {options.map((opt) => (\n <option value={opt.value} selected={opt.value === value}>\n {opt.label}\n </option>\n ))}\n </select>\n {hint ? (\n <p class=\"field__hint\" id={`${name}-hint`}>\n {hint}\n </p>\n ) : null}\n </div>\n );\n};\n"],"mappings":";;;;;AAKA,MAAM,kBAA6F,EACjG,MACA,OACA,WACI;CACJ,IAAI,OACF,OACE,oBAAC,KAAD;EAAG,OAAM;EAAe,IAAI,GAAG,KAAK;EAAS,MAAK;EAC/C,UAAA;CACA,CAAA;CAGP,IAAI,MACF,OACE,oBAAC,KAAD;EAAG,OAAM;EAAc,IAAI,GAAG,KAAK;EAChC,UAAA;CACA,CAAA;CAGP,OAAO;AACT;AAEA,SAAS,iBACP,MACA,OACA,MACoB;CACpB,IAAI,OACF,OAAO,GAAG,KAAK;CAEjB,IAAI,MACF,OAAO,GAAG,KAAK;AAGnB;;AAIA,MAAa,SAUP,EAAE,OAAO,MAAM,OAAO,QAAQ,OAAO,aAAa,UAAU,OAAO,MAAM,mBAAmB;CAChG,OACE,qBAAC,OAAD;EAAK,OAAM;EAAX,UAAA;GACE,qBAAC,SAAD;IAAO,OAAM;IAAe,KAAK;IAAjC,UAAA,CACG,OACA,WAAW,oBAAC,QAAD;KAAM,eAAY;KAAO,UAAA;IAAQ,CAAA,IAAI,IAC5C;;GACP,oBAAC,SAAD;IACE,OAAO,gBAAgB,QAAQ,wBAAwB;IACvD,IAAI;IACE;IACA;IACC;IACM;IACH;IACV,gBAAc,QAAQ,SAAS,KAAA;IAC/B,oBAAkB,iBAAiB,MAAM,OAAO,IAAI;IACtC;GACf,CAAA;GACD,oBAAC,gBAAD;IAAsB;IAAa;IAAa;GAAO,CAAA;EACpD;;AAET;;AAIA,MAAa,iBAQP,EAAE,OAAO,MAAM,OAAO,aAAa,OAAO,GAAG,MAAM,YAAY;CACnE,OACE,qBAAC,OAAD;EAAK,OAAM;EAAX,UAAA;GACE,oBAAC,SAAD;IAAO,OAAM;IAAe,KAAK;IAC9B,UAAA;GACI,CAAA;GACP,oBAAC,YAAD;IACE,OAAO,uCAAuC,QAAQ,wBAAwB;IAC9E,IAAI;IACE;IACO;IACP;IACN,gBAAc,QAAQ,SAAS,KAAA;IAC/B,oBAAkB,iBAAiB,MAAM,OAAO,IAAI;IAEnD,UAAA;GACO,CAAA;GACV,oBAAC,gBAAD;IAAsB;IAAa;IAAa;GAAO,CAAA;EACpD;;AAET;;AAIA,MAAa,eAMP,EAAE,OAAO,MAAM,OAAO,SAAS,WAAW;CAC9C,OACE,qBAAC,OAAD;EAAK,OAAM;EAAX,UAAA;GACE,oBAAC,SAAD;IAAO,OAAM;IAAe,KAAK;IAC9B,UAAA;GACI,CAAA;GACP,oBAAC,UAAD;IACE,OAAM;IACN,IAAI;IACE;IACN,oBAAkB,OAAO,GAAG,KAAK,SAAS,KAAA;IAEzC,UAAA,QAAQ,KAAK,QACZ,oBAAC,UAAD;KAAQ,OAAO,IAAI;KAAO,UAAU,IAAI,UAAU;KAC/C,UAAA,IAAI;IACC,CAAA,CACT;GACK,CAAA;GACP,OACC,oBAAC,KAAD;IAAG,OAAM;IAAc,IAAI,GAAG,KAAK;IAChC,UAAA;GACA,CAAA,IACD;EACD;;AAET"}
|
package/dist/ui/styles.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"styles.mjs","names":[],"sources":["../../src/ui/styles.ts"],"sourcesContent":["import type { BrandTheme } from \"./theme.ts\";\n\n/** Build the global CSS stylesheet from the light and dark brand themes. */\nexport function baseStyle(light: BrandTheme, dark: BrandTheme): string {\n return `\n :root {\n --accent: ${light.accent};\n --accent-contrast: #fff;\n --surface-base: ${light.surface.base};\n --surface-card: ${light.surface.card};\n --surface-muted: #f4f4f5;\n --text-primary: ${light.text.primary};\n --text-secondary: ${light.text.secondary};\n --border: ${light.border};\n --radius: 10px;\n --radius-sm: 6px;\n --shadow: 0 1px 2px rgba(0,0,0,.06), 0 4px 12px rgba(0,0,0,.04);\n --status-approved: ${light.status.approved};\n --status-new: ${light.status.new};\n --status-rejected: ${light.status.rejected};\n --topbar-bg: ${light.accent};\n --sidebar-bg: #ffffff;\n --sidebar-width: 240px;\n }\n [data-theme=\"dark\"] {\n --accent: ${dark.accent};\n --surface-base: ${dark.surface.base};\n --surface-card: ${dark.surface.card};\n --surface-muted: #1e1e22;\n --text-primary: ${dark.text.primary};\n --text-secondary: ${dark.text.secondary};\n --border: ${dark.border};\n --status-approved: ${dark.status.approved};\n --status-new: ${dark.status.new};\n --status-rejected: ${dark.status.rejected};\n --topbar-bg: #0f172a;\n --sidebar-bg: #111113;\n }\n @media (prefers-color-scheme: dark) {\n [data-theme=\"system\"] {\n --accent: ${dark.accent};\n --surface-base: ${dark.surface.base};\n --surface-card: ${dark.surface.card};\n --surface-muted: #1e1e22;\n --text-primary: ${dark.text.primary};\n --text-secondary: ${dark.text.secondary};\n --border: ${dark.border};\n --status-approved: ${dark.status.approved};\n --status-new: ${dark.status.new};\n --status-rejected: ${dark.status.rejected};\n --topbar-bg: #0f172a;\n --sidebar-bg: #111113;\n }\n }\n * { box-sizing: border-box; }\n html { scroll-behavior: smooth; }\n body { margin: 0; font-family: ui-sans-system, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background: var(--surface-base); color: var(--text-primary); line-height: 1.5; }\n a { color: var(--accent); text-decoration: none; }\n a:hover { text-decoration: underline; }\n a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n .skip-link { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }\n .skip-link:focus { left: 1rem; top: 1rem; width: auto; height: auto; background: var(--surface-card); color: var(--text-primary); padding: .5rem .75rem; border-radius: var(--radius-sm); box-shadow: var(--shadow); z-index: 100; }\n .topbar { position: sticky; top: 0; z-index: 40; background: var(--topbar-bg); color: #fff; border-bottom: 1px solid rgba(255,255,255,.12); }\n .topbar__inner { max-width: 1440px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .6rem 1rem; }\n .topbar__left, .topbar__right { display: flex; align-items: center; gap: .75rem; min-width: 0; }\n .topbar__menu { display: none; background: transparent; border: 1px solid rgba(255,255,255,.3); color: #fff; border-radius: 6px; padding: .35rem .5rem; cursor: pointer; }\n .brand { display: inline-flex; align-items: center; gap: .5rem; color: #fff; font-weight: 650; text-decoration: none; }\n .brand__mark { width: 28px; height: 28px; display: inline-grid; place-items: center; background: rgba(255,255,255,.18); border-radius: 8px; }\n .logo { border-radius: 6px; display: block; }\n .project-crumb { display: inline-flex; align-items: center; gap: .35rem; color: rgba(255,255,255,.9); }\n .project-crumb a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }\n .project-crumb__sep { opacity: .7; }\n .topbar__theme { background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.22); color: #fff; border-radius: 999px; padding: .35rem .6rem; cursor: pointer; display: inline-flex; gap: .25rem; }\n .topbar__theme [data-theme-icon] { display: none; }\n [data-theme=\"light\"] [data-theme-icon=\"light\"], [data-theme=\"dark\"] [data-theme-icon=\"dark\"], [data-theme=\"system\"] [data-theme-icon=\"system\"] { display: inline; }\n .topbar__login { background: #fff; color: var(--accent); padding: .4rem .75rem; border-radius: 999px; font-weight: 600; text-decoration: none; }\n .user-menu { display: inline-flex; align-items: center; gap: .5rem; background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.2); padding: .25rem .5rem .25rem .35rem; border-radius: 999px; }\n .user-menu__avatar { width: 28px; height: 28px; border-radius: 999px; object-fit: cover; background: rgba(255,255,255,.2); }\n .user-menu__avatar--fallback { display: inline-grid; place-items: center; font-weight: 700; color: #fff; }\n .user-menu__name { color: #fff; font-weight: 600; max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .user-menu__role { font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; background: rgba(255,255,255,.2); color: #fff; padding: .15rem .4rem; border-radius: 999px; }\n .user-menu__logout { color: #fff; font-size: .85rem; text-decoration: underline; text-underline-offset: 2px; margin-left: .25rem; }\n .shell { max-width: 1440px; margin: 0 auto; display: grid; grid-template-columns: var(--sidebar-width) 1fr; min-height: calc(100vh - 56px); }\n .sidebar { background: var(--sidebar-bg); border-right: 1px solid var(--border); padding: 1rem .75rem; position: sticky; top: 56px; height: calc(100vh - 56px); overflow: auto; }\n .sidebar__nav { display: flex; flex-direction: column; gap: .25rem; }\n .sidebar__section { margin: 1rem 0 .35rem; font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-secondary); padding: 0 .5rem; }\n .sidebar__link { display: flex; align-items: center; gap: .5rem; padding: .5rem .6rem; border-radius: 8px; color: var(--text-primary); text-decoration: none; }\n .sidebar__link:hover { background: var(--surface-muted); text-decoration: none; }\n .sidebar__link--active { background: var(--surface-muted); font-weight: 600; }\n .content { padding: 1.25rem 1.5rem 2rem; min-width: 0; max-width: 1100px; }\n .page-header { margin-bottom: 1.25rem; }\n .page-header__row { display: flex; gap: 1rem; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }\n .page-header__title { margin: 0; font-size: 1.6rem; line-height: 1.2; letter-spacing: -0.02em; }\n .page-header__desc { margin: .35rem 0 0; color: var(--text-secondary); max-width: 60ch; }\n .page-header__actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }\n .breadcrumbs ol { list-style: none; padding: 0; margin: 0 0 .5rem; display: flex; gap: .4rem; flex-wrap: wrap; color: var(--text-secondary); font-size: .85rem; }\n .breadcrumbs li + li::before { content: \"/\"; margin-right: .4rem; color: var(--text-secondary); }\n .card { background: var(--surface-card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }\n .card--padded { padding: 1rem; }\n .btn { appearance: none; border: 1px solid transparent; border-radius: 8px; padding: .55rem .85rem; font-weight: 600; font-size: .9rem; cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: .4rem; line-height: 1; }\n .btn--primary { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }\n .btn--primary:hover { filter: brightness(1.05); text-decoration: none; }\n .btn--secondary { background: var(--surface-card); color: var(--text-primary); border-color: var(--border); }\n .btn--ghost { background: transparent; color: var(--text-primary); border-color: transparent; }\n .btn--danger { background: var(--status-rejected); color: #fff; border-color: var(--status-rejected); }\n .btn:disabled { opacity: .6; cursor: not-allowed; }\n .badge { display: inline-flex; align-items: center; padding: .15rem .5rem; border-radius: 999px; font-size: .75rem; font-weight: 650; letter-spacing: .02em; border: 1px solid var(--border); background: var(--surface-muted); color: var(--text-secondary); }\n .badge--success { background: color-mix(in srgb, var(--status-approved) 14%, var(--surface-card)); color: var(--status-approved); border-color: color-mix(in srgb, var(--status-approved) 30%, var(--border)); }\n .badge--warning { background: color-mix(in srgb, var(--status-new) 14%, var(--surface-card)); color: var(--status-new); border-color: color-mix(in srgb, var(--status-new) 30%, var(--border)); }\n .badge--danger { background: color-mix(in srgb, var(--status-rejected) 14%, var(--surface-card)); color: var(--status-rejected); border-color: color-mix(in srgb, var(--status-rejected) 30%, var(--border)); }\n .badge--info { background: color-mix(in srgb, var(--accent) 10%, var(--surface-card)); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 25%, var(--border)); }\n .badge--neutral { background: var(--surface-muted); color: var(--text-secondary); }\n .field { display: grid; gap: .35rem; margin-bottom: .9rem; }\n .field__label { font-weight: 600; font-size: .9rem; }\n .field__input { width: 100%; padding: .6rem .7rem; border-radius: 8px; border: 1px solid var(--border); background: var(--surface-card); color: var(--text-primary); font: inherit; }\n .field__input:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }\n .field__input--error { border-color: var(--status-rejected); }\n .field__input--textarea { resize: vertical; }\n .field__hint { margin: 0; color: var(--text-secondary); font-size: .85rem; }\n .field__error { margin: 0; color: var(--status-rejected); font-size: .85rem; }\n .alert { border-radius: 8px; padding: .75rem .85rem; border: 1px solid var(--border); background: var(--surface-card); }\n .alert--info { border-color: color-mix(in srgb, var(--accent) 22%, var(--border)); background: color-mix(in srgb, var(--accent) 7%, var(--surface-card)); }\n .alert--success { border-color: color-mix(in srgb, var(--status-approved) 22%, var(--border)); background: color-mix(in srgb, var(--status-approved) 7%, var(--surface-card)); }\n .alert--warning { border-color: color-mix(in srgb, var(--status-new) 22%, var(--border)); background: color-mix(in srgb, var(--status-new) 7%, var(--surface-card)); }\n .alert--danger { border-color: color-mix(in srgb, var(--status-rejected) 22%, var(--border)); background: color-mix(in srgb, var(--status-rejected) 7%, var(--surface-card)); }\n .alert__title { display: block; margin-bottom: .2rem; }\n .tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--border); margin-bottom: 1rem; overflow-x: auto; }\n .tabs__link { padding: .6rem .75rem; border-bottom: 2px solid transparent; color: var(--text-secondary); text-decoration: none; white-space: nowrap; font-weight: 600; }\n .tabs__link:hover { color: var(--text-primary); text-decoration: none; }\n .tabs__link--active { color: var(--text-primary); border-bottom-color: var(--accent); }\n .empty { text-align: center; padding: 2rem 1rem; border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface-card); }\n .empty__title { margin: 0 0 .3rem; font-size: 1.1rem; }\n .empty__desc { margin: 0 auto; color: var(--text-secondary); max-width: 50ch; }\n .empty__action { margin-top: 1rem; }\n .grid { display: grid; gap: 1rem; }\n .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n @media (max-width: 880px) { .grid--2, .grid--3 { grid-template-columns: 1fr; } }\n .table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-card); }\n table { width: 100%; border-collapse: collapse; font-size: .9rem; }\n th, td { text-align: left; padding: .65rem .75rem; border-bottom: 1px solid var(--border); vertical-align: top; }\n th { background: var(--surface-muted); font-weight: 650; color: var(--text-secondary); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }\n tr:last-child td { border-bottom: 0; }\n .stat { text-align: center; padding: .5rem; }\n .stat__value { font-size: 1.4rem; font-weight: 750; line-height: 1; }\n .stat__label { color: var(--text-secondary); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }\n .snapshot-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }\n .snapshot-card { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-card); display: flex; flex-direction: column; }\n .snapshot-card__head { padding: .6rem .75rem; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; gap: .5rem; align-items: center; }\n .snapshot-card__meta { font-size: .8rem; color: var(--text-secondary); }\n .snapshot-card__body { padding: .5rem; display: grid; gap: .5rem; }\n .diff-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem; }\n @media (max-width: 900px) { .diff-grid { grid-template-columns: 1fr; } }\n .diff-pane { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-card); }\n .diff-pane__label { padding: .4rem .6rem; font-weight: 650; font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-secondary); background: var(--surface-muted); border-bottom: 1px solid var(--border); }\n .diff-pane__img { display: block; width: 100%; height: auto; background: repeating-conic-gradient(#e5e7eb 0% 25%, #f9fafb 0% 50%) 0 0 / 16px 16px; }\n .comment { border: 1px solid var(--border); border-radius: var(--radius); padding: .75rem; background: var(--surface-card); }\n .comment__head { display: flex; gap: .5rem; align-items: center; font-size: .85rem; color: var(--text-secondary); }\n .comment__body { margin: .5rem 0 0; white-space: pre-wrap; word-break: break-word; }\n @media (max-width: 880px) {\n .topbar__menu { display: inline-flex; }\n .shell { grid-template-columns: 1fr; }\n .sidebar { display: none; position: fixed; inset: 56px 0 0 0; z-index: 30; height: auto; }\n .sidebar--open { display: block; }\n .content { padding: 1rem; }\n }\n `;\n}"],"mappings":";;;;;AAGA,SAAgB,UAAU,OAAmB,MAA0B;CACrE,OAAO;;kBAES,MAAM,OAAO;;wBAEP,MAAM,QAAQ,KAAK;wBACnB,MAAM,QAAQ,KAAK;;wBAEnB,MAAM,KAAK,QAAQ;0BACjB,MAAM,KAAK,UAAU;kBAC7B,MAAM,OAAO;;;;2BAIJ,MAAM,OAAO,SAAS;sBAC3B,MAAM,OAAO,IAAI;2BACZ,MAAM,OAAO,SAAS;qBAC5B,MAAM,OAAO;;;;;kBAKhB,KAAK,OAAO;wBACN,KAAK,QAAQ,KAAK;wBAClB,KAAK,QAAQ,KAAK;;wBAElB,KAAK,KAAK,QAAQ;0BAChB,KAAK,KAAK,UAAU;kBAC5B,KAAK,OAAO;2BACH,KAAK,OAAO,SAAS;sBAC1B,KAAK,OAAO,IAAI;2BACX,KAAK,OAAO,SAAS;;;;;;oBAM5B,KAAK,OAAO;0BACN,KAAK,QAAQ,KAAK;0BAClB,KAAK,QAAQ,KAAK;;0BAElB,KAAK,KAAK,QAAQ;4BAChB,KAAK,KAAK,UAAU;oBAC5B,KAAK,OAAO;6BACH,KAAK,OAAO,SAAS;wBAC1B,KAAK,OAAO,IAAI;6BACX,KAAK,OAAO,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsHlD"}
|
|
1
|
+
{"version":3,"file":"styles.mjs","names":[],"sources":["../../src/ui/styles.ts"],"sourcesContent":["import type { BrandTheme } from \"./theme.ts\";\n\n/** Build the global CSS stylesheet from the light and dark brand themes. */\nexport function baseStyle(light: BrandTheme, dark: BrandTheme): string {\n return `\n :root {\n --accent: ${light.accent};\n --accent-contrast: #fff;\n --surface-base: ${light.surface.base};\n --surface-card: ${light.surface.card};\n --surface-muted: #f4f4f5;\n --text-primary: ${light.text.primary};\n --text-secondary: ${light.text.secondary};\n --border: ${light.border};\n --radius: 10px;\n --radius-sm: 6px;\n --shadow: 0 1px 2px rgba(0,0,0,.06), 0 4px 12px rgba(0,0,0,.04);\n --status-approved: ${light.status.approved};\n --status-new: ${light.status.new};\n --status-rejected: ${light.status.rejected};\n --topbar-bg: ${light.accent};\n --sidebar-bg: #ffffff;\n --sidebar-width: 240px;\n }\n [data-theme=\"dark\"] {\n --accent: ${dark.accent};\n --surface-base: ${dark.surface.base};\n --surface-card: ${dark.surface.card};\n --surface-muted: #1e1e22;\n --text-primary: ${dark.text.primary};\n --text-secondary: ${dark.text.secondary};\n --border: ${dark.border};\n --status-approved: ${dark.status.approved};\n --status-new: ${dark.status.new};\n --status-rejected: ${dark.status.rejected};\n --topbar-bg: #0f172a;\n --sidebar-bg: #111113;\n }\n @media (prefers-color-scheme: dark) {\n [data-theme=\"system\"] {\n --accent: ${dark.accent};\n --surface-base: ${dark.surface.base};\n --surface-card: ${dark.surface.card};\n --surface-muted: #1e1e22;\n --text-primary: ${dark.text.primary};\n --text-secondary: ${dark.text.secondary};\n --border: ${dark.border};\n --status-approved: ${dark.status.approved};\n --status-new: ${dark.status.new};\n --status-rejected: ${dark.status.rejected};\n --topbar-bg: #0f172a;\n --sidebar-bg: #111113;\n }\n }\n * { box-sizing: border-box; }\n html { scroll-behavior: smooth; }\n body { margin: 0; font-family: ui-sans-system, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; background: var(--surface-base); color: var(--text-primary); line-height: 1.5; }\n a { color: var(--accent); text-decoration: none; }\n a:hover { text-decoration: underline; }\n a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }\n .skip-link { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }\n .skip-link:focus { left: 1rem; top: 1rem; width: auto; height: auto; background: var(--surface-card); color: var(--text-primary); padding: .5rem .75rem; border-radius: var(--radius-sm); box-shadow: var(--shadow); z-index: 100; }\n .topbar { position: sticky; top: 0; z-index: 40; background: var(--topbar-bg); color: #fff; border-bottom: 1px solid rgba(255,255,255,.12); }\n .topbar__inner { max-width: 1440px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .6rem 1rem; }\n .topbar__left, .topbar__right { display: flex; align-items: center; gap: .75rem; min-width: 0; }\n .topbar__menu { display: none; background: transparent; border: 1px solid rgba(255,255,255,.3); color: #fff; border-radius: 6px; padding: .35rem .5rem; cursor: pointer; }\n .brand { display: inline-flex; align-items: center; gap: .5rem; color: #fff; font-weight: 650; text-decoration: none; }\n .brand__mark { width: 28px; height: 28px; display: inline-grid; place-items: center; background: rgba(255,255,255,.18); border-radius: 8px; }\n .logo { border-radius: 6px; display: block; }\n .project-crumb { display: inline-flex; align-items: center; gap: .35rem; color: rgba(255,255,255,.9); }\n .project-crumb a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }\n .project-crumb__sep { opacity: .7; }\n .topbar__theme { background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.22); color: #fff; border-radius: 999px; padding: .35rem .6rem; cursor: pointer; display: inline-flex; gap: .25rem; }\n .topbar__theme [data-theme-icon] { display: none; }\n [data-theme=\"light\"] [data-theme-icon=\"light\"], [data-theme=\"dark\"] [data-theme-icon=\"dark\"], [data-theme=\"system\"] [data-theme-icon=\"system\"] { display: inline; }\n .topbar__login { background: #fff; color: var(--accent); padding: .4rem .75rem; border-radius: 999px; font-weight: 600; text-decoration: none; }\n .user-menu { display: inline-flex; align-items: center; gap: .5rem; background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.2); padding: .25rem .5rem .25rem .35rem; border-radius: 999px; }\n .user-menu__avatar { width: 28px; height: 28px; border-radius: 999px; object-fit: cover; background: rgba(255,255,255,.2); }\n .user-menu__avatar--fallback { display: inline-grid; place-items: center; font-weight: 700; color: #fff; }\n .user-menu__name { color: #fff; font-weight: 600; max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .user-menu__role { font-size: .7rem; text-transform: uppercase; letter-spacing: .06em; background: rgba(255,255,255,.2); color: #fff; padding: .15rem .4rem; border-radius: 999px; }\n .user-menu__logout { color: #fff; font-size: .85rem; text-decoration: underline; text-underline-offset: 2px; margin-left: .25rem; }\n .shell { max-width: 1440px; margin: 0 auto; display: grid; grid-template-columns: var(--sidebar-width) 1fr; min-height: calc(100vh - 56px); }\n .sidebar { background: var(--sidebar-bg); border-right: 1px solid var(--border); padding: 1rem .75rem; position: sticky; top: 56px; height: calc(100vh - 56px); overflow: auto; }\n .sidebar__nav { display: flex; flex-direction: column; gap: .25rem; }\n .sidebar__section { margin: 1rem 0 .35rem; font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-secondary); padding: 0 .5rem; }\n .sidebar__link { display: flex; align-items: center; gap: .5rem; padding: .5rem .6rem; border-radius: 8px; color: var(--text-primary); text-decoration: none; }\n .sidebar__link:hover { background: var(--surface-muted); text-decoration: none; }\n .sidebar__link--active { background: var(--surface-muted); font-weight: 600; }\n .content { padding: 1.25rem 1.5rem 2rem; min-width: 0; max-width: 1100px; }\n .page-header { margin-bottom: 1.25rem; }\n .page-header__row { display: flex; gap: 1rem; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }\n .page-header__title { margin: 0; font-size: 1.6rem; line-height: 1.2; letter-spacing: -0.02em; }\n .page-header__desc { margin: .35rem 0 0; color: var(--text-secondary); max-width: 60ch; }\n .page-header__actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }\n .breadcrumbs ol { list-style: none; padding: 0; margin: 0 0 .5rem; display: flex; gap: .4rem; flex-wrap: wrap; color: var(--text-secondary); font-size: .85rem; }\n .breadcrumbs li + li::before { content: \"/\"; margin-right: .4rem; color: var(--text-secondary); }\n .card { background: var(--surface-card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }\n .card--padded { padding: 1rem; }\n .btn { appearance: none; border: 1px solid transparent; border-radius: 8px; padding: .55rem .85rem; font-weight: 600; font-size: .9rem; cursor: pointer; text-decoration: none; display: inline-flex; align-items: center; justify-content: center; gap: .4rem; line-height: 1; }\n .btn--primary { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }\n .btn--primary:hover { filter: brightness(1.05); text-decoration: none; }\n .btn--secondary { background: var(--surface-card); color: var(--text-primary); border-color: var(--border); }\n .btn--ghost { background: transparent; color: var(--text-primary); border-color: transparent; }\n .btn--danger { background: var(--status-rejected); color: #fff; border-color: var(--status-rejected); }\n .btn:disabled { opacity: .6; cursor: not-allowed; }\n .badge { display: inline-flex; align-items: center; padding: .15rem .5rem; border-radius: 999px; font-size: .75rem; font-weight: 650; letter-spacing: .02em; border: 1px solid var(--border); background: var(--surface-muted); color: var(--text-secondary); }\n .badge--success { background: color-mix(in srgb, var(--status-approved) 14%, var(--surface-card)); color: var(--status-approved); border-color: color-mix(in srgb, var(--status-approved) 30%, var(--border)); }\n .badge--warning { background: color-mix(in srgb, var(--status-new) 14%, var(--surface-card)); color: var(--status-new); border-color: color-mix(in srgb, var(--status-new) 30%, var(--border)); }\n .badge--danger { background: color-mix(in srgb, var(--status-rejected) 14%, var(--surface-card)); color: var(--status-rejected); border-color: color-mix(in srgb, var(--status-rejected) 30%, var(--border)); }\n .badge--info { background: color-mix(in srgb, var(--accent) 10%, var(--surface-card)); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 25%, var(--border)); }\n .badge--neutral { background: var(--surface-muted); color: var(--text-secondary); }\n .field { display: grid; gap: .35rem; margin-bottom: .9rem; }\n .field__label { font-weight: 600; font-size: .9rem; }\n .field__input { width: 100%; padding: .6rem .7rem; border-radius: 8px; border: 1px solid var(--border); background: var(--surface-card); color: var(--text-primary); font: inherit; }\n .field__input:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }\n .field__input--error { border-color: var(--status-rejected); }\n .field__input--textarea { resize: vertical; }\n .field__hint { margin: 0; color: var(--text-secondary); font-size: .85rem; }\n .field__error { margin: 0; color: var(--status-rejected); font-size: .85rem; }\n .alert { border-radius: 8px; padding: .75rem .85rem; border: 1px solid var(--border); background: var(--surface-card); }\n .alert--info { border-color: color-mix(in srgb, var(--accent) 22%, var(--border)); background: color-mix(in srgb, var(--accent) 7%, var(--surface-card)); }\n .alert--success { border-color: color-mix(in srgb, var(--status-approved) 22%, var(--border)); background: color-mix(in srgb, var(--status-approved) 7%, var(--surface-card)); }\n .alert--warning { border-color: color-mix(in srgb, var(--status-new) 22%, var(--border)); background: color-mix(in srgb, var(--status-new) 7%, var(--surface-card)); }\n .alert--danger { border-color: color-mix(in srgb, var(--status-rejected) 22%, var(--border)); background: color-mix(in srgb, var(--status-rejected) 7%, var(--surface-card)); }\n .alert__title { display: block; margin-bottom: .2rem; }\n .tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--border); margin-bottom: 1rem; overflow-x: auto; }\n .tabs__link { padding: .6rem .75rem; border-bottom: 2px solid transparent; color: var(--text-secondary); text-decoration: none; white-space: nowrap; font-weight: 600; }\n .tabs__link:hover { color: var(--text-primary); text-decoration: none; }\n .tabs__link--active { color: var(--text-primary); border-bottom-color: var(--accent); }\n .empty { text-align: center; padding: 2rem 1rem; border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface-card); }\n .empty__title { margin: 0 0 .3rem; font-size: 1.1rem; }\n .empty__desc { margin: 0 auto; color: var(--text-secondary); max-width: 50ch; }\n .empty__action { margin-top: 1rem; }\n .grid { display: grid; gap: 1rem; }\n .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }\n @media (max-width: 880px) { .grid--2, .grid--3 { grid-template-columns: 1fr; } }\n .table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-card); }\n table { width: 100%; border-collapse: collapse; font-size: .9rem; }\n th, td { text-align: left; padding: .65rem .75rem; border-bottom: 1px solid var(--border); vertical-align: top; }\n th { background: var(--surface-muted); font-weight: 650; color: var(--text-secondary); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }\n tr:last-child td { border-bottom: 0; }\n .stat { text-align: center; padding: .5rem; }\n .stat__value { font-size: 1.4rem; font-weight: 750; line-height: 1; }\n .stat__label { color: var(--text-secondary); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }\n .snapshot-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }\n .snapshot-card { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-card); display: flex; flex-direction: column; }\n .snapshot-card__head { padding: .6rem .75rem; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; gap: .5rem; align-items: center; }\n .snapshot-card__meta { font-size: .8rem; color: var(--text-secondary); }\n .snapshot-card__body { padding: .5rem; display: grid; gap: .5rem; }\n .diff-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem; }\n @media (max-width: 900px) { .diff-grid { grid-template-columns: 1fr; } }\n .diff-pane { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-card); }\n .diff-pane__label { padding: .4rem .6rem; font-weight: 650; font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; color: var(--text-secondary); background: var(--surface-muted); border-bottom: 1px solid var(--border); }\n .diff-pane__img { display: block; width: 100%; height: auto; background: repeating-conic-gradient(#e5e7eb 0% 25%, #f9fafb 0% 50%) 0 0 / 16px 16px; }\n .comment { border: 1px solid var(--border); border-radius: var(--radius); padding: .75rem; background: var(--surface-card); }\n .comment__head { display: flex; gap: .5rem; align-items: center; font-size: .85rem; color: var(--text-secondary); }\n .comment__body { margin: .5rem 0 0; white-space: pre-wrap; word-break: break-word; }\n @media (max-width: 880px) {\n .topbar__menu { display: inline-flex; }\n .shell { grid-template-columns: 1fr; }\n .sidebar { display: none; position: fixed; inset: 56px 0 0 0; z-index: 30; height: auto; }\n .sidebar--open { display: block; }\n .content { padding: 1rem; }\n }\n `;\n}\n"],"mappings":";;;;;AAGA,SAAgB,UAAU,OAAmB,MAA0B;CACrE,OAAO;;kBAES,MAAM,OAAO;;wBAEP,MAAM,QAAQ,KAAK;wBACnB,MAAM,QAAQ,KAAK;;wBAEnB,MAAM,KAAK,QAAQ;0BACjB,MAAM,KAAK,UAAU;kBAC7B,MAAM,OAAO;;;;2BAIJ,MAAM,OAAO,SAAS;sBAC3B,MAAM,OAAO,IAAI;2BACZ,MAAM,OAAO,SAAS;qBAC5B,MAAM,OAAO;;;;;kBAKhB,KAAK,OAAO;wBACN,KAAK,QAAQ,KAAK;wBAClB,KAAK,QAAQ,KAAK;;wBAElB,KAAK,KAAK,QAAQ;0BAChB,KAAK,KAAK,UAAU;kBAC5B,KAAK,OAAO;2BACH,KAAK,OAAO,SAAS;sBAC1B,KAAK,OAAO,IAAI;2BACX,KAAK,OAAO,SAAS;;;;;;oBAM5B,KAAK,OAAO;0BACN,KAAK,QAAQ,KAAK;0BAClB,KAAK,QAAQ,KAAK;;0BAElB,KAAK,KAAK,QAAQ;4BAChB,KAAK,KAAK,UAAU;oBAC5B,KAAK,OAAO;6BACH,KAAK,OAAO,SAAS;wBAC1B,KAAK,OAAO,IAAI;6BACX,KAAK,OAAO,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsHlD"}
|
package/dist/urls.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"urls.mjs","names":[],"sources":["../src/urls.ts"],"sourcesContent":["/** Type-safe URL builder for project pages and published Storybooks. */\nexport interface UrlBuilder {\n projectsList(): string;\n project(slug: string): string;\n buildsList(slug: string): string;\n build(slug: string, buildId: string): string;\n labels(slug: string): string;\n label(slug: string, key: string, value: string): string;\n storybook(slug: string): string;\n storybookLabel(slug: string, key: string, value: string): string;\n storybookBuild(slug: string, buildId: string): string;\n settings(slug: string): string;\n}\n\n/**\n * Create a URL builder rooted at the given base URL.\n *\n * @param baseUrl - Public root URL of the shelf server.\n * @param publishedBaseDomain - Optional wildcard domain for published Storybooks.\n * @returns The URL builder.\n */\nexport function createUrlBuilder(baseUrl: string, publishedBaseDomain?: string): UrlBuilder {\n const root = baseUrl.replace(/\\/+$/u, \"\");\n\n return {\n projectsList: () => root,\n project: (slug) => `${root}/projects/${slug}`,\n buildsList: (slug) => `${root}/projects/${slug}/builds`,\n build: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}`,\n labels: (slug) => `${root}/projects/${slug}/labels`,\n label: (slug, key, value)
|
|
1
|
+
{"version":3,"file":"urls.mjs","names":[],"sources":["../src/urls.ts"],"sourcesContent":["/** Type-safe URL builder for project pages and published Storybooks. */\nexport interface UrlBuilder {\n projectsList(): string;\n project(slug: string): string;\n buildsList(slug: string): string;\n build(slug: string, buildId: string): string;\n labels(slug: string): string;\n label(slug: string, key: string, value: string): string;\n storybook(slug: string): string;\n storybookLabel(slug: string, key: string, value: string): string;\n storybookBuild(slug: string, buildId: string): string;\n settings(slug: string): string;\n}\n\n/**\n * Create a URL builder rooted at the given base URL.\n *\n * @param baseUrl - Public root URL of the shelf server.\n * @param publishedBaseDomain - Optional wildcard domain for published Storybooks.\n * @returns The URL builder.\n */\nexport function createUrlBuilder(baseUrl: string, publishedBaseDomain?: string): UrlBuilder {\n const root = baseUrl.replace(/\\/+$/u, \"\");\n\n return {\n projectsList: () => root,\n project: (slug) => `${root}/projects/${slug}`,\n buildsList: (slug) => `${root}/projects/${slug}/builds`,\n build: (slug, buildId) => `${root}/projects/${slug}/builds/${buildId}`,\n labels: (slug) => `${root}/projects/${slug}/labels`,\n label: (slug, key, value) =>\n `${root}/projects/${slug}/labels/${encodeURIComponent(key)}/${encodeURI(value)}`,\n storybook: (slug) =>\n publishedBaseDomain\n ? `https://${slug}.${publishedBaseDomain}`\n : `${root}/projects/${slug}/storybook`,\n storybookLabel: (slug, key, value) =>\n `${root}/projects/${slug}/storybook/${encodeURIComponent(key)}/${encodeURI(value)}`,\n storybookBuild: (slug, buildId) =>\n publishedBaseDomain\n ? `https://${buildId}.${slug}.${publishedBaseDomain}`\n : `${root}/projects/${slug}/storybook/build/${buildId}`,\n settings: (slug) => `${root}/projects/${slug}/settings`,\n };\n}\n"],"mappings":";;;;;;;;;;;AAqBA,SAAgB,iBAAiB,SAAiB,qBAA0C;CAC1F,MAAM,OAAO,QAAQ,QAAQ,SAAS,EAAE;CAExC,OAAO;EACL,oBAAoB;EACpB,UAAU,SAAS,GAAG,KAAK,YAAY;EACvC,aAAa,SAAS,GAAG,KAAK,YAAY,KAAK;EAC/C,QAAQ,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,UAAU;EAC7D,SAAS,SAAS,GAAG,KAAK,YAAY,KAAK;EAC3C,QAAQ,MAAM,KAAK,UACjB,GAAG,KAAK,YAAY,KAAK,UAAU,mBAAmB,GAAG,EAAE,GAAG,UAAU,KAAK;EAC/E,YAAY,SACV,sBACI,WAAW,KAAK,GAAG,wBACnB,GAAG,KAAK,YAAY,KAAK;EAC/B,iBAAiB,MAAM,KAAK,UAC1B,GAAG,KAAK,YAAY,KAAK,aAAa,mBAAmB,GAAG,EAAE,GAAG,UAAU,KAAK;EAClF,iBAAiB,MAAM,YACrB,sBACI,WAAW,QAAQ,GAAG,KAAK,GAAG,wBAC9B,GAAG,KAAK,YAAY,KAAK,mBAAmB;EAClD,WAAW,SAAS,GAAG,KAAK,YAAY,KAAK;CAC/C;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyshelf/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "StoryShelf core: Hono router, adapter interfaces, models, capture pipeline, diff, retention.",
|
|
5
5
|
"homepage": "https://github.com/GuptaSiddhant/StoryShelf#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -31,6 +31,10 @@
|
|
|
31
31
|
"source": "./src/adapters/auth.ts",
|
|
32
32
|
"default": "./dist/adapter/auth.mjs"
|
|
33
33
|
},
|
|
34
|
+
"./adapter/capture-queue": {
|
|
35
|
+
"source": "./src/adapters/capture-queue.ts",
|
|
36
|
+
"default": "./dist/adapter/capture-queue.mjs"
|
|
37
|
+
},
|
|
34
38
|
"./adapter/capture-runner": {
|
|
35
39
|
"source": "./src/adapters/capture-runner.ts",
|
|
36
40
|
"default": "./dist/adapter/capture-runner.mjs"
|
|
@@ -43,85 +47,81 @@
|
|
|
43
47
|
"source": "./src/adapters/git-host/index.ts",
|
|
44
48
|
"default": "./dist/adapter/git-host.mjs"
|
|
45
49
|
},
|
|
50
|
+
"./adapter/git-host/comments": {
|
|
51
|
+
"source": "./src/adapters/git-host/comments.ts",
|
|
52
|
+
"default": "./dist/adapter/git-host/comments.mjs"
|
|
53
|
+
},
|
|
46
54
|
"./adapter/git-host/helpers": {
|
|
47
55
|
"source": "./src/adapters/git-host/helpers.ts",
|
|
48
56
|
"default": "./dist/adapter/git-host/helpers.mjs"
|
|
49
57
|
},
|
|
58
|
+
"./adapter/init": {
|
|
59
|
+
"source": "./src/adapters/init.ts",
|
|
60
|
+
"default": "./dist/adapter/init.mjs"
|
|
61
|
+
},
|
|
62
|
+
"./adapter/metadata": {
|
|
63
|
+
"source": "./src/adapters/metadata.ts",
|
|
64
|
+
"default": "./dist/adapter/metadata.mjs"
|
|
65
|
+
},
|
|
50
66
|
"./adapter/storage": {
|
|
51
67
|
"source": "./src/adapters/storage.ts",
|
|
52
68
|
"default": "./dist/adapter/storage.mjs"
|
|
53
69
|
},
|
|
70
|
+
"./capture": {
|
|
71
|
+
"source": "./src/capture/index.ts",
|
|
72
|
+
"default": "./dist/capture.mjs"
|
|
73
|
+
},
|
|
54
74
|
"./ddl": {
|
|
55
75
|
"source": "./src/ddl.ts",
|
|
56
76
|
"default": "./dist/ddl.mjs"
|
|
57
77
|
},
|
|
58
|
-
"./
|
|
59
|
-
"source": "./src/
|
|
60
|
-
"default": "./dist/
|
|
61
|
-
},
|
|
62
|
-
"./models/build": {
|
|
63
|
-
"source": "./src/models/build.ts",
|
|
64
|
-
"default": "./dist/models/build.mjs"
|
|
78
|
+
"./diff": {
|
|
79
|
+
"source": "./src/diff/index.ts",
|
|
80
|
+
"default": "./dist/diff.mjs"
|
|
65
81
|
},
|
|
66
|
-
"./
|
|
67
|
-
"source": "./src/
|
|
68
|
-
"default": "./dist/
|
|
82
|
+
"./logger": {
|
|
83
|
+
"source": "./src/logger.ts",
|
|
84
|
+
"default": "./dist/logger.mjs"
|
|
69
85
|
},
|
|
70
|
-
"./
|
|
71
|
-
"source": "./src/
|
|
72
|
-
"default": "./dist/
|
|
73
|
-
},
|
|
74
|
-
"./models/member": {
|
|
75
|
-
"source": "./src/models/member.ts",
|
|
76
|
-
"default": "./dist/models/member.mjs"
|
|
77
|
-
},
|
|
78
|
-
"./models/project": {
|
|
79
|
-
"source": "./src/models/project.ts",
|
|
80
|
-
"default": "./dist/models/project.mjs"
|
|
81
|
-
},
|
|
82
|
-
"./models/snapshot": {
|
|
83
|
-
"source": "./src/models/snapshot.ts",
|
|
84
|
-
"default": "./dist/models/snapshot.mjs"
|
|
85
|
-
},
|
|
86
|
-
"./models/token": {
|
|
87
|
-
"source": "./src/models/token.ts",
|
|
88
|
-
"default": "./dist/models/token.mjs"
|
|
89
|
-
},
|
|
90
|
-
"./models/webhook": {
|
|
91
|
-
"source": "./src/models/webhook.ts",
|
|
92
|
-
"default": "./dist/models/webhook.mjs"
|
|
86
|
+
"./paths": {
|
|
87
|
+
"source": "./src/utils/paths.ts",
|
|
88
|
+
"default": "./dist/paths.mjs"
|
|
93
89
|
},
|
|
94
90
|
"./schema": {
|
|
95
|
-
"source": "./src/schema.ts",
|
|
91
|
+
"source": "./src/schema/index.ts",
|
|
96
92
|
"default": "./dist/schema.mjs"
|
|
97
93
|
},
|
|
98
94
|
"./types": {
|
|
99
95
|
"source": "./src/types.ts",
|
|
100
96
|
"default": "./dist/types.mjs"
|
|
101
97
|
},
|
|
98
|
+
"./urls": {
|
|
99
|
+
"source": "./src/urls.ts",
|
|
100
|
+
"default": "./dist/urls.mjs"
|
|
101
|
+
},
|
|
102
102
|
"./package.json": "./package.json"
|
|
103
103
|
},
|
|
104
104
|
"publishConfig": {
|
|
105
105
|
"exports": {
|
|
106
106
|
".": "./dist/index.mjs",
|
|
107
107
|
"./adapter/auth": "./dist/adapter/auth.mjs",
|
|
108
|
+
"./adapter/capture-queue": "./dist/adapter/capture-queue.mjs",
|
|
108
109
|
"./adapter/capture-runner": "./dist/adapter/capture-runner.mjs",
|
|
109
110
|
"./adapter/database": "./dist/adapter/database.mjs",
|
|
110
111
|
"./adapter/git-host": "./dist/adapter/git-host.mjs",
|
|
112
|
+
"./adapter/git-host/comments": "./dist/adapter/git-host/comments.mjs",
|
|
111
113
|
"./adapter/git-host/helpers": "./dist/adapter/git-host/helpers.mjs",
|
|
114
|
+
"./adapter/init": "./dist/adapter/init.mjs",
|
|
115
|
+
"./adapter/metadata": "./dist/adapter/metadata.mjs",
|
|
112
116
|
"./adapter/storage": "./dist/adapter/storage.mjs",
|
|
117
|
+
"./capture": "./dist/capture.mjs",
|
|
113
118
|
"./ddl": "./dist/ddl.mjs",
|
|
114
|
-
"./
|
|
115
|
-
"./
|
|
116
|
-
"./
|
|
117
|
-
"./models/label": "./dist/models/label.mjs",
|
|
118
|
-
"./models/member": "./dist/models/member.mjs",
|
|
119
|
-
"./models/project": "./dist/models/project.mjs",
|
|
120
|
-
"./models/snapshot": "./dist/models/snapshot.mjs",
|
|
121
|
-
"./models/token": "./dist/models/token.mjs",
|
|
122
|
-
"./models/webhook": "./dist/models/webhook.mjs",
|
|
119
|
+
"./diff": "./dist/diff.mjs",
|
|
120
|
+
"./logger": "./dist/logger.mjs",
|
|
121
|
+
"./paths": "./dist/paths.mjs",
|
|
123
122
|
"./schema": "./dist/schema.mjs",
|
|
124
123
|
"./types": "./dist/types.mjs",
|
|
124
|
+
"./urls": "./dist/urls.mjs",
|
|
125
125
|
"./package.json": "./package.json"
|
|
126
126
|
},
|
|
127
127
|
"access": "public"
|
|
@@ -140,18 +140,20 @@
|
|
|
140
140
|
"dependencies": {
|
|
141
141
|
"@hono/swagger-ui": "^0.6.1",
|
|
142
142
|
"@hono/zod-openapi": "^1.1.5",
|
|
143
|
-
"adm-zip": "^0.6.0",
|
|
144
143
|
"drizzle-orm": "^0.44.0",
|
|
145
144
|
"hono": "^4.11.0",
|
|
146
145
|
"pino": "^10.3.1",
|
|
147
146
|
"pixelmatch": "^7.1.0",
|
|
148
147
|
"pngjs": "^7.0.0",
|
|
148
|
+
"unzipper": "0.12.5",
|
|
149
149
|
"zod": "^4.2.0"
|
|
150
150
|
},
|
|
151
151
|
"devDependencies": {
|
|
152
152
|
"@types/node": "catalog:",
|
|
153
153
|
"@types/pngjs": "^6.0.5",
|
|
154
|
+
"@types/unzipper": "0.10.11",
|
|
154
155
|
"@vitest/coverage-v8": "catalog:",
|
|
156
|
+
"adm-zip": "0.6.0",
|
|
155
157
|
"oxfmt": "catalog:",
|
|
156
158
|
"oxlint": "catalog:",
|
|
157
159
|
"oxlint-tsgolint": "catalog:",
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import __tsdown_shims_path from 'node:path';
|
|
2
|
-
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { z } from "zod";
|
|
4
|
-
//#region src/adapters/metadata.d.ts
|
|
5
|
-
/** Common adapter identity — every adapter instance exposes this. */
|
|
6
|
-
interface AdapterMetadata {
|
|
7
|
-
/** Human label for UI/logs. */
|
|
8
|
-
readonly name: string;
|
|
9
|
-
/** Package version injected at build via __PKG_VERSION__. */
|
|
10
|
-
readonly version: string;
|
|
11
|
-
/** Optional short description. */
|
|
12
|
-
readonly description?: string;
|
|
13
|
-
/** Machine key (e.g. "github", "sqlite", "local", "s3", "password", "oauth", "playwright", "sqs", "memory"). */
|
|
14
|
-
readonly kind: string;
|
|
15
|
-
}
|
|
16
|
-
/** Git-specific metadata extension (adds logo + validation schema). */
|
|
17
|
-
interface GitAdapterMetadata extends AdapterMetadata {
|
|
18
|
-
readonly kind: string;
|
|
19
|
-
readonly logo?: string;
|
|
20
|
-
readonly schema: z.ZodType;
|
|
21
|
-
}
|
|
22
|
-
//#endregion
|
|
23
|
-
export { AdapterMetadata, GitAdapterMetadata };
|
|
24
|
-
//# sourceMappingURL=metadata.d.mts.map
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import __tsdown_shims_path from 'node:path';
|
|
2
|
-
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
4
|
-
import { StorageAdapter } from "../adapter/storage.mjs";
|
|
5
|
-
import { Baseline } from "../schema.mjs";
|
|
6
|
-
//#region src/models/baseline.d.ts
|
|
7
|
-
/** Data operations for baseline screenshots. */
|
|
8
|
-
declare class BaselineModel {
|
|
9
|
-
private readonly db;
|
|
10
|
-
private readonly storage;
|
|
11
|
-
constructor(db: DatabaseAdapter, storage: StorageAdapter);
|
|
12
|
-
getFor(projectId: string, storyId: string, viewport: string, branch: string): Promise<Baseline | null>;
|
|
13
|
-
resolve(projectId: string, storyId: string, viewport: string, branch: string, defaultBranch: string): Promise<Baseline | null>;
|
|
14
|
-
read(baseline: Baseline): Promise<Buffer>;
|
|
15
|
-
upsert(projectId: string, storyId: string, viewport: string, branch: string, snapshotId: string, sourcePath: string): Promise<Baseline>;
|
|
16
|
-
list(projectId: string): Promise<Baseline[]>;
|
|
17
|
-
removeOrphans(projectId: string, validStoryIds: Set<string>): Promise<number>;
|
|
18
|
-
}
|
|
19
|
-
//#endregion
|
|
20
|
-
export { type Baseline, BaselineModel };
|
|
21
|
-
//# sourceMappingURL=baseline.d.mts.map
|
package/dist/models/build.d.mts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import __tsdown_shims_path from 'node:path';
|
|
2
|
-
import __tsdown_shims_url from 'node:url';
|
|
3
|
-
import { BuildStatus } from "../types.mjs";
|
|
4
|
-
import { DatabaseAdapter } from "../adapter/database.mjs";
|
|
5
|
-
import { Build } from "../schema.mjs";
|
|
6
|
-
//#region src/models/build.d.ts
|
|
7
|
-
/**
|
|
8
|
-
* Return whether a build is publicly viewable without a session.
|
|
9
|
-
*
|
|
10
|
-
* A build is public iff `builds.public` is set or its branch matches the
|
|
11
|
-
* project's `public_branch_regex` (ADR 0011). Supplying an empty/nonexistent
|
|
12
|
-
* regex makes every build require auth.
|
|
13
|
-
*/
|
|
14
|
-
declare function isPublicBuild(project: {
|
|
15
|
-
publicBranchRegex: string | null;
|
|
16
|
-
}, build: Pick<Build, "public" | "gitBranch">): boolean;
|
|
17
|
-
/** Input for creating a build. */
|
|
18
|
-
interface BuildCreateInput {
|
|
19
|
-
gitSha: string;
|
|
20
|
-
gitBranch: string;
|
|
21
|
-
isDefault?: boolean;
|
|
22
|
-
authorEmail?: string;
|
|
23
|
-
authorName?: string;
|
|
24
|
-
message?: string;
|
|
25
|
-
public?: boolean;
|
|
26
|
-
}
|
|
27
|
-
/** Filter options for listing builds. */
|
|
28
|
-
interface BuildListFilter {
|
|
29
|
-
status?: BuildStatus;
|
|
30
|
-
branch?: string;
|
|
31
|
-
labelKey?: string;
|
|
32
|
-
labelValue?: string;
|
|
33
|
-
}
|
|
34
|
-
/** Data operations for build records. */
|
|
35
|
-
declare class BuildModel {
|
|
36
|
-
private readonly db;
|
|
37
|
-
constructor(db: DatabaseAdapter);
|
|
38
|
-
create(projectId: string, input: BuildCreateInput): Promise<Build>;
|
|
39
|
-
get(id: string): Promise<Build | null>;
|
|
40
|
-
list(projectId: string, filter?: BuildListFilter): Promise<Build[]>;
|
|
41
|
-
/** Return the most recent build intended for publishing, if any. */
|
|
42
|
-
latestPublished(project: {
|
|
43
|
-
id: string;
|
|
44
|
-
publicBranchRegex: string | null;
|
|
45
|
-
}): Promise<Build | null>;
|
|
46
|
-
update(id: string, patch: Partial<Pick<Build, "status" | "public" | "message" | "authorEmail" | "authorName">>): Promise<Build>;
|
|
47
|
-
setStatus(id: string, status: BuildStatus): Promise<Build>;
|
|
48
|
-
updateCounts(id: string): Promise<Build>;
|
|
49
|
-
remove(id: string): Promise<void>;
|
|
50
|
-
}
|
|
51
|
-
//#endregion
|
|
52
|
-
export { type Build, BuildCreateInput, BuildListFilter, BuildModel, isPublicBuild };
|
|
53
|
-
//# sourceMappingURL=build.d.mts.map
|