dsh-claude-slides 2.9.2 → 2.10.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/lib/client.js DELETED
@@ -1,1800 +0,0 @@
1
- // dsh-claude-slides 2.9.2: built from baoyu-design.
2
- window.__ModuleLoader__.load({
3
- id: "dsh-claude-slides",
4
- factory: (require) => {
5
- var module = { exports: {} };
6
- var exports = module.exports;
7
- "use strict";
8
- var __defProp = Object.defineProperty;
9
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
- var __getOwnPropNames = Object.getOwnPropertyNames;
11
- var __hasOwnProp = Object.prototype.hasOwnProperty;
12
- var __export = (target, all) => {
13
- for (var name in all)
14
- __defProp(target, name, { get: all[name], enumerable: true });
15
- };
16
- var __copyProps = (to, from, except, desc) => {
17
- if (from && typeof from === "object" || typeof from === "function") {
18
- for (let key of __getOwnPropNames(from))
19
- if (!__hasOwnProp.call(to, key) && key !== except)
20
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
- }
22
- return to;
23
- };
24
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
-
26
- var client_exports = {};
27
- __export(client_exports, {
28
- apply: () => apply,
29
- inject: () => inject
30
- });
31
- module.exports = __toCommonJS(client_exports);
32
-
33
- var define_CLIENT_default = { plugin: "dsh-claude-slides", skill: "claude-slides", key: "dsh-claude-slides", simple: false };
34
-
35
- var import_react2 = require("react");
36
-
37
- var import_react = require("react");
38
-
39
- var base = (skill) => `/api/baoyu-design.${skill}.artifacts`;
40
- var listPath = base;
41
- var openPath = (skill) => `${base(skill)}.open`;
42
- var previewPath = (skill) => `${base(skill)}.preview`;
43
- var releasePath = (skill) => `${base(skill)}.release`;
44
- var thumbnailPath = (skill) => `${base(skill)}.thumbnail`;
45
- var updatePath = (skill) => `${base(skill)}.update`;
46
- var deletePath = (skill) => `${base(skill)}.delete`;
47
- var restorePath = (skill) => `${base(skill)}.restore`;
48
-
49
- function desktopBrowser() {
50
- const carrier = globalThis.dshDesktop;
51
- return carrier?.protocolVersion === 1 ? carrier.browser : void 0;
52
- }
53
- var WORKSPACE = "baoyu-design-thumbnails";
54
- var WIDTH = 720;
55
- var QUALITY = 0.82;
56
- var LOAD_MS = 2e4;
57
- var SETTLE_MS = 1800;
58
- var BLANK_RETRY_MS = 3e3;
59
- var REGIONS = {
60
- // The current slide on the editor's canvas.
61
- "claude-slides": { width: 1280, height: 800, find: `document.querySelector('.bg-editor-canvas > .shadow-lg')` },
62
- // The first artboard.
63
- "claude-design": { width: 1280, height: 800, find: `document.querySelector('[data-mega-artboard]')` },
64
- // What is beside the section list: the system's cover.
65
- "claude-design-system": {
66
- width: 1280,
67
- height: 800,
68
- find: `(() => {
69
- const nav = document.querySelector('[data-testid="ds-section-nav"]');
70
- if (!nav || !document.querySelector('h1,h2')) return null;
71
- const r = nav.getBoundingClientRect();
72
- return { x: r.right, y: r.top, width: innerWidth - r.right, height: innerHeight - r.top };
73
- })()`
74
- },
75
- // The page, below the bar.
76
- "claude-dashboard": { width: 1280, height: 800, find: `document.querySelector('main')` },
77
- // The doc's frame, below the bars, at a width where the text fills it.
78
- "claude-docs": { width: 860, height: 700, find: `document.querySelector('iframe')` },
79
- // The film's first frame.
80
- "claude-motion": { width: 1280, height: 800, find: `document.querySelector('.an-stage iframe')` }
81
- };
82
- var sleep = (ms, signal) => new Promise((resolve, reject) => {
83
- if (signal.aborted) return reject(signal.reason);
84
- const timer = setTimeout(resolve, ms);
85
- signal.addEventListener("abort", () => {
86
- clearTimeout(timer);
87
- reject(signal.reason);
88
- }, { once: true });
89
- });
90
- async function toCanvas(image) {
91
- const picture = new Image();
92
- await new Promise((resolve, reject) => {
93
- picture.onload = () => resolve();
94
- picture.onerror = () => reject(new Error("the picture did not decode"));
95
- picture.src = image.toDataURL();
96
- });
97
- const scale = Math.min(1, WIDTH / picture.naturalWidth);
98
- const canvas = document.createElement("canvas");
99
- canvas.width = Math.max(1, Math.round(picture.naturalWidth * scale));
100
- canvas.height = Math.max(1, Math.round(picture.naturalHeight * scale));
101
- const context = canvas.getContext("2d");
102
- if (context === null) throw new Error("no canvas to draw on");
103
- context.imageSmoothingQuality = "high";
104
- context.drawImage(picture, 0, 0, canvas.width, canvas.height);
105
- return canvas;
106
- }
107
- function isFlat(canvas) {
108
- const { data } = canvas.getContext("2d").getImageData(0, 0, canvas.width, canvas.height);
109
- const step = Math.max(4, Math.floor(data.length / 4 / 400) * 4);
110
- for (let i = step; i + 2 < data.length; i += step) {
111
- if (Math.abs(data[i] - data[0]) > 3 || Math.abs(data[i + 1] - data[1]) > 3 || Math.abs(data[i + 2] - data[2]) > 3) return false;
112
- }
113
- return true;
114
- }
115
- async function captureThumbnail(browser, url, skill, signal) {
116
- const region = REGIONS[skill] ?? { width: 1280, height: 800, find: "null" };
117
- const { lease, partition } = await browser.acquire(WORKSPACE);
118
- const guest = document.createElement("webview");
119
- try {
120
- guest.setAttribute("name", lease);
121
- guest.setAttribute("partition", partition);
122
- guest.setAttribute("src", `about:blank#${lease}`);
123
- guest.setAttribute("aria-hidden", "true");
124
- guest.tabIndex = -1;
125
- guest.style.cssText = `position:fixed;left:calc(100vw - 1px);top:0;width:${region.width}px;height:${region.height}px;opacity:.01;pointer-events:none;z-index:-1`;
126
- const ready = new Promise((resolve) => guest.addEventListener("dom-ready", () => resolve(), { once: true }));
127
- document.body.append(guest);
128
- await Promise.race([ready, sleep(LOAD_MS, signal)]);
129
- guest.setAudioMuted(true);
130
- const loaded = new Promise((resolve) => guest.addEventListener("did-stop-loading", () => resolve(), { once: true }));
131
- void guest.loadURL(url).catch(() => void 0);
132
- await Promise.race([loaded, sleep(LOAD_MS, signal)]);
133
- const measure = `(() => {
134
- const found = ${region.find};
135
- if (!found) return null;
136
- const r = found.getBoundingClientRect ? found.getBoundingClientRect() : found;
137
- if (r.width < 80 || r.height < 60) return null;
138
- const x = Math.max(0, r.x), y = Math.max(0, r.y);
139
- return { x, y, width: Math.min(r.width, innerWidth - x), height: Math.min(r.height, innerHeight - y) };
140
- })()`;
141
- let rect = null;
142
- const deadline = Date.now() + LOAD_MS;
143
- while (rect === null && Date.now() < deadline) {
144
- rect = await guest.executeJavaScript(measure).catch(() => null);
145
- if (rect === null) await sleep(250, signal);
146
- }
147
- await guest.insertCSS("::-webkit-scrollbar{display:none!important}").catch(() => "");
148
- await guest.executeJavaScript("document.fonts.ready.then(() => true)").catch(() => null);
149
- await sleep(SETTLE_MS, signal);
150
- rect = await guest.executeJavaScript(measure).catch(() => null) ?? rect;
151
- const area = rect && {
152
- x: Math.round(rect.x),
153
- y: Math.round(rect.y),
154
- width: Math.round(rect.width),
155
- height: Math.round(rect.height)
156
- };
157
- const take = async () => {
158
- const image = await guest.capturePage(area ?? void 0);
159
- if (image.isEmpty()) throw new Error("the page gave no picture");
160
- return toCanvas(image);
161
- };
162
- let canvas = await take();
163
- if (isFlat(canvas)) {
164
- await sleep(BLANK_RETRY_MS, signal);
165
- canvas = await take();
166
- }
167
- const blob = await new Promise((resolve) => canvas.toBlob(resolve, "image/jpeg", QUALITY));
168
- if (blob === null) throw new Error("the picture did not encode");
169
- return new Uint8Array(await blob.arrayBuffer());
170
- } finally {
171
- guest.remove();
172
- await browser.release(lease).catch(() => void 0);
173
- }
174
- }
175
-
176
- var import_jsx_runtime = require("react/jsx-runtime");
177
- var PAGE_VERSION = 2;
178
- var PANEL_ID = "baoyu-design.artifacts";
179
- var NS = "baoyu-design-artifacts";
180
- var VIEW_KEY = "baoyu-design.artifacts.view";
181
- var HUB = Symbol.for("baoyu-design/dsh-artifacts-page");
182
- function hub() {
183
- const g = globalThis;
184
- return g[HUB] ??= { members: /* @__PURE__ */ new Map(), owner: null, listeners: /* @__PURE__ */ new Set() };
185
- }
186
- function newest(h) {
187
- let best;
188
- for (const m of h.members.values()) if (best === void 0 || m.version > best.version) best = m;
189
- return best;
190
- }
191
- function settle(h) {
192
- const next = newest(h);
193
- if (h.owner !== null && h.members.has(h.owner.plugin) && (next === void 0 || next.version <= h.owner.version)) return;
194
- if (h.owner !== null) {
195
- const old = h.owner;
196
- h.owner = null;
197
- old.dispose();
198
- }
199
- if (next === void 0) return;
200
- try {
201
- h.owner = { plugin: next.plugin, version: next.version, dispose: next.mount() };
202
- } catch (error) {
203
- console.error(`${next.plugin}: the Artifacts page did not register:`, error);
204
- }
205
- }
206
- function changed(h) {
207
- for (const listener of [...h.listeners]) {
208
- try {
209
- listener();
210
- } catch (error) {
211
- console.error("baoyu-design Artifacts page listener failed:", error);
212
- }
213
- }
214
- }
215
- function createStore(initial) {
216
- let state = initial;
217
- const listeners = /* @__PURE__ */ new Set();
218
- return {
219
- getSnapshot: () => state,
220
- subscribe(listener) {
221
- listeners.add(listener);
222
- return () => listeners.delete(listener);
223
- },
224
- set(patch) {
225
- state = { ...state, ...patch };
226
- for (const listener of [...listeners]) listener();
227
- }
228
- };
229
- }
230
- var EMPTY_SESSIONS = { getSnapshot: () => ({}), subscribe: () => () => {
231
- } };
232
- function isStore(value) {
233
- const v = value;
234
- return typeof v?.getSnapshot === "function" && typeof v.subscribe === "function";
235
- }
236
- function linkState(id, sessions, workspaces) {
237
- if (sessions === void 0) return "unavailable";
238
- if (workspaces?.state === "error") return "unavailable";
239
- if (sessions.phase === "pending" || workspaces?.phase === "pending") return "loading";
240
- if (workspaces?.archivedSessionIds?.includes(id)) return "archived";
241
- if (!sessions.ids?.includes(id)) return "unavailable";
242
- return "available";
243
- }
244
- var zh = {
245
- panel: "作品",
246
- title: "作品",
247
- "time.locale": "zh-CN",
248
- search: "搜索作品",
249
- "search.clear": "清除搜索",
250
- "type.claude-slides": "幻灯片",
251
- "type.claude-design": "设计",
252
- "type.claude-design-system": "设计系统",
253
- "type.claude-dashboard": "看板",
254
- "type.claude-docs": "文档",
255
- "type.claude-motion": "动画",
256
- "create.heading": "新建",
257
- "create.new": "新建",
258
- "create.session": "新会话",
259
- "prompt.claude-slides": "帮我做一份幻灯片,主题是:",
260
- "prompt.claude-design": "帮我设计:",
261
- "prompt.claude-design-system": "帮我做一套设计系统,品牌是:",
262
- "prompt.claude-dashboard": "帮我做一个数据看板,数据是:",
263
- "prompt.claude-docs": "帮我写一份文档,内容是:",
264
- "prompt.claude-motion": "帮我做一段动画,内容是:",
265
- "view.list": "列表视图",
266
- "view.grid": "网格视图",
267
- "filter.button": "排序和筛选",
268
- "filter.sort": "排序方式",
269
- "filter.type": "类型",
270
- "filter.date": "打开时间",
271
- "filter.sharing": "共享",
272
- "filter.pinned": "已固定",
273
- "filter.any": "不限",
274
- "filter.some": "{count} 项",
275
- "filter.clear": "清除筛选",
276
- "sort.opened": "最近打开",
277
- "sort.updated": "最近修改",
278
- "sort.created": "创建时间",
279
- "sort.name": "名称",
280
- "date.any": "不限",
281
- "date.today": "今天",
282
- "date.yesterday": "昨天",
283
- "date.week": "最近 7 天",
284
- "date.month": "最近 30 天",
285
- "sharing.any": "不限",
286
- "sharing.shared": "已共享",
287
- "sharing.private": "未共享",
288
- "card.opened": "{time}打开",
289
- "card.justNow": "刚刚打开",
290
- "card.opening": "正在打开…",
291
- "card.shared": "已在局域网共享",
292
- "action.more": "更多操作",
293
- "action.pin": "固定",
294
- "action.unpin": "取消固定",
295
- "action.rename": "重命名",
296
- "action.copy": "复制链接",
297
- "action.delete": "删除",
298
- "rename.title": "重命名作品",
299
- "rename.save": "保存",
300
- "dialog.cancel": "取消",
301
- "delete.title": "删除“{title}”?",
302
- "delete.moves": "这会移除这个作品,它的文件夹移到应用数据目录下的 baoyu-design/trash。",
303
- "delete.keeps": "这会把它从作品里移除。它的文件夹里还有别的文件,所以留在原处:{path}",
304
- "delete.confirm": "删除",
305
- "toast.copied": "链接已复制到剪贴板。",
306
- "toast.deleted": "已删除“{title}”。",
307
- "toast.removed": "已从作品里移除“{title}”,文件夹还在原处。",
308
- "toast.undo": "撤销",
309
- "toast.close": "关闭",
310
- "empty.title": "还没有作品",
311
- "empty.body": "Agent 用 baoyu-design 的技能做出来的东西都会出现在这里。点上面的入口开始做一个。",
312
- "empty.noMatches": "没有符合条件的作品",
313
- "load.error": "读取作品列表失败:{message}",
314
- "load.retry": "重试",
315
- "open.pluginOff": "{plugin} 插件没有开启,打不开这个作品。",
316
- "open.failed": "打不开:{message}",
317
- "open.noSession": "原来的对话已不在,编辑器在新窗口里打开了。",
318
- "action.failed": "没有做成:{message}"
319
- };
320
- var en = {
321
- panel: "Artifacts",
322
- title: "Artifacts",
323
- "time.locale": "en",
324
- search: "Search artifacts",
325
- "search.clear": "Clear search",
326
- "type.claude-slides": "Slides",
327
- "type.claude-design": "Design",
328
- "type.claude-design-system": "Design system",
329
- "type.claude-dashboard": "Dashboard",
330
- "type.claude-docs": "Docs",
331
- "type.claude-motion": "Motion",
332
- "create.heading": "Make something new",
333
- "create.new": "New",
334
- "create.session": "New session",
335
- "prompt.claude-slides": "Make me a slide deck about: ",
336
- "prompt.claude-design": "Design this for me: ",
337
- "prompt.claude-design-system": "Make me a design system for this brand: ",
338
- "prompt.claude-dashboard": "Make me a dashboard from this data: ",
339
- "prompt.claude-docs": "Write me a doc about: ",
340
- "prompt.claude-motion": "Make me an animation about: ",
341
- "view.list": "List view",
342
- "view.grid": "Grid view",
343
- "filter.button": "Sort and filter",
344
- "filter.sort": "Sort by",
345
- "filter.type": "Type",
346
- "filter.date": "Date opened",
347
- "filter.sharing": "Sharing",
348
- "filter.pinned": "Pinned",
349
- "filter.any": "Any",
350
- "filter.some": "{count} selected",
351
- "filter.clear": "Clear filters",
352
- "sort.opened": "Last opened",
353
- "sort.updated": "Last edited",
354
- "sort.created": "Date created",
355
- "sort.name": "Name",
356
- "date.any": "Any time",
357
- "date.today": "Today",
358
- "date.yesterday": "Yesterday",
359
- "date.week": "Past 7 days",
360
- "date.month": "Past 30 days",
361
- "sharing.any": "Any",
362
- "sharing.shared": "Shared",
363
- "sharing.private": "Not shared",
364
- "card.opened": "Opened {time}",
365
- "card.justNow": "Opened just now",
366
- "card.opening": "Opening…",
367
- "card.shared": "Shared on the local network",
368
- "action.more": "More actions",
369
- "action.pin": "Pin",
370
- "action.unpin": "Unpin",
371
- "action.rename": "Rename",
372
- "action.copy": "Copy link",
373
- "action.delete": "Delete",
374
- "rename.title": "Rename artifact",
375
- "rename.save": "Save",
376
- "dialog.cancel": "Cancel",
377
- "delete.title": "Delete {title}?",
378
- "delete.moves": "This removes the artifact and moves its folder to baoyu-design/trash in the app's data folder.",
379
- "delete.keeps": "This takes it off your artifacts. Its folder holds other files too, so it stays where it is: {path}",
380
- "delete.confirm": "Delete",
381
- "toast.copied": "Link copied to clipboard.",
382
- "toast.deleted": "Deleted “{title}”.",
383
- "toast.removed": "Took “{title}” off your artifacts. Its folder stays where it is.",
384
- "toast.undo": "Undo",
385
- "toast.close": "Close",
386
- "empty.title": "No artifacts yet",
387
- "empty.body": "What the agent makes with a baoyu-design skill shows up here. Start one with a tile above.",
388
- "empty.noMatches": "No artifacts match",
389
- "load.error": "Could not read the artifacts: {message}",
390
- "load.retry": "Try again",
391
- "open.pluginOff": "The {plugin} plugin is off, so this artifact cannot open.",
392
- "open.failed": "Could not open it: {message}",
393
- "open.noSession": "The conversation is gone, so the editor opened in a new window.",
394
- "action.failed": "That did not work: {message}"
395
- };
396
- var SKILLS = ["claude-docs", "claude-slides", "claude-design", "claude-dashboard", "claude-design-system", "claude-motion"];
397
- var isSkill = (s) => SKILLS.includes(s);
398
- var creatable = (on) => SKILLS.filter((s) => on.includes(s));
399
- var promptFor = (skill, t) => `/${skill} ${t(`prompt.${skill}`)}`;
400
- var NO_FILTERS = { sort: "opened", types: [], date: "any", sharing: "any", pinned: false };
401
- var SORTS = ["opened", "updated", "created", "name"];
402
- var DATES = ["any", "today", "yesterday", "week", "month"];
403
- var SHARINGS = ["any", "shared", "private"];
404
- var isFiltered = (f) => f.types.length > 0 || f.date !== "any" || f.sharing !== "any" || f.pinned;
405
- function inRange(iso, range, now) {
406
- if (range === "any") return true;
407
- const then = Date.parse(iso);
408
- if (!Number.isFinite(then)) return false;
409
- const day = new Date(now);
410
- const today = new Date(day.getFullYear(), day.getMonth(), day.getDate()).getTime();
411
- const DAY = 864e5;
412
- switch (range) {
413
- case "today":
414
- return then >= today;
415
- case "yesterday":
416
- return then >= new Date(day.getFullYear(), day.getMonth(), day.getDate() - 1).getTime() && then < today;
417
- case "week":
418
- return then >= now - 7 * DAY;
419
- case "month":
420
- return then >= now - 30 * DAY;
421
- }
422
- }
423
- function sorted(views, sort, locale) {
424
- const by = (key) => (a, b) => a[key] < b[key] ? 1 : a[key] > b[key] ? -1 : 0;
425
- const compare = sort === "name" ? (a, b) => a.title.localeCompare(b.title, locale) : by(sort === "updated" ? "updatedAt" : sort === "created" ? "firstOpenedAt" : "openedAt");
426
- return [...views].sort(compare);
427
- }
428
- var CSS = `
429
- .bda-page{position:relative;width:100%;min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base);font-size:14px;line-height:1.6;display:flex;flex-direction:column;overflow:hidden}
430
- .bda-scroll{flex:1;min-height:0;overflow:auto;scrollbar-gutter:stable}
431
- .bda-content{max-width:1120px;margin:0 auto;padding:0 clamp(24px,4vw,48px) 56px}
432
- .bda-heading{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px 16px;padding-top:28px;margin-bottom:24px}
433
- [data-platform=darwin] .bda-heading{padding-top:calc(28px + var(--dsh-frame-top-clearance,0px))}
434
- .bda-heading h1{margin:0;font-size:20px;font-weight:500;line-height:28px}
435
- .bda-tools{display:flex;align-items:center;gap:4px;margin-left:auto}
436
- .bda-tool{position:relative;display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:0;border-radius:8px;background:none;color:var(--dsw-alias-label-secondary);cursor:pointer}
437
- .bda-tool:hover,.bda-tool[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
438
- .bda-tool[data-active=true]::after{content:"";position:absolute;top:6px;right:6px;width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-business-primary)}
439
- .bda-search{display:flex;align-items:center;gap:6px;width:min(240px,50vw);height:32px;padding:0 8px 0 10px;border:.5px solid var(--dsw-alias-border-l2);border-radius:8px;color:var(--dsw-alias-label-tertiary)}
440
- .bda-search:focus-within{border-color:var(--dsw-alias-state-business-primary)}
441
- .bda-search input{flex:1;min-width:0;height:100%;border:0;padding:0;background:none;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;outline:none}
442
- .bda-search input::placeholder{color:var(--dsw-alias-label-caption)}
443
- .bda-search input::-webkit-search-cancel-button{display:none}
444
- .bda-search button{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;margin-right:-4px;padding:0;border:0;border-radius:6px;background:none;color:inherit;cursor:pointer}
445
- .bda-search button:hover{background:var(--dsw-alias-interactive-bg-hover)}
446
- .bda-section-title{margin:0 0 12px;font-size:13px;font-weight:400;line-height:20px;color:var(--dsw-alias-label-tertiary)}
447
- .bda-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(118px,1fr));gap:14px;margin:0 0 36px;padding:0;list-style:none}
448
- .bda-tile{display:flex;flex-direction:column;gap:8px;width:100%;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
449
- .bda-tile-art{position:relative;display:flex;align-items:center;justify-content:center;aspect-ratio:7/5;border-radius:14px;overflow:hidden;background:color-mix(in srgb,var(--bda-tint) 24%,var(--dsw-alias-bg-base));color:color-mix(in srgb,var(--bda-tint) 78%,var(--dsw-alias-label-primary));transition:background-color .15s}
450
- .bda-tile:hover .bda-tile-art{background:color-mix(in srgb,var(--bda-tint) 34%,var(--dsw-alias-bg-base))}
451
- .bda-tile:focus-visible{outline:none}
452
- .bda-tile:focus-visible .bda-tile-art{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
453
- .bda-tile-squiggle{position:absolute;inset:0;width:100%;height:100%;opacity:.28}
454
- .bda-tile-label{padding-left:2px;font-size:14px;line-height:20px}
455
- .bda-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:20px;margin:0;padding:0;list-style:none}
456
- .bda-item{position:relative;min-width:0}
457
- .bda-card{display:flex;flex-direction:column;width:100%;padding:0;border:.5px solid var(--dsw-alias-border-l2);border-radius:14px;overflow:hidden;background:var(--dsw-alias-bg-base);color:inherit;font:inherit;text-align:left;cursor:pointer;transition:background-color .15s}
458
- .bda-item:hover .bda-card{background:var(--dsw-alias-interactive-bg-hover)}
459
- .bda-card:disabled{cursor:progress}
460
- .bda-card:focus-visible,.bda-row:focus-visible{outline:var(--dsw-focus-ring-width,2px) solid var(--dsw-focus-ring-color,var(--dsw-alias-state-business-primary));outline-offset:2px}
461
- .bda-preview{position:relative;display:block;width:100%;aspect-ratio:2/1;overflow:hidden;background:color-mix(in srgb,var(--bda-tint) 16%,var(--dsw-alias-bg-base))}
462
- .bda-sheet{position:absolute;left:12%;right:12%;top:13%;bottom:-8px;border-radius:8px 8px 0 0;overflow:hidden;background:var(--dsw-alias-bg-base);box-shadow:0 0 0 .5px var(--dsw-alias-border-l2),0 6px 18px -8px rgba(0,0,0,.28);transition:transform .2s}
463
- .bda-item:hover .bda-sheet{transform:translateY(-3px)}
464
- .bda-sheet img{display:block;width:100%;height:100%;object-fit:cover;object-position:top center;user-select:none}
465
- .bda-preview[data-stack=true] .bda-sheet{left:20%;right:20%}
466
- .bda-preview[data-stack=true]::before{content:"";position:absolute;left:21%;right:19%;top:10%;bottom:-8px;border-radius:8px 8px 0 0;background:var(--dsw-alias-bg-base);box-shadow:0 0 0 .5px var(--dsw-alias-border-l2);transform:rotate(1.6deg);transform-origin:bottom center}
467
- .bda-paper{position:absolute;left:14%;right:14%;top:13%;bottom:-8px;border-radius:8px 8px 0 0;background:var(--dsw-alias-bg-base);box-shadow:0 0 0 .5px var(--dsw-alias-border-l2),0 6px 18px -8px rgba(0,0,0,.25);padding:6% 7% 0;display:flex;flex-direction:column;gap:6px;overflow:hidden;transition:transform .2s}
468
- .bda-item:hover .bda-paper{transform:translateY(-3px)}
469
- .bda-paper-title{font-size:11px;line-height:1.35;font-weight:600;color:var(--dsw-alias-label-primary);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}
470
- .bda-line{height:5px;border-radius:3px;background:var(--dsw-alias-border-l2)}
471
- .bda-slide{position:absolute;left:14%;right:14%;top:13%;aspect-ratio:16/9;border-radius:6px;background:var(--dsw-alias-bg-base);box-shadow:0 0 0 .5px var(--dsw-alias-border-l2),0 6px 18px -8px rgba(0,0,0,.25);display:flex;flex-direction:column;justify-content:center;gap:6px;padding:0 9%;transition:transform .2s}
472
- .bda-item:hover .bda-slide{transform:translateY(-3px)}
473
- .bda-slide .bda-paper-title{font-size:12px}
474
- .bda-slide .bda-line{width:40%;background:var(--bda-tint);opacity:.55}
475
- .bda-boards{display:flex;gap:6px;flex:1;margin-top:2px}
476
- .bda-board{flex:1;border-radius:3px;background:color-mix(in srgb,var(--bda-tint) 18%,var(--dsw-alias-bg-base));box-shadow:0 0 0 .5px var(--dsw-alias-border-l2)}
477
- .bda-board:nth-child(2){flex:.7;margin-top:10%}
478
- .bda-swatches{display:flex;gap:4px}
479
- .bda-swatch{width:16px;height:16px;border-radius:50%;background:var(--bda-tint)}
480
- .bda-swatch:nth-child(2){opacity:.7}.bda-swatch:nth-child(3){opacity:.45}.bda-swatch:nth-child(4){opacity:.25}
481
- .bda-specimen{font-size:20px;line-height:1;font-weight:600;color:var(--dsw-alias-label-secondary)}
482
- .bda-kpis{display:flex;gap:5px}
483
- .bda-kpi{flex:1;height:16px;border-radius:3px;box-shadow:0 0 0 .5px var(--dsw-alias-border-l2)}
484
- .bda-bars{display:flex;align-items:flex-end;gap:5px;height:34%;margin-top:2px}
485
- .bda-bar{flex:1;border-radius:2px 2px 0 0;background:var(--bda-tint);opacity:.7}
486
- .bda-film{position:absolute;left:14%;right:14%;top:13%;aspect-ratio:16/9;border-radius:6px;background:#1d1d1f;box-shadow:0 6px 18px -8px rgba(0,0,0,.35);display:flex;align-items:center;justify-content:center;transition:transform .2s;color:#fff}
487
- .bda-item:hover .bda-film{transform:translateY(-3px)}
488
- .bda-film-bar{position:absolute;left:8%;right:8%;bottom:10%;height:3px;border-radius:2px;background:rgba(255,255,255,.25)}
489
- .bda-film-bar::after{content:"";position:absolute;left:0;top:0;bottom:0;width:38%;border-radius:2px;background:var(--bda-tint)}
490
- .bda-film-title{position:absolute;left:8%;right:8%;top:10%;font-size:10px;font-weight:600;color:rgba(255,255,255,.85);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
491
- .bda-busy{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;gap:8px;background:color-mix(in srgb,var(--dsw-alias-bg-base) 70%,transparent);color:var(--dsw-alias-label-secondary);font-size:13px}
492
- .bda-spinner{width:14px;height:14px;border-radius:50%;border:1.5px solid currentColor;border-right-color:transparent;animation:bda-spin .8s linear infinite}
493
- @keyframes bda-spin{to{transform:rotate(360deg)}}
494
- .bda-info{display:flex;align-items:center;gap:12px;min-width:0;padding:12px 14px}
495
- .bda-glyph{flex:none;display:flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:9px;background:color-mix(in srgb,var(--bda-tint) 16%,var(--dsw-alias-bg-base));color:color-mix(in srgb,var(--bda-tint) 78%,var(--dsw-alias-label-primary))}
496
- .bda-text{display:flex;flex-direction:column;min-width:0;flex:1}
497
- .bda-name{font-weight:500;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
498
- .bda-meta{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
499
- .bda-actions{position:absolute;top:10px;right:10px;display:flex;align-items:center;gap:6px}
500
- .bda-act{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:.5px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;transition:opacity .12s}
501
- .bda-act:hover{color:var(--dsw-alias-label-primary);background:color-mix(in srgb,var(--dsw-alias-label-primary) 6%,var(--dsw-alias-bg-base))}
502
- .bda-item:hover .bda-act,.bda-item:focus-within .bda-act,.bda-act[aria-expanded=true],.bda-act[data-on=true]{opacity:1}
503
- .bda-act[data-on=true]{color:var(--dsw-alias-label-primary)}
504
- .bda-list{display:flex;flex-direction:column;gap:2px;margin:0;padding:0;list-style:none}
505
- .bda-list .bda-item{display:flex;align-items:center;border-radius:10px;padding-right:8px}
506
- .bda-list .bda-item:hover,.bda-list .bda-item[data-menu=true]{background:var(--dsw-alias-interactive-bg-hover)}
507
- .bda-row{display:flex;align-items:center;gap:12px;flex:1;min-width:0;padding:8px 10px;border:0;border-radius:10px;background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
508
- .bda-row:disabled{cursor:progress}
509
- .bda-row .bda-name{flex:1;min-width:0}
510
- .bda-row .bda-meta{flex:none;margin-left:16px}
511
- .bda-row-tools{flex:none;display:flex;align-items:center;gap:2px;margin-left:4px;color:var(--dsw-alias-label-tertiary)}
512
- .bda-shared{display:inline-flex;align-items:center;margin-right:6px;color:var(--dsw-alias-label-tertiary)}
513
- .bda-list .bda-act{width:28px;height:28px;border:0;background:none}
514
- .bda-list .bda-act:hover{background:color-mix(in srgb,var(--dsw-alias-label-primary) 8%,transparent)}
515
- .bda-list .bda-act-more{opacity:1}
516
- @media (max-width:560px){.bda-row .bda-meta{display:none}}
517
- .bda-menu{position:fixed;z-index:1000;min-width:200px;padding:6px;border:.5px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-base);box-shadow:0 8px 28px -6px rgba(0,0,0,.28);font-size:14px}
518
- .bda-menu-item{display:flex;align-items:center;gap:10px;width:100%;min-height:34px;padding:5px 10px;border:0;border-radius:8px;background:none;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;white-space:nowrap;cursor:pointer}
519
- .bda-menu-item:hover,.bda-menu-item:focus-visible,.bda-menu-item[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);outline:none}
520
- .bda-menu-item[data-danger=true]{color:var(--dsw-alias-state-error-primary)}
521
- .bda-menu-item svg{flex:none}
522
- .bda-menu-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
523
- .bda-menu-value{margin-left:16px;color:var(--dsw-alias-label-tertiary)}
524
- .bda-menu-count{margin-left:16px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums}
525
- .bda-menu-key{margin-left:20px;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:12px}
526
- .bda-menu-rule{height:.5px;margin:6px 4px;background:var(--dsw-alias-border-l2)}
527
- .bda-menu-chev{margin-left:6px;color:var(--dsw-alias-label-tertiary)}
528
- .bda-menu-row{position:relative}
529
- .bda-submenu{position:absolute;left:calc(100% + 12px);top:-6px;z-index:1001;min-width:190px;padding:6px;border:.5px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-base);box-shadow:0 8px 28px -6px rgba(0,0,0,.28)}
530
- .bda-submenu[data-flip=true]{left:auto;right:calc(100% + 12px)}
531
- .bda-check{flex:none;display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border:1px solid var(--dsw-alias-border-l1);border-radius:5px;color:transparent}
532
- .bda-check[data-on=true]{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary);color:#fff}
533
- .bda-tick{flex:none;margin-left:16px;color:var(--dsw-alias-state-business-primary)}
534
- .bda-scrim{position:fixed;inset:0;z-index:1100;display:flex;align-items:center;justify-content:center;padding:24px;background:rgba(0,0,0,.36)}
535
- .bda-dialog{width:min(420px,100%);padding:20px;border-radius:16px;background:var(--dsw-alias-bg-base);box-shadow:0 18px 48px -12px rgba(0,0,0,.4)}
536
- .bda-dialog h2{margin:0 0 12px;font-size:16px;font-weight:600;line-height:24px;overflow-wrap:anywhere}
537
- .bda-dialog p{margin:0;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:1.55;overflow-wrap:anywhere}
538
- .bda-dialog input{box-sizing:border-box;width:100%;height:38px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:none;color:var(--dsw-alias-label-primary);font:inherit;outline:none}
539
- .bda-dialog input:focus{border-color:var(--dsw-alias-state-business-primary)}
540
- .bda-dialog-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}
541
- .bda-btn{height:34px;padding:0 14px;border:0;border-radius:9px;background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:inherit;font-weight:500;cursor:pointer}
542
- .bda-btn:hover{background:color-mix(in srgb,var(--dsw-alias-label-primary) 12%,var(--dsw-alias-bg-base))}
543
- .bda-btn:disabled{color:var(--dsw-alias-label-caption);cursor:default;background:var(--dsw-alias-interactive-bg-hover)}
544
- .bda-btn[data-primary=true]{background:var(--dsw-alias-state-business-primary);color:#fff}
545
- .bda-btn[data-primary=true]:hover:not(:disabled){filter:brightness(1.08)}
546
- .bda-btn[data-primary=true]:disabled{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-caption)}
547
- .bda-btn[data-danger=true]{border:1px solid var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,var(--dsw-alias-bg-base));color:var(--dsw-alias-state-error-primary)}
548
- .bda-btn[data-danger=true]:hover{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 18%,var(--dsw-alias-bg-base))}
549
- .bda-toast{position:absolute;left:50%;bottom:24px;z-index:900;display:flex;align-items:center;gap:10px;max-width:min(560px,calc(100% - 32px));padding:9px 10px 9px 14px;border:.5px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-base);box-shadow:0 8px 28px -6px rgba(0,0,0,.28);transform:translateX(-50%);font-size:14px}
550
- .bda-toast[data-kind=error]{color:var(--dsw-alias-state-error-primary)}
551
- .bda-toast svg{flex:none}
552
- .bda-toast-text{min-width:0;overflow-wrap:anywhere}
553
- .bda-toast-undo{flex:none;padding:2px 8px;border:0;border-radius:6px;background:none;color:var(--dsw-alias-state-business-primary);font:inherit;font-weight:500;cursor:pointer}
554
- .bda-toast-undo:hover{background:var(--dsw-alias-interactive-bg-hover)}
555
- .bda-toast-close{flex:none;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;padding:0;border:0;border-radius:6px;background:none;color:var(--dsw-alias-label-tertiary);cursor:pointer}
556
- .bda-toast-close:hover{background:var(--dsw-alias-interactive-bg-hover)}
557
- .bda-empty{display:flex;flex-direction:column;align-items:center;gap:8px;padding:56px 20px;text-align:center;color:var(--dsw-alias-label-tertiary)}
558
- .bda-empty svg{color:var(--dsw-alias-label-caption);margin-bottom:4px}
559
- .bda-empty h2{margin:0;font-size:14px;font-weight:500;color:var(--dsw-alias-label-secondary)}
560
- .bda-empty p{margin:0;max-width:420px;font-size:13px;line-height:1.6}
561
- .bda-retry{margin-top:8px;height:30px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l2);border-radius:15px;background:none;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;cursor:pointer}
562
- .bda-retry:hover{background:var(--dsw-alias-interactive-bg-hover)}
563
- .bda-skeleton .bda-card{cursor:default}
564
- .bda-skeleton .bda-preview{background:var(--dsw-alias-bg-skeleton,var(--dsw-alias-interactive-bg-hover))}
565
- .bda-skeleton .bda-line{width:60%;height:10px;margin:18px 14px}
566
- @media (prefers-reduced-motion:reduce){.bda-sheet,.bda-paper,.bda-slide,.bda-film,.bda-act,.bda-tile-art,.bda-card{transition:none}.bda-spinner{animation-duration:2s}}
567
- `;
568
- var TINTS = {
569
- "claude-slides": "#e8703a",
570
- "claude-design": "#7a5cf0",
571
- "claude-design-system": "#c79a1b",
572
- "claude-dashboard": "#e5484d",
573
- "claude-docs": "#3f8ef0",
574
- "claude-motion": "#1fa971"
575
- };
576
- var tintOf = (skill) => isSkill(skill) ? TINTS[skill] : "#8a8a8a";
577
- var svg = (size) => ({ display: "block", width: size, height: size, flex: "none" });
578
- function ArtifactsIcon({ size = 16 }) {
579
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", style: svg(size), children: [
580
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "6", width: "8.5", height: "11", rx: "2", stroke: "currentColor", strokeWidth: "1.5" }),
581
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8.5 6V5a2 2 0 0 1 2-2h4.5a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2h-3.5", stroke: "currentColor", strokeWidth: "1.5" })
582
- ] });
583
- }
584
- function TypeIcon({ skill, size = 18 }) {
585
- const p = { stroke: "currentColor", strokeWidth: 1.5, strokeLinecap: "round", strokeLinejoin: "round" };
586
- const body = (() => {
587
- switch (skill) {
588
- case "claude-slides":
589
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2.75 3.5h14.5M4 3.5v8.25a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V3.5M7.25 16.75 10 12.75l2.75 4", ...p }) });
590
- case "claude-design":
591
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
592
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 2.75a7.25 7.25 0 1 0 0 14.5c1.1 0 1.75-.8 1.75-1.7 0-.5-.2-.9-.45-1.25-.25-.35-.45-.7-.45-1.15 0-.95.75-1.65 1.7-1.65h1.6a3.1 3.1 0 0 0 3.1-3.1c0-3.1-3.2-5.65-7.25-5.65Z", ...p }),
593
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6.4", cy: "9.4", r: ".9", fill: "currentColor" }),
594
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8.8", cy: "6.3", r: ".9", fill: "currentColor" }),
595
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12.5", cy: "6.8", r: ".9", fill: "currentColor" })
596
- ] });
597
- case "claude-design-system":
598
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
599
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6.5", cy: "6.5", r: "3.25", ...p }),
600
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "13.5", cy: "6.5", r: "3.25", ...p }),
601
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10", cy: "13", r: "3.25", ...p })
602
- ] });
603
- case "claude-dashboard":
604
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
605
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2.75", y: "10", width: "4.5", height: "7.25", rx: "1", ...p }),
606
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "7.75", y: "2.75", width: "4.5", height: "14.5", rx: "1", ...p }),
607
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "12.75", y: "7", width: "4.5", height: "10.25", rx: "1", ...p })
608
- ] });
609
- case "claude-docs":
610
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
611
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5.5 2.75h6l4 4v9.5a1 1 0 0 1-1 1h-9a1 1 0 0 1-1-1V3.75a1 1 0 0 1 1-1Z", ...p }),
612
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M11.5 2.75v4h4", ...p })
613
- ] });
614
- case "claude-motion":
615
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
616
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2.75", y: "4", width: "14.5", height: "12", rx: "2", ...p }),
617
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m8.5 7.75 4 2.25-4 2.25v-4.5Z", ...p })
618
- ] });
619
- default:
620
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "3", y: "3", width: "14", height: "14", rx: "2", ...p });
621
- }
622
- })();
623
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 20 20", fill: "none", "aria-hidden": "true", style: svg(size), children: body });
624
- }
625
- function Icon({ d, size = 16, fill }) {
626
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", fill: fill ? "currentColor" : "none", stroke: fill ? void 0 : "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", style: svg(size), children: typeof d === "string" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d }) : d });
627
- }
628
- var ICON = {
629
- search: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
630
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "7", cy: "7", r: "4.5" }),
631
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m10.5 10.5 3 3" })
632
- ] }),
633
- clear: "m4.5 4.5 7 7m0-7-7 7",
634
- filter: "M2.5 4.5h11M4.5 8h7M6.5 11.5h3",
635
- list: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
636
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5.75 4h7.75M5.75 8h7.75M5.75 12h7.75" }),
637
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2.5 4h.01M2.5 8h.01M2.5 12h.01", strokeWidth: "1.8" })
638
- ] }),
639
- grid: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
640
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2.5", y: "2.5", width: "4.5", height: "4.5", rx: "1" }),
641
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "2.5", width: "4.5", height: "4.5", rx: "1" }),
642
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "2.5", y: "9", width: "4.5", height: "4.5", rx: "1" }),
643
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "9", y: "9", width: "4.5", height: "4.5", rx: "1" })
644
- ] }),
645
- plus: "M8 3v10M3 8h10",
646
- chat: "M3 3.5h10a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H8.2L5.4 13.8a.3.3 0 0 1-.5-.23V11.5H3a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1Z",
647
- pin: "M9.75 2.25 13.75 6.25M10.75 3.25 7 6.25 4.5 6.5 9.5 11.5 9.75 9 12.75 5.25M7 9l-4 4",
648
- more: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
649
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "3.5", cy: "8", r: ".6", fill: "currentColor" }),
650
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: ".6", fill: "currentColor" }),
651
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12.5", cy: "8", r: ".6", fill: "currentColor" })
652
- ] }),
653
- rename: "M10.5 3 13 5.5 5.5 13 2.5 13.5 3 10.5 10.5 3Z",
654
- link: "M6.75 9.25a2.5 2.5 0 0 0 3.54 0l2.25-2.25a2.5 2.5 0 0 0-3.54-3.54L8.25 4.2M9.25 6.75a2.5 2.5 0 0 0-3.54 0L3.46 9a2.5 2.5 0 0 0 3.54 3.54l.75-.75",
655
- trash: "M2.75 4.25h10.5M6.25 4.25V3a.75.75 0 0 1 .75-.75h2a.75.75 0 0 1 .75.75v1.25M4 4.25l.6 8.6a1 1 0 0 0 1 .9h4.8a1 1 0 0 0 1-.9l.6-8.6M6.75 7v4M9.25 7v4",
656
- info: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
657
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "8", cy: "8", r: "6" }),
658
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 7.5v3.25M8 5.25h.01" })
659
- ] }),
660
- chevron: "m6 3.5 4.5 4.5L6 12.5",
661
- tick: "m3 8.5 3.25 3.25L13 4.75",
662
- people: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
663
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "5.5", r: "2.25" }),
664
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 13c0-2.2 1.8-3.75 4-3.75S10 10.8 10 13M10.5 3.5a2.25 2.25 0 0 1 0 4M12 9.5c1.3.45 2.25 1.75 2.25 3.5" })
665
- ] })
666
- };
667
- function Drawn({ skill, title }) {
668
- const name = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-paper-title", children: title });
669
- switch (skill) {
670
- case "claude-slides":
671
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-slide", children: [
672
- name,
673
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-line" })
674
- ] });
675
- case "claude-motion":
676
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-film", children: [
677
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-film-title", children: title }),
678
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 20 20", "aria-hidden": "true", style: svg(22), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M7 5.5v9l7.5-4.5L7 5.5Z", fill: "currentColor" }) }),
679
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-film-bar" })
680
- ] });
681
- case "claude-design":
682
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-paper", children: [
683
- name,
684
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-boards", children: [
685
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-board" }),
686
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-board" })
687
- ] })
688
- ] });
689
- case "claude-design-system":
690
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-paper", children: [
691
- name,
692
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-swatches", children: [
693
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-swatch" }),
694
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-swatch" }),
695
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-swatch" }),
696
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-swatch" })
697
- ] }),
698
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-specimen", children: "Aa" })
699
- ] });
700
- case "claude-dashboard":
701
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-paper", children: [
702
- name,
703
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-kpis", children: [
704
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-kpi" }),
705
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-kpi" }),
706
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-kpi" })
707
- ] }),
708
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-bars", children: [45, 70, 55, 90, 65, 80].map((h, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-bar", style: { height: `${h}%` } }, i)) })
709
- ] });
710
- default:
711
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-paper", children: [
712
- name,
713
- [92, 100, 84, 96, 70].map((w, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-line", style: { width: `${w}%` } }, i))
714
- ] });
715
- }
716
- }
717
- function Preview({ view, thumbnailUrl }) {
718
- const url = thumbnailUrl(view);
719
- const [broken, setBroken] = (0, import_react.useState)(null);
720
- const shown = url !== null && broken !== url;
721
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-preview", "data-stack": shown && view.skill === "claude-docs", children: shown ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-sheet", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: url, alt: "", draggable: false, onError: () => setBroken(url) }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Drawn, { skill: view.skill, title: view.title }) });
722
- }
723
- function ago(iso, now, t) {
724
- const then = Date.parse(iso);
725
- if (!Number.isFinite(then)) return "";
726
- const seconds = Math.round((then - now) / 1e3);
727
- if (seconds > -60) return t("card.justNow");
728
- const steps = [["minute", 60], ["hour", 3600], ["day", 86400], ["week", 604800], ["month", 2629800], ["year", 31557600]];
729
- let unit = "minute";
730
- let size = 60;
731
- for (const [u, s] of steps) if (-seconds >= s) [unit, size] = [u, s];
732
- let format;
733
- try {
734
- format = new Intl.RelativeTimeFormat(t("time.locale"), { numeric: "auto" });
735
- } catch {
736
- format = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
737
- }
738
- return t("card.opened", { time: format.format(Math.round(seconds / size), unit) });
739
- }
740
- function useNow() {
741
- const [now, setNow] = (0, import_react.useState)(() => Date.now());
742
- (0, import_react.useEffect)(() => {
743
- const timer = setInterval(() => setNow(Date.now()), 6e4);
744
- return () => clearInterval(timer);
745
- }, []);
746
- return now;
747
- }
748
- var ITEMS = "[role^=menuitem]";
749
- function menuKeys(event, close) {
750
- if (event.key === "Escape") {
751
- event.preventDefault();
752
- event.stopPropagation();
753
- close();
754
- return;
755
- }
756
- if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
757
- event.preventDefault();
758
- event.stopPropagation();
759
- const items = [...event.currentTarget.querySelectorAll(ITEMS)].filter((item) => item.closest("[role=menu]") === event.currentTarget);
760
- const at = items.indexOf(document.activeElement);
761
- items[(at + (event.key === "ArrowDown" ? 1 : items.length - 1)) % items.length]?.focus();
762
- }
763
- function Menu({ anchor, label, onClose, onKey, children }) {
764
- const ref = (0, import_react.useRef)(null);
765
- const [place, setPlace] = (0, import_react.useState)({ visibility: "hidden" });
766
- (0, import_react.useLayoutEffect)(() => {
767
- const box = anchor.getBoundingClientRect();
768
- const height = ref.current?.offsetHeight ?? 0;
769
- const width = ref.current?.offsetWidth ?? 0;
770
- const right = Math.max(8, window.innerWidth - box.right);
771
- const fits = box.bottom + 6 + height <= window.innerHeight - 8;
772
- setPlace({
773
- right: window.innerWidth - right - width < 8 ? window.innerWidth - width - 8 : right,
774
- ...fits ? { top: box.bottom + 6 } : { bottom: Math.max(8, window.innerHeight - box.top + 6) }
775
- });
776
- }, [anchor]);
777
- const placed = place.visibility !== "hidden";
778
- (0, import_react.useEffect)(() => {
779
- if (placed) ref.current?.querySelector(ITEMS)?.focus({ preventScroll: true });
780
- }, [placed]);
781
- (0, import_react.useEffect)(() => {
782
- const away = (event) => {
783
- const target = event.target;
784
- if (!ref.current?.contains(target) && !anchor.contains(target)) onClose();
785
- };
786
- const gone = () => onClose();
787
- document.addEventListener("pointerdown", away, true);
788
- window.addEventListener("resize", gone);
789
- return () => {
790
- document.removeEventListener("pointerdown", away, true);
791
- window.removeEventListener("resize", gone);
792
- };
793
- }, [anchor, onClose]);
794
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
795
- "div",
796
- {
797
- ref,
798
- className: "bda-menu",
799
- role: "menu",
800
- "aria-label": label,
801
- style: place,
802
- onKeyDown: (event) => {
803
- if (onKey && !event.metaKey && !event.ctrlKey && !event.altKey && onKey(event.key.toLowerCase())) {
804
- event.preventDefault();
805
- return;
806
- }
807
- menuKeys(event, () => {
808
- onClose();
809
- anchor.focus();
810
- });
811
- },
812
- children
813
- }
814
- );
815
- }
816
- function ChoiceItem({ label, on, count, onPick }) {
817
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-menu-item", role: "menuitemradio", "aria-checked": on, onClick: onPick, children: [
818
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: label }),
819
- count !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-count", children: count }),
820
- on && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-tick", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.tick }) })
821
- ] });
822
- }
823
- function SubMenu({ id, label, value, open, setOpen, children }) {
824
- const isOpen = open === id;
825
- const panel = (0, import_react.useRef)(null);
826
- const [flip, setFlip] = (0, import_react.useState)(false);
827
- (0, import_react.useLayoutEffect)(() => {
828
- if (isOpen && panel.current) setFlip(panel.current.getBoundingClientRect().right + (flip ? panel.current.offsetWidth : 0) > window.innerWidth - 8);
829
- }, [isOpen]);
830
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-menu-row", onMouseEnter: () => setOpen(id), children: [
831
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
832
- "button",
833
- {
834
- type: "button",
835
- className: "bda-menu-item",
836
- role: "menuitem",
837
- "aria-haspopup": "menu",
838
- "aria-expanded": isOpen,
839
- onClick: () => setOpen(isOpen ? null : id),
840
- onKeyDown: (event) => {
841
- if (event.key === "ArrowRight" || event.key === "Enter" || event.key === " ") {
842
- event.preventDefault();
843
- setOpen(id);
844
- requestAnimationFrame(() => panel.current?.querySelector(ITEMS)?.focus());
845
- }
846
- },
847
- children: [
848
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: label }),
849
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-value", children: value }),
850
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-chev", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.chevron, size: 12 }) })
851
- ]
852
- }
853
- ),
854
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
855
- "div",
856
- {
857
- ref: panel,
858
- className: "bda-submenu",
859
- role: "menu",
860
- "aria-label": label,
861
- "data-flip": flip,
862
- onKeyDown: (event) => {
863
- if (event.key === "ArrowLeft" || event.key === "Escape") {
864
- event.preventDefault();
865
- event.stopPropagation();
866
- setOpen(null);
867
- event.currentTarget.previousElementSibling?.focus();
868
- return;
869
- }
870
- menuKeys(event, () => setOpen(null));
871
- },
872
- children
873
- }
874
- )
875
- ] });
876
- }
877
- function FilterMenu({ anchor, filters, setFilters, types, counts, t, onClose }) {
878
- const [open, setOpen] = (0, import_react.useState)(null);
879
- const typeLabel = filters.types.length === 0 ? t("filter.any") : filters.types.length === 1 ? t(`type.${filters.types[0]}`) : t("filter.some", { count: String(filters.types.length) });
880
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Menu, { anchor, label: t("filter.button"), onClose, children: [
881
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SubMenu, { id: "sort", label: t("filter.sort"), value: t(`sort.${filters.sort}`), open, setOpen, children: SORTS.map((sort) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChoiceItem, { label: t(`sort.${sort}`), on: filters.sort === sort, onPick: () => setFilters({ ...filters, sort }) }, sort)) }),
882
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-menu-rule", role: "separator" }),
883
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SubMenu, { id: "type", label: t("filter.type"), value: typeLabel, open, setOpen, children: types.map((type) => {
884
- const on = filters.types.includes(type);
885
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
886
- "button",
887
- {
888
- type: "button",
889
- className: "bda-menu-item",
890
- role: "menuitemcheckbox",
891
- "aria-checked": on,
892
- onClick: () => setFilters({ ...filters, types: on ? filters.types.filter((x) => x !== type) : [...filters.types, type] }),
893
- children: [
894
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-check", "data-on": on, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.tick, size: 12 }) }),
895
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: t(`type.${type}`) }),
896
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-count", children: counts.get(type) ?? 0 })
897
- ]
898
- },
899
- type
900
- );
901
- }) }),
902
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SubMenu, { id: "date", label: t("filter.date"), value: t(`date.${filters.date}`), open, setOpen, children: DATES.map((date) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChoiceItem, { label: t(`date.${date}`), on: filters.date === date, onPick: () => setFilters({ ...filters, date }) }, date)) }),
903
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SubMenu, { id: "sharing", label: t("filter.sharing"), value: t(`sharing.${filters.sharing}`), open, setOpen, children: SHARINGS.map((sharing) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ChoiceItem, { label: t(`sharing.${sharing}`), on: filters.sharing === sharing, onPick: () => setFilters({ ...filters, sharing }) }, sharing)) }),
904
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-menu-rule", role: "separator" }),
905
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { onMouseEnter: () => setOpen(null), children: [
906
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-menu-item", role: "menuitemcheckbox", "aria-checked": filters.pinned, onClick: () => setFilters({ ...filters, pinned: !filters.pinned }), children: [
907
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: t("filter.pinned") }),
908
- filters.pinned && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-tick", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.tick }) })
909
- ] }),
910
- isFiltered(filters) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-menu-item", role: "menuitem", onClick: () => setFilters({ ...NO_FILTERS, sort: filters.sort }), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: t("filter.clear") }) })
911
- ] })
912
- ] });
913
- }
914
- function ActionsMenu({ anchor, view, t, onClose, act }) {
915
- const item = (what, icon, label, key) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-menu-item", role: "menuitem", "aria-keyshortcuts": key, onClick: () => act(what), children: [
916
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: icon }),
917
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: label }),
918
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("kbd", { className: "bda-menu-key", children: key })
919
- ] });
920
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
921
- Menu,
922
- {
923
- anchor,
924
- label: t("action.more"),
925
- onClose,
926
- onKey: (key) => {
927
- const what = { p: "pin", r: "rename", c: "copy" }[key];
928
- if (what === void 0) return false;
929
- act(what);
930
- return true;
931
- },
932
- children: [
933
- item("pin", ICON.pin, t(view.pinned ? "action.unpin" : "action.pin"), "P"),
934
- item("rename", ICON.rename, t("action.rename"), "R"),
935
- item("copy", ICON.link, t("action.copy"), "C"),
936
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-menu-rule", role: "separator" }),
937
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-menu-item", role: "menuitem", "data-danger": "true", onClick: () => act("delete"), children: [
938
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.trash }),
939
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: t("action.delete") })
940
- ] })
941
- ]
942
- }
943
- );
944
- }
945
- function CreateMenu({ anchor, skills, canCreate, t, onClose, create }) {
946
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Menu, { anchor, label: t("create.new"), onClose, children: [
947
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-menu-item", role: "menuitem", disabled: !canCreate, onClick: () => create(), children: [
948
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.chat }),
949
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: t("create.session") })
950
- ] }),
951
- skills.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-menu-rule", role: "separator" }),
952
- skills.map((skill) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-menu-item", role: "menuitem", "data-skill": skill, onClick: () => create(skill), style: { "--bda-tint": tintOf(skill) }, children: [
953
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: "color-mix(in srgb,var(--bda-tint) 78%,var(--dsw-alias-label-primary))" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypeIcon, { skill, size: 16 }) }),
954
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-menu-label", children: t(`type.${skill}`) })
955
- ] }, skill))
956
- ] });
957
- }
958
- function Dialog({ label, onClose, children }) {
959
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
960
- "div",
961
- {
962
- className: "bda-scrim",
963
- onPointerDown: (event) => {
964
- if (event.target === event.currentTarget) onClose();
965
- },
966
- onKeyDown: (event) => {
967
- if (event.key === "Escape") {
968
- event.stopPropagation();
969
- onClose();
970
- }
971
- },
972
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-dialog", role: "dialog", "aria-modal": "true", "aria-label": label, children })
973
- }
974
- );
975
- }
976
- function RenameDialog({ view, t, onClose, onSave }) {
977
- const [title, setTitle] = (0, import_react.useState)(view.title);
978
- const input = (0, import_react.useRef)(null);
979
- (0, import_react.useEffect)(() => {
980
- input.current?.focus();
981
- input.current?.select();
982
- }, []);
983
- const clean = title.trim();
984
- const ready = clean !== "" && clean !== view.title;
985
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Dialog, { label: t("rename.title"), onClose, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
986
- "form",
987
- {
988
- onSubmit: (event) => {
989
- event.preventDefault();
990
- if (ready) onSave(clean);
991
- },
992
- children: [
993
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("rename.title") }),
994
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ref: input, value: title, "aria-label": t("rename.title"), maxLength: 200, onChange: (event) => setTitle(event.target.value) }),
995
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-dialog-actions", children: [
996
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-btn", onClick: onClose, children: t("dialog.cancel") }),
997
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "submit", className: "bda-btn", "data-primary": "true", disabled: !ready, children: t("rename.save") })
998
- ] })
999
- ]
1000
- }
1001
- ) });
1002
- }
1003
- function DeleteDialog({ view, t, onClose, onDelete }) {
1004
- const confirm = (0, import_react.useRef)(null);
1005
- (0, import_react.useEffect)(() => confirm.current?.focus(), []);
1006
- const title = t("delete.title", { title: view.title });
1007
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Dialog, { label: title, onClose, children: [
1008
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: title }),
1009
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: view.deletable ? t("delete.moves") : t("delete.keeps", { path: view.root }) }),
1010
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-dialog-actions", children: [
1011
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-btn", onClick: onClose, children: t("dialog.cancel") }),
1012
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ref: confirm, type: "button", className: "bda-btn", "data-danger": "true", onClick: onDelete, children: t("delete.confirm") })
1013
- ] })
1014
- ] });
1015
- }
1016
- function ToastBar({ toast, t, onClose, onUndo }) {
1017
- (0, import_react.useEffect)(() => {
1018
- const timer = setTimeout(onClose, toast.undo || toast.kind === "error" ? 1e4 : 4e3);
1019
- return () => clearTimeout(timer);
1020
- }, [toast, onClose]);
1021
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-toast", role: toast.kind === "error" ? "alert" : "status", "data-kind": toast.kind, children: [
1022
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.info }),
1023
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-toast-text", children: toast.message }),
1024
- toast.undo && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-toast-undo", onClick: () => onUndo(toast.undo), children: t("toast.undo") }),
1025
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-toast-close", "aria-label": t("toast.close"), onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.clear, size: 14 }) })
1026
- ] });
1027
- }
1028
- var hint = (view, conversation) => conversation ? `${view.root}
1029
- ${conversation}` : view.root;
1030
- function PinButton({ view, t, onPin }) {
1031
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-act", "data-on": view.pinned, "aria-pressed": view.pinned, "aria-label": t(view.pinned ? "action.unpin" : "action.pin"), title: t(view.pinned ? "action.unpin" : "action.pin"), onClick: () => onPin(view), children: view.pinned ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", "aria-hidden": "true", style: svg(16), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9.75 2.25 13.75 6.25M10.75 3.25 7 6.25 4.5 6.5 9.5 11.5 9.75 9 12.75 5.25M7 9l-4 4", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.pin }) });
1032
- }
1033
- function MoreButton({ view, t, menuOpen, onMenu, extra }) {
1034
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: `bda-act ${extra ?? ""}`, "aria-label": t("action.more"), title: t("action.more"), "aria-haspopup": "menu", "aria-expanded": menuOpen, onClick: (event) => onMenu(view, event.currentTarget), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.more }) });
1035
- }
1036
- function Card({ view, state, conversation, now, t, thumbnailUrl, onOpen, onPin, menuOpen, onMenu }) {
1037
- const opening = state.opening === view.root;
1038
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "bda-item", "data-menu": menuOpen, style: { "--bda-tint": tintOf(view.skill) }, children: [
1039
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-card", disabled: state.opening !== null, "aria-busy": opening, title: hint(view, conversation), onClick: () => onOpen(view), "data-skill": view.skill, children: [
1040
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "bda-preview-wrap", style: { display: "block", position: "relative", width: "100%" }, children: [
1041
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Preview, { view, thumbnailUrl }),
1042
- opening && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "bda-busy", children: [
1043
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-spinner" }),
1044
- t("card.opening")
1045
- ] })
1046
- ] }),
1047
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "bda-info", children: [
1048
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-glyph", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypeIcon, { skill: view.skill }) }),
1049
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "bda-text", children: [
1050
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-name", children: view.title }),
1051
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-meta", children: ago(view.openedAt, now, t) })
1052
- ] })
1053
- ] })
1054
- ] }),
1055
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-actions", children: [
1056
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MoreButton, { view, t, menuOpen, onMenu }),
1057
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PinButton, { view, t, onPin })
1058
- ] })
1059
- ] });
1060
- }
1061
- function Row({ view, state, conversation, now, t, onOpen, onPin, menuOpen, onMenu }) {
1062
- const opening = state.opening === view.root;
1063
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: "bda-item", "data-menu": menuOpen, style: { "--bda-tint": tintOf(view.skill) }, children: [
1064
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-row", disabled: state.opening !== null, "aria-busy": opening, title: hint(view, conversation), onClick: () => onOpen(view), "data-skill": view.skill, children: [
1065
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-glyph", children: opening ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-spinner" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypeIcon, { skill: view.skill }) }),
1066
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-name", children: view.title }),
1067
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-meta", children: opening ? t("card.opening") : ago(view.openedAt, now, t) })
1068
- ] }),
1069
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-row-tools", children: [
1070
- view.shared && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-shared", title: t("card.shared"), "aria-label": t("card.shared"), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.people }) }),
1071
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PinButton, { view, t, onPin }),
1072
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MoreButton, { view, t, menuOpen, onMenu, extra: "bda-act-more" })
1073
- ] })
1074
- ] });
1075
- }
1076
- function readView() {
1077
- try {
1078
- return localStorage.getItem(VIEW_KEY) === "list" ? "list" : "grid";
1079
- } catch {
1080
- return "grid";
1081
- }
1082
- }
1083
- function writeView(view) {
1084
- try {
1085
- localStorage.setItem(VIEW_KEY, view);
1086
- } catch {
1087
- }
1088
- }
1089
- function ArtifactsPage(props) {
1090
- const { t, artifactsStore, sessionsStore, reloadArtifacts, openArtifact, create, canCreate, createOptions, pin, rename, copyLink, remove, undo, thumbnailUrl, watchThumbnails, dismissToast } = props;
1091
- const state = (0, import_react.useSyncExternalStore)(artifactsStore.subscribe, artifactsStore.getSnapshot);
1092
- const sessions = (0, import_react.useSyncExternalStore)(sessionsStore.subscribe, sessionsStore.getSnapshot);
1093
- const [query, setQuery] = (0, import_react.useState)("");
1094
- const [searching, setSearching] = (0, import_react.useState)(false);
1095
- const [filters, setFilters] = (0, import_react.useState)(NO_FILTERS);
1096
- const [layout, setLayout] = (0, import_react.useState)(readView);
1097
- const [popup, setPopup] = (0, import_react.useState)(null);
1098
- const [dialog, setDialog] = (0, import_react.useState)(null);
1099
- const searchBox = (0, import_react.useRef)(null);
1100
- const now = useNow();
1101
- (0, import_react.useEffect)(() => {
1102
- reloadArtifacts();
1103
- const again = () => {
1104
- if (document.visibilityState === "visible") reloadArtifacts();
1105
- };
1106
- document.addEventListener("visibilitychange", again);
1107
- return () => document.removeEventListener("visibilitychange", again);
1108
- }, [reloadArtifacts]);
1109
- (0, import_react.useEffect)(() => watchThumbnails(), [watchThumbnails]);
1110
- (0, import_react.useEffect)(() => {
1111
- if (searching) searchBox.current?.focus();
1112
- }, [searching]);
1113
- const counts = (0, import_react.useMemo)(() => {
1114
- const by = /* @__PURE__ */ new Map();
1115
- for (const a of state.artifacts) by.set(a.skill, (by.get(a.skill) ?? 0) + 1);
1116
- return by;
1117
- }, [state.artifacts]);
1118
- const types = (0, import_react.useMemo)(() => SKILLS.filter((s) => state.skills.includes(s) || counts.has(s)), [state.skills, counts]);
1119
- const tiles = (0, import_react.useMemo)(() => createOptions(), [state.skills, createOptions]);
1120
- const shown = (0, import_react.useMemo)(() => {
1121
- const q = query.trim().toLowerCase();
1122
- const kept = state.artifacts.filter((a) => {
1123
- if (filters.types.length > 0 && !filters.types.includes(a.skill)) return false;
1124
- if (filters.pinned && !a.pinned) return false;
1125
- if (filters.sharing !== "any" && a.shared !== (filters.sharing === "shared")) return false;
1126
- if (!inRange(a.openedAt, filters.date, now)) return false;
1127
- if (!q) return true;
1128
- const conversation = sessions.byId?.[a.sessionId]?.title ?? "";
1129
- return a.title.toLowerCase().includes(q) || conversation.toLowerCase().includes(q) || a.root.toLowerCase().includes(q);
1130
- });
1131
- return sorted(kept, filters.sort, t("time.locale"));
1132
- }, [state.artifacts, filters, query, sessions, now, t]);
1133
- const closePopup = (0, import_react.useMemo)(() => () => setPopup(null), []);
1134
- const actionsFor = popup?.kind === "actions" ? state.artifacts.find((a) => a.root === popup.root) : void 0;
1135
- const dialogFor = dialog ? state.artifacts.find((a) => a.root === dialog.root) : void 0;
1136
- const itemProps = (view) => ({
1137
- view,
1138
- state,
1139
- conversation: sessions.byId?.[view.sessionId]?.title?.trim() ?? "",
1140
- now,
1141
- t,
1142
- thumbnailUrl,
1143
- onOpen: openArtifact,
1144
- onPin: (v) => pin(v, !v.pinned),
1145
- menuOpen: popup?.kind === "actions" && popup.root === view.root,
1146
- onMenu: (v, anchor) => setPopup((p) => p?.kind === "actions" && p.root === v.root ? null : { kind: "actions", anchor, root: v.root })
1147
- });
1148
- const toggle = (kind, anchor) => setPopup((p) => p?.kind === kind ? null : { kind, anchor });
1149
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "bda-page", "aria-label": t("title"), "data-testid": "baoyu-design-artifacts", children: [
1150
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-scroll", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-content", children: [
1151
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-heading", children: [
1152
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: t("title") }),
1153
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-tools", children: [
1154
- searching || query ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "bda-search", children: [
1155
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.search, size: 14 }),
1156
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1157
- "input",
1158
- {
1159
- ref: searchBox,
1160
- type: "search",
1161
- value: query,
1162
- placeholder: t("search"),
1163
- "aria-label": t("search"),
1164
- onChange: (e) => setQuery(e.target.value),
1165
- onBlur: () => {
1166
- if (!query) setSearching(false);
1167
- },
1168
- onKeyDown: (e) => {
1169
- if (e.key === "Escape") {
1170
- setQuery("");
1171
- setSearching(false);
1172
- }
1173
- }
1174
- }
1175
- ),
1176
- query && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1177
- "button",
1178
- {
1179
- type: "button",
1180
- "aria-label": t("search.clear"),
1181
- onClick: () => {
1182
- setQuery("");
1183
- searchBox.current?.focus();
1184
- },
1185
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.clear, size: 12 })
1186
- }
1187
- )
1188
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-tool", "aria-label": t("search"), title: t("search"), onClick: () => setSearching(true), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.search, size: 18 }) }),
1189
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-tool", "aria-label": t("filter.button"), title: t("filter.button"), "aria-haspopup": "menu", "aria-expanded": popup?.kind === "filter", "data-active": isFiltered(filters), onClick: (e) => toggle("filter", e.currentTarget), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.filter, size: 18 }) }),
1190
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1191
- "button",
1192
- {
1193
- type: "button",
1194
- className: "bda-tool",
1195
- "aria-label": t(layout === "grid" ? "view.list" : "view.grid"),
1196
- title: t(layout === "grid" ? "view.list" : "view.grid"),
1197
- onClick: () => {
1198
- const next = layout === "grid" ? "list" : "grid";
1199
- setLayout(next);
1200
- writeView(next);
1201
- },
1202
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: layout === "grid" ? ICON.list : ICON.grid, size: 18 })
1203
- }
1204
- ),
1205
- canCreate() && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-tool", "aria-label": t("create.new"), title: t("create.new"), "aria-haspopup": "menu", "aria-expanded": popup?.kind === "create", onClick: (e) => toggle("create", e.currentTarget), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { d: ICON.plus, size: 18 }) })
1206
- ] })
1207
- ] }),
1208
- tiles.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1209
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "bda-section-title", children: t("create.heading") }),
1210
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "bda-tiles", children: tiles.map((skill) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "bda-tile", "data-skill": skill, style: { "--bda-tint": tintOf(skill) }, onClick: () => create(skill), children: [
1211
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "bda-tile-art", children: [
1212
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { className: "bda-tile-squiggle", viewBox: "0 0 140 100", preserveAspectRatio: "xMidYMid slice", fill: "none", stroke: "currentColor", strokeWidth: "1.1", strokeDasharray: "0 3.2", strokeLinecap: "round", "aria-hidden": "true", children: [
1213
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 84C20 16 42 98 62 42s38 58 74-28" }),
1214
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M6 88C24 22 44 104 66 46s36 56 72-26" }),
1215
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M2 80C18 12 40 92 58 38s40 58 76-28" })
1216
- ] }),
1217
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TypeIcon, { skill, size: 40 })
1218
- ] }),
1219
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "bda-tile-label", children: t(`type.${skill}`) })
1220
- ] }) }, skill)) })
1221
- ] }),
1222
- state.status === "loading" && state.artifacts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "bda-grid bda-skeleton", "aria-hidden": "true", children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { className: "bda-item", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-card", children: [
1223
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-preview" }),
1224
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "bda-line" })
1225
- ] }) }, i)) }) : state.status === "error" && state.artifacts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-empty", role: "alert", children: [
1226
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("load.error", { message: state.error }) }),
1227
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-retry", onClick: reloadArtifacts, children: t("load.retry") })
1228
- ] }) : state.artifacts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-empty", children: [
1229
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ArtifactsIcon, { size: 28 }),
1230
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("empty.title") }),
1231
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("empty.body") })
1232
- ] }) : shown.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "bda-empty", children: [
1233
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("empty.noMatches") }),
1234
- isFiltered(filters) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "bda-retry", onClick: () => setFilters({ ...NO_FILTERS, sort: filters.sort }), children: t("filter.clear") })
1235
- ] }) : layout === "grid" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "bda-grid", children: shown.map((view) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Card, { ...itemProps(view) }, view.root)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "bda-list", children: shown.map((view) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Row, { ...itemProps(view) }, view.root)) })
1236
- ] }) }),
1237
- popup?.kind === "filter" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FilterMenu, { anchor: popup.anchor, filters, setFilters, types, counts, t, onClose: closePopup }),
1238
- popup?.kind === "create" && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1239
- CreateMenu,
1240
- {
1241
- anchor: popup.anchor,
1242
- skills: tiles,
1243
- canCreate: canCreate(),
1244
- t,
1245
- onClose: closePopup,
1246
- create: (skill) => {
1247
- setPopup(null);
1248
- create(skill);
1249
- }
1250
- }
1251
- ),
1252
- popup?.kind === "actions" && actionsFor && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1253
- ActionsMenu,
1254
- {
1255
- anchor: popup.anchor,
1256
- view: actionsFor,
1257
- t,
1258
- onClose: closePopup,
1259
- act: (what) => {
1260
- setPopup(null);
1261
- if (what === "pin") pin(actionsFor, !actionsFor.pinned);
1262
- else if (what === "copy") copyLink(actionsFor);
1263
- else setDialog({ kind: what, root: actionsFor.root });
1264
- }
1265
- }
1266
- ),
1267
- dialog?.kind === "rename" && dialogFor && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1268
- RenameDialog,
1269
- {
1270
- view: dialogFor,
1271
- t,
1272
- onClose: () => setDialog(null),
1273
- onSave: (title) => {
1274
- setDialog(null);
1275
- rename(dialogFor, title);
1276
- }
1277
- }
1278
- ),
1279
- dialog?.kind === "delete" && dialogFor && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1280
- DeleteDialog,
1281
- {
1282
- view: dialogFor,
1283
- t,
1284
- onClose: () => setDialog(null),
1285
- onDelete: () => {
1286
- setDialog(null);
1287
- remove(dialogFor);
1288
- }
1289
- }
1290
- ),
1291
- state.toast && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToastBar, { toast: state.toast, t, onClose: dismissToast, onUndo: undo }, state.toast.id)
1292
- ] });
1293
- }
1294
- var SIDEBAR_WAIT_MS = 5e3;
1295
- async function openInSidebar(sidebar, sessionId, url) {
1296
- if (typeof sidebar.tabsIn !== "function") {
1297
- sidebar.openTabIn(sessionId, "browser", { params: { url } });
1298
- return true;
1299
- }
1300
- const browsers = () => sidebar.tabsIn(sessionId).filter((tab) => tab.kind === "browser").length;
1301
- const deadline = Date.now() + SIDEBAR_WAIT_MS;
1302
- for (; ; ) {
1303
- const before = browsers();
1304
- sidebar.openTabIn(sessionId, "browser", { params: { url } });
1305
- if (browsers() > before) return true;
1306
- if (Date.now() >= deadline) return false;
1307
- await new Promise((resolve) => setTimeout(resolve, 100));
1308
- }
1309
- }
1310
- var route = (path) => path.slice(1);
1311
- function mountPage(ctx, h, self) {
1312
- const disposers = [];
1313
- const style = typeof document === "undefined" ? null : document.createElement("style");
1314
- if (style) {
1315
- style.dataset.pluginCss = "baoyu-design/artifacts-page.css";
1316
- style.textContent = CSS;
1317
- document.head.appendChild(style);
1318
- disposers.push(() => style.remove());
1319
- }
1320
- disposers.push(ctx.locale.register(NS, { zh, en }));
1321
- const t = ctx.locale.bind?.(NS) ?? ((key) => en[key] ?? key);
1322
- const skillsOn = () => [...new Set([...h.members.values()].map((m) => m.skill))];
1323
- const store = createStore({ status: "loading", artifacts: [], error: "", skills: skillsOn(), opening: null, toast: null });
1324
- const onMembers = () => store.set({ skills: skillsOn() });
1325
- h.listeners.add(onMembers);
1326
- disposers.push(() => h.listeners.delete(onMembers));
1327
- let toastId = 0;
1328
- const toast = (message, kind = "info", undo2) => store.set({ toast: { id: ++toastId, message, kind, ...undo2 ? { undo: undo2 } : {} } });
1329
- const failed = (error) => toast(t("action.failed", { message: error.message }), "error");
1330
- const patchView = (root, patch) => store.set({ artifacts: store.getSnapshot().artifacts.map((a) => a.root === root ? { ...a, ...patch } : a) });
1331
- const call = async (path, params, init = { method: "POST" }) => {
1332
- const response = await fetch(`${route(path)}?${new URLSearchParams(params)}`, init);
1333
- const body = await response.json().catch(() => ({}));
1334
- if (!response.ok) throw new Error(typeof body.error === "string" ? body.error : `HTTP ${response.status}`);
1335
- return body;
1336
- };
1337
- const ownPluginOn = (view) => {
1338
- if (skillsOn().includes(view.skill)) return true;
1339
- toast(t("open.pluginOff", { plugin: view.plugin }), "error");
1340
- return false;
1341
- };
1342
- let pump = () => {
1343
- };
1344
- let loading = null;
1345
- const reload = () => {
1346
- if (loading) return;
1347
- if (store.getSnapshot().artifacts.length === 0) store.set({ status: "loading" });
1348
- const order = [self, ...skillsOn().filter((s) => s !== self)];
1349
- loading = (async () => {
1350
- let message = "";
1351
- for (const skill of order) {
1352
- try {
1353
- const response = await fetch(route(listPath(skill)), { cache: "no-store" });
1354
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
1355
- const body = await response.json();
1356
- const artifacts = Array.isArray(body.artifacts) ? body.artifacts.filter((a) => a && typeof a.root === "string") : [];
1357
- store.set({ status: "ready", artifacts, error: "" });
1358
- pump();
1359
- return;
1360
- } catch (error) {
1361
- message ||= error.message;
1362
- }
1363
- }
1364
- store.set({ status: "error", error: message });
1365
- })().finally(() => {
1366
- loading = null;
1367
- });
1368
- };
1369
- const open = (view) => {
1370
- if (store.getSnapshot().opening !== null) return;
1371
- if (!ownPluginOn(view)) return;
1372
- store.set({ opening: view.root, toast: null });
1373
- void (async () => {
1374
- try {
1375
- const response = await fetch(`${route(openPath(view.skill))}?${new URLSearchParams({ root: view.root })}`, { method: "POST" });
1376
- const body = await response.json().catch(() => ({}));
1377
- if (!response.ok || typeof body.url !== "string") throw new Error(typeof body.error === "string" ? body.error : `HTTP ${response.status}`);
1378
- const url = body.url;
1379
- const sessionId = typeof body.sessionId === "string" ? body.sessionId : view.sessionId;
1380
- const sessions = ctx.get("sessions");
1381
- const workspaces = ctx.get("workspaces");
1382
- const workspace = ctx.get("uiWorkspace");
1383
- const sidebar = ctx.get("sidebarRight");
1384
- const tabs = ctx.get("sidebarRightTabs");
1385
- const reachable = workspace !== void 0 && linkState(sessionId, sessions?.list?.getSnapshot(), workspaces?.list?.getSnapshot()) === "available";
1386
- if (reachable) {
1387
- workspace.openSession(sessionId);
1388
- const shown = sidebar !== void 0 && tabs?.get("browser") !== void 0 && await openInSidebar(sidebar, sessionId, url);
1389
- if (!shown) window.open(url, "_blank", "noopener,noreferrer");
1390
- store.set({ opening: null });
1391
- } else {
1392
- window.open(url, "_blank", "noopener,noreferrer");
1393
- store.set({ opening: null });
1394
- toast(t("open.noSession"));
1395
- }
1396
- reload();
1397
- } catch (error) {
1398
- store.set({ opening: null });
1399
- toast(t("open.failed", { message: error.message }), "error");
1400
- }
1401
- })();
1402
- };
1403
- const workspaceNav = () => ctx.get("uiWorkspace");
1404
- const canCreate = () => typeof workspaceNav()?.startSession === "function";
1405
- const createOptions = () => canCreate() ? creatable(skillsOn()) : [];
1406
- const create = (skill) => {
1407
- const nav = workspaceNav();
1408
- if (typeof nav?.startSession !== "function") return;
1409
- if (skill === void 0 || !isSkill(skill)) return nav.startSession();
1410
- nav.startSession(void 0, { prompt: promptFor(skill, t), whenDraftExists: "append" });
1411
- };
1412
- const pin = (view, pinned) => {
1413
- if (!ownPluginOn(view)) return;
1414
- patchView(view.root, { pinned });
1415
- call(updatePath(view.skill), { root: view.root }, { method: "POST", body: JSON.stringify({ pinned }) }).catch((error) => {
1416
- patchView(view.root, { pinned: view.pinned });
1417
- failed(error);
1418
- });
1419
- };
1420
- const rename = (view, title) => {
1421
- if (!ownPluginOn(view)) return;
1422
- patchView(view.root, { title });
1423
- call(updatePath(view.skill), { root: view.root }, { method: "POST", body: JSON.stringify({ title }) }).then(reload, (error) => {
1424
- patchView(view.root, { title: view.title });
1425
- failed(error);
1426
- });
1427
- };
1428
- const copyText = async (text) => {
1429
- try {
1430
- await navigator.clipboard.writeText(text);
1431
- } catch {
1432
- const area = document.createElement("textarea");
1433
- area.value = text;
1434
- area.style.cssText = "position:fixed;opacity:0";
1435
- document.body.append(area);
1436
- area.select();
1437
- const done = document.execCommand("copy");
1438
- area.remove();
1439
- if (!done) throw new Error("the clipboard refused it");
1440
- }
1441
- };
1442
- const copyLink = (view) => {
1443
- if (!ownPluginOn(view)) return;
1444
- void (async () => {
1445
- try {
1446
- const { url } = await call(previewPath(view.skill), { root: view.root });
1447
- await call(releasePath(view.skill), { root: view.root, keep: "1" });
1448
- if (typeof url !== "string") throw new Error("no address");
1449
- await copyText(url);
1450
- toast(t("toast.copied"));
1451
- } catch (error) {
1452
- failed(error);
1453
- }
1454
- })();
1455
- };
1456
- const remove = (view) => {
1457
- if (!ownPluginOn(view)) return;
1458
- void (async () => {
1459
- try {
1460
- const { trash, moved } = await call(deletePath(view.skill), { root: view.root });
1461
- store.set({ artifacts: store.getSnapshot().artifacts.filter((a) => a.root !== view.root) });
1462
- undoVia.set(String(trash), view.skill);
1463
- toast(t(moved === true ? "toast.deleted" : "toast.removed", { title: view.title }), "info", String(trash));
1464
- } catch (error) {
1465
- failed(error);
1466
- }
1467
- })();
1468
- };
1469
- const undoVia = /* @__PURE__ */ new Map();
1470
- const undo = (id) => {
1471
- store.set({ toast: null });
1472
- call(restorePath(undoVia.get(id) ?? self), { trash: id }).then(reload, failed);
1473
- };
1474
- const thumbnailUrl = (view) => view.thumbnail === null ? null : `${route(thumbnailPath(self))}?${new URLSearchParams({ root: view.root, v: view.thumbnail })}`;
1475
- const browser = desktopBrowser();
1476
- const tried = /* @__PURE__ */ new Set();
1477
- let watching = null;
1478
- let taking = false;
1479
- const takeOne = async (view, signal) => {
1480
- const { url } = await call(previewPath(view.skill), { root: view.root });
1481
- if (typeof url !== "string") throw new Error("no address");
1482
- try {
1483
- const bytes = await captureThumbnail(browser, url, view.skill, signal);
1484
- const saved = await call(thumbnailPath(view.skill), { root: view.root }, { method: "POST", headers: { "content-type": "image/jpeg" }, body: new Uint8Array(bytes) });
1485
- if (typeof saved.thumbnail === "string") patchView(view.root, { thumbnail: saved.thumbnail, updatedAt: saved.thumbnail });
1486
- } finally {
1487
- await call(releasePath(view.skill), { root: view.root }).catch(() => null);
1488
- }
1489
- };
1490
- pump = () => {
1491
- if (taking || watching === null || browser === void 0) return;
1492
- const signal = watching.signal;
1493
- taking = true;
1494
- void (async () => {
1495
- try {
1496
- for (; ; ) {
1497
- if (signal.aborted) return;
1498
- if (document.visibilityState !== "visible") return;
1499
- const on = skillsOn();
1500
- const next = store.getSnapshot().artifacts.find((a) => a.thumbnail !== a.updatedAt && on.includes(a.skill) && !tried.has(`${a.root}\0${a.updatedAt}`));
1501
- if (next === void 0) return;
1502
- tried.add(`${next.root}\0${next.updatedAt}`);
1503
- try {
1504
- await takeOne(next, signal);
1505
- } catch (error) {
1506
- if (!signal.aborted) console.warn(`baoyu-design Artifacts page: no thumbnail for ${next.root}:`, error);
1507
- }
1508
- }
1509
- } finally {
1510
- taking = false;
1511
- }
1512
- })();
1513
- };
1514
- const watchThumbnails = () => {
1515
- const controller = new AbortController();
1516
- watching = controller;
1517
- pump();
1518
- return () => {
1519
- controller.abort(new Error("the page closed"));
1520
- if (watching === controller) watching = null;
1521
- };
1522
- };
1523
- disposers.push(() => watching?.abort(new Error("the plugin stopped")));
1524
- const sessionsStore = () => {
1525
- const list = ctx.get("sessions")?.list;
1526
- return isStore(list) ? list : EMPTY_SESSIONS;
1527
- };
1528
- disposers.push(toDisposer(ctx.slots.inject(
1529
- "main",
1530
- () => ctx.slots.register(
1531
- {
1532
- name: "main",
1533
- key: PANEL_ID,
1534
- locale: NS,
1535
- inject: () => ({
1536
- artifactsStore: store,
1537
- sessionsStore: sessionsStore(),
1538
- reloadArtifacts: reload,
1539
- openArtifact: open,
1540
- create,
1541
- canCreate,
1542
- createOptions,
1543
- pin,
1544
- rename,
1545
- copyLink,
1546
- remove,
1547
- undo,
1548
- thumbnailUrl,
1549
- watchThumbnails,
1550
- dismissToast: () => store.set({ toast: null })
1551
- })
1552
- },
1553
- ArtifactsPage
1554
- )
1555
- )));
1556
- disposers.push(toDisposer(ctx.slots.inject(
1557
- "sidebar.panellist",
1558
- () => ctx.slots.register(
1559
- { name: "sidebar.panellist", id: PANEL_ID, order: 20, locale: NS, label: () => t("panel") },
1560
- ArtifactsIcon
1561
- )
1562
- )));
1563
- return () => {
1564
- for (const dispose of disposers.splice(0).reverse()) {
1565
- try {
1566
- dispose();
1567
- } catch (error) {
1568
- console.error("baoyu-design Artifacts page: unregistering failed:", error);
1569
- }
1570
- }
1571
- };
1572
- }
1573
- function toDisposer(value) {
1574
- return typeof value === "function" ? value : () => {
1575
- };
1576
- }
1577
- function joinArtifactsPage(ctx, plugin, skill) {
1578
- const h = hub();
1579
- h.members.set(plugin, { plugin, skill, version: PAGE_VERSION, mount: () => mountPage(ctx, h, skill) });
1580
- settle(h);
1581
- changed(h);
1582
- ctx.effect(() => () => {
1583
- h.members.delete(plugin);
1584
- if (h.owner?.plugin === plugin) {
1585
- const old = h.owner;
1586
- h.owner = null;
1587
- old.dispose();
1588
- }
1589
- settle(h);
1590
- changed(h);
1591
- }, `${plugin}: Artifacts page`);
1592
- }
1593
-
1594
- var import_jsx_runtime2 = require("react/jsx-runtime");
1595
- var CLIENT = define_CLIENT_default;
1596
- var COMMENT_SOURCE = "baoyu-design-comment";
1597
- var KIND = `${CLIENT.key}:comment`;
1598
- var NS2 = CLIENT.key;
1599
- var zh2 = {
1600
- "card.title": "已将对“{title}”的评论发给 Agent",
1601
- "card.request": "已将“{title}”上的 {label} 发给 Agent",
1602
- "card.view": "查看评论",
1603
- "card.more": "显示位置",
1604
- "card.less": "收起位置"
1605
- };
1606
- var en2 = {
1607
- "card.title": "Comment on “{title}” sent to agent",
1608
- "card.request": "{label} on “{title}” sent to agent",
1609
- "card.view": "View thread",
1610
- "card.more": "Show where",
1611
- "card.less": "Hide where"
1612
- };
1613
- var str = (value) => typeof value === "string" ? value : "";
1614
- function ours(event) {
1615
- if (event.type !== "user/message" || event.surfaceOp !== "append") return false;
1616
- const source = event.data?.source;
1617
- return source?.kind === COMMENT_SOURCE && source.plugin === CLIENT.plugin;
1618
- }
1619
- function cardData(event) {
1620
- const source = event.data?.source ?? {};
1621
- const threads = Array.isArray(source.threads) ? source.threads : [];
1622
- const requests = Array.isArray(source.requests) ? source.requests : [];
1623
- return {
1624
- title: str(source.title),
1625
- url: str(source.url),
1626
- threads: threads.map((t) => ({ id: str(t.id), where: str(t.where), text: str(t.text) })).filter((t) => t.id),
1627
- requests: requests.map((r) => ({ id: str(r.id), label: str(r.label), text: str(r.text) })).filter((r) => r.id && r.text),
1628
- seq: event.seq
1629
- };
1630
- }
1631
- var definition = {
1632
- kind: KIND,
1633
- target: "chat",
1634
- match: (event) => (
1635
- // Claimed: the built-in input-message Definition would draw it as a context row.
1636
- ours(event) ? { id: String(event.data?.id), role: "start", exclusive: true } : null
1637
- ),
1638
- start: (_context, match) => cardData(match.event),
1639
- update: (context) => context.state,
1640
- buildViewNode: (context) => {
1641
- if (context.state === void 0) return null;
1642
- return {
1643
- key: context.key,
1644
- kind: KIND,
1645
- id: context.id,
1646
- target: "chat",
1647
- anchorSeq: context.state.seq,
1648
- location: context.start?.location ?? context.matches[0]?.location ?? { kind: "unresolved" },
1649
- visibility: "visible",
1650
- // A person's input, as a user message: it opens the agent's reply below it.
1651
- groupTree: "input",
1652
- data: context.state
1653
- };
1654
- }
1655
- };
1656
- var CSS2 = `
1657
- .bdc-row{display:flex;flex-direction:column;align-items:flex-end;gap:8px;width:100%}
1658
- .bdc-card{box-sizing:border-box;max-width:min(calc(var(--dsh-chat-content-width, 748px) * 0.702), 82%);min-width:min(320px, 82%);
1659
- border:0.5px solid var(--dsw-alias-border-l1);border-radius:var(--dsw-radius-xl, 12px);background:var(--dsw-alias-markdown-code-block);
1660
- color:var(--dsw-alias-label-primary);padding:10px 14px 12px;display:flex;flex-direction:column;gap:6px}
1661
- .bdc-head{display:flex;align-items:center;gap:6px;color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xxs-12, 12px/18px sans-serif)}
1662
- .bdc-head svg{flex:none}
1663
- .bdc-head-text{flex:1;min-width:0;display:flex;white-space:nowrap;overflow:hidden}
1664
- .bdc-head-text>span{flex:none}
1665
- .bdc-head-text>.bdc-head-title{flex:0 1 auto;min-width:1.5em;overflow:hidden;text-overflow:ellipsis}
1666
- .bdc-toggle{flex:none;display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:-2px -4px -2px 0;
1667
- border:0;border-radius:var(--dsw-radius-sm, 6px);background:none;color:inherit;cursor:pointer;padding:0}
1668
- .bdc-toggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}
1669
- .bdc-toggle svg{transition:transform .15s}
1670
- .bdc-toggle[aria-expanded=false] svg{transform:rotate(-90deg)}
1671
- .bdc-body{font-size:var(--dsh-content-font-size, 14px);line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere}
1672
- .bdc-meta{display:flex;flex-direction:column;gap:6px;padding-top:6px;border-top:0.5px solid var(--dsw-alias-border-l1)}
1673
- .bdc-where{color:var(--dsw-alias-label-tertiary);font:var(--dsw-font-xxs-12, 12px/18px sans-serif);overflow-wrap:anywhere}
1674
- .bdc-view{align-self:flex-start;display:inline-flex;align-items:center;gap:2px;height:24px;margin-left:-6px;padding:0 6px;border:0;
1675
- border-radius:var(--dsw-radius-sm, 6px);background:none;color:var(--dsw-alias-label-secondary);font:var(--dsw-font-xxs-12, 12px/18px sans-serif);cursor:pointer}
1676
- .bdc-view:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
1677
- .bdc-view:focus-visible,.bdc-toggle:focus-visible{outline:var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));outline-offset:1px}
1678
- @media (prefers-reduced-motion:reduce){.bdc-toggle svg{transition:none}}
1679
- `;
1680
- var iconStyle = { display: "block" };
1681
- var TITLE_MARK = "";
1682
- function CommentIcon() {
1683
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", style: iconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1684
- "path",
1685
- {
1686
- d: "M3 3.5h10a1 1 0 0 1 1 1v6a1 1 0 0 1-1 1H8.2L5.4 13.8a.3.3 0 0 1-.5-.23V11.5H3a1 1 0 0 1-1-1v-6a1 1 0 0 1 1-1Z",
1687
- stroke: "currentColor",
1688
- strokeWidth: "1.2",
1689
- strokeLinejoin: "round"
1690
- }
1691
- ) });
1692
- }
1693
- function RequestIcon() {
1694
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", style: iconStyle, children: [
1695
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("rect", { x: "2", y: "4", width: "12", height: "7", rx: "2", stroke: "currentColor", strokeWidth: "1.2" }),
1696
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M8.5 8.5 11 14l.9-2.1L14 11l-5.5-2.5Z", fill: "currentColor", stroke: "var(--dsw-alias-markdown-code-block, #fff)", strokeWidth: "0.8", strokeLinejoin: "round" })
1697
- ] });
1698
- }
1699
- function ChevronDown() {
1700
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", style: iconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3 4.5 6 7.5l3-3", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }) });
1701
- }
1702
- function ChevronRight() {
1703
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", style: iconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4.5 3 7.5 6l-3 3", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }) });
1704
- }
1705
- function Card2({ title, thread, url, t, openThread }) {
1706
- const [open, setOpen] = (0, import_react2.useState)(true);
1707
- const heading = t("card.title", { title });
1708
- const meta = !CLIENT.simple && (thread.where || url);
1709
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bdc-card", "data-comment-id": thread.id, children: [
1710
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bdc-head", children: [
1711
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CommentIcon, {}),
1712
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Heading, { text: heading, title, parts: t("card.title", { title: TITLE_MARK }).split(TITLE_MARK) }),
1713
- meta && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "bdc-toggle", "aria-expanded": open, "aria-label": t(open ? "card.less" : "card.more"), onClick: () => setOpen(!open), children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDown, {}) })
1714
- ] }),
1715
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "bdc-body", children: thread.text }),
1716
- meta && open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bdc-meta", children: [
1717
- thread.where && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "bdc-where", children: thread.where }),
1718
- url && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: "bdc-view", onClick: () => openThread(url, thread.id), children: [
1719
- t("card.view"),
1720
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronRight, {})
1721
- ] })
1722
- ] })
1723
- ] });
1724
- }
1725
- function Heading({ text, title, parts }) {
1726
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "bdc-head-text", title: text, children: parts.length === 2 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1727
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: parts[0] }),
1728
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "bdc-head-title", children: title }),
1729
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: parts[1] })
1730
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "bdc-head-title", children: text }) });
1731
- }
1732
- function RequestCardView({ title, request, t }) {
1733
- const label = request.label || "Request";
1734
- const heading = t("card.request", { title, label });
1735
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bdc-card", "data-request-id": request.id, children: [
1736
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bdc-head", children: [
1737
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RequestIcon, {}),
1738
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Heading, { text: heading, title, parts: t("card.request", { title: TITLE_MARK, label }).split(TITLE_MARK) })
1739
- ] }),
1740
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "bdc-body", children: request.text })
1741
- ] });
1742
- }
1743
- function CommentCards({ node, t, openThread }) {
1744
- const { title, url, threads, requests } = node.data;
1745
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "bdc-row", children: [
1746
- threads.map((thread) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Card2, { title, thread, url, t, openThread }, thread.id)),
1747
- (requests ?? []).map((request) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RequestCardView, { title, request, t }, request.id))
1748
- ] });
1749
- }
1750
- var inject = ["slots", "locale", "uiConversation"];
1751
- function threadUrl(url, id) {
1752
- try {
1753
- const at = new URL(url);
1754
- at.searchParams.set("comment", id);
1755
- return at.href;
1756
- } catch {
1757
- return url;
1758
- }
1759
- }
1760
- function apply(ctx) {
1761
- ctx.effect(() => {
1762
- if (typeof document === "undefined") return () => {
1763
- };
1764
- const id = `${CLIENT.plugin}/comment-card.css`;
1765
- if (document.querySelector(`style[data-plugin-css=${JSON.stringify(id)}]`)) return () => {
1766
- };
1767
- const tag = document.createElement("style");
1768
- tag.dataset.plugin = CLIENT.plugin;
1769
- tag.dataset.pluginCss = id;
1770
- tag.textContent = CSS2;
1771
- document.head.appendChild(tag);
1772
- return () => tag.remove();
1773
- }, `${CLIENT.plugin}: comment card styles`);
1774
- ctx.effect(() => ctx.locale.register(NS2, { zh: zh2, en: en2 }), `${CLIENT.plugin}: dictionaries`);
1775
- ctx.uiConversation.events.register(definition);
1776
- ctx.slots.inject(
1777
- "conversation.chat.node",
1778
- () => ctx.slots.register(
1779
- {
1780
- name: "conversation.chat.node",
1781
- key: KIND,
1782
- locale: NS2,
1783
- inject: (sessionId) => ({
1784
- openThread: (url, threadId) => {
1785
- const target = threadUrl(url, threadId);
1786
- const sidebar = ctx.get("sidebarRight");
1787
- const tabs = ctx.get("sidebarRightTabs");
1788
- if (sidebar && tabs?.get("browser") !== void 0) sidebar.openTabIn(sessionId, "browser", { params: { url: target } });
1789
- else window.open(target, "_blank", "noopener,noreferrer");
1790
- }
1791
- })
1792
- },
1793
- CommentCards
1794
- )
1795
- );
1796
- joinArtifactsPage(ctx, CLIENT.plugin, CLIENT.skill);
1797
- }
1798
- return module.exports;
1799
- }
1800
- });