@storyshelf/app 0.7.0 → 0.9.0-next-d2cc082
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/dist/app-types.d.mts +1 -3
- package/dist/asset-manifest.mjs +1 -2
- package/dist/assets/htmx.mjs +1 -2
- package/dist/assets/mark.mjs +1 -2
- package/dist/boot-tasks.mjs +1 -2
- package/dist/build-state-flags.mjs +1 -2
- package/dist/build-state-setup.mjs +1 -2
- package/dist/capture-alerts.mjs +1 -2
- package/dist/capture-process.mjs +1 -2
- package/dist/capture-setup.mjs +1 -2
- package/dist/connections.mjs +1 -2
- package/dist/consumer-setup.mjs +1 -2
- package/dist/credential-keys.mjs +1 -2
- package/dist/credentials.mjs +1 -2
- package/dist/design-events.mjs +71 -0
- package/dist/design-events.mjs.map +1 -0
- package/dist/git-status.mjs +1 -2
- package/dist/hidden-data.mjs +1 -2
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +2 -3
- package/dist/insights/budget.mjs +1 -2
- package/dist/insights/deps.mjs +1 -2
- package/dist/insights/errors.mjs +1 -2
- package/dist/insights/health-panel.mjs +0 -1
- package/dist/insights/job.mjs +1 -2
- package/dist/insights/load-health.mjs +1 -2
- package/dist/insights/load-triage.mjs +1 -2
- package/dist/insights/panel.mjs +1 -2
- package/dist/insights/request.mjs +1 -2
- package/dist/insights/stale.mjs +1 -2
- package/dist/insights/usage-report.mjs +1 -2
- package/dist/insights/view.mjs +1 -2
- package/dist/job-canceller.mjs +1 -2
- package/dist/job-queue.mjs +1 -2
- package/dist/jobs-setup.mjs +1 -2
- package/dist/lifecycle.mjs +2 -3
- package/dist/lifecycle.mjs.map +1 -1
- package/dist/middleware/auth-gate.mjs +1 -2
- package/dist/middleware/csrf.mjs +1 -2
- package/dist/middleware/rate-limit.mjs +1 -2
- package/dist/middleware/request-log.mjs +1 -2
- package/dist/middleware/require-review.mjs +1 -2
- package/dist/middleware/require-testing.mjs +1 -2
- package/dist/middleware/server-timing.mjs +1 -2
- package/dist/middleware/setup-gate.mjs +1 -2
- package/dist/middleware/store-scope.mjs +1 -2
- package/dist/notifications-pause.mjs +1 -2
- package/dist/notify.d.mts +1 -3
- package/dist/notify.mjs +5 -3
- package/dist/notify.mjs.map +1 -1
- package/dist/pages/a11y-violations.mjs +1 -2
- package/dist/pages/admin-ai.mjs +1 -2
- package/dist/pages/admin-system-origin.mjs +19 -10
- package/dist/pages/admin-system-origin.mjs.map +1 -1
- package/dist/pages/admin-system-targets.mjs +1 -2
- package/dist/pages/admin-system.mjs +1 -2
- package/dist/pages/build-detail.mjs +1 -2
- package/dist/pages/build-diff-actions.mjs +1 -2
- package/dist/pages/build-diff-comments.mjs +1 -2
- package/dist/pages/build-diff-default.mjs +53 -0
- package/dist/pages/build-diff-default.mjs.map +1 -0
- package/dist/pages/build-diff-environment.mjs +34 -5
- package/dist/pages/build-diff-environment.mjs.map +1 -1
- package/dist/pages/build-diff-header.mjs +1 -2
- package/dist/pages/build-diff-insight.mjs +1 -2
- package/dist/pages/build-diff-model.mjs +20 -3
- package/dist/pages/build-diff-model.mjs.map +1 -1
- package/dist/pages/build-diff-nav.mjs +1 -2
- package/dist/pages/build-diff-reference.mjs +84 -0
- package/dist/pages/build-diff-reference.mjs.map +1 -0
- package/dist/pages/build-diff-shortcuts.mjs +1 -2
- package/dist/pages/build-diff-stale.mjs +1 -2
- package/dist/pages/build-diff-usage.mjs +1 -2
- package/dist/pages/build-diff-viewer.mjs +38 -12
- package/dist/pages/build-diff-viewer.mjs.map +1 -1
- package/dist/pages/build-diff.mjs +6 -12
- package/dist/pages/build-diff.mjs.map +1 -1
- package/dist/pages/build-tests.mjs +1 -2
- package/dist/pages/component-detail.mjs +1 -2
- package/dist/pages/component-stories.mjs +1 -2
- package/dist/pages/compute-jobs.mjs +1 -2
- package/dist/pages/design-links.mjs +1 -2
- package/dist/pages/environment-change.mjs +16 -4
- package/dist/pages/environment-change.mjs.map +1 -1
- package/dist/pages/health-panel.mjs +1 -2
- package/dist/pages/invite.mjs +1 -2
- package/dist/pages/label-detail.mjs +1 -2
- package/dist/pages/library-grid.mjs +1 -2
- package/dist/pages/library-model.mjs +1 -2
- package/dist/pages/library-snapshots.mjs +1 -2
- package/dist/pages/library.mjs +1 -2
- package/dist/pages/login.mjs +1 -2
- package/dist/pages/notifications-paused.mjs +1 -2
- package/dist/pages/passkey-ceremony.mjs +1 -2
- package/dist/pages/profile.mjs +1 -2
- package/dist/pages/project-builds-table.mjs +1 -2
- package/dist/pages/project-builds.mjs +1 -2
- package/dist/pages/project-create.mjs +1 -2
- package/dist/pages/project-settings.mjs +1 -2
- package/dist/pages/projects-card.mjs +1 -2
- package/dist/pages/projects.mjs +1 -2
- package/dist/pages/review-changeset.mjs +1 -2
- package/dist/pages/review-comments.mjs +1 -2
- package/dist/pages/review-verdict.mjs +1 -2
- package/dist/pages/root.mjs +1 -2
- package/dist/pages/settings-ai.mjs +1 -2
- package/dist/pages/settings-capture.mjs +1 -2
- package/dist/pages/settings-design-credential.mjs +1 -2
- package/dist/pages/settings-design-links.mjs +1 -2
- package/dist/pages/settings-design.mjs +1 -2
- package/dist/pages/settings-general.mjs +1 -2
- package/dist/pages/settings-labels.mjs +1 -2
- package/dist/pages/settings-links.mjs +1 -2
- package/dist/pages/settings-members.mjs +1 -2
- package/dist/pages/settings-notifications-git.mjs +1 -2
- package/dist/pages/settings-notifications.mjs +1 -2
- package/dist/pages/settings-tests.mjs +1 -2
- package/dist/pages/settings-tokens.mjs +1 -2
- package/dist/pages/settings-webhooks.mjs +1 -2
- package/dist/pages/storybook.mjs +1 -2
- package/dist/pages/target-choices.mjs +1 -2
- package/dist/publish-setup.mjs +1 -2
- package/dist/retention-timer.mjs +10 -11
- package/dist/retention-timer.mjs.map +1 -1
- package/dist/review-events.mjs +1 -2
- package/dist/routers/admin-pages.mjs +1 -2
- package/dist/routers/admin-public-origin.mjs +10 -3
- package/dist/routers/admin-public-origin.mjs.map +1 -1
- package/dist/routers/admin.mjs +8 -4
- package/dist/routers/admin.mjs.map +1 -1
- package/dist/routers/assets.mjs +1 -2
- package/dist/routers/attempts.mjs +1 -2
- package/dist/routers/auth-sync.mjs +1 -2
- package/dist/routers/auth.mjs +1 -2
- package/dist/routers/baseline-guard.mjs +2 -3
- package/dist/routers/baseline-guard.mjs.map +1 -1
- package/dist/routers/baseline-reference.mjs +72 -0
- package/dist/routers/baseline-reference.mjs.map +1 -0
- package/dist/routers/baselines.handlers.mjs +1 -2
- package/dist/routers/baselines.mjs +1 -2
- package/dist/routers/build-cancel.mjs +1 -2
- package/dist/routers/build-changeset.mjs +1 -2
- package/dist/routers/build-reviews.handlers.mjs +1 -2
- package/dist/routers/build-reviews.mjs +1 -2
- package/dist/routers/builds.handlers.mjs +23 -9
- package/dist/routers/builds.handlers.mjs.map +1 -1
- package/dist/routers/builds.mjs +7 -3
- package/dist/routers/builds.mjs.map +1 -1
- package/dist/routers/capture-cache.mjs +29 -0
- package/dist/routers/capture-cache.mjs.map +1 -0
- package/dist/routers/capture-config.mjs +1 -2
- package/dist/routers/comments.mjs +1 -2
- package/dist/routers/comparison-image.mjs +29 -0
- package/dist/routers/comparison-image.mjs.map +1 -0
- package/dist/routers/component-catalog.handlers.mjs +1 -2
- package/dist/routers/component.handlers.mjs +1 -2
- package/dist/routers/connections.mjs +1 -2
- package/dist/routers/design-connect.handlers.mjs +1 -2
- package/dist/routers/design.handlers.mjs +8 -2
- package/dist/routers/design.handlers.mjs.map +1 -1
- package/dist/routers/flash.mjs +1 -2
- package/dist/routers/health-report.mjs +1 -2
- package/dist/routers/health.mjs +1 -2
- package/dist/routers/helpers.mjs +1 -2
- package/dist/routers/htmx.mjs +1 -2
- package/dist/routers/insights-ui.mjs +1 -2
- package/dist/routers/insights.handlers.mjs +1 -2
- package/dist/routers/insights.mjs +1 -2
- package/dist/routers/labels.mjs +1 -2
- package/dist/routers/links.handlers.mjs +1 -2
- package/dist/routers/links.mjs +1 -2
- package/dist/routers/media.mjs +14 -5
- package/dist/routers/media.mjs.map +1 -1
- package/dist/routers/members.mjs +1 -2
- package/dist/routers/notification-channels.mjs +1 -2
- package/dist/routers/notification-subscriptions.mjs +1 -2
- package/dist/routers/oauth-state.mjs +1 -2
- package/dist/routers/preview-base.mjs +1 -2
- package/dist/routers/preview-token.mjs +1 -2
- package/dist/routers/profile.mjs +1 -2
- package/dist/routers/projects.mjs +1 -2
- package/dist/routers/publish-upload.mjs +19 -12
- package/dist/routers/publish-upload.mjs.map +1 -1
- package/dist/routers/published-access.mjs +1 -2
- package/dist/routers/published-compression.mjs +109 -0
- package/dist/routers/published-compression.mjs.map +1 -0
- package/dist/routers/published-files.mjs +26 -9
- package/dist/routers/published-files.mjs.map +1 -1
- package/dist/routers/review-forms.mjs +1 -2
- package/dist/routers/review-next.mjs +1 -2
- package/dist/routers/review-section.handlers.mjs +1 -2
- package/dist/routers/review-switch-off.mjs +1 -2
- package/dist/routers/schemas.mjs +1 -2
- package/dist/routers/scoped-models.mjs +1 -2
- package/dist/routers/settings-ai.mjs +1 -2
- package/dist/routers/settings-capture.mjs +1 -2
- package/dist/routers/settings-design.mjs +1 -2
- package/dist/routers/settings-general.mjs +1 -2
- package/dist/routers/settings-git-channel.mjs +1 -2
- package/dist/routers/settings-labels.mjs +1 -2
- package/dist/routers/settings-links.mjs +1 -2
- package/dist/routers/settings-members.mjs +1 -2
- package/dist/routers/settings-notifications.mjs +1 -2
- package/dist/routers/settings-tokens.mjs +1 -2
- package/dist/routers/settings-webhooks.mjs +1 -2
- package/dist/routers/settings.handlers.mjs +1 -2
- package/dist/routers/settings.mjs +1 -2
- package/dist/routers/signed-storybook.mjs +5 -3
- package/dist/routers/signed-storybook.mjs.map +1 -1
- package/dist/routers/snapshot-groups.mjs +1 -2
- package/dist/routers/snapshots.mjs +1 -2
- package/dist/routers/storybook.mjs +21 -17
- package/dist/routers/storybook.mjs.map +1 -1
- package/dist/routers/tokens.mjs +1 -2
- package/dist/routers/ui.mjs +4 -2
- package/dist/routers/ui.mjs.map +1 -1
- package/dist/routers/webhooks.mjs +1 -2
- package/dist/routers/well-known.mjs +1 -2
- package/dist/routes/api-routes.mjs +1 -2
- package/dist/routes/classification.mjs +1 -2
- package/dist/routes/openapi-classes.mjs +1 -2
- package/dist/routes/page-routes.mjs +2 -3
- package/dist/routes/page-routes.mjs.map +1 -1
- package/dist/runtime.mjs +1 -2
- package/dist/serverless.mjs +1 -2
- package/dist/store.mjs +1 -2
- package/dist/targets.mjs +1 -2
- package/dist/ui/avatar.mjs +1 -2
- package/dist/ui/buttons.mjs +1 -2
- package/dist/ui/code-block.mjs +1 -2
- package/dist/ui/compare-stage.mjs +86 -54
- package/dist/ui/compare-stage.mjs.map +1 -1
- package/dist/ui/csrf-field.mjs +1 -2
- package/dist/ui/css.mjs +1 -2
- package/dist/ui/design-reference.mjs +1 -2
- package/dist/ui/document.mjs +1 -2
- package/dist/ui/dropdown.mjs +1 -2
- package/dist/ui/feedback.mjs +1 -2
- package/dist/ui/filter-input.mjs +1 -2
- package/dist/ui/forms.mjs +1 -2
- package/dist/ui/icons/icon.mjs +1 -2
- package/dist/ui/icons/paths.mjs +1 -2
- package/dist/ui/icons/sprite.mjs +1 -2
- package/dist/ui/kbd.mjs +1 -2
- package/dist/ui/layout.mjs +1 -2
- package/dist/ui/preview-embed.mjs +1 -2
- package/dist/ui/progress.mjs +1 -2
- package/dist/ui/segmented.mjs +1 -2
- package/dist/ui/shell/account.mjs +1 -2
- package/dist/ui/shell/bare.mjs +1 -2
- package/dist/ui/shell/boot-script.mjs +1 -2
- package/dist/ui/shell/client-script.mjs +1 -2
- package/dist/ui/shell/nav.mjs +1 -2
- package/dist/ui/shell/review-script.mjs +17 -3
- package/dist/ui/shell/review-script.mjs.map +1 -1
- package/dist/ui/shell/sidebar.mjs +1 -2
- package/dist/ui/shell/topbar.mjs +1 -2
- package/dist/ui/stacks.mjs +1 -2
- package/dist/ui/styles/base.mjs +1 -2
- package/dist/ui/styles/behavior.mjs +1 -2
- package/dist/ui/styles/review-layout.mjs +1 -2
- package/dist/ui/styles/review.mjs +1 -2
- package/dist/ui/styles/tokens.mjs +1 -2
- package/dist/ui/styles.mjs +1 -2
- package/dist/ui/subnav.mjs +1 -2
- package/dist/ui/table.mjs +1 -2
- package/dist/ui/theme.mjs +1 -2
- package/dist/ui/thumbnail.mjs +1 -2
- package/dist/ui/time.mjs +1 -2
- package/package.json +9 -18
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { getStore } from "../store.mjs";
|
|
5
|
-
|
|
5
|
+
// src/routers/well-known.ts
|
|
6
6
|
/** SSO-capable login methods (oauth buttons + SSO) with IdP reply URLs. */
|
|
7
7
|
function ssoProviders(auth, origin) {
|
|
8
8
|
return auth.loginMethods().filter((method) => method.kind === "oauth" || method.kind === "sso").map((method) => ({
|
|
@@ -44,7 +44,6 @@ function registerWellKnown(app, auth) {
|
|
|
44
44
|
});
|
|
45
45
|
app.get("/.well-known/change-password", (c) => c.redirect("/profile", 302));
|
|
46
46
|
}
|
|
47
|
-
//#endregion
|
|
48
47
|
export { registerWellKnown };
|
|
49
48
|
|
|
50
49
|
//# sourceMappingURL=well-known.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/routes/api-routes.ts
|
|
5
5
|
/** JSON API routes, keyed by `METHOD /hono-pattern`. */
|
|
6
6
|
const API_ROUTE_CLASSES = {
|
|
7
7
|
"GET /api/v1/projects": "hosting",
|
|
@@ -87,7 +87,6 @@ const API_ROUTE_CLASSES = {
|
|
|
87
87
|
"POST /api/v1/projects/:slug/builds/:buildId/reviews": "review",
|
|
88
88
|
"GET /api/v1/projects/:slug/builds/:buildId/changeset": "review"
|
|
89
89
|
};
|
|
90
|
-
//#endregion
|
|
91
90
|
export { API_ROUTE_CLASSES };
|
|
92
91
|
|
|
93
92
|
//# sourceMappingURL=api-routes.mjs.map
|
|
@@ -3,7 +3,7 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { API_ROUTE_CLASSES } from "./api-routes.mjs";
|
|
5
5
|
import { PAGE_ROUTE_CLASSES } from "./page-routes.mjs";
|
|
6
|
-
|
|
6
|
+
// src/routes/classification.ts
|
|
7
7
|
/**
|
|
8
8
|
* Route classification (ADR 0006, decision 8): every route the app registers declares whether it
|
|
9
9
|
* belongs to hosting, testing, review, or both. `classification.test.ts` fails on any registered
|
|
@@ -32,7 +32,6 @@ function classOfRoute(method, path) {
|
|
|
32
32
|
if (exact !== void 0) return exact;
|
|
33
33
|
return ROUTE_PREFIX_CLASSES.find((rule) => path.startsWith(rule.prefix))?.routeClass;
|
|
34
34
|
}
|
|
35
|
-
//#endregion
|
|
36
35
|
export { ROUTE_CLASSES, ROUTE_PREFIX_CLASSES, classOfRoute };
|
|
37
36
|
|
|
38
37
|
//# sourceMappingURL=classification.mjs.map
|
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { classOfRoute } from "./classification.mjs";
|
|
5
|
-
|
|
5
|
+
// src/routes/openapi-classes.ts
|
|
6
6
|
/** Tags every operation of an OpenAPI document with the class of its route (`x-storyshelf-class`). */
|
|
7
7
|
/** OpenAPI path templates (`{slug}`) as Hono patterns (`:slug`), the form the route table uses. */
|
|
8
8
|
function honoPattern(path) {
|
|
@@ -16,7 +16,6 @@ function markRouteClasses(document) {
|
|
|
16
16
|
}
|
|
17
17
|
return document;
|
|
18
18
|
}
|
|
19
|
-
//#endregion
|
|
20
19
|
export { markRouteClasses };
|
|
21
20
|
|
|
22
21
|
//# sourceMappingURL=openapi-classes.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
-
|
|
4
|
+
// src/routes/page-routes.ts
|
|
5
5
|
/** HTML and auth routes, keyed by `METHOD /hono-pattern`. */
|
|
6
6
|
const PAGE_ROUTE_CLASSES = {
|
|
7
7
|
"GET /": "hosting",
|
|
@@ -53,7 +53,7 @@ const PAGE_ROUTE_CLASSES = {
|
|
|
53
53
|
"GET /_/:id": "hosting",
|
|
54
54
|
"GET /_/:id/*": "hosting",
|
|
55
55
|
"GET /projects/:slug/storybook": "hosting",
|
|
56
|
-
"GET /projects/:slug/storybook/:key
|
|
56
|
+
"GET /projects/:slug/storybook/:key/*": "hosting",
|
|
57
57
|
"GET /projects/:slug/storybook/build/:buildId/*": "hosting",
|
|
58
58
|
"GET /_s/:token/*": "testing",
|
|
59
59
|
"GET /auth/login": "hosting",
|
|
@@ -98,7 +98,6 @@ const PAGE_ROUTE_CLASSES = {
|
|
|
98
98
|
"GET /projects/:slug/library": "both",
|
|
99
99
|
"GET /projects/:slug/components/*": "both"
|
|
100
100
|
};
|
|
101
|
-
//#endregion
|
|
102
101
|
export { PAGE_ROUTE_CLASSES };
|
|
103
102
|
|
|
104
103
|
//# sourceMappingURL=page-routes.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page-routes.mjs","names":[],"sources":["../../src/routes/page-routes.ts"],"sourcesContent":["/** Classes of the HTML pages, Storybook serving, auth flow and engine routes. */\nimport type { RouteClass } from \"./classification.ts\";\n\n/** HTML and auth routes, keyed by `METHOD /hono-pattern`. */\nexport const PAGE_ROUTE_CLASSES: Readonly<Record<string, RouteClass>> = {\n // hosting\n \"GET /\": \"hosting\",\n \"GET /projects\": \"hosting\",\n \"GET /projects/new\": \"hosting\",\n \"POST /projects/new\": \"hosting\",\n \"GET /projects/:slug/labels\": \"hosting\",\n \"GET /projects/:slug/labels/:key/*\": \"hosting\",\n \"GET /projects/:slug/settings\": \"hosting\",\n \"POST /projects/:slug/settings\": \"hosting\",\n \"POST /projects/:slug/settings/review\": \"hosting\",\n \"POST /projects/:slug/delete\": \"hosting\",\n \"GET /projects/:slug/settings/labels\": \"hosting\",\n \"POST /projects/:slug/settings/labels\": \"hosting\",\n \"POST /projects/:slug/settings/labels/:key\": \"hosting\",\n \"POST /projects/:slug/settings/labels/:key/delete\": \"hosting\",\n \"GET /projects/:slug/settings/links\": \"hosting\",\n \"POST /projects/:slug/settings/links\": \"hosting\",\n \"POST /projects/:slug/settings/links/delete\": \"hosting\",\n \"GET /projects/:slug/settings/design\": \"hosting\",\n \"POST /projects/:slug/settings/design/files\": \"hosting\",\n \"POST /projects/:slug/settings/design/files/:id/delete\": \"hosting\",\n \"POST /projects/:slug/settings/design/components\": \"hosting\",\n \"POST /projects/:slug/settings/design/components/:id/delete\": \"hosting\",\n \"POST /projects/:slug/settings/design/:provider/token\": \"hosting\",\n \"POST /projects/:slug/settings/design/:provider/token/delete\": \"hosting\",\n \"GET /projects/:slug/settings/tokens\": \"hosting\",\n \"POST /projects/:slug/settings/tokens\": \"hosting\",\n \"POST /projects/:slug/settings/tokens/:tokenId/delete\": \"hosting\",\n \"GET /projects/:slug/settings/webhooks\": \"hosting\",\n \"POST /projects/:slug/settings/webhooks\": \"hosting\",\n \"POST /projects/:slug/settings/webhooks/:webhookId/delete\": \"hosting\",\n \"GET /projects/:slug/settings/notifications\": \"hosting\",\n \"POST /projects/:slug/settings/notifications\": \"hosting\",\n \"POST /projects/:slug/settings/notifications/:channelId/delete\": \"hosting\",\n \"POST /projects/:slug/settings/notifications/me\": \"hosting\",\n \"GET /projects/:slug/settings/members\": \"hosting\",\n \"POST /projects/:slug/settings/members\": \"hosting\",\n \"POST /projects/:slug/settings/members/:userId/remove\": \"hosting\",\n \"POST /projects/:slug/settings/members/groups\": \"hosting\",\n \"POST /projects/:slug/settings/members/groups/:mappingId/remove\": \"hosting\",\n \"GET /admin\": \"hosting\",\n \"POST /admin/credentials/reencrypt\": \"hosting\",\n \"POST /admin/public-origin\": \"hosting\",\n \"POST /admin/public-origin/report\": \"hosting\",\n \"POST /admin/public-origin/clear\": \"hosting\",\n \"GET /_\": \"hosting\",\n \"GET /_/\": \"hosting\",\n \"GET /_/:id\": \"hosting\",\n \"GET /_/:id/*\": \"hosting\",\n \"GET /projects/:slug/storybook\": \"hosting\",\n \"GET /projects/:slug/storybook/:key
|
|
1
|
+
{"version":3,"file":"page-routes.mjs","names":[],"sources":["../../src/routes/page-routes.ts"],"sourcesContent":["/** Classes of the HTML pages, Storybook serving, auth flow and engine routes. */\nimport type { RouteClass } from \"./classification.ts\";\n\n/** HTML and auth routes, keyed by `METHOD /hono-pattern`. */\nexport const PAGE_ROUTE_CLASSES: Readonly<Record<string, RouteClass>> = {\n // hosting\n \"GET /\": \"hosting\",\n \"GET /projects\": \"hosting\",\n \"GET /projects/new\": \"hosting\",\n \"POST /projects/new\": \"hosting\",\n \"GET /projects/:slug/labels\": \"hosting\",\n \"GET /projects/:slug/labels/:key/*\": \"hosting\",\n \"GET /projects/:slug/settings\": \"hosting\",\n \"POST /projects/:slug/settings\": \"hosting\",\n \"POST /projects/:slug/settings/review\": \"hosting\",\n \"POST /projects/:slug/delete\": \"hosting\",\n \"GET /projects/:slug/settings/labels\": \"hosting\",\n \"POST /projects/:slug/settings/labels\": \"hosting\",\n \"POST /projects/:slug/settings/labels/:key\": \"hosting\",\n \"POST /projects/:slug/settings/labels/:key/delete\": \"hosting\",\n \"GET /projects/:slug/settings/links\": \"hosting\",\n \"POST /projects/:slug/settings/links\": \"hosting\",\n \"POST /projects/:slug/settings/links/delete\": \"hosting\",\n \"GET /projects/:slug/settings/design\": \"hosting\",\n \"POST /projects/:slug/settings/design/files\": \"hosting\",\n \"POST /projects/:slug/settings/design/files/:id/delete\": \"hosting\",\n \"POST /projects/:slug/settings/design/components\": \"hosting\",\n \"POST /projects/:slug/settings/design/components/:id/delete\": \"hosting\",\n \"POST /projects/:slug/settings/design/:provider/token\": \"hosting\",\n \"POST /projects/:slug/settings/design/:provider/token/delete\": \"hosting\",\n \"GET /projects/:slug/settings/tokens\": \"hosting\",\n \"POST /projects/:slug/settings/tokens\": \"hosting\",\n \"POST /projects/:slug/settings/tokens/:tokenId/delete\": \"hosting\",\n \"GET /projects/:slug/settings/webhooks\": \"hosting\",\n \"POST /projects/:slug/settings/webhooks\": \"hosting\",\n \"POST /projects/:slug/settings/webhooks/:webhookId/delete\": \"hosting\",\n \"GET /projects/:slug/settings/notifications\": \"hosting\",\n \"POST /projects/:slug/settings/notifications\": \"hosting\",\n \"POST /projects/:slug/settings/notifications/:channelId/delete\": \"hosting\",\n \"POST /projects/:slug/settings/notifications/me\": \"hosting\",\n \"GET /projects/:slug/settings/members\": \"hosting\",\n \"POST /projects/:slug/settings/members\": \"hosting\",\n \"POST /projects/:slug/settings/members/:userId/remove\": \"hosting\",\n \"POST /projects/:slug/settings/members/groups\": \"hosting\",\n \"POST /projects/:slug/settings/members/groups/:mappingId/remove\": \"hosting\",\n \"GET /admin\": \"hosting\",\n \"POST /admin/credentials/reencrypt\": \"hosting\",\n \"POST /admin/public-origin\": \"hosting\",\n \"POST /admin/public-origin/report\": \"hosting\",\n \"POST /admin/public-origin/clear\": \"hosting\",\n \"GET /_\": \"hosting\",\n \"GET /_/\": \"hosting\",\n \"GET /_/:id\": \"hosting\",\n \"GET /_/:id/*\": \"hosting\",\n \"GET /projects/:slug/storybook\": \"hosting\",\n \"GET /projects/:slug/storybook/:key/*\": \"hosting\",\n \"GET /projects/:slug/storybook/build/:buildId/*\": \"hosting\",\n \"GET /_s/:token/*\": \"testing\",\n \"GET /auth/login\": \"hosting\",\n \"GET /auth/engine/login\": \"hosting\",\n \"POST /auth/engine/login\": \"hosting\",\n \"GET /auth/engine/:providerId\": \"hosting\",\n \"GET /auth/invites/:inviteId\": \"hosting\",\n \"POST /auth/invites/:inviteId\": \"hosting\",\n \"POST /auth/logout\": \"hosting\",\n \"GET /.well-known/openid-configuration\": \"hosting\",\n \"GET /.well-known/change-password\": \"hosting\",\n \"GET /profile\": \"hosting\",\n \"POST /profile\": \"hosting\",\n \"POST /profile/password\": \"hosting\",\n \"POST /profile/sessions/revoke\": \"hosting\",\n \"POST /profile/sessions/revoke-others\": \"hosting\",\n \"POST /profile/passkeys/:passkeyId/delete\": \"hosting\",\n \"POST /profile/notifications\": \"hosting\",\n \"GET /connections/:service/start\": \"hosting\",\n \"GET /connections/:service/callback\": \"hosting\",\n \"POST /connections/:service/disconnect\": \"hosting\",\n \"ALL /api/auth/*\": \"hosting\",\n // testing\n \"GET /projects/:slug/jobs\": \"testing\",\n \"GET /projects/:slug/builds/:buildId/diff\": \"testing\",\n \"GET /projects/:slug/settings/tests\": \"testing\",\n \"POST /projects/:slug/settings/tests\": \"testing\",\n \"GET /projects/:slug/settings/capture\": \"testing\",\n \"POST /projects/:slug/settings/capture\": \"testing\",\n \"GET /projects/:slug/settings/ai\": \"testing\",\n \"POST /projects/:slug/settings/ai\": \"testing\",\n \"GET /admin/ai\": \"testing\",\n \"GET /projects/:slug/insights/health/panel\": \"testing\",\n \"POST /projects/:slug/insights/health/generate\": \"testing\",\n \"GET /projects/:slug/builds/:buildId/insights/panel\": \"testing\",\n \"POST /projects/:slug/builds/:buildId/insights/generate\": \"testing\",\n // review\n \"POST /projects/:slug/builds/:buildId/comments\": \"review\",\n \"POST /projects/:slug/builds/:buildId/comments/:commentId/resolve\": \"review\",\n \"POST /projects/:slug/builds/:buildId/reviews\": \"review\",\n // both\n \"GET /projects/:slug\": \"both\",\n \"GET /projects/:slug/builds\": \"both\",\n \"GET /projects/:slug/builds/:buildId\": \"both\",\n \"GET /projects/:slug/library\": \"both\",\n \"GET /projects/:slug/components/*\": \"both\",\n};\n"],"mappings":";;;;;AAIA,MAAa,qBAA2D;CAEtE,SAAS;CACT,iBAAiB;CACjB,qBAAqB;CACrB,sBAAsB;CACtB,8BAA8B;CAC9B,qCAAqC;CACrC,gCAAgC;CAChC,iCAAiC;CACjC,wCAAwC;CACxC,+BAA+B;CAC/B,uCAAuC;CACvC,wCAAwC;CACxC,6CAA6C;CAC7C,oDAAoD;CACpD,sCAAsC;CACtC,uCAAuC;CACvC,8CAA8C;CAC9C,uCAAuC;CACvC,8CAA8C;CAC9C,yDAAyD;CACzD,mDAAmD;CACnD,8DAA8D;CAC9D,wDAAwD;CACxD,+DAA+D;CAC/D,uCAAuC;CACvC,wCAAwC;CACxC,wDAAwD;CACxD,yCAAyC;CACzC,0CAA0C;CAC1C,4DAA4D;CAC5D,8CAA8C;CAC9C,+CAA+C;CAC/C,iEAAiE;CACjE,kDAAkD;CAClD,wCAAwC;CACxC,yCAAyC;CACzC,wDAAwD;CACxD,gDAAgD;CAChD,kEAAkE;CAClE,cAAc;CACd,qCAAqC;CACrC,6BAA6B;CAC7B,oCAAoC;CACpC,mCAAmC;CACnC,UAAU;CACV,WAAW;CACX,cAAc;CACd,gBAAgB;CAChB,iCAAiC;CACjC,wCAAwC;CACxC,kDAAkD;CAClD,oBAAoB;CACpB,mBAAmB;CACnB,0BAA0B;CAC1B,2BAA2B;CAC3B,gCAAgC;CAChC,+BAA+B;CAC/B,gCAAgC;CAChC,qBAAqB;CACrB,yCAAyC;CACzC,oCAAoC;CACpC,gBAAgB;CAChB,iBAAiB;CACjB,0BAA0B;CAC1B,iCAAiC;CACjC,wCAAwC;CACxC,4CAA4C;CAC5C,+BAA+B;CAC/B,mCAAmC;CACnC,sCAAsC;CACtC,yCAAyC;CACzC,mBAAmB;CAEnB,4BAA4B;CAC5B,4CAA4C;CAC5C,sCAAsC;CACtC,uCAAuC;CACvC,wCAAwC;CACxC,yCAAyC;CACzC,mCAAmC;CACnC,oCAAoC;CACpC,iBAAiB;CACjB,6CAA6C;CAC7C,iDAAiD;CACjD,sDAAsD;CACtD,0DAA0D;CAE1D,iDAAiD;CACjD,oEAAoE;CACpE,gDAAgD;CAEhD,uBAAuB;CACvB,8BAA8B;CAC9B,uCAAuC;CACvC,+BAA+B;CAC/B,oCAAoC;AACtC"}
|
package/dist/runtime.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { validateConfig, validateUiConfig } from "@storyshelf/core/config";
|
|
5
5
|
import { createPublicOriginResolver } from "@storyshelf/core/models";
|
|
6
6
|
import { createShelfLogger } from "@storyshelf/core/logger";
|
|
7
|
-
|
|
7
|
+
// src/runtime.ts
|
|
8
8
|
function addOptionalSnapshots(snap, options) {
|
|
9
9
|
if (options.testing?.runner) snap["captureRunner"] = options.testing.runner.metadata;
|
|
10
10
|
}
|
|
@@ -51,7 +51,6 @@ function resolveRuntime(options) {
|
|
|
51
51
|
})
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
//#endregion
|
|
55
54
|
export { buildAdapterSnapshot, resolveRuntime };
|
|
56
55
|
|
|
57
56
|
//# sourceMappingURL=runtime.mjs.map
|
package/dist/serverless.mjs
CHANGED
package/dist/store.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { createCatalogLoader } from "@storyshelf/core/capture";
|
|
5
5
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
6
|
-
|
|
6
|
+
// src/store.ts
|
|
7
7
|
const storage = new AsyncLocalStorage();
|
|
8
8
|
/** Run a function with the given request store in scope. */
|
|
9
9
|
function runWithStore(store, fn) {
|
|
@@ -32,7 +32,6 @@ function catalogOf(store = getStore()) {
|
|
|
32
32
|
logger: store.logger
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
-
//#endregion
|
|
36
35
|
export { catalogOf, getStore, runWithStore, testingEnabled };
|
|
37
36
|
|
|
38
37
|
//# sourceMappingURL=store.mjs.map
|
package/dist/targets.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { getStore } from "./store.mjs";
|
|
|
5
5
|
import { MAX_BROWSERS, assertSupportedBrowsers, offeredTargets } from "@storyshelf/core/capture";
|
|
6
6
|
import { HTTPException } from "hono/http-exception";
|
|
7
7
|
import { isCaptureTarget, parseTarget } from "@storyshelf/core/adapter/capture-runner";
|
|
8
|
-
|
|
8
|
+
// src/targets.ts
|
|
9
9
|
/** Which capture targets this instance offers right now, and the checks a settings save runs (ADR 0007). */
|
|
10
10
|
/**
|
|
11
11
|
* The targets the runner offers, with the ones that need a URL marked `unavailable` while there is
|
|
@@ -40,7 +40,6 @@ async function assertTargetsSelectable(targets, current = []) {
|
|
|
40
40
|
throw new HTTPException(400, { message: error instanceof Error ? error.message : "Refused" });
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
//#endregion
|
|
44
43
|
export { assertTargetsSelectable, runnerTargets, targetLabel };
|
|
45
44
|
|
|
46
45
|
//# sourceMappingURL=targets.mjs.map
|
package/dist/ui/avatar.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { jsx } from "hono/jsx/jsx-runtime";
|
|
6
|
-
|
|
6
|
+
// src/ui/avatar.tsx
|
|
7
7
|
const avatarBase = css`
|
|
8
8
|
/* avatar */
|
|
9
9
|
flex: none;
|
|
@@ -70,7 +70,6 @@ const Avatar = ({ name, src, size = "md" }) => {
|
|
|
70
70
|
children: initials(name) || "?"
|
|
71
71
|
});
|
|
72
72
|
};
|
|
73
|
-
//#endregion
|
|
74
73
|
export { Avatar, initials };
|
|
75
74
|
|
|
76
75
|
//# sourceMappingURL=avatar.mjs.map
|
package/dist/ui/buttons.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { Icon } from "./icons/icon.mjs";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/buttons.tsx
|
|
8
8
|
const btnBase = css`
|
|
9
9
|
/* btn */
|
|
10
10
|
appearance: none;
|
|
@@ -212,7 +212,6 @@ const Tabs = ({ tabs, label = "Sections" }) => {
|
|
|
212
212
|
}))
|
|
213
213
|
});
|
|
214
214
|
};
|
|
215
|
-
//#endregion
|
|
216
215
|
export { Button, Tabs };
|
|
217
216
|
|
|
218
217
|
//# sourceMappingURL=buttons.mjs.map
|
package/dist/ui/code-block.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { Button } from "./buttons.mjs";
|
|
6
6
|
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/code-block.tsx
|
|
8
8
|
const codeWrap = css`
|
|
9
9
|
/* code-block */
|
|
10
10
|
display: flex;
|
|
@@ -41,7 +41,6 @@ const CodeBlock = ({ code, label = "Copy" }) => {
|
|
|
41
41
|
})]
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
|
-
//#endregion
|
|
45
44
|
export { CodeBlock };
|
|
46
45
|
|
|
47
46
|
//# sourceMappingURL=code-block.mjs.map
|
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { Segmented } from "./segmented.mjs";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/compare-stage.tsx
|
|
8
8
|
/**
|
|
9
9
|
* Screenshot comparison surface. All modes share one set of images; the
|
|
10
10
|
* `data-view` / `data-zoom` / `data-flip` attributes on the root (driven by
|
|
@@ -70,6 +70,10 @@ const stageRoot = css`
|
|
|
70
70
|
font-size: var(--text-sm);
|
|
71
71
|
text-align: center;
|
|
72
72
|
}
|
|
73
|
+
.stage__note {
|
|
74
|
+
color: var(--text-secondary);
|
|
75
|
+
font-size: var(--text-sm);
|
|
76
|
+
}
|
|
73
77
|
.stage__divider,
|
|
74
78
|
.stage__controls {
|
|
75
79
|
display: none;
|
|
@@ -103,6 +107,10 @@ const stageRoot = css`
|
|
|
103
107
|
&[data-zoom="400"] .stage__img {
|
|
104
108
|
image-rendering: pixelated;
|
|
105
109
|
}
|
|
110
|
+
/* Design variant: screenshot against a render, two panes and no diff. */
|
|
111
|
+
&[data-variant="design"][data-view="split"] .stage__grid {
|
|
112
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
113
|
+
}
|
|
106
114
|
&[data-view="diff"] .stage__grid,
|
|
107
115
|
&[data-view="flip"] .stage__grid,
|
|
108
116
|
&[data-view="swipe"] .stage__grid,
|
|
@@ -218,6 +226,12 @@ const ZOOMS = [
|
|
|
218
226
|
value: "400"
|
|
219
227
|
}
|
|
220
228
|
];
|
|
229
|
+
/** Modes and zoom a design comparison offers: no pixel diff, and the render always fits the stage. */
|
|
230
|
+
const DESIGN_MODES = [
|
|
231
|
+
"split",
|
|
232
|
+
"swipe",
|
|
233
|
+
"onion"
|
|
234
|
+
];
|
|
221
235
|
function withActive(items, active) {
|
|
222
236
|
return items.map((item) => ({
|
|
223
237
|
...item,
|
|
@@ -244,12 +258,12 @@ const Pane = ({ kind, label, src, alt, empty, meta }) => {
|
|
|
244
258
|
});
|
|
245
259
|
};
|
|
246
260
|
/** Swipe and onion-skin sliders; each is shown only in its own mode (CSS). */
|
|
247
|
-
const RangeControls = () => {
|
|
261
|
+
const RangeControls = ({ baselineLabel }) => {
|
|
248
262
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("label", {
|
|
249
263
|
class: "stage__controls",
|
|
250
264
|
"data-for": "swipe",
|
|
251
265
|
children: [
|
|
252
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
266
|
+
/* @__PURE__ */ jsx("span", { children: baselineLabel }),
|
|
253
267
|
/* @__PURE__ */ jsx("input", {
|
|
254
268
|
type: "range",
|
|
255
269
|
min: "0",
|
|
@@ -264,7 +278,7 @@ const RangeControls = () => {
|
|
|
264
278
|
class: "stage__controls",
|
|
265
279
|
"data-for": "onion",
|
|
266
280
|
children: [
|
|
267
|
-
/* @__PURE__ */ jsx("span", { children:
|
|
281
|
+
/* @__PURE__ */ jsx("span", { children: baselineLabel }),
|
|
268
282
|
/* @__PURE__ */ jsx("input", {
|
|
269
283
|
type: "range",
|
|
270
284
|
min: "0",
|
|
@@ -277,68 +291,86 @@ const RangeControls = () => {
|
|
|
277
291
|
]
|
|
278
292
|
})] });
|
|
279
293
|
};
|
|
294
|
+
/** Mode switch, plus the zoom switch (a design comparison always fits, so it has none). */
|
|
295
|
+
const StageBar = ({ design }) => {
|
|
296
|
+
const modes = design ? MODES.filter((mode) => DESIGN_MODES.includes(mode.value)) : MODES;
|
|
297
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
298
|
+
class: "stage__bar",
|
|
299
|
+
children: [/* @__PURE__ */ jsx(Segmented, {
|
|
300
|
+
label: "Comparison mode",
|
|
301
|
+
"data-compare-mode": true,
|
|
302
|
+
items: withActive(modes, "split")
|
|
303
|
+
}), design ? null : /* @__PURE__ */ jsx(Segmented, {
|
|
304
|
+
label: "Zoom",
|
|
305
|
+
"data-compare-zoom": true,
|
|
306
|
+
items: withActive(ZOOMS, "fit")
|
|
307
|
+
})]
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
/** The panes (baseline or design, current, diff) and the swipe divider. */
|
|
311
|
+
const StageGrid = ({ baselineSrc, currentSrc, diffSrc, subject, baselineEmpty = "New story — no baseline yet. Approve to set the baseline.", diffEmpty = "No diff", diffMeta, design, baselineLabel }) => /* @__PURE__ */ jsxs("div", {
|
|
312
|
+
class: "stage__grid",
|
|
313
|
+
children: [
|
|
314
|
+
/* @__PURE__ */ jsx(Pane, {
|
|
315
|
+
kind: "baseline",
|
|
316
|
+
label: baselineLabel,
|
|
317
|
+
src: baselineSrc,
|
|
318
|
+
alt: `${baselineLabel} for ${subject}`,
|
|
319
|
+
empty: baselineEmpty
|
|
320
|
+
}),
|
|
321
|
+
/* @__PURE__ */ jsx(Pane, {
|
|
322
|
+
kind: "current",
|
|
323
|
+
label: "Current",
|
|
324
|
+
src: currentSrc,
|
|
325
|
+
alt: `Current for ${subject}`,
|
|
326
|
+
empty: "No screenshot"
|
|
327
|
+
}),
|
|
328
|
+
design ? null : /* @__PURE__ */ jsx(Pane, {
|
|
329
|
+
kind: "diff",
|
|
330
|
+
label: "Diff",
|
|
331
|
+
src: diffSrc,
|
|
332
|
+
alt: `Diff for ${subject}`,
|
|
333
|
+
empty: diffEmpty,
|
|
334
|
+
meta: diffMeta
|
|
335
|
+
}),
|
|
336
|
+
/* @__PURE__ */ jsx("span", {
|
|
337
|
+
class: "stage__divider",
|
|
338
|
+
"aria-hidden": "true",
|
|
339
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
340
|
+
class: "stage__knob",
|
|
341
|
+
"data-compare-knob": true,
|
|
342
|
+
children: "↔"
|
|
343
|
+
})
|
|
344
|
+
})
|
|
345
|
+
]
|
|
346
|
+
});
|
|
280
347
|
/** Baseline / current / diff comparison with swipe, onion-skin, flip, and zoom. */
|
|
281
|
-
const CompareStage = ({
|
|
348
|
+
const CompareStage = ({ variant = "baseline", baselineLabel = "Baseline", note, ...images }) => {
|
|
349
|
+
const design = variant === "design";
|
|
282
350
|
return /* @__PURE__ */ jsxs("div", {
|
|
283
351
|
class: stageRoot,
|
|
284
352
|
"data-compare": true,
|
|
285
353
|
"data-view": "split",
|
|
286
354
|
"data-zoom": "fit",
|
|
287
355
|
"data-flip": "current",
|
|
356
|
+
"data-variant": variant,
|
|
357
|
+
"data-modes": design ? DESIGN_MODES.join(",") : void 0,
|
|
358
|
+
"data-zooms": design ? "fit" : void 0,
|
|
288
359
|
children: [
|
|
289
|
-
/* @__PURE__ */
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
items: withActive(ZOOMS, "fit")
|
|
299
|
-
})]
|
|
300
|
-
}),
|
|
301
|
-
/* @__PURE__ */ jsxs("div", {
|
|
302
|
-
class: "stage__grid",
|
|
303
|
-
children: [
|
|
304
|
-
/* @__PURE__ */ jsx(Pane, {
|
|
305
|
-
kind: "baseline",
|
|
306
|
-
label: "Baseline",
|
|
307
|
-
src: baselineSrc,
|
|
308
|
-
alt: `Baseline for ${subject}`,
|
|
309
|
-
empty: baselineEmpty
|
|
310
|
-
}),
|
|
311
|
-
/* @__PURE__ */ jsx(Pane, {
|
|
312
|
-
kind: "current",
|
|
313
|
-
label: "Current",
|
|
314
|
-
src: currentSrc,
|
|
315
|
-
alt: `Current for ${subject}`,
|
|
316
|
-
empty: "No screenshot"
|
|
317
|
-
}),
|
|
318
|
-
/* @__PURE__ */ jsx(Pane, {
|
|
319
|
-
kind: "diff",
|
|
320
|
-
label: "Diff",
|
|
321
|
-
src: diffSrc,
|
|
322
|
-
alt: `Diff for ${subject}`,
|
|
323
|
-
empty: diffEmpty,
|
|
324
|
-
meta: diffMeta
|
|
325
|
-
}),
|
|
326
|
-
/* @__PURE__ */ jsx("span", {
|
|
327
|
-
class: "stage__divider",
|
|
328
|
-
"aria-hidden": "true",
|
|
329
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
330
|
-
class: "stage__knob",
|
|
331
|
-
"data-compare-knob": true,
|
|
332
|
-
children: "↔"
|
|
333
|
-
})
|
|
334
|
-
})
|
|
335
|
-
]
|
|
360
|
+
/* @__PURE__ */ jsx(StageBar, { design }),
|
|
361
|
+
note ? /* @__PURE__ */ jsx("p", {
|
|
362
|
+
class: "stage__note",
|
|
363
|
+
children: note
|
|
364
|
+
}) : null,
|
|
365
|
+
/* @__PURE__ */ jsx(StageGrid, {
|
|
366
|
+
...images,
|
|
367
|
+
design,
|
|
368
|
+
baselineLabel
|
|
336
369
|
}),
|
|
337
|
-
/* @__PURE__ */ jsx(RangeControls, {})
|
|
370
|
+
/* @__PURE__ */ jsx(RangeControls, { baselineLabel })
|
|
338
371
|
]
|
|
339
372
|
});
|
|
340
373
|
};
|
|
341
|
-
//#endregion
|
|
342
374
|
export { CompareStage };
|
|
343
375
|
|
|
344
376
|
//# sourceMappingURL=compare-stage.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-stage.mjs","names":[],"sources":["../../src/ui/compare-stage.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\nimport { css } from \"./css.ts\";\nimport { Segmented } from \"./segmented.tsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n/**\n * Screenshot comparison surface. All modes share one set of images; the\n * `data-view` / `data-zoom` / `data-flip` attributes on the root (driven by\n * the review script) decide what is shown. Without JS it stays side-by-side.\n */\nconst stageRoot = css`\n /* compare-stage */\n display: grid;\n gap: var(--space-3);\n .stage__bar {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n align-items: center;\n justify-content: space-between;\n }\n .stage__grid {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--space-3);\n align-items: start;\n }\n .stage__pane {\n position: relative;\n min-width: 0;\n max-height: 78vh;\n overflow: auto;\n background: var(--surface-card);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n }\n .stage__label {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.35rem 0.6rem;\n background: var(--surface-subtle);\n border-bottom: 1px solid var(--border);\n color: var(--text-secondary);\n font-size: var(--text-xs);\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n }\n .stage__img {\n display: block;\n width: 100%;\n height: auto;\n background: repeating-conic-gradient(var(--surface-muted) 0% 25%, var(--surface-subtle) 0% 50%)\n 0 0 / 16px 16px;\n }\n .stage__empty {\n display: grid;\n place-items: center;\n aspect-ratio: 16 / 9;\n padding: var(--space-4);\n background: var(--surface-subtle);\n color: var(--text-secondary);\n font-size: var(--text-sm);\n text-align: center;\n }\n .stage__divider,\n .stage__controls {\n display: none;\n }\n .stage__controls {\n align-items: center;\n gap: var(--space-3);\n color: var(--text-secondary);\n font-size: var(--text-sm);\n }\n .stage__controls input {\n flex: 1;\n accent-color: var(--accent);\n }\n &[data-zoom=\"100\"] .stage__img {\n width: auto;\n max-width: none;\n }\n &[data-zoom=\"200\"] .stage__img {\n width: auto;\n max-width: none;\n zoom: 2;\n }\n &[data-zoom=\"400\"] .stage__img {\n width: auto;\n max-width: none;\n zoom: 4;\n }\n /* Zoomed in, show real pixels instead of a smoothed blur. */\n &[data-zoom=\"200\"] .stage__img,\n &[data-zoom=\"400\"] .stage__img {\n image-rendering: pixelated;\n }\n &[data-view=\"diff\"] .stage__grid,\n &[data-view=\"flip\"] .stage__grid,\n &[data-view=\"swipe\"] .stage__grid,\n &[data-view=\"onion\"] .stage__grid {\n grid-template-columns: minmax(0, 1fr);\n }\n &[data-view=\"diff\"] .stage__pane:not([data-pane=\"diff\"]) {\n display: none;\n }\n &[data-view=\"flip\"][data-flip=\"baseline\"] .stage__pane:not([data-pane=\"baseline\"]),\n &[data-view=\"flip\"]:not([data-flip=\"baseline\"]) .stage__pane:not([data-pane=\"current\"]) {\n display: none;\n }\n &[data-view=\"swipe\"] .stage__pane[data-pane=\"diff\"],\n &[data-view=\"onion\"] .stage__pane[data-pane=\"diff\"] {\n display: none;\n }\n &[data-view=\"swipe\"] .stage__pane,\n &[data-view=\"onion\"] .stage__pane,\n &[data-view=\"swipe\"] .stage__divider {\n grid-area: 1 / 1;\n }\n &[data-view=\"swipe\"] .stage__label,\n &[data-view=\"onion\"] .stage__label {\n display: none;\n }\n &[data-view=\"swipe\"] .stage__pane[data-pane=\"current\"] {\n clip-path: inset(0 0 0 var(--swipe, 50%));\n background: transparent;\n }\n &[data-view=\"onion\"] .stage__pane[data-pane=\"current\"] {\n opacity: var(--onion, 0.5);\n background: transparent;\n }\n &[data-view=\"swipe\"] .stage__divider {\n position: relative;\n display: block;\n z-index: 3;\n justify-self: start;\n width: 2px;\n height: 100%;\n margin-left: var(--swipe, 50%);\n background: var(--accent);\n pointer-events: none;\n }\n /* The only part of the divider that takes pointer input: drag it to wipe. */\n .stage__knob {\n position: absolute;\n top: 50%;\n left: 50%;\n display: grid;\n place-items: center;\n width: 32px;\n height: 32px;\n transform: translate(-50%, -50%);\n background: var(--accent);\n color: var(--accent-contrast);\n border: 2px solid var(--surface-card);\n border-radius: var(--radius-pill);\n box-shadow: var(--shadow-2);\n font-size: var(--text-lg);\n line-height: 1;\n cursor: ew-resize;\n pointer-events: auto;\n touch-action: none;\n user-select: none;\n }\n &[data-view=\"flip\"] .stage__grid {\n cursor: pointer;\n }\n &[data-view=\"swipe\"] .stage__controls[data-for=\"swipe\"],\n &[data-view=\"onion\"] .stage__controls[data-for=\"onion\"] {\n display: flex;\n }\n`;\n\nconst MODES = [\n { label: \"Side by side\", value: \"split\" },\n { label: \"Swipe\", value: \"swipe\" },\n { label: \"Onion skin\", value: \"onion\" },\n { label: \"Diff\", value: \"diff\" },\n { label: \"Flip\", value: \"flip\" },\n];\n\nconst ZOOMS = [\n { label: \"Fit\", value: \"fit\" },\n { label: \"100%\", value: \"100\" },\n { label: \"200%\", value: \"200\" },\n { label: \"400%\", value: \"400\" },\n];\n\nfunction withActive(\n items: { label: string; value: string }[],\n active: string,\n): { label: string; value: string; active: boolean }[] {\n return items.map((item) => ({ ...item, active: item.value === active }));\n}\n\ninterface PaneProps {\n kind: \"baseline\" | \"current\" | \"diff\";\n label: string;\n src: string | null;\n alt: string;\n empty: unknown;\n meta?: string;\n}\n\nconst Pane: FC<PaneProps> = ({ kind, label, src, alt, empty, meta }) => {\n return (\n <div class=\"stage__pane\" data-pane={kind}>\n <div class=\"stage__label\">\n <span>{label}</span>\n {meta ? <span>{meta}</span> : null}\n </div>\n {src ? (\n <img class=\"stage__img\" src={src} alt={alt} loading=\"lazy\" decoding=\"async\" />\n ) : (\n <div class=\"stage__empty\">{empty}</div>\n )}\n </div>\n );\n};\n\n/** Swipe and onion-skin sliders; each is shown only in its own mode (CSS). */\nconst RangeControls: FC = () => {\n return (\n <>\n <label class=\"stage__controls\" data-for=\"swipe\">\n <span>Baseline</span>\n <input type=\"range\" min=\"0\" max=\"100\" value=\"50\" data-compare-swipe aria-label=\"Swipe\" />\n <span>Current</span>\n </label>\n <label class=\"stage__controls\" data-for=\"onion\">\n <span>Baseline</span>\n <input type=\"range\" min=\"0\" max=\"100\" value=\"50\" data-compare-onion aria-label=\"Opacity\" />\n <span>Current</span>\n </label>\n </>\n );\n};\n\n/** Props for the screenshot comparison surface. */\nexport interface CompareStageProps {\n /** Baseline image URL, or null when the story has no baseline yet. */\n baselineSrc: string | null;\n currentSrc: string;\n /** Diff overlay URL, or null when none was produced. */\n diffSrc: string | null;\n /** Accessible description shared by the images, e.g. \"Button / Primary\". */\n subject: string;\n baselineEmpty?: unknown;\n diffEmpty?: unknown;\n diffMeta?: string;\n}\n\n/** Baseline / current / diff comparison with swipe, onion-skin, flip, and zoom. */\nexport const CompareStage: FC<CompareStageProps> = ({\n baselineSrc,\n currentSrc,\n diffSrc,\n subject,\n baselineEmpty = \"New story — no baseline yet. Approve to set the baseline.\",\n diffEmpty = \"No diff\",\n diffMeta,\n}) => {\n return (\n <div class={stageRoot} data-compare data-view=\"split\" data-zoom=\"fit\" data-flip=\"current\">\n <div class=\"stage__bar\">\n <Segmented label=\"Comparison mode\" data-compare-mode items={withActive(MODES, \"split\")} />\n <Segmented label=\"Zoom\" data-compare-zoom items={withActive(ZOOMS, \"fit\")} />\n </div>\n <div class=\"stage__grid\">\n <Pane\n kind=\"baseline\"\n label=\"Baseline\"\n src={baselineSrc}\n alt={`Baseline for ${subject}`}\n empty={baselineEmpty}\n />\n <Pane\n kind=\"current\"\n label=\"Current\"\n src={currentSrc}\n alt={`Current for ${subject}`}\n empty=\"No screenshot\"\n />\n <Pane\n kind=\"diff\"\n label=\"Diff\"\n src={diffSrc}\n alt={`Diff for ${subject}`}\n empty={diffEmpty}\n meta={diffMeta}\n />\n <span class=\"stage__divider\" aria-hidden=\"true\">\n <span class=\"stage__knob\" data-compare-knob>\n ↔\n </span>\n </span>\n </div>\n <RangeControls />\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compare-stage.mjs","names":[],"sources":["../../src/ui/compare-stage.tsx"],"sourcesContent":["import type { FC } from \"hono/jsx\";\nimport { css } from \"./css.ts\";\nimport { Segmented } from \"./segmented.tsx\";\n\n/* eslint-disable promise-function-async -- Hono JSX components return HtmlEscapedString | Promise<HtmlEscapedString> */\n\n/**\n * Screenshot comparison surface. All modes share one set of images; the\n * `data-view` / `data-zoom` / `data-flip` attributes on the root (driven by\n * the review script) decide what is shown. Without JS it stays side-by-side.\n */\nconst stageRoot = css`\n /* compare-stage */\n display: grid;\n gap: var(--space-3);\n .stage__bar {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-3);\n align-items: center;\n justify-content: space-between;\n }\n .stage__grid {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--space-3);\n align-items: start;\n }\n .stage__pane {\n position: relative;\n min-width: 0;\n max-height: 78vh;\n overflow: auto;\n background: var(--surface-card);\n border: 1px solid var(--border);\n border-radius: var(--radius);\n }\n .stage__label {\n position: sticky;\n top: 0;\n left: 0;\n z-index: 2;\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.35rem 0.6rem;\n background: var(--surface-subtle);\n border-bottom: 1px solid var(--border);\n color: var(--text-secondary);\n font-size: var(--text-xs);\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n }\n .stage__img {\n display: block;\n width: 100%;\n height: auto;\n background: repeating-conic-gradient(var(--surface-muted) 0% 25%, var(--surface-subtle) 0% 50%)\n 0 0 / 16px 16px;\n }\n .stage__empty {\n display: grid;\n place-items: center;\n aspect-ratio: 16 / 9;\n padding: var(--space-4);\n background: var(--surface-subtle);\n color: var(--text-secondary);\n font-size: var(--text-sm);\n text-align: center;\n }\n .stage__note {\n color: var(--text-secondary);\n font-size: var(--text-sm);\n }\n .stage__divider,\n .stage__controls {\n display: none;\n }\n .stage__controls {\n align-items: center;\n gap: var(--space-3);\n color: var(--text-secondary);\n font-size: var(--text-sm);\n }\n .stage__controls input {\n flex: 1;\n accent-color: var(--accent);\n }\n &[data-zoom=\"100\"] .stage__img {\n width: auto;\n max-width: none;\n }\n &[data-zoom=\"200\"] .stage__img {\n width: auto;\n max-width: none;\n zoom: 2;\n }\n &[data-zoom=\"400\"] .stage__img {\n width: auto;\n max-width: none;\n zoom: 4;\n }\n /* Zoomed in, show real pixels instead of a smoothed blur. */\n &[data-zoom=\"200\"] .stage__img,\n &[data-zoom=\"400\"] .stage__img {\n image-rendering: pixelated;\n }\n /* Design variant: screenshot against a render, two panes and no diff. */\n &[data-variant=\"design\"][data-view=\"split\"] .stage__grid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n &[data-view=\"diff\"] .stage__grid,\n &[data-view=\"flip\"] .stage__grid,\n &[data-view=\"swipe\"] .stage__grid,\n &[data-view=\"onion\"] .stage__grid {\n grid-template-columns: minmax(0, 1fr);\n }\n &[data-view=\"diff\"] .stage__pane:not([data-pane=\"diff\"]) {\n display: none;\n }\n &[data-view=\"flip\"][data-flip=\"baseline\"] .stage__pane:not([data-pane=\"baseline\"]),\n &[data-view=\"flip\"]:not([data-flip=\"baseline\"]) .stage__pane:not([data-pane=\"current\"]) {\n display: none;\n }\n &[data-view=\"swipe\"] .stage__pane[data-pane=\"diff\"],\n &[data-view=\"onion\"] .stage__pane[data-pane=\"diff\"] {\n display: none;\n }\n &[data-view=\"swipe\"] .stage__pane,\n &[data-view=\"onion\"] .stage__pane,\n &[data-view=\"swipe\"] .stage__divider {\n grid-area: 1 / 1;\n }\n &[data-view=\"swipe\"] .stage__label,\n &[data-view=\"onion\"] .stage__label {\n display: none;\n }\n &[data-view=\"swipe\"] .stage__pane[data-pane=\"current\"] {\n clip-path: inset(0 0 0 var(--swipe, 50%));\n background: transparent;\n }\n &[data-view=\"onion\"] .stage__pane[data-pane=\"current\"] {\n opacity: var(--onion, 0.5);\n background: transparent;\n }\n &[data-view=\"swipe\"] .stage__divider {\n position: relative;\n display: block;\n z-index: 3;\n justify-self: start;\n width: 2px;\n height: 100%;\n margin-left: var(--swipe, 50%);\n background: var(--accent);\n pointer-events: none;\n }\n /* The only part of the divider that takes pointer input: drag it to wipe. */\n .stage__knob {\n position: absolute;\n top: 50%;\n left: 50%;\n display: grid;\n place-items: center;\n width: 32px;\n height: 32px;\n transform: translate(-50%, -50%);\n background: var(--accent);\n color: var(--accent-contrast);\n border: 2px solid var(--surface-card);\n border-radius: var(--radius-pill);\n box-shadow: var(--shadow-2);\n font-size: var(--text-lg);\n line-height: 1;\n cursor: ew-resize;\n pointer-events: auto;\n touch-action: none;\n user-select: none;\n }\n &[data-view=\"flip\"] .stage__grid {\n cursor: pointer;\n }\n &[data-view=\"swipe\"] .stage__controls[data-for=\"swipe\"],\n &[data-view=\"onion\"] .stage__controls[data-for=\"onion\"] {\n display: flex;\n }\n`;\n\nconst MODES = [\n { label: \"Side by side\", value: \"split\" },\n { label: \"Swipe\", value: \"swipe\" },\n { label: \"Onion skin\", value: \"onion\" },\n { label: \"Diff\", value: \"diff\" },\n { label: \"Flip\", value: \"flip\" },\n];\n\nconst ZOOMS = [\n { label: \"Fit\", value: \"fit\" },\n { label: \"100%\", value: \"100\" },\n { label: \"200%\", value: \"200\" },\n { label: \"400%\", value: \"400\" },\n];\n\n/** Modes and zoom a design comparison offers: no pixel diff, and the render always fits the stage. */\nconst DESIGN_MODES = [\"split\", \"swipe\", \"onion\"];\n\nfunction withActive(\n items: { label: string; value: string }[],\n active: string,\n): { label: string; value: string; active: boolean }[] {\n return items.map((item) => ({ ...item, active: item.value === active }));\n}\n\ninterface PaneProps {\n kind: \"baseline\" | \"current\" | \"diff\";\n label: string;\n src: string | null;\n alt: string;\n empty: unknown;\n meta?: string;\n}\n\nconst Pane: FC<PaneProps> = ({ kind, label, src, alt, empty, meta }) => {\n return (\n <div class=\"stage__pane\" data-pane={kind}>\n <div class=\"stage__label\">\n <span>{label}</span>\n {meta ? <span>{meta}</span> : null}\n </div>\n {src ? (\n <img class=\"stage__img\" src={src} alt={alt} loading=\"lazy\" decoding=\"async\" />\n ) : (\n <div class=\"stage__empty\">{empty}</div>\n )}\n </div>\n );\n};\n\n/** Swipe and onion-skin sliders; each is shown only in its own mode (CSS). */\nconst RangeControls: FC<{ baselineLabel: string }> = ({ baselineLabel }) => {\n return (\n <>\n <label class=\"stage__controls\" data-for=\"swipe\">\n <span>{baselineLabel}</span>\n <input type=\"range\" min=\"0\" max=\"100\" value=\"50\" data-compare-swipe aria-label=\"Swipe\" />\n <span>Current</span>\n </label>\n <label class=\"stage__controls\" data-for=\"onion\">\n <span>{baselineLabel}</span>\n <input type=\"range\" min=\"0\" max=\"100\" value=\"50\" data-compare-onion aria-label=\"Opacity\" />\n <span>Current</span>\n </label>\n </>\n );\n};\n\n/** Props for the screenshot comparison surface. */\nexport interface CompareStageProps {\n /** Baseline image URL, or null when the story has no baseline yet. */\n baselineSrc: string | null;\n currentSrc: string;\n /** Diff overlay URL, or null when none was produced. */\n diffSrc: string | null;\n /** Accessible description shared by the images, e.g. \"Button / Primary\". */\n subject: string;\n baselineEmpty?: unknown;\n diffEmpty?: unknown;\n diffMeta?: string;\n /**\n * `design` compares the screenshot with a design render instead of a baseline: side by side,\n * swipe and onion only (no diff, no flip), fit zoom only.\n */\n variant?: \"baseline\" | \"design\";\n /** Name of the left-hand image in labels and sliders (default \"Baseline\"). */\n baselineLabel?: string;\n /** A line under the controls, e.g. what the left-hand image is. */\n note?: string;\n}\n\n/** Mode switch, plus the zoom switch (a design comparison always fits, so it has none). */\nconst StageBar: FC<{ design: boolean }> = ({ design }) => {\n const modes = design ? MODES.filter((mode) => DESIGN_MODES.includes(mode.value)) : MODES;\n return (\n <div class=\"stage__bar\">\n <Segmented label=\"Comparison mode\" data-compare-mode items={withActive(modes, \"split\")} />\n {design ? null : (\n <Segmented label=\"Zoom\" data-compare-zoom items={withActive(ZOOMS, \"fit\")} />\n )}\n </div>\n );\n};\n\n/** The panes (baseline or design, current, diff) and the swipe divider. */\nconst StageGrid: FC<CompareStageProps & { design: boolean; baselineLabel: string }> = ({\n baselineSrc,\n currentSrc,\n diffSrc,\n subject,\n baselineEmpty = \"New story — no baseline yet. Approve to set the baseline.\",\n diffEmpty = \"No diff\",\n diffMeta,\n design,\n baselineLabel,\n}) => (\n <div class=\"stage__grid\">\n <Pane\n kind=\"baseline\"\n label={baselineLabel}\n src={baselineSrc}\n alt={`${baselineLabel} for ${subject}`}\n empty={baselineEmpty}\n />\n <Pane\n kind=\"current\"\n label=\"Current\"\n src={currentSrc}\n alt={`Current for ${subject}`}\n empty=\"No screenshot\"\n />\n {design ? null : (\n <Pane\n kind=\"diff\"\n label=\"Diff\"\n src={diffSrc}\n alt={`Diff for ${subject}`}\n empty={diffEmpty}\n meta={diffMeta}\n />\n )}\n <span class=\"stage__divider\" aria-hidden=\"true\">\n <span class=\"stage__knob\" data-compare-knob>\n ↔\n </span>\n </span>\n </div>\n);\n\n/** Baseline / current / diff comparison with swipe, onion-skin, flip, and zoom. */\nexport const CompareStage: FC<CompareStageProps> = ({\n variant = \"baseline\",\n baselineLabel = \"Baseline\",\n note,\n ...images\n}) => {\n const design = variant === \"design\";\n return (\n <div\n class={stageRoot}\n data-compare\n data-view=\"split\"\n data-zoom=\"fit\"\n data-flip=\"current\"\n data-variant={variant}\n data-modes={design ? DESIGN_MODES.join(\",\") : undefined}\n data-zooms={design ? \"fit\" : undefined}\n >\n <StageBar design={design} />\n {note ? <p class=\"stage__note\">{note}</p> : null}\n <StageGrid {...images} design={design} baselineLabel={baselineLabel} />\n <RangeControls baselineLabel={baselineLabel} />\n </div>\n );\n};\n"],"mappings":"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"}
|
package/dist/ui/csrf-field.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { getStore } from "../store.mjs";
|
|
5
5
|
import { getCsrfToken } from "../middleware/csrf.mjs";
|
|
6
6
|
import { jsx } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/csrf-field.tsx
|
|
8
8
|
/** Hidden CSRF token so native (non-HTMX) form posts pass the csrf middleware. */
|
|
9
9
|
function csrfField() {
|
|
10
10
|
const { config, sessionId } = getStore();
|
|
@@ -14,7 +14,6 @@ function csrfField() {
|
|
|
14
14
|
value: getCsrfToken(config.secret, sessionId)
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
|
-
//#endregion
|
|
18
17
|
export { csrfField };
|
|
19
18
|
|
|
20
19
|
//# sourceMappingURL=csrf-field.mjs.map
|
package/dist/ui/css.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { createCssContext } from "hono/css";
|
|
5
|
-
|
|
5
|
+
// src/ui/css.ts
|
|
6
6
|
/**
|
|
7
7
|
* hono/css building blocks for the server-rendered UI.
|
|
8
8
|
*
|
|
@@ -30,7 +30,6 @@ const context = createCssContext({
|
|
|
30
30
|
const css = (strings, ...values) => context.css(strings, ...values);
|
|
31
31
|
/** Collects every used class into `<style id="storyshelf-css">`. */
|
|
32
32
|
const Style = (args) => context.Style(args);
|
|
33
|
-
//#endregion
|
|
34
33
|
export { Style, css };
|
|
35
34
|
|
|
36
35
|
//# sourceMappingURL=css.mjs.map
|
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { Icon } from "./icons/icon.mjs";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/design-reference.tsx
|
|
8
8
|
const referenceRoot = css`
|
|
9
9
|
/* design-reference */
|
|
10
10
|
display: grid;
|
|
@@ -91,7 +91,6 @@ const DesignPreview = ({ src, name, providerName }) => /* @__PURE__ */ jsxs(Frag
|
|
|
91
91
|
class: previewCaption,
|
|
92
92
|
children: name
|
|
93
93
|
}) : null] });
|
|
94
|
-
//#endregion
|
|
95
94
|
export { DesignPreview, DesignReference };
|
|
96
95
|
|
|
97
96
|
//# sourceMappingURL=design-reference.mjs.map
|
package/dist/ui/document.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import { baseStyle } from "./styles.mjs";
|
|
|
13
13
|
import { DARK_THEME, LIGHT_THEME } from "./theme.mjs";
|
|
14
14
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
15
15
|
import { raw } from "hono/html";
|
|
16
|
-
|
|
16
|
+
// src/ui/document.tsx
|
|
17
17
|
const shellRoot = css`
|
|
18
18
|
/* shell */
|
|
19
19
|
display: grid;
|
|
@@ -123,7 +123,6 @@ const DocumentLayout = ({ title, nav, layout = "default", children }) => {
|
|
|
123
123
|
] })]
|
|
124
124
|
})] });
|
|
125
125
|
};
|
|
126
|
-
//#endregion
|
|
127
126
|
export { DocumentLayout };
|
|
128
127
|
|
|
129
128
|
//# sourceMappingURL=document.mjs.map
|
package/dist/ui/dropdown.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { Icon } from "./icons/icon.mjs";
|
|
6
6
|
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/dropdown.tsx
|
|
8
8
|
const dropdownRoot = css`
|
|
9
9
|
/* dropdown */
|
|
10
10
|
position: relative;
|
|
@@ -175,7 +175,6 @@ const DropdownDivider = () => {
|
|
|
175
175
|
role: "separator"
|
|
176
176
|
});
|
|
177
177
|
};
|
|
178
|
-
//#endregion
|
|
179
178
|
export { Dropdown, DropdownDivider, DropdownItem };
|
|
180
179
|
|
|
181
180
|
//# sourceMappingURL=dropdown.mjs.map
|
package/dist/ui/feedback.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import.meta.url;
|
|
|
4
4
|
import { css } from "./css.mjs";
|
|
5
5
|
import { Icon } from "./icons/icon.mjs";
|
|
6
6
|
import { jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
7
|
-
|
|
7
|
+
// src/ui/feedback.tsx
|
|
8
8
|
const badgeBase = css`
|
|
9
9
|
/* badge */
|
|
10
10
|
display: inline-flex;
|
|
@@ -335,7 +335,6 @@ const Meta = ({ as = "p", mono = false, tone = "neutral", center = false, childr
|
|
|
335
335
|
children
|
|
336
336
|
});
|
|
337
337
|
};
|
|
338
|
-
//#endregion
|
|
339
338
|
export { Alert, Badge, EmptyState, Meta, Stat, statusTone };
|
|
340
339
|
|
|
341
340
|
//# sourceMappingURL=feedback.mjs.map
|