@storyshelf/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -0
- package/dist/adapter/auth.d.mts +50 -0
- package/dist/adapter/auth.mjs +10 -0
- package/dist/adapter/auth.mjs.map +1 -0
- package/dist/adapter/capture-runner.d.mts +70 -0
- package/dist/adapter/capture-runner.mjs +4 -0
- package/dist/adapter/database.d.mts +43 -0
- package/dist/adapter/database.mjs +4 -0
- package/dist/adapter/git-host/helpers.d.mts +12 -0
- package/dist/adapter/git-host/helpers.mjs +29 -0
- package/dist/adapter/git-host/helpers.mjs.map +1 -0
- package/dist/adapter/git-host.d.mts +46 -0
- package/dist/adapter/git-host.mjs +4 -0
- package/dist/adapter/storage.d.mts +22 -0
- package/dist/adapter/storage.mjs +4 -0
- package/dist/adapters/capture-queue.d.mts +49 -0
- package/dist/adapters/metadata.d.mts +24 -0
- package/dist/adapters/webhook-events.mjs +39 -0
- package/dist/adapters/webhook-events.mjs.map +1 -0
- package/dist/capture/adapter.d.mts +29 -0
- package/dist/capture/adapter.mjs +13 -0
- package/dist/capture/adapter.mjs.map +1 -0
- package/dist/capture/orchestrator.d.mts +23 -0
- package/dist/capture/orchestrator.mjs +103 -0
- package/dist/capture/orchestrator.mjs.map +1 -0
- package/dist/capture/pipeline.d.mts +41 -0
- package/dist/capture/pipeline.mjs +119 -0
- package/dist/capture/pipeline.mjs.map +1 -0
- package/dist/capture/queue.d.mts +35 -0
- package/dist/capture/queue.mjs +96 -0
- package/dist/capture/queue.mjs.map +1 -0
- package/dist/capture/status-fanout.mjs +66 -0
- package/dist/capture/status-fanout.mjs.map +1 -0
- package/dist/capture/storybook.d.mts +14 -0
- package/dist/capture/storybook.mjs +40 -0
- package/dist/capture/storybook.mjs.map +1 -0
- package/dist/config.d.mts +68 -0
- package/dist/config.mjs +69 -0
- package/dist/config.mjs.map +1 -0
- package/dist/ddl.d.mts +7 -0
- package/dist/ddl.mjs +155 -0
- package/dist/ddl.mjs.map +1 -0
- package/dist/diff/engine.d.mts +8 -0
- package/dist/diff/engine.mjs +79 -0
- package/dist/diff/engine.mjs.map +1 -0
- package/dist/diff/options.d.mts +40 -0
- package/dist/diff/options.mjs +15 -0
- package/dist/diff/options.mjs.map +1 -0
- package/dist/index.d.mts +48 -0
- package/dist/index.mjs +327 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logger.d.mts +39 -0
- package/dist/logger.mjs +35 -0
- package/dist/logger.mjs.map +1 -0
- package/dist/middleware/csrf.mjs +39 -0
- package/dist/middleware/csrf.mjs.map +1 -0
- package/dist/middleware/rate-limit.mjs +38 -0
- package/dist/middleware/rate-limit.mjs.map +1 -0
- package/dist/models/baseline.d.mts +20 -0
- package/dist/models/baseline.mjs +89 -0
- package/dist/models/baseline.mjs.map +1 -0
- package/dist/models/build.d.mts +35 -0
- package/dist/models/build.mjs +77 -0
- package/dist/models/build.mjs.map +1 -0
- package/dist/models/comment.d.mts +20 -0
- package/dist/models/comment.mjs +42 -0
- package/dist/models/comment.mjs.map +1 -0
- package/dist/models/label.d.mts +43 -0
- package/dist/models/label.mjs +107 -0
- package/dist/models/label.mjs.map +1 -0
- package/dist/models/member.d.mts +27 -0
- package/dist/models/member.mjs +54 -0
- package/dist/models/member.mjs.map +1 -0
- package/dist/models/project.d.mts +42 -0
- package/dist/models/project.mjs +78 -0
- package/dist/models/project.mjs.map +1 -0
- package/dist/models/snapshot.d.mts +46 -0
- package/dist/models/snapshot.mjs +75 -0
- package/dist/models/snapshot.mjs.map +1 -0
- package/dist/models/status-config.mjs +61 -0
- package/dist/models/status-config.mjs.map +1 -0
- package/dist/models/token.d.mts +33 -0
- package/dist/models/token.mjs +60 -0
- package/dist/models/token.mjs.map +1 -0
- package/dist/models/webhook.d.mts +37 -0
- package/dist/models/webhook.mjs +67 -0
- package/dist/models/webhook.mjs.map +1 -0
- package/dist/pages/build-detail.mjs +333 -0
- package/dist/pages/build-detail.mjs.map +1 -0
- package/dist/pages/build-diff.mjs +437 -0
- package/dist/pages/build-diff.mjs.map +1 -0
- package/dist/pages/compute-jobs.mjs +196 -0
- package/dist/pages/compute-jobs.mjs.map +1 -0
- package/dist/pages/login.mjs +77 -0
- package/dist/pages/login.mjs.map +1 -0
- package/dist/pages/project-builds.mjs +228 -0
- package/dist/pages/project-builds.mjs.map +1 -0
- package/dist/pages/project-create.mjs +168 -0
- package/dist/pages/project-create.mjs.map +1 -0
- package/dist/pages/project-settings.mjs +111 -0
- package/dist/pages/project-settings.mjs.map +1 -0
- package/dist/pages/projects.mjs +178 -0
- package/dist/pages/projects.mjs.map +1 -0
- package/dist/pages/root.mjs +90 -0
- package/dist/pages/root.mjs.map +1 -0
- package/dist/pages/settings-general.mjs +191 -0
- package/dist/pages/settings-general.mjs.map +1 -0
- package/dist/pages/settings-labels.mjs +149 -0
- package/dist/pages/settings-labels.mjs.map +1 -0
- package/dist/pages/settings-members.mjs +124 -0
- package/dist/pages/settings-members.mjs.map +1 -0
- package/dist/pages/settings-status.mjs +150 -0
- package/dist/pages/settings-status.mjs.map +1 -0
- package/dist/pages/settings-tokens.mjs +95 -0
- package/dist/pages/settings-tokens.mjs.map +1 -0
- package/dist/pages/settings-webhooks.mjs +149 -0
- package/dist/pages/settings-webhooks.mjs.map +1 -0
- package/dist/retention/purge.d.mts +28 -0
- package/dist/retention/purge.mjs +66 -0
- package/dist/retention/purge.mjs.map +1 -0
- package/dist/routers/admin.mjs +41 -0
- package/dist/routers/admin.mjs.map +1 -0
- package/dist/routers/assets.mjs +24 -0
- package/dist/routers/assets.mjs.map +1 -0
- package/dist/routers/auth.mjs +77 -0
- package/dist/routers/auth.mjs.map +1 -0
- package/dist/routers/builds.handlers.mjs +87 -0
- package/dist/routers/builds.handlers.mjs.map +1 -0
- package/dist/routers/builds.mjs +162 -0
- package/dist/routers/builds.mjs.map +1 -0
- package/dist/routers/comments.mjs +89 -0
- package/dist/routers/comments.mjs.map +1 -0
- package/dist/routers/helpers.mjs +76 -0
- package/dist/routers/helpers.mjs.map +1 -0
- package/dist/routers/htmx.mjs +18 -0
- package/dist/routers/htmx.mjs.map +1 -0
- package/dist/routers/labels.mjs +77 -0
- package/dist/routers/labels.mjs.map +1 -0
- package/dist/routers/media.mjs +54 -0
- package/dist/routers/media.mjs.map +1 -0
- package/dist/routers/members.mjs +101 -0
- package/dist/routers/members.mjs.map +1 -0
- package/dist/routers/projects.mjs +121 -0
- package/dist/routers/projects.mjs.map +1 -0
- package/dist/routers/schemas.mjs +188 -0
- package/dist/routers/schemas.mjs.map +1 -0
- package/dist/routers/settings.mjs +235 -0
- package/dist/routers/settings.mjs.map +1 -0
- package/dist/routers/snapshots.mjs +143 -0
- package/dist/routers/snapshots.mjs.map +1 -0
- package/dist/routers/status-configs.mjs +100 -0
- package/dist/routers/status-configs.mjs.map +1 -0
- package/dist/routers/tokens.mjs +80 -0
- package/dist/routers/tokens.mjs.map +1 -0
- package/dist/routers/ui.mjs +142 -0
- package/dist/routers/ui.mjs.map +1 -0
- package/dist/routers/webhooks.mjs +89 -0
- package/dist/routers/webhooks.mjs.map +1 -0
- package/dist/schema.d.mts +4372 -0
- package/dist/schema.mjs +158 -0
- package/dist/schema.mjs.map +1 -0
- package/dist/store.mjs +18 -0
- package/dist/store.mjs.map +1 -0
- package/dist/types.d.mts +18 -0
- package/dist/types.mjs +49 -0
- package/dist/types.mjs.map +1 -0
- package/dist/ui/components.mjs +127 -0
- package/dist/ui/components.mjs.map +1 -0
- package/dist/ui/document.d.mts +8 -0
- package/dist/ui/document.mjs +338 -0
- package/dist/ui/document.mjs.map +1 -0
- package/dist/ui/styles.mjs +173 -0
- package/dist/ui/styles.mjs.map +1 -0
- package/dist/ui/theme.mjs +42 -0
- package/dist/ui/theme.mjs.map +1 -0
- package/dist/urls.d.mts +19 -0
- package/dist/urls.mjs +23 -0
- package/dist/urls.mjs.map +1 -0
- package/dist/utils/encrypt.mjs +49 -0
- package/dist/utils/encrypt.mjs.map +1 -0
- package/dist/utils/hash.mjs +22 -0
- package/dist/utils/hash.mjs.map +1 -0
- package/dist/utils/paths.d.mts +11 -0
- package/dist/utils/paths.mjs +23 -0
- package/dist/utils/paths.mjs.map +1 -0
- package/dist/utils/ulid.d.mts +8 -0
- package/dist/utils/ulid.mjs +41 -0
- package/dist/utils/ulid.mjs.map +1 -0
- package/package.json +162 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { getStore } from "../store.mjs";
|
|
5
|
+
import { baseStyle } from "./styles.mjs";
|
|
6
|
+
import { DARK_THEME, LIGHT_THEME } from "./theme.mjs";
|
|
7
|
+
import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime";
|
|
8
|
+
//#region src/ui/document.tsx
|
|
9
|
+
const DocumentLayout = ({ title, nav, children }) => {
|
|
10
|
+
const { ui } = getStore();
|
|
11
|
+
const name = ui.name ?? "StoryShelf";
|
|
12
|
+
const light = ui.lightTheme ?? LIGHT_THEME;
|
|
13
|
+
const dark = ui.darkTheme ?? DARK_THEME;
|
|
14
|
+
return /* @__PURE__ */ jsxs("html", {
|
|
15
|
+
lang: "en",
|
|
16
|
+
"data-theme": "system",
|
|
17
|
+
children: [/* @__PURE__ */ jsxs("head", { children: [
|
|
18
|
+
/* @__PURE__ */ jsx("meta", { charset: "utf-8" }),
|
|
19
|
+
/* @__PURE__ */ jsx("meta", {
|
|
20
|
+
name: "viewport",
|
|
21
|
+
content: "width=device-width, initial-scale=1"
|
|
22
|
+
}),
|
|
23
|
+
/* @__PURE__ */ jsx("meta", {
|
|
24
|
+
name: "color-scheme",
|
|
25
|
+
content: "light dark"
|
|
26
|
+
}),
|
|
27
|
+
ui.favicon ? /* @__PURE__ */ jsx("link", {
|
|
28
|
+
rel: "icon",
|
|
29
|
+
href: ui.favicon
|
|
30
|
+
}) : null,
|
|
31
|
+
/* @__PURE__ */ jsxs("title", { children: [
|
|
32
|
+
title,
|
|
33
|
+
" · ",
|
|
34
|
+
name
|
|
35
|
+
] }),
|
|
36
|
+
/* @__PURE__ */ jsx("style", { children: baseStyle(light, dark) }),
|
|
37
|
+
/* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: themeScript() } })
|
|
38
|
+
] }), /* @__PURE__ */ jsxs("body", { children: [
|
|
39
|
+
/* @__PURE__ */ jsx("a", {
|
|
40
|
+
class: "skip-link",
|
|
41
|
+
href: "#main-content",
|
|
42
|
+
children: "Skip to content"
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ jsx(TopBar, {
|
|
45
|
+
name,
|
|
46
|
+
logo: ui.logo,
|
|
47
|
+
nav
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ jsxs("div", {
|
|
50
|
+
class: "shell",
|
|
51
|
+
children: [/* @__PURE__ */ jsx(Sidebar, { nav }), /* @__PURE__ */ jsx("main", {
|
|
52
|
+
id: "main-content",
|
|
53
|
+
class: "content",
|
|
54
|
+
tabindex: -1,
|
|
55
|
+
children
|
|
56
|
+
})]
|
|
57
|
+
}),
|
|
58
|
+
/* @__PURE__ */ jsx("script", { src: "/assets/htmx.js" }),
|
|
59
|
+
/* @__PURE__ */ jsx("script", { dangerouslySetInnerHTML: { __html: clientScript() } })
|
|
60
|
+
] })]
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const TopBar = ({ name, logo, nav }) => {
|
|
64
|
+
return /* @__PURE__ */ jsx("header", {
|
|
65
|
+
class: "topbar",
|
|
66
|
+
role: "banner",
|
|
67
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
68
|
+
class: "topbar__inner",
|
|
69
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
70
|
+
class: "topbar__left",
|
|
71
|
+
children: [
|
|
72
|
+
/* @__PURE__ */ jsx("button", {
|
|
73
|
+
class: "topbar__menu",
|
|
74
|
+
type: "button",
|
|
75
|
+
"aria-label": "Toggle navigation",
|
|
76
|
+
"aria-expanded": "false",
|
|
77
|
+
"aria-controls": "sidebar",
|
|
78
|
+
"data-sidebar-toggle": true,
|
|
79
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
80
|
+
"aria-hidden": "true",
|
|
81
|
+
children: "☰"
|
|
82
|
+
})
|
|
83
|
+
}),
|
|
84
|
+
/* @__PURE__ */ jsxs("a", {
|
|
85
|
+
class: "brand",
|
|
86
|
+
href: "/",
|
|
87
|
+
children: [logo ? /* @__PURE__ */ jsx("img", {
|
|
88
|
+
class: "logo",
|
|
89
|
+
src: logo,
|
|
90
|
+
alt: name,
|
|
91
|
+
width: "28",
|
|
92
|
+
height: "28"
|
|
93
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
94
|
+
class: "brand__mark",
|
|
95
|
+
"aria-hidden": "true",
|
|
96
|
+
children: "◆"
|
|
97
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
98
|
+
class: "brand__name",
|
|
99
|
+
children: name
|
|
100
|
+
})]
|
|
101
|
+
}),
|
|
102
|
+
nav?.projectSlug ? /* @__PURE__ */ jsxs("nav", {
|
|
103
|
+
class: "project-crumb",
|
|
104
|
+
"aria-label": "Project",
|
|
105
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
106
|
+
class: "project-crumb__sep",
|
|
107
|
+
"aria-hidden": "true",
|
|
108
|
+
children: "/"
|
|
109
|
+
}), /* @__PURE__ */ jsx("a", {
|
|
110
|
+
href: `/projects/${nav.projectSlug}/builds`,
|
|
111
|
+
children: nav.projectName ?? nav.projectSlug
|
|
112
|
+
})]
|
|
113
|
+
}) : null
|
|
114
|
+
]
|
|
115
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
116
|
+
class: "topbar__right",
|
|
117
|
+
children: [/* @__PURE__ */ jsx(ThemeToggle, {}), /* @__PURE__ */ jsx(AuthMenu, {})]
|
|
118
|
+
})]
|
|
119
|
+
})
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
const ThemeToggle = () => {
|
|
123
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
124
|
+
class: "topbar__theme",
|
|
125
|
+
type: "button",
|
|
126
|
+
"aria-label": "Toggle theme",
|
|
127
|
+
"data-theme-toggle": true,
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ jsx("span", {
|
|
130
|
+
"data-theme-icon": "light",
|
|
131
|
+
"aria-hidden": "true",
|
|
132
|
+
children: "☀"
|
|
133
|
+
}),
|
|
134
|
+
/* @__PURE__ */ jsx("span", {
|
|
135
|
+
"data-theme-icon": "dark",
|
|
136
|
+
"aria-hidden": "true",
|
|
137
|
+
children: "☾"
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ jsx("span", {
|
|
140
|
+
"data-theme-icon": "system",
|
|
141
|
+
"aria-hidden": "true",
|
|
142
|
+
children: "◐"
|
|
143
|
+
})
|
|
144
|
+
]
|
|
145
|
+
});
|
|
146
|
+
};
|
|
147
|
+
const AuthMenu = () => {
|
|
148
|
+
const { user, authEnabled } = getStore();
|
|
149
|
+
if (!authEnabled) return null;
|
|
150
|
+
if (!user) return /* @__PURE__ */ jsx("a", {
|
|
151
|
+
class: "topbar__login",
|
|
152
|
+
href: "/auth/login",
|
|
153
|
+
children: "Sign in"
|
|
154
|
+
});
|
|
155
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
156
|
+
class: "user-menu",
|
|
157
|
+
children: [
|
|
158
|
+
user.avatarUrl ? /* @__PURE__ */ jsx("img", {
|
|
159
|
+
class: "user-menu__avatar",
|
|
160
|
+
src: user.avatarUrl,
|
|
161
|
+
alt: "",
|
|
162
|
+
width: "28",
|
|
163
|
+
height: "28"
|
|
164
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
165
|
+
class: "user-menu__avatar user-menu__avatar--fallback",
|
|
166
|
+
"aria-hidden": "true",
|
|
167
|
+
children: user.name.slice(0, 1).toUpperCase()
|
|
168
|
+
}),
|
|
169
|
+
/* @__PURE__ */ jsx("span", {
|
|
170
|
+
class: "user-menu__name",
|
|
171
|
+
children: user.name
|
|
172
|
+
}),
|
|
173
|
+
/* @__PURE__ */ jsx("span", {
|
|
174
|
+
class: `user-menu__role user-menu__role--${user.role}`,
|
|
175
|
+
children: user.role
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ jsx("form", {
|
|
178
|
+
method: "post",
|
|
179
|
+
action: "/auth/logout",
|
|
180
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
181
|
+
class: "user-menu__logout",
|
|
182
|
+
type: "submit",
|
|
183
|
+
children: "Sign out"
|
|
184
|
+
})
|
|
185
|
+
})
|
|
186
|
+
]
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
const Sidebar = ({ nav }) => {
|
|
190
|
+
return /* @__PURE__ */ jsx("aside", {
|
|
191
|
+
id: "sidebar",
|
|
192
|
+
class: "sidebar",
|
|
193
|
+
"aria-label": "Primary",
|
|
194
|
+
children: /* @__PURE__ */ jsxs("nav", {
|
|
195
|
+
class: "sidebar__nav",
|
|
196
|
+
children: [
|
|
197
|
+
/* @__PURE__ */ jsxs("a", {
|
|
198
|
+
class: `sidebar__link ${nav?.active === "projects" ? "sidebar__link--active" : ""}`,
|
|
199
|
+
href: "/projects",
|
|
200
|
+
"aria-current": nav?.active === "projects" ? "page" : void 0,
|
|
201
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
202
|
+
"aria-hidden": "true",
|
|
203
|
+
children: "▦"
|
|
204
|
+
}), " Projects"]
|
|
205
|
+
}),
|
|
206
|
+
nav?.projectSlug ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
207
|
+
/* @__PURE__ */ jsx("div", {
|
|
208
|
+
class: "sidebar__section",
|
|
209
|
+
children: "Project"
|
|
210
|
+
}),
|
|
211
|
+
/* @__PURE__ */ jsxs("a", {
|
|
212
|
+
class: `sidebar__link ${nav.active === "builds" ? "sidebar__link--active" : ""}`,
|
|
213
|
+
href: `/projects/${nav.projectSlug}/builds`,
|
|
214
|
+
"aria-current": nav.active === "builds" ? "page" : void 0,
|
|
215
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
216
|
+
"aria-hidden": "true",
|
|
217
|
+
children: "◧"
|
|
218
|
+
}), " Builds"]
|
|
219
|
+
}),
|
|
220
|
+
/* @__PURE__ */ jsxs("a", {
|
|
221
|
+
class: `sidebar__link ${nav.active === "jobs" ? "sidebar__link--active" : ""}`,
|
|
222
|
+
href: `/projects/${nav.projectSlug}/jobs`,
|
|
223
|
+
"aria-current": nav.active === "jobs" ? "page" : void 0,
|
|
224
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
225
|
+
"aria-hidden": "true",
|
|
226
|
+
children: "◫"
|
|
227
|
+
}), " Jobs"]
|
|
228
|
+
}),
|
|
229
|
+
/* @__PURE__ */ jsxs("a", {
|
|
230
|
+
class: `sidebar__link ${nav.active === "settings" ? "sidebar__link--active" : ""}`,
|
|
231
|
+
href: `/projects/${nav.projectSlug}/settings`,
|
|
232
|
+
"aria-current": nav.active === "settings" ? "page" : void 0,
|
|
233
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
234
|
+
"aria-hidden": "true",
|
|
235
|
+
children: "⚙"
|
|
236
|
+
}), " Settings"]
|
|
237
|
+
})
|
|
238
|
+
] }) : null,
|
|
239
|
+
/* @__PURE__ */ jsx("div", {
|
|
240
|
+
class: "sidebar__section",
|
|
241
|
+
children: "Resources"
|
|
242
|
+
}),
|
|
243
|
+
/* @__PURE__ */ jsxs("a", {
|
|
244
|
+
class: "sidebar__link",
|
|
245
|
+
href: "/api/v1/projects",
|
|
246
|
+
"aria-label": "API (JSON)",
|
|
247
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
248
|
+
"aria-hidden": "true",
|
|
249
|
+
children: "{} "
|
|
250
|
+
}), " API"]
|
|
251
|
+
})
|
|
252
|
+
]
|
|
253
|
+
})
|
|
254
|
+
});
|
|
255
|
+
};
|
|
256
|
+
function themeScript() {
|
|
257
|
+
return `
|
|
258
|
+
(function(){
|
|
259
|
+
var cookieName='storyshelf_theme';
|
|
260
|
+
function readCookie(n){
|
|
261
|
+
var m=document.cookie.match(new RegExp('(?:^|; )'+n.replace(/([.$?*|{}\\[\\]\\\\/\\+^])/gu,'\\\\$1')+'=([^;]*)'));
|
|
262
|
+
return m?decodeURIComponent(m[1]):null;
|
|
263
|
+
}
|
|
264
|
+
function writeCookie(n,v){
|
|
265
|
+
document.cookie=n+'='+encodeURIComponent(v)+'; Path=/; Max-Age=31536000; SameSite=Lax';
|
|
266
|
+
}
|
|
267
|
+
function applyTheme(v){
|
|
268
|
+
var html=document.documentElement;
|
|
269
|
+
if(v==='light'||v==='dark'||v==='system'){ html.setAttribute('data-theme',v); }
|
|
270
|
+
else { html.setAttribute('data-theme','system'); }
|
|
271
|
+
}
|
|
272
|
+
var initial=readCookie(cookieName);
|
|
273
|
+
if(initial){ applyTheme(initial); }
|
|
274
|
+
window.__storyshelfTheme={readCookie:readCookie,writeCookie:writeCookie,applyTheme:applyTheme,cookieName:cookieName};
|
|
275
|
+
})();
|
|
276
|
+
`.trim();
|
|
277
|
+
}
|
|
278
|
+
function clientScript() {
|
|
279
|
+
return `
|
|
280
|
+
(function(){
|
|
281
|
+
var theme=window.__storyshelfTheme;
|
|
282
|
+
var toggle=document.querySelector('[data-theme-toggle]');
|
|
283
|
+
if(toggle&&theme){
|
|
284
|
+
toggle.addEventListener('click',function(){
|
|
285
|
+
var cur=document.documentElement.getAttribute('data-theme')||'system';
|
|
286
|
+
var next=cur==='system'?'light':cur==='light'?'dark':'system';
|
|
287
|
+
theme.applyTheme(next);
|
|
288
|
+
theme.writeCookie(theme.cookieName,next);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
var menuBtn=document.querySelector('[data-sidebar-toggle]');
|
|
292
|
+
var sidebar=document.getElementById('sidebar');
|
|
293
|
+
if(menuBtn&&sidebar){
|
|
294
|
+
menuBtn.addEventListener('click',function(){
|
|
295
|
+
var open=sidebar.classList.toggle('sidebar--open');
|
|
296
|
+
menuBtn.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
document.addEventListener('keydown',function(e){
|
|
300
|
+
if(e.key==='Escape'&&sidebar&&sidebar.classList.contains('sidebar--open')){
|
|
301
|
+
sidebar.classList.remove('sidebar--open');
|
|
302
|
+
if(menuBtn) menuBtn.setAttribute('aria-expanded','false');
|
|
303
|
+
menuBtn && menuBtn.focus();
|
|
304
|
+
}
|
|
305
|
+
});
|
|
306
|
+
// HTMX after swap focus management
|
|
307
|
+
document.body.addEventListener('htmx:afterSwap',function(e){
|
|
308
|
+
var target=e.detail && e.detail.target;
|
|
309
|
+
if(target&&target.querySelector){
|
|
310
|
+
var focusable=target.querySelector('[autofocus], input, select, textarea, button');
|
|
311
|
+
if(focusable) try{ focusable.focus(); }catch(_){}
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
// Diff keyboard shortcuts
|
|
315
|
+
document.addEventListener('keydown',function(e){
|
|
316
|
+
if(e.target instanceof HTMLElement && (e.target.tagName==='INPUT'||e.target.tagName==='TEXTAREA'||e.target.isContentEditable)) return;
|
|
317
|
+
var diffRoot=document.querySelector('[data-diff-nav]');
|
|
318
|
+
if(!diffRoot) return;
|
|
319
|
+
if(e.key==='ArrowLeft' || e.key==='ArrowRight'){
|
|
320
|
+
var links=Array.from(diffRoot.querySelectorAll('[data-snapshot-link]'));
|
|
321
|
+
if(links.length===0) return;
|
|
322
|
+
var active=document.activeElement;
|
|
323
|
+
var idx=links.indexOf(active);
|
|
324
|
+
if(idx===-1){
|
|
325
|
+
var current=diffRoot.getAttribute('data-current');
|
|
326
|
+
idx=links.findIndex(function(a){ return a.getAttribute('data-snapshot-id')===current; });
|
|
327
|
+
}
|
|
328
|
+
var nextIdx=e.key==='ArrowRight' ? Math.min(links.length-1, idx+1) : Math.max(0, idx-1);
|
|
329
|
+
if(links[nextIdx]){ e.preventDefault(); links[nextIdx].focus(); links[nextIdx].click(); }
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
})();
|
|
333
|
+
`.trim();
|
|
334
|
+
}
|
|
335
|
+
//#endregion
|
|
336
|
+
export { DocumentLayout };
|
|
337
|
+
|
|
338
|
+
//# sourceMappingURL=document.mjs.map
|
|
@@ -0,0 +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\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// 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 === \"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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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/ui/styles.ts
|
|
5
|
+
function baseStyle(light, dark) {
|
|
6
|
+
return `
|
|
7
|
+
:root {
|
|
8
|
+
--accent: ${light.accent};
|
|
9
|
+
--accent-contrast: #fff;
|
|
10
|
+
--surface-base: ${light.surface.base};
|
|
11
|
+
--surface-card: ${light.surface.card};
|
|
12
|
+
--surface-muted: #f4f4f5;
|
|
13
|
+
--text-primary: ${light.text.primary};
|
|
14
|
+
--text-secondary: ${light.text.secondary};
|
|
15
|
+
--border: ${light.border};
|
|
16
|
+
--radius: 10px;
|
|
17
|
+
--radius-sm: 6px;
|
|
18
|
+
--shadow: 0 1px 2px rgba(0,0,0,.06), 0 4px 12px rgba(0,0,0,.04);
|
|
19
|
+
--status-approved: ${light.status.approved};
|
|
20
|
+
--status-new: ${light.status.new};
|
|
21
|
+
--status-rejected: ${light.status.rejected};
|
|
22
|
+
--topbar-bg: ${light.accent};
|
|
23
|
+
--sidebar-bg: #ffffff;
|
|
24
|
+
--sidebar-width: 240px;
|
|
25
|
+
}
|
|
26
|
+
[data-theme="dark"] {
|
|
27
|
+
--accent: ${dark.accent};
|
|
28
|
+
--surface-base: ${dark.surface.base};
|
|
29
|
+
--surface-card: ${dark.surface.card};
|
|
30
|
+
--surface-muted: #1e1e22;
|
|
31
|
+
--text-primary: ${dark.text.primary};
|
|
32
|
+
--text-secondary: ${dark.text.secondary};
|
|
33
|
+
--border: ${dark.border};
|
|
34
|
+
--status-approved: ${dark.status.approved};
|
|
35
|
+
--status-new: ${dark.status.new};
|
|
36
|
+
--status-rejected: ${dark.status.rejected};
|
|
37
|
+
--topbar-bg: #0f172a;
|
|
38
|
+
--sidebar-bg: #111113;
|
|
39
|
+
}
|
|
40
|
+
@media (prefers-color-scheme: dark) {
|
|
41
|
+
[data-theme="system"] {
|
|
42
|
+
--accent: ${dark.accent};
|
|
43
|
+
--surface-base: ${dark.surface.base};
|
|
44
|
+
--surface-card: ${dark.surface.card};
|
|
45
|
+
--surface-muted: #1e1e22;
|
|
46
|
+
--text-primary: ${dark.text.primary};
|
|
47
|
+
--text-secondary: ${dark.text.secondary};
|
|
48
|
+
--border: ${dark.border};
|
|
49
|
+
--status-approved: ${dark.status.approved};
|
|
50
|
+
--status-new: ${dark.status.new};
|
|
51
|
+
--status-rejected: ${dark.status.rejected};
|
|
52
|
+
--topbar-bg: #0f172a;
|
|
53
|
+
--sidebar-bg: #111113;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
* { box-sizing: border-box; }
|
|
57
|
+
html { scroll-behavior: smooth; }
|
|
58
|
+
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; }
|
|
59
|
+
a { color: var(--accent); text-decoration: none; }
|
|
60
|
+
a:hover { text-decoration: underline; }
|
|
61
|
+
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
62
|
+
.skip-link { position: absolute; left: -9999px; top: auto; width: 1px; height: 1px; overflow: hidden; }
|
|
63
|
+
.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; }
|
|
64
|
+
.topbar { position: sticky; top: 0; z-index: 40; background: var(--topbar-bg); color: #fff; border-bottom: 1px solid rgba(255,255,255,.12); }
|
|
65
|
+
.topbar__inner { max-width: 1440px; margin: 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .6rem 1rem; }
|
|
66
|
+
.topbar__left, .topbar__right { display: flex; align-items: center; gap: .75rem; min-width: 0; }
|
|
67
|
+
.topbar__menu { display: none; background: transparent; border: 1px solid rgba(255,255,255,.3); color: #fff; border-radius: 6px; padding: .35rem .5rem; cursor: pointer; }
|
|
68
|
+
.brand { display: inline-flex; align-items: center; gap: .5rem; color: #fff; font-weight: 650; text-decoration: none; }
|
|
69
|
+
.brand__mark { width: 28px; height: 28px; display: inline-grid; place-items: center; background: rgba(255,255,255,.18); border-radius: 8px; }
|
|
70
|
+
.logo { border-radius: 6px; display: block; }
|
|
71
|
+
.project-crumb { display: inline-flex; align-items: center; gap: .35rem; color: rgba(255,255,255,.9); }
|
|
72
|
+
.project-crumb a { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
|
|
73
|
+
.project-crumb__sep { opacity: .7; }
|
|
74
|
+
.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; }
|
|
75
|
+
.topbar__theme [data-theme-icon] { display: none; }
|
|
76
|
+
[data-theme="light"] [data-theme-icon="light"], [data-theme="dark"] [data-theme-icon="dark"], [data-theme="system"] [data-theme-icon="system"] { display: inline; }
|
|
77
|
+
.topbar__login { background: #fff; color: var(--accent); padding: .4rem .75rem; border-radius: 999px; font-weight: 600; text-decoration: none; }
|
|
78
|
+
.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; }
|
|
79
|
+
.user-menu__avatar { width: 28px; height: 28px; border-radius: 999px; object-fit: cover; background: rgba(255,255,255,.2); }
|
|
80
|
+
.user-menu__avatar--fallback { display: inline-grid; place-items: center; font-weight: 700; color: #fff; }
|
|
81
|
+
.user-menu__name { color: #fff; font-weight: 600; max-width: 12ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
82
|
+
.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; }
|
|
83
|
+
.user-menu__logout { color: #fff; font-size: .85rem; text-decoration: underline; text-underline-offset: 2px; margin-left: .25rem; }
|
|
84
|
+
.shell { max-width: 1440px; margin: 0 auto; display: grid; grid-template-columns: var(--sidebar-width) 1fr; min-height: calc(100vh - 56px); }
|
|
85
|
+
.sidebar { background: var(--sidebar-bg); border-right: 1px solid var(--border); padding: 1rem .75rem; position: sticky; top: 56px; height: calc(100vh - 56px); overflow: auto; }
|
|
86
|
+
.sidebar__nav { display: flex; flex-direction: column; gap: .25rem; }
|
|
87
|
+
.sidebar__section { margin: 1rem 0 .35rem; font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--text-secondary); padding: 0 .5rem; }
|
|
88
|
+
.sidebar__link { display: flex; align-items: center; gap: .5rem; padding: .5rem .6rem; border-radius: 8px; color: var(--text-primary); text-decoration: none; }
|
|
89
|
+
.sidebar__link:hover { background: var(--surface-muted); text-decoration: none; }
|
|
90
|
+
.sidebar__link--active { background: var(--surface-muted); font-weight: 600; }
|
|
91
|
+
.content { padding: 1.25rem 1.5rem 2rem; min-width: 0; max-width: 1100px; }
|
|
92
|
+
.page-header { margin-bottom: 1.25rem; }
|
|
93
|
+
.page-header__row { display: flex; gap: 1rem; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; }
|
|
94
|
+
.page-header__title { margin: 0; font-size: 1.6rem; line-height: 1.2; letter-spacing: -0.02em; }
|
|
95
|
+
.page-header__desc { margin: .35rem 0 0; color: var(--text-secondary); max-width: 60ch; }
|
|
96
|
+
.page-header__actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
|
|
97
|
+
.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; }
|
|
98
|
+
.breadcrumbs li + li::before { content: "/"; margin-right: .4rem; color: var(--text-secondary); }
|
|
99
|
+
.card { background: var(--surface-card); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow); }
|
|
100
|
+
.card--padded { padding: 1rem; }
|
|
101
|
+
.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; }
|
|
102
|
+
.btn--primary { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }
|
|
103
|
+
.btn--primary:hover { filter: brightness(1.05); text-decoration: none; }
|
|
104
|
+
.btn--secondary { background: var(--surface-card); color: var(--text-primary); border-color: var(--border); }
|
|
105
|
+
.btn--ghost { background: transparent; color: var(--text-primary); border-color: transparent; }
|
|
106
|
+
.btn--danger { background: var(--status-rejected); color: #fff; border-color: var(--status-rejected); }
|
|
107
|
+
.btn:disabled { opacity: .6; cursor: not-allowed; }
|
|
108
|
+
.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); }
|
|
109
|
+
.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)); }
|
|
110
|
+
.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)); }
|
|
111
|
+
.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)); }
|
|
112
|
+
.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)); }
|
|
113
|
+
.badge--neutral { background: var(--surface-muted); color: var(--text-secondary); }
|
|
114
|
+
.field { display: grid; gap: .35rem; margin-bottom: .9rem; }
|
|
115
|
+
.field__label { font-weight: 600; font-size: .9rem; }
|
|
116
|
+
.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; }
|
|
117
|
+
.field__input:focus { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }
|
|
118
|
+
.field__input--error { border-color: var(--status-rejected); }
|
|
119
|
+
.field__input--textarea { resize: vertical; }
|
|
120
|
+
.field__hint { margin: 0; color: var(--text-secondary); font-size: .85rem; }
|
|
121
|
+
.field__error { margin: 0; color: var(--status-rejected); font-size: .85rem; }
|
|
122
|
+
.alert { border-radius: 8px; padding: .75rem .85rem; border: 1px solid var(--border); background: var(--surface-card); }
|
|
123
|
+
.alert--info { border-color: color-mix(in srgb, var(--accent) 22%, var(--border)); background: color-mix(in srgb, var(--accent) 7%, var(--surface-card)); }
|
|
124
|
+
.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)); }
|
|
125
|
+
.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)); }
|
|
126
|
+
.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)); }
|
|
127
|
+
.alert__title { display: block; margin-bottom: .2rem; }
|
|
128
|
+
.tabs { display: flex; gap: .25rem; border-bottom: 1px solid var(--border); margin-bottom: 1rem; overflow-x: auto; }
|
|
129
|
+
.tabs__link { padding: .6rem .75rem; border-bottom: 2px solid transparent; color: var(--text-secondary); text-decoration: none; white-space: nowrap; font-weight: 600; }
|
|
130
|
+
.tabs__link:hover { color: var(--text-primary); text-decoration: none; }
|
|
131
|
+
.tabs__link--active { color: var(--text-primary); border-bottom-color: var(--accent); }
|
|
132
|
+
.empty { text-align: center; padding: 2rem 1rem; border: 1px dashed var(--border); border-radius: var(--radius); background: var(--surface-card); }
|
|
133
|
+
.empty__title { margin: 0 0 .3rem; font-size: 1.1rem; }
|
|
134
|
+
.empty__desc { margin: 0 auto; color: var(--text-secondary); max-width: 50ch; }
|
|
135
|
+
.empty__action { margin-top: 1rem; }
|
|
136
|
+
.grid { display: grid; gap: 1rem; }
|
|
137
|
+
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
138
|
+
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
139
|
+
@media (max-width: 880px) { .grid--2, .grid--3 { grid-template-columns: 1fr; } }
|
|
140
|
+
.table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-card); }
|
|
141
|
+
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
|
|
142
|
+
th, td { text-align: left; padding: .65rem .75rem; border-bottom: 1px solid var(--border); vertical-align: top; }
|
|
143
|
+
th { background: var(--surface-muted); font-weight: 650; color: var(--text-secondary); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }
|
|
144
|
+
tr:last-child td { border-bottom: 0; }
|
|
145
|
+
.stat { text-align: center; padding: .5rem; }
|
|
146
|
+
.stat__value { font-size: 1.4rem; font-weight: 750; line-height: 1; }
|
|
147
|
+
.stat__label { color: var(--text-secondary); font-size: .8rem; text-transform: uppercase; letter-spacing: .06em; }
|
|
148
|
+
.snapshot-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); }
|
|
149
|
+
.snapshot-card { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-card); display: flex; flex-direction: column; }
|
|
150
|
+
.snapshot-card__head { padding: .6rem .75rem; border-bottom: 1px solid var(--border); display: flex; justify-content: space-between; gap: .5rem; align-items: center; }
|
|
151
|
+
.snapshot-card__meta { font-size: .8rem; color: var(--text-secondary); }
|
|
152
|
+
.snapshot-card__body { padding: .5rem; display: grid; gap: .5rem; }
|
|
153
|
+
.diff-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .75rem; }
|
|
154
|
+
@media (max-width: 900px) { .diff-grid { grid-template-columns: 1fr; } }
|
|
155
|
+
.diff-pane { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--surface-card); }
|
|
156
|
+
.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); }
|
|
157
|
+
.diff-pane__img { display: block; width: 100%; height: auto; background: repeating-conic-gradient(#e5e7eb 0% 25%, #f9fafb 0% 50%) 0 0 / 16px 16px; }
|
|
158
|
+
.comment { border: 1px solid var(--border); border-radius: var(--radius); padding: .75rem; background: var(--surface-card); }
|
|
159
|
+
.comment__head { display: flex; gap: .5rem; align-items: center; font-size: .85rem; color: var(--text-secondary); }
|
|
160
|
+
.comment__body { margin: .5rem 0 0; white-space: pre-wrap; word-break: break-word; }
|
|
161
|
+
@media (max-width: 880px) {
|
|
162
|
+
.topbar__menu { display: inline-flex; }
|
|
163
|
+
.shell { grid-template-columns: 1fr; }
|
|
164
|
+
.sidebar { display: none; position: fixed; inset: 56px 0 0 0; z-index: 30; height: auto; }
|
|
165
|
+
.sidebar--open { display: block; }
|
|
166
|
+
.content { padding: 1rem; }
|
|
167
|
+
}
|
|
168
|
+
`;
|
|
169
|
+
}
|
|
170
|
+
//#endregion
|
|
171
|
+
export { baseStyle };
|
|
172
|
+
|
|
173
|
+
//# sourceMappingURL=styles.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.mjs","names":[],"sources":["../../src/ui/styles.ts"],"sourcesContent":["import type { BrandTheme } from \"./theme.ts\";\n\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":";;;;AAEA,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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/ui/theme.ts
|
|
5
|
+
const LIGHT_THEME = {
|
|
6
|
+
accent: "#2b7fff",
|
|
7
|
+
surface: {
|
|
8
|
+
base: "#f6f6f7",
|
|
9
|
+
card: "#ffffff"
|
|
10
|
+
},
|
|
11
|
+
text: {
|
|
12
|
+
primary: "#09090b",
|
|
13
|
+
secondary: "#71717b"
|
|
14
|
+
},
|
|
15
|
+
border: "#e4e4e7",
|
|
16
|
+
status: {
|
|
17
|
+
approved: "#16a34a",
|
|
18
|
+
new: "#d97706",
|
|
19
|
+
rejected: "#dc2626"
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const DARK_THEME = {
|
|
23
|
+
accent: "#4f8fff",
|
|
24
|
+
surface: {
|
|
25
|
+
base: "#09090b",
|
|
26
|
+
card: "#18181b"
|
|
27
|
+
},
|
|
28
|
+
text: {
|
|
29
|
+
primary: "#fafafa",
|
|
30
|
+
secondary: "#9f9fa9"
|
|
31
|
+
},
|
|
32
|
+
border: "#ffffff1a",
|
|
33
|
+
status: {
|
|
34
|
+
approved: "#22c55e",
|
|
35
|
+
new: "#f59e0b",
|
|
36
|
+
rejected: "#ef4444"
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { DARK_THEME, LIGHT_THEME };
|
|
41
|
+
|
|
42
|
+
//# sourceMappingURL=theme.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.mjs","names":[],"sources":["../../src/ui/theme.ts"],"sourcesContent":["export interface BrandTheme {\n accent: string;\n surface: { base: string; card: string };\n text: { primary: string; secondary: string };\n border: string;\n status: { approved: string; new: string; rejected: string };\n}\n\nexport const LIGHT_THEME: BrandTheme = {\n accent: \"#2b7fff\",\n surface: { base: \"#f6f6f7\", card: \"#ffffff\" },\n text: { primary: \"#09090b\", secondary: \"#71717b\" },\n border: \"#e4e4e7\",\n status: { approved: \"#16a34a\", new: \"#d97706\", rejected: \"#dc2626\" },\n};\n\nexport const DARK_THEME: BrandTheme = {\n accent: \"#4f8fff\",\n surface: { base: \"#09090b\", card: \"#18181b\" },\n text: { primary: \"#fafafa\", secondary: \"#9f9fa9\" },\n border: \"#ffffff1a\",\n status: { approved: \"#22c55e\", new: \"#f59e0b\", rejected: \"#ef4444\" },\n};\n"],"mappings":";;;;AAQA,MAAa,cAA0B;CACrC,QAAQ;CACR,SAAS;EAAE,MAAM;EAAW,MAAM;CAAU;CAC5C,MAAM;EAAE,SAAS;EAAW,WAAW;CAAU;CACjD,QAAQ;CACR,QAAQ;EAAE,UAAU;EAAW,KAAK;EAAW,UAAU;CAAU;AACrE;AAEA,MAAa,aAAyB;CACpC,QAAQ;CACR,SAAS;EAAE,MAAM;EAAW,MAAM;CAAU;CAC5C,MAAM;EAAE,SAAS;EAAW,WAAW;CAAU;CACjD,QAAQ;CACR,QAAQ;EAAE,UAAU;EAAW,KAAK;EAAW,UAAU;CAAU;AACrE"}
|
package/dist/urls.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import __tsdown_shims_path from 'node:path';
|
|
2
|
+
import __tsdown_shims_url from 'node:url';
|
|
3
|
+
//#region src/urls.d.ts
|
|
4
|
+
interface UrlBuilder {
|
|
5
|
+
projectsList(): string;
|
|
6
|
+
project(slug: string): string;
|
|
7
|
+
buildsList(slug: string): string;
|
|
8
|
+
build(slug: string, buildId: string): string;
|
|
9
|
+
labels(slug: string): string;
|
|
10
|
+
label(slug: string, key: string, value: string): string;
|
|
11
|
+
storybook(slug: string): string;
|
|
12
|
+
storybookLabel(slug: string, key: string, value: string): string;
|
|
13
|
+
storybookBuild(slug: string, buildId: string): string;
|
|
14
|
+
settings(slug: string): string;
|
|
15
|
+
}
|
|
16
|
+
declare function createUrlBuilder(baseUrl: string, publishedBaseDomain?: string): UrlBuilder;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { UrlBuilder, createUrlBuilder };
|
|
19
|
+
//# sourceMappingURL=urls.d.mts.map
|