@deepblend/dsh-blender-ui 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +235 -93
- package/package.json +2 -2
package/lib/client.js
CHANGED
|
@@ -108,6 +108,19 @@ window.__ModuleLoader__.load({
|
|
|
108
108
|
// `contract/workbench-copy.test.mjs`, so a missing key cannot leave a hole in either direction.
|
|
109
109
|
const STRINGS = {
|
|
110
110
|
zh: {
|
|
111
|
+
'workbench.appearance': '外观',
|
|
112
|
+
'workbench.system': '跟随系统',
|
|
113
|
+
'workbench.light': '浅色',
|
|
114
|
+
'workbench.dark': '深色',
|
|
115
|
+
'workbench.navigation': '工作台页面',
|
|
116
|
+
'workbench.unsaved': '有未保存的修改',
|
|
117
|
+
'projects.name': '作品名称',
|
|
118
|
+
'projects.storage': '项目存储位置',
|
|
119
|
+
'projects.startHint': '选择一个作品起点,调整参数,再创建自己的项目。',
|
|
120
|
+
'guide.notes': '使用说明与当前进度',
|
|
121
|
+
'scene.outline': '场景内容',
|
|
122
|
+
'scene.inspector': '编辑与素材',
|
|
123
|
+
|
|
111
124
|
'inspection.mismatch': '检查回执与请求的版本、相机或帧不一致,未标记为成功。',
|
|
112
125
|
'inspection.cameraUnavailable': '{camera}(当前版本不可用)',
|
|
113
126
|
"inspection.title": "固定视角检查",
|
|
@@ -513,9 +526,10 @@ window.__ModuleLoader__.load({
|
|
|
513
526
|
'jobs.provenanceMissing': '{count} 帧尚未完成',
|
|
514
527
|
'jobs.cancel': '取消',
|
|
515
528
|
'jobs.resume': '继续渲染',
|
|
516
|
-
'jobs.startDelivery': '
|
|
517
|
-
'jobs.frameStart': '
|
|
518
|
-
'jobs.frameEnd': '
|
|
529
|
+
'jobs.startDelivery': '启动交付渲染',
|
|
530
|
+
'jobs.frameStart': '起始帧',
|
|
531
|
+
'jobs.frameEnd': '结束帧',
|
|
532
|
+
'jobs.profile': '渲染配置',
|
|
519
533
|
'jobs.start': '启动',
|
|
520
534
|
'qa.passed': '技术校验通过',
|
|
521
535
|
'qa.none': '无技术校验记录',
|
|
@@ -621,6 +635,19 @@ window.__ModuleLoader__.load({
|
|
|
621
635
|
'revisions.title': '版本({count})',
|
|
622
636
|
},
|
|
623
637
|
en: {
|
|
638
|
+
'workbench.appearance': 'Appearance',
|
|
639
|
+
'workbench.system': 'System',
|
|
640
|
+
'workbench.light': 'Light',
|
|
641
|
+
'workbench.dark': 'Dark',
|
|
642
|
+
'workbench.navigation': 'Workbench pages',
|
|
643
|
+
'workbench.unsaved': 'Unsaved changes',
|
|
644
|
+
'projects.name': 'Project name',
|
|
645
|
+
'projects.storage': 'Project storage',
|
|
646
|
+
'projects.startHint': 'Choose a starting point, adjust its parameters, and create your own project.',
|
|
647
|
+
'guide.notes': 'Guidance and current progress',
|
|
648
|
+
'scene.outline': 'Scene contents',
|
|
649
|
+
'scene.inspector': 'Editing and assets',
|
|
650
|
+
|
|
624
651
|
'inspection.mismatch': 'The inspection receipt does not match the requested revision, camera or frame; success was not recorded.',
|
|
625
652
|
'inspection.cameraUnavailable': '{camera} (unavailable in this revision)',
|
|
626
653
|
"inspection.title": "Inspect a fixed view",
|
|
@@ -1026,9 +1053,10 @@ window.__ModuleLoader__.load({
|
|
|
1026
1053
|
'jobs.provenanceMissing': '{count} frames not completed',
|
|
1027
1054
|
'jobs.cancel': 'Cancel',
|
|
1028
1055
|
'jobs.resume': 'Resume render',
|
|
1029
|
-
'jobs.startDelivery': 'Start a delivery render
|
|
1056
|
+
'jobs.startDelivery': 'Start a delivery render',
|
|
1030
1057
|
'jobs.frameStart': 'from frame',
|
|
1031
1058
|
'jobs.frameEnd': 'to frame',
|
|
1059
|
+
'jobs.profile': 'Render profile',
|
|
1032
1060
|
'jobs.start': 'Start',
|
|
1033
1061
|
'qa.passed': 'technical checks passed',
|
|
1034
1062
|
'qa.none': 'no technical check recorded',
|
|
@@ -1292,55 +1320,130 @@ window.__ModuleLoader__.load({
|
|
|
1292
1320
|
// one <style> tagged with this package, deduped by querySelector.
|
|
1293
1321
|
// =========================================================================
|
|
1294
1322
|
|
|
1323
|
+
// Existing project mark: deepblend/docs/brand/logo.svg (MIT), embedded for offline loading.
|
|
1324
|
+
const BRAND_MARK = 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22512%22%20height%3D%22512%22%20viewBox%3D%220%200%20512%20512%22%20role%3D%22img%22%20aria-label%3D%22DeepBlend%20Studio%20logo%22%3E%0A%20%20%3Ctitle%3EDeepBlend%20Studio%3C%2Ftitle%3E%0A%20%20%3Cdefs%3E%0A%20%20%20%20%3ClinearGradient%20id%3D%22mark%22%20x1%3D%220.1%22%20y1%3D%220%22%20x2%3D%220.85%22%20y2%3D%221%22%3E%0A%20%20%20%20%20%20%3Cstop%20offset%3D%220%22%20stop-color%3D%22%23FFC078%22%2F%3E%0A%20%20%20%20%20%20%3Cstop%20offset%3D%220.45%22%20stop-color%3D%22%23F2802A%22%2F%3E%0A%20%20%20%20%20%20%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23C85C08%22%2F%3E%0A%20%20%20%20%3C%2FlinearGradient%3E%0A%20%20%3C%2Fdefs%3E%0A%20%20%3Crect%20width%3D%22512%22%20height%3D%22512%22%20rx%3D%22112%22%20fill%3D%22url%28%23mark%29%22%2F%3E%0A%20%20%3Cg%20stroke%3D%22%23FFFFFF%22%20stroke-width%3D%2211%22%20stroke-linejoin%3D%22round%22%20stroke-linecap%3D%22round%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M256%20106%20L386%20181%20L386%20331%20L256%20406%20L126%20331%20L126%20181%20Z%22%20fill%3D%22%23FFFFFF%22%20fill-opacity%3D%220.14%22%2F%3E%0A%20%20%20%20%3Cpath%20d%3D%22M256%20106%20L386%20181%20L256%20256%20L126%20181%20Z%22%20fill%3D%22%23FFFFFF%22%20fill-opacity%3D%220.34%22%20stroke%3D%22none%22%2F%3E%0A%20%20%20%20%3Cpath%20d%3D%22M256%20256%20L126%20181%20L126%20331%20L256%20406%20Z%22%20fill%3D%22%237A3200%22%20fill-opacity%3D%220.16%22%20stroke%3D%22none%22%2F%3E%0A%20%20%20%20%3Cpath%20d%3D%22M256%20256%20L386%20181%20L386%20331%20L256%20406%20Z%22%20fill%3D%22%235C2400%22%20fill-opacity%3D%220.22%22%20stroke%3D%22none%22%2F%3E%0A%20%20%20%20%3Cpath%20d%3D%22M256%20106%20L386%20181%20L386%20331%20L256%20406%20L126%20331%20L126%20181%20Z%22%20fill%3D%22none%22%20opacity%3D%220.93%22%2F%3E%0A%20%20%20%20%3Cpath%20d%3D%22M256%20256%20L256%20106%20M256%20256%20L386%20331%20M256%20256%20L126%20331%22%20fill%3D%22none%22%20opacity%3D%220.93%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A'
|
|
1325
|
+
|
|
1295
1326
|
const CSS = `
|
|
1296
|
-
.db-root{display:flex;flex-direction:column;height:100%;min-height:0;color:var(--
|
|
1297
|
-
.db-
|
|
1298
|
-
.db-
|
|
1299
|
-
.db-
|
|
1300
|
-
.db-
|
|
1301
|
-
.db-
|
|
1302
|
-
.db-
|
|
1303
|
-
.db-
|
|
1304
|
-
.db-
|
|
1305
|
-
.db-
|
|
1306
|
-
.db-
|
|
1307
|
-
.db-
|
|
1308
|
-
.db-
|
|
1309
|
-
.db-
|
|
1327
|
+
.db-root{container-type:inline-size;container-name:deepblend;--db-good:#23704e;--db-warn:#946109;--db-bad:#b0303c;--db-input-border:#8492a5;--db-accent:#b95516;--db-accent-soft:#f8e9de;--db-canvas:var(--dsw-alias-bg-layer-1);--db-surface:var(--dsw-alias-bg-layer-1);--db-border:var(--dsw-alias-border-l1);--db-fill:var(--dsw-alias-fill-l2);--db-text:var(--dsw-alias-label-primary);--db-subtle:var(--dsw-alias-label-secondary);--db-muted:var(--dsw-alias-label-secondary);display:flex;flex-direction:column;height:100%;min-height:0;min-width:0;background:var(--db-canvas);color:var(--db-text);font:13px/1.55 var(--dsw-font-sans,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif)}
|
|
1328
|
+
.db-root[data-theme=light],.db-root[data-theme=system]{color-scheme:light;--db-canvas:#f1f3f6;--db-surface:#fff;--db-border:#dce1e8;--db-fill:#f0f3f7;--db-text:#202b3c;--db-subtle:#4e5d70;--db-muted:#637186}
|
|
1329
|
+
.db-root[data-theme=dark]{color-scheme:dark;--db-canvas:#10151d;--db-surface:#19212d;--db-border:#334155;--db-fill:#253142;--db-text:#edf2f8;--db-subtle:#c2ccda;--db-muted:#a2afc1;--db-good:#77c9a0;--db-warn:#efbc73;--db-bad:#ff979c;--db-input-border:#657692;--db-accent:#f3a365;--db-accent-soft:#3c2d23}
|
|
1330
|
+
.db-root *{box-sizing:border-box}
|
|
1331
|
+
.db-head{display:flex;align-items:center;gap:12px;padding:14px 20px;border-bottom:1px solid var(--db-border,var(--dsw-alias-border-l1));background:var(--db-surface,var(--dsw-alias-bg-layer-1));flex:none;flex-wrap:wrap}
|
|
1332
|
+
.db-brand{display:flex;align-items:center;gap:10px;flex:none}
|
|
1333
|
+
.db-logo{width:34px;height:34px;border-radius:9px}
|
|
1334
|
+
.db-title{margin:0;font-size:16px;font-weight:650;line-height:1.25;letter-spacing:-.3px}
|
|
1335
|
+
.db-brand small{display:block;font-size:11px;color:var(--db-muted);margin-top:3px}
|
|
1336
|
+
.db-project-context{display:flex;align-items:center;gap:8px;min-width:0;max-width:35%;padding-left:16px;border-left:1px solid var(--db-border)}
|
|
1337
|
+
.db-project-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:600}
|
|
1338
|
+
.db-head-actions{display:flex;align-items:center;gap:8px;margin-left:auto;flex-wrap:wrap}
|
|
1339
|
+
.db-theme{width:auto!important;min-width:94px}
|
|
1340
|
+
.db-muted{color:var(--db-muted,var(--dsw-alias-label-secondary))}
|
|
1341
|
+
.db-mono{font-family:var(--dsw-font-mono,ui-monospace,monospace)}
|
|
1342
|
+
.db-nav{display:flex;gap:6px;padding:8px 20px;border-bottom:1px solid var(--db-border);background:var(--db-surface);flex:none;overflow-x:auto;scrollbar-width:thin}
|
|
1343
|
+
.db-nav button{background:transparent;border:1px solid transparent;border-radius:7px;color:var(--db-subtle);cursor:pointer;font:inherit;min-height:34px;padding:6px 14px;white-space:nowrap;flex:none}
|
|
1344
|
+
.db-nav button:hover{background:var(--db-fill);color:var(--db-text)}
|
|
1345
|
+
.db-nav button[data-active=true]{background:var(--db-accent-soft);border-color:var(--db-accent);color:var(--db-accent);font-weight:650}
|
|
1346
|
+
.db-tabs{display:flex;gap:8px;padding:2px 0 12px;flex:none;flex-wrap:wrap;align-items:center}
|
|
1347
|
+
.db-body{flex:1;min-height:0;overflow:auto;padding:20px 24px 32px;scrollbar-width:thin;scrollbar-color:var(--db-border) transparent;scroll-padding:16px}
|
|
1348
|
+
.db-body>[data-view],.db-body>.db-guide{max-width:1440px;margin-left:auto;margin-right:auto}
|
|
1349
|
+
.db-card{background:var(--db-surface,var(--dsw-alias-bg-layer-1));border:1px solid var(--db-border,var(--dsw-alias-border-l1));border-radius:12px;padding:16px 18px;margin-bottom:14px;min-width:0}
|
|
1350
|
+
.db-card h4{margin:0 0 12px;font-size:14px;font-weight:650;color:var(--db-text,var(--dsw-alias-label-primary))}
|
|
1351
|
+
.db-card h5{margin:10px 0 8px;font-size:13px;font-weight:650}
|
|
1352
|
+
.db-card p{margin:8px 0 12px}
|
|
1353
|
+
.db-row{display:flex;gap:12px;align-items:baseline;padding:4px 0;line-height:20px}
|
|
1354
|
+
.db-row>span:first-child{color:var(--db-muted,var(--dsw-alias-label-tertiary));flex:none;min-width:90px}
|
|
1310
1355
|
.db-row>span:last-child{min-width:0;overflow-wrap:anywhere;font-family:var(--dsw-font-mono);font-size:12px}
|
|
1311
|
-
.db-btn{background:var(--dsw-alias-fill-l2);border:1px solid var(--dsw-alias-border-l1);border-radius:
|
|
1312
|
-
.db-btn:disabled{
|
|
1313
|
-
.db-btn
|
|
1314
|
-
.db-btn
|
|
1315
|
-
.db-
|
|
1356
|
+
.db-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;background:var(--db-fill,var(--dsw-alias-fill-l2));border:1px solid var(--db-border,var(--dsw-alias-border-l1));border-radius:7px;color:var(--db-text,var(--dsw-alias-label-primary));cursor:pointer;font:inherit;font-size:12px;min-height:34px;padding:6px 12px;text-decoration:none;line-height:1.4}
|
|
1357
|
+
.db-btn:hover:not(:disabled){border-color:var(--db-accent,var(--dsw-alias-brand-primary));background:var(--db-accent-soft,var(--dsw-alias-fill-l2))}
|
|
1358
|
+
.db-btn:active:not(:disabled){filter:brightness(.95)}
|
|
1359
|
+
.db-btn:disabled{opacity:.48;cursor:not-allowed}
|
|
1360
|
+
.db-btn[data-tone=primary]{background:var(--db-accent,var(--dsw-alias-brand-primary,#3b6ef5));border-color:transparent;color:#fff;font-weight:650}
|
|
1361
|
+
.db-root[data-theme=dark] .db-btn[data-tone=primary]{color:#20170f}
|
|
1362
|
+
.db-btn[data-tone=danger]{color:var(--db-bad,var(--dsw-alias-label-error,#d13438))}
|
|
1363
|
+
.db-btn[aria-pressed=true]{border-color:var(--db-accent);background:var(--db-accent-soft);color:var(--db-accent)}
|
|
1364
|
+
.db-root :is(button,a,input,select,textarea,summary):focus-visible{outline:2px solid var(--db-accent);outline-offset:3px}
|
|
1365
|
+
.db-input,.db-area{background:var(--db-surface,var(--dsw-alias-bg-layer-1));border:1px solid var(--db-input-border,var(--dsw-alias-border-l1));border-radius:7px;color:inherit;font:inherit;font-size:13px;min-height:34px;padding:7px 10px;width:100%;box-sizing:border-box}
|
|
1366
|
+
.db-input:hover,.db-area:hover{border-color:var(--db-muted,var(--dsw-alias-label-secondary))}
|
|
1367
|
+
.db-input:disabled,.db-area:disabled{opacity:.55;background:var(--db-fill,var(--dsw-alias-fill-l2));cursor:not-allowed}
|
|
1316
1368
|
.db-area{font-family:var(--dsw-font-mono);min-height:150px;white-space:pre;overflow:auto}
|
|
1317
|
-
.db-inline{display:flex;gap:
|
|
1318
|
-
.db-
|
|
1319
|
-
.db-
|
|
1320
|
-
.db-
|
|
1321
|
-
.db-
|
|
1322
|
-
.db-
|
|
1323
|
-
.db-
|
|
1324
|
-
.db-
|
|
1369
|
+
.db-inline{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
|
|
1370
|
+
.db-inline>label{display:flex;flex-direction:column;gap:5px;min-width:0}
|
|
1371
|
+
.db-number-control{display:flex;flex-direction:column;gap:4px;min-width:0;max-width:160px}
|
|
1372
|
+
.db-input[aria-invalid=true]{border-color:var(--db-bad,var(--dsw-alias-label-error));background:var(--db-surface)}
|
|
1373
|
+
.db-field-feedback{font:11px/1.4 var(--dsw-font-sans,system-ui,sans-serif);color:var(--db-bad,var(--dsw-alias-label-error));white-space:normal}
|
|
1374
|
+
.db-field{display:flex;flex-direction:column;gap:6px;min-width:0;font-size:12px;font-weight:550}
|
|
1375
|
+
.db-field .db-input{font-weight:400}
|
|
1376
|
+
.db-badge{display:inline-flex;align-items:center;border-radius:5px;font-size:11px;line-height:18px;padding:2px 7px;border:1px solid var(--db-border,var(--dsw-alias-border-l1));color:var(--db-subtle,var(--dsw-alias-label-secondary));white-space:nowrap}
|
|
1377
|
+
.db-badge[data-tone=ok]{color:var(--db-good,var(--dsw-alias-label-success,#2f9e44));border-color:currentColor}
|
|
1378
|
+
.db-badge[data-tone=warn]{color:var(--db-warn,var(--dsw-alias-label-warning,#b8791b));border-color:currentColor}
|
|
1379
|
+
.db-badge[data-tone=bad]{color:var(--db-bad,var(--dsw-alias-label-error,#d13438));border-color:currentColor}
|
|
1380
|
+
.db-badge[data-tone=live]{color:var(--db-accent,var(--dsw-alias-brand-primary));border-color:currentColor}
|
|
1381
|
+
.db-bar{background:var(--db-fill,var(--dsw-alias-fill-l2));border-radius:999px;height:7px;overflow:hidden;width:100%;margin:8px 0}
|
|
1382
|
+
.db-bar>i{background:var(--db-accent,var(--dsw-alias-brand-primary));display:block;height:100%}
|
|
1325
1383
|
.db-list{list-style:none;margin:0;padding:0}
|
|
1326
|
-
.db-list>li{border-bottom:1px solid var(--dsw-alias-border-l1);padding:
|
|
1384
|
+
.db-list>li{border-bottom:1px solid var(--db-border,var(--dsw-alias-border-l1));padding:10px 0}
|
|
1327
1385
|
.db-list>li:last-child{border-bottom:0}
|
|
1328
|
-
.db-kind{color:var(--dsw-alias-label-tertiary);min-width:96px;display:inline-block}
|
|
1329
|
-
.db-error{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-label-error,#
|
|
1330
|
-
.db-grid{display:grid;gap:
|
|
1331
|
-
.db-shot{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:
|
|
1332
|
-
.db-shot img{display:block;width:100%;height:auto;border-radius:
|
|
1333
|
-
.db-shot h5{margin:0 0
|
|
1334
|
-
.db-chip{display:inline-flex;align-items:center;gap:
|
|
1335
|
-
.db-chip:hover{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}
|
|
1336
|
-
.db-dot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-tertiary);display:inline-block}
|
|
1337
|
-
.db-dot[data-tone=live]{background:var(--dsw-alias-brand-primary
|
|
1386
|
+
.db-kind{color:var(--db-muted,var(--dsw-alias-label-tertiary));min-width:96px;display:inline-block}
|
|
1387
|
+
.db-error{background:var(--db-surface,var(--dsw-alias-bg-layer-1));border:1px solid var(--db-bad,var(--dsw-alias-label-error,#d13438));border-radius:9px;color:var(--db-bad,var(--dsw-alias-label-error,#d13438));padding:12px 14px;margin-bottom:12px;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
1388
|
+
.db-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr))}
|
|
1389
|
+
.db-shot{background:var(--db-surface,var(--dsw-alias-bg-layer-1));border:1px solid var(--db-border,var(--dsw-alias-border-l1));border-radius:12px;padding:12px;min-width:0}
|
|
1390
|
+
.db-shot img{display:block;width:100%;height:auto;border-radius:8px;background:#0d1117}
|
|
1391
|
+
.db-shot h5{margin:0 0 10px;font-size:13px;font-weight:600}
|
|
1392
|
+
.db-chip{display:inline-flex;align-items:center;gap:6px;background:transparent;border:0;border-radius:7px;color:var(--db-subtle,var(--dsw-alias-label-secondary));cursor:pointer;font:inherit;font-size:12px;padding:6px 8px}
|
|
1393
|
+
.db-chip:hover{background:var(--db-fill,var(--dsw-alias-fill-l2));color:var(--db-text,var(--dsw-alias-label-primary))}
|
|
1394
|
+
.db-dot{width:7px;height:7px;border-radius:50%;background:var(--db-muted,var(--dsw-alias-label-tertiary));display:inline-block}
|
|
1395
|
+
.db-dot[data-tone=live]{background:var(--db-accent,var(--dsw-alias-brand-primary))}
|
|
1338
1396
|
.db-dot[data-tone=ok]{background:var(--dsw-alias-label-success,#2f9e44)}
|
|
1339
|
-
.db-dot[data-tone=bad]{background:var(--dsw-alias-label-error,#
|
|
1340
|
-
.db-kv{display:grid;grid-template-columns:auto 1fr;gap:
|
|
1341
|
-
.db-kv dt{color:var(--dsw-alias-label-
|
|
1397
|
+
.db-dot[data-tone=bad]{background:var(--dsw-alias-label-error,#d13438)}
|
|
1398
|
+
.db-kv{display:grid;grid-template-columns:auto minmax(0,1fr);gap:7px 14px;font-size:12px;margin:0}
|
|
1399
|
+
.db-kv dt{color:var(--db-muted,var(--dsw-alias-label-secondary))}
|
|
1342
1400
|
.db-kv dd{margin:0;font-family:var(--dsw-font-mono);overflow-wrap:anywhere}
|
|
1343
|
-
.db-pre{background:var(--dsw-alias-bg-layer-1);border-radius:8px;font-family:var(--dsw-font-mono);font-size:11px;margin:
|
|
1401
|
+
.db-pre{background:var(--db-fill,var(--dsw-alias-bg-layer-1));border-radius:8px;font-family:var(--dsw-font-mono);font-size:11px;margin:8px 0 0;max-height:200px;overflow:auto;padding:12px;white-space:pre-wrap}
|
|
1402
|
+
.db-root details>summary{cursor:pointer;min-height:34px;padding:6px 0;font-weight:550;color:var(--db-subtle)}
|
|
1403
|
+
.db-root details[open]>summary{margin-bottom:8px;color:var(--db-text)}
|
|
1404
|
+
.db-guide{padding:12px 16px}
|
|
1405
|
+
.db-guide-top{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
|
|
1406
|
+
.db-guide-top>strong{font-size:12px;flex:none}
|
|
1407
|
+
.db-guide .db-btn{min-height:30px;padding:5px 9px;font-size:11px}
|
|
1408
|
+
.db-guide-notes{font-size:12px;margin-top:5px}
|
|
1409
|
+
.db-guide-notes>summary{font-size:11px;min-height:26px!important;padding:4px 0!important;font-weight:400!important}
|
|
1410
|
+
.db-guide-notes p{margin:4px 0 8px}
|
|
1411
|
+
.db-create-footer{position:sticky;bottom:0;z-index:2;background:var(--db-surface);border-top:1px solid var(--db-border);display:grid;grid-template-columns:minmax(140px,1fr) minmax(160px,1.2fr) auto;gap:12px;align-items:end;margin:16px -18px -16px;padding:14px 18px;border-radius:0 0 12px 12px;box-shadow:0 -5px 18px #00000008}
|
|
1412
|
+
.db-create-footer .db-btn{min-height:36px}
|
|
1413
|
+
.db-recipes{margin-bottom:16px}
|
|
1414
|
+
.db-recipe-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-top:14px}
|
|
1415
|
+
.db-recipe{display:flex;flex-direction:column;gap:8px;min-width:0;border:1px solid var(--db-border);border-radius:10px;padding:12px;background:var(--db-surface)}
|
|
1416
|
+
.db-recipe[data-selected=true]{border-color:var(--db-accent);box-shadow:0 0 0 1px var(--db-accent);background:var(--db-accent-soft)}
|
|
1417
|
+
.db-recipe img{display:block;width:100%;aspect-ratio:4/3;object-fit:contain;border-radius:7px;background:#10151d}
|
|
1418
|
+
.db-recipe h5{margin:2px 0;font-size:13px}
|
|
1419
|
+
.db-recipe p{margin:0;font-size:12px}
|
|
1420
|
+
.db-recipe .db-btn{margin-top:auto;align-self:stretch}
|
|
1421
|
+
.db-recipe-description{line-height:1.6}
|
|
1422
|
+
.db-recipe-license{font-size:10px!important}
|
|
1423
|
+
.db-recipe-parameters{margin-top:16px;padding:14px;border:1px solid var(--db-border);border-radius:9px}
|
|
1424
|
+
.db-recipe-parameters legend{font-size:12px;font-weight:600;padding:0 6px}
|
|
1425
|
+
.db-recipe-parameters .db-inline{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));margin-top:12px}
|
|
1426
|
+
.db-recipe-parameters label{padding:8px;background:var(--db-fill);border-radius:7px}
|
|
1427
|
+
.db-recipe-parameters input[type=color]{height:34px;width:64px;border:1px solid var(--db-border);border-radius:6px;padding:3px;background:var(--db-surface)}
|
|
1428
|
+
.db-storage{margin-top:8px;font-size:11px;overflow-wrap:anywhere}
|
|
1429
|
+
.db-scene-layout{display:grid;grid-template-columns:minmax(220px,300px) minmax(0,1fr);gap:20px;align-items:start}
|
|
1430
|
+
.db-scene-outline{min-width:0;position:sticky;top:0;max-height:calc(100dvh - 180px);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--db-border) transparent}
|
|
1431
|
+
.db-scene-outline>.db-grid{display:block}
|
|
1432
|
+
.db-scene-outline .db-card{padding:12px 14px}
|
|
1433
|
+
.db-scene-outline .db-kind{min-width:0;display:inline;margin:0 6px}
|
|
1434
|
+
.db-scene-outline .db-list>li>div{overflow-wrap:anywhere;font-size:12px}
|
|
1435
|
+
.db-scene-inspector{min-width:0}
|
|
1436
|
+
.db-notice{border-left:3px solid var(--db-good,var(--dsw-alias-label-success,#2f9e44));background:var(--db-fill,var(--dsw-alias-fill-l2));border-radius:6px;padding:9px 12px;color:var(--db-text,var(--dsw-alias-label-primary))}
|
|
1437
|
+
.db-editor-actions{position:sticky;bottom:0;z-index:2;background:var(--db-surface);border-top:1px solid var(--db-border);margin:16px -18px -16px;padding:12px 18px;border-radius:0 0 12px 12px;box-shadow:0 -5px 18px #00000008}
|
|
1438
|
+
@media(prefers-color-scheme:dark){.db-root[data-theme=system]{color-scheme:dark;--db-accent:#f3a365;--db-accent-soft:#3c2d23;--db-canvas:#10151d;--db-surface:#19212d;--db-border:#334155;--db-fill:#253142;--db-text:#edf2f8;--db-subtle:#c2ccda;--db-muted:#a2afc1;--db-good:#77c9a0;--db-warn:#efbc73;--db-bad:#ff979c;--db-input-border:#657692}.db-root[data-theme=system] .db-btn[data-tone=primary]{color:#20170f}}
|
|
1439
|
+
@media(max-width:1000px){.db-recipe-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.db-head{padding:12px 16px}.db-body{padding:16px}.db-project-context{max-width:45%}.db-scene-layout{grid-template-columns:minmax(190px,240px) minmax(0,1fr);gap:14px}}
|
|
1440
|
+
@media(max-width:700px){.db-scene-layout{grid-template-columns:minmax(0,1fr)}.db-scene-outline{position:static;max-height:none;overflow:visible}.db-scene-outline>.db-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.db-project-context{max-width:100%;border-left:0;padding-left:0}.db-head-actions{margin-left:0;width:100%}.db-head-actions .db-theme{margin-left:auto}.db-head{gap:8px}.db-nav{padding:8px 12px}.db-create-footer{grid-template-columns:1fr 1fr}.db-create-footer .db-btn{grid-column:1/-1}.db-card{padding:14px}.db-body{padding:12px}.db-create-footer{margin:14px -14px -14px;padding:12px 14px}}
|
|
1441
|
+
@media(max-width:440px){.db-recipe-grid{grid-template-columns:minmax(0,1fr)}.db-create-footer{position:static;grid-template-columns:minmax(0,1fr)}.db-scene-outline>.db-grid{grid-template-columns:minmax(0,1fr)}.db-badge[data-badge=unsaved]{white-space:normal}.db-nav button{padding:6px 10px}.db-head{padding:10px 12px}.db-body{padding-top:8px}.db-tabs{gap:6px;padding:0 0 6px}}
|
|
1442
|
+
@container deepblend (max-width:1000px){.db-recipe-grid{grid-template-columns:repeat(2,minmax(0,1fr))}.db-head{padding:12px 16px}.db-body{padding:16px}.db-project-context{max-width:45%}.db-scene-layout{grid-template-columns:minmax(190px,240px) minmax(0,1fr);gap:14px}}
|
|
1443
|
+
@container deepblend (max-width:700px){.db-scene-layout{grid-template-columns:minmax(0,1fr)}.db-scene-outline{position:static;max-height:none;overflow:visible}.db-scene-outline>.db-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.db-project-context{max-width:100%;border-left:0;padding-left:0}.db-head-actions{margin-left:0;width:100%}.db-head-actions .db-theme{margin-left:auto}.db-head{gap:8px}.db-nav{padding:8px 12px}.db-create-footer{grid-template-columns:1fr 1fr}.db-create-footer .db-btn{grid-column:1/-1}.db-card{padding:14px}.db-body{padding:12px}.db-create-footer{margin:14px -14px -14px;padding:12px 14px}}
|
|
1444
|
+
@container deepblend (max-width:440px){.db-recipe-grid{grid-template-columns:minmax(0,1fr)}.db-create-footer{position:static;grid-template-columns:minmax(0,1fr)}.db-scene-outline>.db-grid{grid-template-columns:minmax(0,1fr)}.db-badge[data-badge=unsaved]{white-space:normal}.db-nav button{padding:6px 10px}.db-head{padding:10px 12px}.db-body{padding-top:8px}.db-tabs{gap:6px;padding:0 0 6px}}
|
|
1445
|
+
@media(pointer:coarse){.db-root .db-btn,.db-root .db-input,.db-nav button{min-height:42px}}
|
|
1446
|
+
@media(prefers-reduced-motion:reduce){.db-root *{scroll-behavior:auto!important;transition:none!important}}
|
|
1344
1447
|
`
|
|
1345
1448
|
|
|
1346
1449
|
/**
|
|
@@ -1442,7 +1545,7 @@ window.__ModuleLoader__.load({
|
|
|
1442
1545
|
|
|
1443
1546
|
function ErrorBox(props) {
|
|
1444
1547
|
if (props.error === null || props.error === undefined) return null
|
|
1445
|
-
return el('div', { className: 'db-error', 'data-deepblend-error': props.error.code || 'error' },
|
|
1548
|
+
return el('div', { className: 'db-error', role: 'alert', 'data-deepblend-error': props.error.code || 'error' },
|
|
1446
1549
|
el('div', null, `${props.error.code || 'ERROR'}: ${props.error.message || ''}`),
|
|
1447
1550
|
props.error.detail ? el('pre', { className: 'db-pre' }, JSON.stringify(props.error.detail, null, 2)) : null)
|
|
1448
1551
|
}
|
|
@@ -2222,13 +2325,23 @@ window.__ModuleLoader__.load({
|
|
|
2222
2325
|
*
|
|
2223
2326
|
* @param {{ fetch?: typeof fetch, pollLiveMs?: number, pollIdleMs?: number }} [options]
|
|
2224
2327
|
*/
|
|
2328
|
+
const APPEARANCE_KEY = 'deepblend.workbench.appearance'
|
|
2329
|
+
const APPEARANCES = ['system', 'light', 'dark']
|
|
2330
|
+
function appearanceStorage(settings) {
|
|
2331
|
+
try { return settings.preferenceStorage ?? globalThis.localStorage } catch { return undefined }
|
|
2332
|
+
}
|
|
2333
|
+
function savedAppearance(storage) {
|
|
2334
|
+
try { const value = storage?.getItem(APPEARANCE_KEY); return APPEARANCES.includes(value) ? value : 'system' } catch { return 'system' }
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2225
2337
|
function createWorkbenchStore(options) {
|
|
2226
2338
|
const settings = options || {}
|
|
2227
2339
|
const fetchImpl = settings.fetch ?? ((...args) => fetch(...args))
|
|
2228
2340
|
const pollLiveMs = settings.pollLiveMs ?? POLL_LIVE_MS
|
|
2229
2341
|
const pollIdleMs = settings.pollIdleMs ?? POLL_IDLE_MS
|
|
2230
2342
|
|
|
2231
|
-
|
|
2343
|
+
const preferenceStorage = appearanceStorage(settings)
|
|
2344
|
+
let data = { ...emptySnapshot(), appearance: savedAppearance(preferenceStorage) }
|
|
2232
2345
|
let snapshot = { ...data }
|
|
2233
2346
|
const listeners = new Set()
|
|
2234
2347
|
let timer = null
|
|
@@ -2405,6 +2518,11 @@ window.__ModuleLoader__.load({
|
|
|
2405
2518
|
&& FILE_FIELDS.includes(field) && source === fileChoiceKey(data, field) && fileChoiceAllowed(data, field)
|
|
2406
2519
|
const actions = {
|
|
2407
2520
|
acceptsFileChoice,
|
|
2521
|
+
setAppearance: value => {
|
|
2522
|
+
if (!APPEARANCES.includes(value)) return
|
|
2523
|
+
try { preferenceStorage?.setItem(APPEARANCE_KEY, value) } catch { /* A blocked preference must not block a project. */ }
|
|
2524
|
+
set({ appearance: value })
|
|
2525
|
+
},
|
|
2408
2526
|
/**
|
|
2409
2527
|
* Switch tabs, and drop the notice the tab being ENTERED was carrying.
|
|
2410
2528
|
*
|
|
@@ -3188,7 +3306,7 @@ window.__ModuleLoader__.load({
|
|
|
3188
3306
|
const actions = ctx.actions
|
|
3189
3307
|
return el('div', { 'data-view': 'projects' },
|
|
3190
3308
|
ErrorBox({ error: state.error }),
|
|
3191
|
-
el('div', { className: 'db-card' },
|
|
3309
|
+
state.projects.length ? el('div', { className: 'db-card db-project-list' },
|
|
3192
3310
|
el('h4', null, t('tab.projects')),
|
|
3193
3311
|
state.projects.length === 0
|
|
3194
3312
|
? el('div', { className: 'db-muted' }, t('projects.empty'))
|
|
@@ -3207,13 +3325,14 @@ window.__ModuleLoader__.load({
|
|
|
3207
3325
|
el('div', { className: 'db-muted db-mono' }, t('projects.updated', { revision: project.currentRevision || '—', when: formatTime(project.updatedAt) })),
|
|
3208
3326
|
project.goal ? el('div', { className: 'db-muted' }, project.goal) : null,
|
|
3209
3327
|
))),
|
|
3210
|
-
|
|
3211
|
-
),
|
|
3328
|
+
) : null,
|
|
3212
3329
|
|
|
3213
|
-
el('div', { className: 'db-card' },
|
|
3330
|
+
el('div', { className: 'db-card db-project-create' },
|
|
3214
3331
|
el('h4', null, t('projects.create')),
|
|
3332
|
+
!state.projects.length ? el('p', { className: 'db-muted' }, t('projects.startHint')) : null,
|
|
3215
3333
|
RecipesView(ctx),
|
|
3216
|
-
el('div', { className: 'db-
|
|
3334
|
+
el('div', { className: 'db-create-footer' },
|
|
3335
|
+
el('label', { className: 'db-field' }, t('projects.name'),
|
|
3217
3336
|
el('input', {
|
|
3218
3337
|
className: 'db-input',
|
|
3219
3338
|
'data-field': 'project-title',
|
|
@@ -3221,15 +3340,15 @@ window.__ModuleLoader__.load({
|
|
|
3221
3340
|
placeholder: t('projects.titlePlaceholder'),
|
|
3222
3341
|
value: state.forms.title,
|
|
3223
3342
|
onChange: event => actions.setForm('title', event.target.value),
|
|
3224
|
-
}),
|
|
3225
|
-
el('input', {
|
|
3343
|
+
})),
|
|
3344
|
+
el('label', { className: 'db-field' }, t('projects.goal'), el('input', {
|
|
3226
3345
|
className: 'db-input',
|
|
3227
3346
|
'data-field': 'project-goal',
|
|
3228
3347
|
'aria-label': t('projects.goal'),
|
|
3229
3348
|
placeholder: t('projects.goal'),
|
|
3230
3349
|
value: state.forms.goal,
|
|
3231
3350
|
onChange: event => actions.setForm('goal', event.target.value),
|
|
3232
|
-
}),
|
|
3351
|
+
})),
|
|
3233
3352
|
Button({
|
|
3234
3353
|
tone: 'primary',
|
|
3235
3354
|
action: 'create-project',
|
|
@@ -3240,6 +3359,8 @@ window.__ModuleLoader__.load({
|
|
|
3240
3359
|
),
|
|
3241
3360
|
state.notices.projects ? Notice(state.notices.projects, { marginTop: '8px' }) : null,
|
|
3242
3361
|
),
|
|
3362
|
+
el('details', { className: 'db-storage' }, el('summary', null, t('projects.storage')),
|
|
3363
|
+
el('span', { className: 'db-muted db-mono' }, `projectsRoot: ${state.projectsRoot || '—'}`)),
|
|
3243
3364
|
|
|
3244
3365
|
BriefEditor({ state, actions }),
|
|
3245
3366
|
state.selected ? el('div', { className: 'db-card' },
|
|
@@ -3257,7 +3378,7 @@ window.__ModuleLoader__.load({
|
|
|
3257
3378
|
].join(' / ') },
|
|
3258
3379
|
] }),
|
|
3259
3380
|
el('div', { className: 'db-muted', style: { marginTop: '6px' } }, state.selected.qa.summary),
|
|
3260
|
-
) :
|
|
3381
|
+
) : null,
|
|
3261
3382
|
)
|
|
3262
3383
|
}
|
|
3263
3384
|
|
|
@@ -3289,26 +3410,25 @@ window.__ModuleLoader__.load({
|
|
|
3289
3410
|
function RecipesView({ state, actions }) {
|
|
3290
3411
|
const catalog = state.recipeCatalog || { recipes: [], errors: [] }
|
|
3291
3412
|
const selected = state.forms.recipe
|
|
3292
|
-
return el('section', { 'aria-label': t('recipes.heading')
|
|
3413
|
+
return el('section', { className: 'db-recipes', 'aria-label': t('recipes.heading') },
|
|
3293
3414
|
el('h5', null, t('recipes.heading')),
|
|
3294
3415
|
el('p', { className: 'db-muted' }, t('recipes.previewNote')),
|
|
3295
3416
|
!recipeSelectionCurrent(state) ? el('p', { role: 'alert', className: 'db-error' }, t('recipes.stale')) : null,
|
|
3296
3417
|
catalog.errors.length ? el('p', { className: 'db-error' }, t('recipes.unavailable')) : null,
|
|
3297
|
-
Button({ action: 'recipe-blank',
|
|
3418
|
+
Button({ action: 'recipe-blank',
|
|
3298
3419
|
onClick: () => actions.selectRecipe(null), children: t('recipes.blank') }),
|
|
3299
|
-
el('div', {
|
|
3420
|
+
el('div', { className: 'db-recipe-grid' },
|
|
3300
3421
|
catalog.recipes.map(recipe => {
|
|
3301
3422
|
const chosen = selected?.id === recipe.id && selected?.version === recipe.version && selected?.digest === recipe.digest
|
|
3302
|
-
return el('article', { key: `${recipe.id}@${recipe.version}`, 'data-recipe': recipe.id,
|
|
3303
|
-
|
|
3304
|
-
el('
|
|
3305
|
-
el('
|
|
3306
|
-
el('p', { className: 'db-muted' }, `${t('recipes.license')}: ${recipe.author.name} · ${recipe.license} · v${recipe.version}`),
|
|
3423
|
+
return el('article', { key: `${recipe.id}@${recipe.version}`, 'data-recipe': recipe.id, className: 'db-recipe', 'data-selected': String(chosen) },
|
|
3424
|
+
el('img', { src: recipe.previewUrl, alt: recipe.title, loading: 'lazy' }),
|
|
3425
|
+
el('h5', null, recipe.title), el('p', { className: 'db-muted db-recipe-description' }, recipe.description),
|
|
3426
|
+
el('p', { className: 'db-muted db-recipe-license' }, `${t('recipes.license')}: ${recipe.author.name} · ${recipe.license} · v${recipe.version}`),
|
|
3307
3427
|
Button({ action: `select-recipe:${recipe.id}@${recipe.version}`, tone: chosen ? 'primary' : undefined,
|
|
3308
3428
|
onClick: () => actions.selectRecipe(recipe), children: chosen ? t('recipes.selected') : t('recipes.select') }),
|
|
3309
3429
|
)
|
|
3310
3430
|
})),
|
|
3311
|
-
selected ? el('fieldset', {
|
|
3431
|
+
selected ? el('fieldset', { className: 'db-recipe-parameters' },
|
|
3312
3432
|
el('legend', null, t('recipes.parameters')),
|
|
3313
3433
|
Button({ action: 'reset-recipe', onClick: () => actions.selectRecipe(selected), children: t('recipes.reset') }),
|
|
3314
3434
|
el('div', { className: 'db-inline', style: { flexWrap: 'wrap' } }, selected.parameters.map(parameter =>
|
|
@@ -3405,7 +3525,10 @@ window.__ModuleLoader__.load({
|
|
|
3405
3525
|
return el('div', {
|
|
3406
3526
|
'data-result': result.ok ? 'ok' : 'error',
|
|
3407
3527
|
'data-result-kind': result.kind || undefined,
|
|
3408
|
-
className: result.ok ? 'db-
|
|
3528
|
+
className: result.ok ? 'db-notice' : 'db-error',
|
|
3529
|
+
role: result.ok ? 'status' : 'alert',
|
|
3530
|
+
'aria-live': result.ok ? 'polite' : 'assertive',
|
|
3531
|
+
'aria-atomic': 'true',
|
|
3409
3532
|
style: style || undefined,
|
|
3410
3533
|
}, result.message)
|
|
3411
3534
|
}
|
|
@@ -3441,11 +3564,15 @@ window.__ModuleLoader__.load({
|
|
|
3441
3564
|
const numeric = (label, field, value, update, options = {}) => {
|
|
3442
3565
|
const factor = options.factor ?? 1
|
|
3443
3566
|
const displayed = Number.isFinite(value) ? Math.round(value * factor * 1e9) / 1e9 : ''
|
|
3444
|
-
|
|
3445
|
-
|
|
3567
|
+
const invalid = !Number.isFinite(value) && !disabled && options.disabled !== true
|
|
3568
|
+
const errorId = `${draft.projectId}-${draft.entityId}-${field}-error`
|
|
3569
|
+
return el('label', { className: 'db-row', key: field }, el('span', null, label), el('span', { className: 'db-number-control' }, el('input', {
|
|
3570
|
+
className: 'db-input', type: 'number', 'data-field': field, 'aria-label': label,
|
|
3571
|
+
'aria-invalid': invalid ? 'true' : undefined, 'aria-describedby': invalid ? errorId : undefined,
|
|
3572
|
+
value: displayed, step: options.step ?? (options.integer ? 1 : 'any'),
|
|
3446
3573
|
min: options.min, max: options.max, disabled: disabled || options.disabled === true,
|
|
3447
3574
|
style: { width: '125px' }, onChange: event => update(event.target.value === '' ? null : Number(event.target.value) / factor),
|
|
3448
|
-
}))
|
|
3575
|
+
}), invalid ? el('span', { className: 'db-field-feedback', id: errorId }, t('editor.invalid', { field: label })) : null))
|
|
3449
3576
|
}
|
|
3450
3577
|
const choose = (label, field, value, items, update, off = false) => el('label', { className: 'db-row', key: field }, el('span', null, label), el('select', {
|
|
3451
3578
|
className: 'db-input', 'data-field': field, value, disabled: disabled || off, style: { maxWidth: '65%' }, onChange: event => update(event.target.value),
|
|
@@ -3590,7 +3717,7 @@ window.__ModuleLoader__.load({
|
|
|
3590
3717
|
el('div', { className: 'db-inline' }, Object.entries(modifierNames).map(([type, name]) => Button({ action: `editor-modifier-add-${type}`, disabled: disabled || !canModify || draft.entity.modifiers.length >= 8,
|
|
3591
3718
|
children: t('editor.add', { name }), onClick: () => actions.editEditorList('modifiers', 0, 'add', type) })))) : null,
|
|
3592
3719
|
errors.length ? el('div', { className: 'db-error', 'data-editor-errors': true }, errors.join(' ')) : null,
|
|
3593
|
-
el('div', { className: 'db-inline' }, Button({ action: 'editor-apply', tone: 'primary', disabled: disabled || !dirty || errors.length > 0, onClick: actions.applyEditor, children: t('editor.apply') }),
|
|
3720
|
+
el('div', { className: 'db-inline db-editor-actions' }, Button({ action: 'editor-apply', tone: 'primary', disabled: disabled || !dirty || errors.length > 0, onClick: actions.applyEditor, children: t('editor.apply') }),
|
|
3594
3721
|
Button({ action: 'editor-reset', disabled: state.busy.editor, onClick: actions.resetEditor, children: t('editor.reset') }),
|
|
3595
3722
|
Button({ action: 'editor-review-subject', disabled: disabled || draft.entity.visible === false || draft.entity.kind === 'empty'
|
|
3596
3723
|
|| state.briefWork[state.activeProjectId]?.saving || state.visualRuns[state.activeProjectId]?.busy,
|
|
@@ -3827,10 +3954,12 @@ window.__ModuleLoader__.load({
|
|
|
3827
3954
|
Badge({ children: `world ${scene.world ? `${(scene.world.color || []).join(',')} × ${scene.world.strength}` : t('common.default')}` }),
|
|
3828
3955
|
),
|
|
3829
3956
|
),
|
|
3957
|
+
el('div', { className: 'db-scene-layout' },
|
|
3958
|
+
el('aside', { className: 'db-scene-outline', 'data-scroll-key': JSON.stringify([state.activeProjectId, 'scene-outline']), 'aria-label': t('scene.outline') },
|
|
3830
3959
|
el('div', { className: 'db-grid' },
|
|
3831
3960
|
section(t('scene.entities'), scene.nodes.entities, entity => el('div', null,
|
|
3832
3961
|
el('button', { type: 'button', className: 'db-btn', 'data-action': `select-entity:${entity.id}`, 'data-entity-id': entity.id,
|
|
3833
|
-
'aria-pressed': state.editorEntityId === entity.id, onClick: () => actions.selectEditorEntity(entity.id) }, entity.id), ' ',
|
|
3962
|
+
'aria-pressed': String(state.editorEntityId === entity.id), onClick: () => actions.selectEditorEntity(entity.id) }, entity.id), ' ',
|
|
3834
3963
|
el('span', { className: 'db-mono', 'data-node': `entity:${entity.id}` }, entity.id), ' ',
|
|
3835
3964
|
el('span', { className: 'db-kind' }, entity.shape || entity.kind),
|
|
3836
3965
|
entity.materialId ? el('span', { className: 'db-muted' }, t('scene.material', { id: entity.materialId })) : null,
|
|
@@ -3863,10 +3992,11 @@ window.__ModuleLoader__.load({
|
|
|
3863
3992
|
el('span', { className: 'db-mono', 'data-node': `asset:${asset.id}` }, asset.id), ' ',
|
|
3864
3993
|
el('span', { className: 'db-kind' }, asset.type),
|
|
3865
3994
|
el('span', { className: 'db-muted db-mono' }, String(asset.path || '')))),
|
|
3866
|
-
),
|
|
3995
|
+
)),
|
|
3996
|
+
el('section', { className: 'db-scene-inspector', 'aria-label': t('scene.inspector') },
|
|
3997
|
+
SceneEditor(ctx),
|
|
3867
3998
|
PhotographyEditor(ctx),
|
|
3868
3999
|
AssetsView(ctx),
|
|
3869
|
-
SceneEditor(ctx),
|
|
3870
4000
|
el('details', { key: advancedDisclosure, 'data-disclosure': advancedDisclosure, open: state.disclosures?.[advancedDisclosure] ?? false,
|
|
3871
4001
|
onToggle: event => actions.setDisclosure(advancedDisclosure, event.currentTarget.open), className: 'db-card' }, el('summary', null, t('editor.advanced')),
|
|
3872
4002
|
el('h4', null, t('scene.patch')),
|
|
@@ -3888,7 +4018,7 @@ window.__ModuleLoader__.load({
|
|
|
3888
4018
|
Button({ action: 'reset-patch', onClick: () => actions.setForm('patch', null), children: t('scene.resetTemplate') }),
|
|
3889
4019
|
Notice(state.notices.scene, { border: 0, padding: '0 6px', marginBottom: 0 }),
|
|
3890
4020
|
),
|
|
3891
|
-
),
|
|
4021
|
+
))),
|
|
3892
4022
|
)
|
|
3893
4023
|
}
|
|
3894
4024
|
|
|
@@ -4050,15 +4180,18 @@ window.__ModuleLoader__.load({
|
|
|
4050
4180
|
{ id: 'appearance', label: t('guide.appearance'), hint: t('guide.appearanceHint') },
|
|
4051
4181
|
{ id: 'delivery', label: t('guide.delivery'), hint: t('guide.deliveryHint') },
|
|
4052
4182
|
]
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
el('div', { className: 'db-
|
|
4056
|
-
|
|
4183
|
+
const disclosure = JSON.stringify([projectId || 'new', 'guide-notes'])
|
|
4184
|
+
return el('section', { className: 'db-card db-guide', 'data-creation-guide': projectId || 'new' },
|
|
4185
|
+
el('div', { className: 'db-guide-top' }, el('strong', null, t('guide.title')),
|
|
4186
|
+
el('div', { className: 'db-inline' }, steps.map(step =>
|
|
4187
|
+
Button({ action: `guide-${step.id}`, disabled: !projectId && !['goal', 'route'].includes(step.id), onClick: () => actions.openCreationStep(step.id), children: step.label })))),
|
|
4188
|
+
el('details', { className: 'db-guide-notes', 'data-disclosure': disclosure, open: state.disclosures?.[disclosure] ?? false,
|
|
4189
|
+
onToggle: event => actions.setDisclosure(disclosure, event.currentTarget.open) }, el('summary', null, t('guide.notes')),
|
|
4057
4190
|
el('p', { className: 'db-muted', 'data-guide-hint': focus }, steps.find(step => step.id === focus)?.hint || steps[0].hint),
|
|
4058
4191
|
el('p', { className: 'db-muted' }, scene ? t('guide.evidence', { revision: scene.revision,
|
|
4059
4192
|
parts: scene.nodes.entities.filter(entity => entity.kind !== 'empty' && !entity.tags?.includes('environment')).length,
|
|
4060
4193
|
references: scene.project.referenceImages?.length || 0, images: evidence?.diagnostics?.length || 0 }) : t('guide.noProject')),
|
|
4061
|
-
el('small', { className: 'db-muted' }, t('guide.help')))
|
|
4194
|
+
el('small', { className: 'db-muted' }, t('guide.help'))))
|
|
4062
4195
|
}
|
|
4063
4196
|
function InspectionPanel({ state, actions }) {
|
|
4064
4197
|
const projectId = state.activeProjectId, scene = state.selected?.scene, form = inspectionForm(state), work = state.inspectionWork?.[projectId] || {}
|
|
@@ -4329,12 +4462,12 @@ window.__ModuleLoader__.load({
|
|
|
4329
4462
|
el('h4', null, t('jobs.startDelivery')),
|
|
4330
4463
|
el('div', { className: 'db-inline' },
|
|
4331
4464
|
el('label', { className: 'db-muted' }, t('jobs.frameStart')),
|
|
4332
|
-
el('input', { className: 'db-input', 'data-field': 'frame-start', style: { width: '90px' }, value: state.forms.frameStart, onChange: event => actions.setForm('frameStart', event.target.value) }),
|
|
4465
|
+
el('input', { className: 'db-input', 'data-field': 'frame-start', 'aria-label': t('jobs.frameStart'), style: { width: '90px' }, value: state.forms.frameStart, onChange: event => actions.setForm('frameStart', event.target.value) }),
|
|
4333
4466
|
el('label', { className: 'db-muted' }, t('jobs.frameEnd')),
|
|
4334
|
-
el('input', { className: 'db-input', 'data-field': 'frame-end', style: { width: '90px' }, value: state.forms.frameEnd, onChange: event => actions.setForm('frameEnd', event.target.value) }),
|
|
4335
|
-
el('label', { className: 'db-muted' }, 'profile'),
|
|
4467
|
+
el('input', { className: 'db-input', 'data-field': 'frame-end', 'aria-label': t('jobs.frameEnd'), style: { width: '90px' }, value: state.forms.frameEnd, onChange: event => actions.setForm('frameEnd', event.target.value) }),
|
|
4468
|
+
el('label', { className: 'db-muted' }, t('jobs.profile')),
|
|
4336
4469
|
el('select', {
|
|
4337
|
-
className: 'db-input', 'data-field': 'render-profile', style: { width: 'auto' }, value: state.forms.profile,
|
|
4470
|
+
className: 'db-input', 'data-field': 'render-profile', 'aria-label': t('jobs.profile'), style: { width: 'auto' }, value: state.forms.profile,
|
|
4338
4471
|
onChange: event => actions.setForm('profile', event.target.value),
|
|
4339
4472
|
},
|
|
4340
4473
|
el('option', { value: 'preview' }, 'preview'),
|
|
@@ -4503,21 +4636,28 @@ window.__ModuleLoader__.load({
|
|
|
4503
4636
|
: state.status === 'loading'
|
|
4504
4637
|
? el('div', { className: 'db-body db-muted' }, t('host.reading'))
|
|
4505
4638
|
: el('div', { className: 'db-body', 'data-scroll-key': JSON.stringify([state.activeProjectId, state.view]) },
|
|
4506
|
-
state.view === 'preview' ? renderView(ctx) : CreationGuide(ctx),
|
|
4507
|
-
state.view === 'preview' ? CreationGuide(ctx) : renderView(ctx))
|
|
4639
|
+
state.view === 'preview' || !state.activeProjectId ? renderView(ctx) : CreationGuide(ctx),
|
|
4640
|
+
state.view === 'preview' || !state.activeProjectId ? CreationGuide(ctx) : renderView(ctx))
|
|
4508
4641
|
|
|
4509
|
-
return el('div', { className: 'db-root', 'data-deepblend-panel': PANEL_ID },
|
|
4642
|
+
return el('div', { className: 'db-root', 'data-theme': state.appearance || 'system', 'data-deepblend-panel': PANEL_ID },
|
|
4510
4643
|
el('div', { className: 'db-head' },
|
|
4511
|
-
el('
|
|
4512
|
-
|
|
4513
|
-
|
|
4644
|
+
el('div', { className: 'db-brand' },
|
|
4645
|
+
el('img', { className: 'db-logo', src: BRAND_MARK, alt: '', width: 34, height: 34 }),
|
|
4646
|
+
el('div', null, el('h1', { className: 'db-title' }, 'DeepBlend Studio'), el('small', null, t('workbench.title', { panel: PANEL_LABEL })))),
|
|
4647
|
+
state.selected ? el('div', { className: 'db-project-context' },
|
|
4648
|
+
el('span', { className: 'db-project-name', title: state.selected.project.title }, state.selected.project.title),
|
|
4649
|
+
Badge({ children: state.selected.currentRevision || '—' })) : null,
|
|
4650
|
+
projectHasUnsavedDrafts(state) ? Badge({ tone: 'warn', name: 'unsaved', children: t('workbench.unsaved') }) : null,
|
|
4514
4651
|
state.unfinishedJobs.length > 0
|
|
4515
4652
|
? Badge({ tone: 'live', name: 'unfinished', children: t('jobs.unfinished', { count: state.unfinishedJobs.length }) })
|
|
4516
4653
|
: null,
|
|
4517
4654
|
typeof state.hostApiVersion === 'number' && state.hostApiVersion < EXPECTED_HOST_API
|
|
4518
4655
|
? Badge({ tone: 'warn', name: 'api', children: `hostApiVersion ${state.hostApiVersion} < ${EXPECTED_HOST_API}` })
|
|
4519
4656
|
: null,
|
|
4520
|
-
el('
|
|
4657
|
+
el('div', { className: 'db-head-actions' },
|
|
4658
|
+
el('select', { className: 'db-input db-theme', 'data-field': 'workbench-appearance', 'aria-label': t('workbench.appearance'), value: state.appearance || 'system',
|
|
4659
|
+
onChange: event => actions.setAppearance(event.target.value) },
|
|
4660
|
+
[['system', t('workbench.system')], ['light', t('workbench.light')], ['dark', t('workbench.dark')]].map(([theme, label]) => el('option', { value: theme }, label))),
|
|
4521
4661
|
// AN ANCHOR, NOT A BUTTON. The export is a download, and a download is what an anchor with
|
|
4522
4662
|
// `download` does: the browser fetches the route and writes the file itself, in both faces
|
|
4523
4663
|
// (React passes `href`/`download` through, the DOM binding sets them as attributes). A button
|
|
@@ -4529,13 +4669,15 @@ window.__ModuleLoader__.load({
|
|
|
4529
4669
|
'data-action': 'export-diagnostics',
|
|
4530
4670
|
title: t('diagnostics.exportHint'),
|
|
4531
4671
|
}, t('diagnostics.export')),
|
|
4532
|
-
Button({ action: 'reload', onClick: actions.reload, children: t('common.refresh') }),
|
|
4672
|
+
Button({ action: 'reload', onClick: actions.reload, children: t('common.refresh') })),
|
|
4533
4673
|
),
|
|
4534
|
-
el('
|
|
4674
|
+
el('nav', { className: 'db-nav', 'aria-label': t('workbench.navigation') }, VIEWS.map(entry => el('button', {
|
|
4535
4675
|
key: entry.id,
|
|
4536
4676
|
type: 'button',
|
|
4537
4677
|
'data-view-tab': entry.id,
|
|
4538
4678
|
'data-active': String(state.view === entry.id),
|
|
4679
|
+
'aria-current': state.view === entry.id ? 'page' : undefined,
|
|
4680
|
+
'data-field': `nav-${entry.id}`,
|
|
4539
4681
|
onClick: () => actions.setView(entry.id),
|
|
4540
4682
|
}, entry.label))),
|
|
4541
4683
|
state.error !== null && state.error !== undefined && !stale ? el('div', { style: { padding: '8px 14px 0' } }, ErrorBox({ error: state.error })) : null,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepblend/dsh-blender-ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DeepBlend workbench UI: Host half (typed HTTP API) and Web Client half (sidebar, panels, tool cards).",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@deepblend/dsh-blender-contracts": "0.3.
|
|
22
|
+
"@deepblend/dsh-blender-contracts": "0.3.2"
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"repository": {
|