minecodex 1.2.1 → 2.0.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.
Files changed (99) hide show
  1. package/README.md +9 -3
  2. package/features/images/README.md +16 -98
  3. package/features/images/codex-feature.json +6 -14
  4. package/features/images/src/http-server.mjs +15 -5
  5. package/features/images/src/image-library.mjs +37 -9
  6. package/features/images/src/library-prompt-page.mjs +239 -0
  7. package/features/images/src/prompt-index.mjs +27 -24
  8. package/features/images/src/prompt-source.mjs +100 -0
  9. package/features/images/web/app.js +180 -67
  10. package/features/images/web/i18n.mjs +5 -0
  11. package/features/images/web/index.html +29 -24
  12. package/features/images/web/styles.css +169 -139
  13. package/features/model-slider/README.md +13 -1
  14. package/features/model-slider/THIRD_PARTY_NOTICES.md +1 -1
  15. package/features/notes/DESIGN.md +66 -0
  16. package/features/notes/README.md +18 -99
  17. package/features/notes/assets/icons/book-open-nav.svg +15 -0
  18. package/features/notes/assets/icons/book-open.svg +16 -0
  19. package/features/notes/assets/native-emojis.json +1 -0
  20. package/features/notes/assets/native-prompt-icons.json +28 -0
  21. package/features/notes/codex-feature.json +12 -70
  22. package/features/notes/src/main.mjs +2 -2
  23. package/features/notes/src/product.mjs +287 -613
  24. package/features/notes/src/prompt-schema.mjs +117 -0
  25. package/features/notes/src/quick-prompts-page.mjs +1559 -0
  26. package/features/notes/src/quick-prompts-server.mjs +167 -0
  27. package/features/session-status/DESIGN.md +10 -2
  28. package/features/session-status/README.md +13 -3
  29. package/features/session-status/src/session-status.mjs +329 -24
  30. package/features/sidebar-focus/DESIGN.md +16 -0
  31. package/features/sidebar-focus/codex-feature.json +20 -0
  32. package/features/sidebar-focus/src/sidebar-focus.mjs +134 -0
  33. package/features/sidebar-focus/vendor/lucide-LICENSE +43 -0
  34. package/features/unread-inbox/DESIGN.md +28 -0
  35. package/features/unread-inbox/codex-feature.json +20 -0
  36. package/features/unread-inbox/src/unread-inbox.mjs +360 -0
  37. package/features/usage-meter/DESIGN.md +49 -0
  38. package/features/usage-meter/README.md +18 -0
  39. package/features/usage-meter/codex-feature.json +13 -0
  40. package/features/usage-meter/src/usage-meter.mjs +200 -0
  41. package/package.json +21 -6
  42. package/packages/cli/src/config.mjs +4 -1
  43. package/packages/cli/src/control-server.mjs +2 -2
  44. package/packages/runtime-host/src/cloud-images.mjs +123 -0
  45. package/packages/runtime-host/src/codex-cdp.mjs +42 -8
  46. package/packages/runtime-host/src/codex-design-contract.mjs +10 -0
  47. package/packages/runtime-host/src/codex-injection.mjs +364 -116
  48. package/packages/runtime-host/src/codex-runtime.mjs +105 -28
  49. package/packages/runtime-host/src/feature-registry.mjs +3 -0
  50. package/packages/runtime-host/src/session-status-reader.mjs +65 -24
  51. package/features/notes/assets/icons/circle.svg +0 -15
  52. package/features/notes/assets/icons/ellipsis.svg +0 -17
  53. package/features/notes/assets/icons/external-link.svg +0 -17
  54. package/features/notes/assets/icons/list-todo.svg +0 -19
  55. package/features/notes/assets/icons/message-square-quote.svg +0 -17
  56. package/features/notes/assets/icons/paperclip.svg +0 -15
  57. package/features/notes/assets/icons/star-off.svg +0 -17
  58. package/features/notes/assets/icons/star.svg +0 -15
  59. package/features/notes/assets/icons/sticky-note.svg +0 -16
  60. package/features/notes/assets/icons/trash-2.svg +0 -19
  61. package/features/notes/src/http-server.mjs +0 -580
  62. package/features/notes/web/app.js +0 -1202
  63. package/features/notes/web/codex-artifact-document.svg +0 -1
  64. package/features/notes/web/codex-attachment.svg +0 -1
  65. package/features/notes/web/codex-build.svg +0 -1
  66. package/features/notes/web/codex-code.svg +0 -1
  67. package/features/notes/web/codex-cplusplus.svg +0 -1
  68. package/features/notes/web/codex-css.svg +0 -1
  69. package/features/notes/web/codex-document.svg +0 -1
  70. package/features/notes/web/codex-file.svg +0 -1
  71. package/features/notes/web/codex-folder.svg +0 -1
  72. package/features/notes/web/codex-hashes.svg +0 -1
  73. package/features/notes/web/codex-html.svg +0 -1
  74. package/features/notes/web/codex-image.svg +0 -1
  75. package/features/notes/web/codex-java.svg +0 -1
  76. package/features/notes/web/codex-javascript.svg +0 -1
  77. package/features/notes/web/codex-json.svg +0 -1
  78. package/features/notes/web/codex-notebook.svg +0 -1
  79. package/features/notes/web/codex-pdf.svg +0 -1
  80. package/features/notes/web/codex-pencil.svg +0 -3
  81. package/features/notes/web/codex-php.svg +0 -1
  82. package/features/notes/web/codex-plus.svg +0 -3
  83. package/features/notes/web/codex-presentation.svg +0 -1
  84. package/features/notes/web/codex-python.svg +0 -1
  85. package/features/notes/web/codex-react.svg +0 -1
  86. package/features/notes/web/codex-rust.svg +0 -1
  87. package/features/notes/web/codex-shell.svg +0 -1
  88. package/features/notes/web/codex-skill.svg +0 -1
  89. package/features/notes/web/codex-spreadsheet.svg +0 -1
  90. package/features/notes/web/codex-task.svg +0 -3
  91. package/features/notes/web/codex-terminal.svg +0 -1
  92. package/features/notes/web/codex-toml.svg +0 -1
  93. package/features/notes/web/codex-typescript.svg +0 -1
  94. package/features/notes/web/codex-view-all.svg +0 -3
  95. package/features/notes/web/file-icons.mjs +0 -68
  96. package/features/notes/web/i18n.mjs +0 -237
  97. package/features/notes/web/index.html +0 -15
  98. package/features/notes/web/styles.css +0 -1155
  99. package/features/notes/web/todo-drag.mjs +0 -18
@@ -18,20 +18,8 @@
18
18
  </button>
19
19
  <h1 data-i18n="Images">Images</h1>
20
20
  </div>
21
- <button class="icon-button rescan-button" type="button" aria-label="Refresh images" data-i18n-aria-label="Refresh images" title="Refresh images" data-i18n-title="Refresh images">
22
- <svg class="lucide refresh-icon" viewBox="0 0 24 24" aria-hidden="true">
23
- <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path>
24
- <path d="M21 3v5h-5"></path>
25
- <path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path>
26
- <path d="M8 16H3v5"></path>
27
- </svg>
28
- <svg class="lucide loading-ring-icon" viewBox="0 0 24 24" aria-hidden="true">
29
- <path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
30
- </svg>
31
- </button>
32
- </header>
33
-
34
21
  <nav class="library-toolbar" aria-label="Image library controls" data-i18n-aria-label="Image library controls">
22
+ <div class="toolbar-actions">
35
23
  <div class="source-filter">
36
24
  <button
37
25
  class="toolbar-button source-filter-button"
@@ -50,24 +38,24 @@
50
38
  <div class="source-menu" id="source-menu" role="listbox" aria-label="Filter images by source" data-i18n-aria-label="Filter images by source" hidden></div>
51
39
  </div>
52
40
 
53
- <div class="toolbar-actions">
54
41
  <div class="density-control" title="Grid columns" data-i18n-title="Grid columns">
42
+ <button class="toolbar-button density-trigger" type="button" aria-label="Grid columns" data-i18n-aria-label="Grid columns" aria-haspopup="listbox" aria-controls="density-menu" aria-expanded="false">
55
43
  <svg class="lucide density-icon" viewBox="0 0 24 24" aria-hidden="true">
56
44
  <rect width="7" height="7" x="3" y="3" rx="1"></rect>
57
45
  <rect width="7" height="7" x="14" y="3" rx="1"></rect>
58
46
  <rect width="7" height="7" x="3" y="14" rx="1"></rect>
59
47
  <rect width="7" height="7" x="14" y="14" rx="1"></rect>
60
48
  </svg>
61
- <input
62
- class="density-slider"
63
- type="range"
64
- min="2"
65
- max="6"
66
- step="1"
67
- value="3"
68
- aria-label="Grid columns" data-i18n-aria-label="Grid columns"
69
- />
70
- <output class="density-button-value" aria-live="polite">3</output>
49
+ <span class="density-button-value">4</span>
50
+ <svg class="lucide filter-chevron" viewBox="0 0 24 24" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg>
51
+ </button>
52
+ <div class="source-menu density-menu" id="density-menu" role="listbox" aria-label="Grid columns" data-i18n-aria-label="Grid columns" hidden>
53
+ <button class="source-option" type="button" role="option" data-columns="2" aria-selected="false" tabindex="-1">2</button>
54
+ <button class="source-option" type="button" role="option" data-columns="3" aria-selected="false" tabindex="-1">3</button>
55
+ <button class="source-option" type="button" role="option" data-columns="4" aria-selected="true" tabindex="-1">4</button>
56
+ <button class="source-option" type="button" role="option" data-columns="5" aria-selected="false" tabindex="-1">5</button>
57
+ <button class="source-option" type="button" role="option" data-columns="6" aria-selected="false" tabindex="-1">6</button>
58
+ </div>
71
59
  </div>
72
60
 
73
61
  <button
@@ -85,7 +73,23 @@
85
73
  </button>
86
74
  </div>
87
75
  </nav>
76
+ <button class="icon-button rescan-button" type="button" aria-label="Refresh images" data-i18n-aria-label="Refresh images" title="Refresh images" data-i18n-title="Refresh images">
77
+ <svg class="lucide refresh-icon" viewBox="0 0 24 24" aria-hidden="true">
78
+ <path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"></path>
79
+ <path d="M21 3v5h-5"></path>
80
+ <path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"></path>
81
+ <path d="M8 16H3v5"></path>
82
+ </svg>
83
+ <svg class="lucide loading-ring-icon" viewBox="0 0 24 24" aria-hidden="true">
84
+ <path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
85
+ </svg>
86
+ </button>
87
+ </header>
88
88
 
89
+
90
+
91
+ <div class="library-feed">
92
+ <button class="new-images-chip" type="button" hidden><span class="new-images-arrow" aria-hidden="true">↑</span><span class="new-images-label"></span></button>
89
93
  <div class="library-scroll">
90
94
  <section class="empty-state" hidden>
91
95
  <h2 data-i18n="No images yet">No images yet</h2>
@@ -95,6 +99,7 @@
95
99
  <section class="image-grid" aria-label="Generated images" data-i18n-aria-label="Generated images"></section>
96
100
  <div class="page-sentinel" aria-hidden="true" hidden></div>
97
101
  </div>
102
+ </div>
98
103
  </section>
99
104
 
100
105
  <div class="status-announcer" role="status" aria-live="polite" aria-atomic="true"></div>
@@ -44,6 +44,12 @@
44
44
  --radius-lg: 12.5px;
45
45
  --radius-xl: 15px;
46
46
  --shadow-xl: 0 8px 30px rgb(0 0 0 / 14%);
47
+ --library-gutter: clamp(20px, 4vw, 56px);
48
+ --library-card-radius: 16px;
49
+ --library-canvas: color-mix(in srgb, var(--color-token-main-surface-primary) 98.8%, var(--color-text-foreground));
50
+ --library-card-border: light-dark(rgb(0 0 0 / 5%), var(--color-border-subtle));
51
+ --library-card-shadow: 0 4px 16px 0 light-dark(rgb(0 0 0 / 5%), rgb(0 0 0 / 16%));
52
+ --library-detail-gutter: clamp(20px, 3vw, 40px);
47
53
  font-family: var(--font-sans-default);
48
54
  background: var(--color-token-main-surface-primary);
49
55
  color: var(--color-text-foreground);
@@ -162,6 +168,25 @@ button { color: inherit; }
162
168
  background: var(--color-token-main-surface-primary);
163
169
  }
164
170
 
171
+ /* 侧栏分界不占用布局宽度。 */
172
+ :root[data-sidebar-open="true"] .library-shell::before {
173
+ content: "";
174
+ position: absolute;
175
+ z-index: 12;
176
+ inset: 0 auto 0 0;
177
+ width: 1px;
178
+ background: var(--color-border);
179
+ pointer-events: none;
180
+ }
181
+
182
+ .library-header button,
183
+ .library-header select,
184
+ .source-menu { -webkit-app-region: no-drag; }
185
+
186
+ .library-header .rescan-button {
187
+ margin-right: calc(var(--library-scrollbar-width, 0px) - 10px);
188
+ }
189
+
165
190
  .library-pane {
166
191
  width: 100%;
167
192
  min-width: 0;
@@ -170,7 +195,7 @@ button { color: inherit; }
170
195
  flex-direction: column;
171
196
  overflow: hidden;
172
197
  container-type: inline-size;
173
- background: var(--color-token-main-surface-primary);
198
+ background: var(--library-canvas);
174
199
  transform: translateX(0);
175
200
  transition: transform 160ms cubic-bezier(0.23, 1, 0.32, 1);
176
201
  }
@@ -219,7 +244,7 @@ button { color: inherit; }
219
244
 
220
245
  .library-header,
221
246
  .drawer-header {
222
- height: 46px;
247
+ height: 72px;
223
248
  display: flex;
224
249
  align-items: center;
225
250
  border-bottom: 1px solid var(--color-border);
@@ -230,7 +255,10 @@ button { color: inherit; }
230
255
  flex: 0 0 auto;
231
256
  z-index: 4;
232
257
  justify-content: space-between;
233
- padding: 0 10px 0 16px;
258
+ gap: 16px;
259
+ padding: 0 var(--library-gutter);
260
+ border-bottom: 0;
261
+ background: var(--library-canvas);
234
262
  }
235
263
 
236
264
  .identity {
@@ -261,23 +289,27 @@ h1,
261
289
  letter-spacing: -0.01em;
262
290
  }
263
291
 
292
+ .library-header h1 {
293
+ font-size: 26px;
294
+ font-weight: 600;
295
+ letter-spacing: -0.035em;
296
+ }
297
+
264
298
  .library-toolbar {
265
- min-height: 42px;
266
- padding: 0 10px 0 12px;
267
- flex: 0 0 auto;
268
- z-index: 3;
299
+ min-width: 0;
300
+ flex: 1 1 auto;
269
301
  display: flex;
270
302
  align-items: center;
271
- justify-content: space-between;
303
+ justify-content: flex-end;
272
304
  gap: 12px;
273
- border-bottom: 1px solid var(--color-border);
274
- background: var(--color-token-main-surface-primary);
305
+ border: 0;
306
+ background: transparent;
275
307
  }
276
308
 
277
309
  .drawer-open .library-pane,
278
310
  .thread-context .library-pane {
279
311
  width: 20%;
280
- transform: translateX(-8px);
312
+ transform: translateX(0);
281
313
  transition-duration: 200ms;
282
314
  }
283
315
 
@@ -298,18 +330,18 @@ h1,
298
330
  }
299
331
 
300
332
  .toolbar-button {
301
- height: 28px;
333
+ height: 36px;
302
334
  min-width: 0;
303
335
  border: 1px solid transparent;
304
- border-radius: 8px;
336
+ border-radius: 999px;
305
337
  display: inline-flex;
306
338
  align-items: center;
307
339
  gap: 6px;
308
- padding: 0 8px;
340
+ padding: 0 14px;
309
341
  color: var(--color-text-foreground-secondary);
310
342
  background: transparent;
311
343
  cursor: pointer;
312
- font-size: var(--text-xs);
344
+ font-size: var(--text-sm);
313
345
  font-weight: 500;
314
346
  }
315
347
 
@@ -353,10 +385,9 @@ h1,
353
385
 
354
386
  .filter-count {
355
387
  flex: 0 0 auto;
356
- min-width: 20px;
357
- padding: 2px 5px;
358
- border-radius: 5px;
359
- background: var(--color-background-button-secondary);
388
+ min-width: 0;
389
+ padding: 0;
390
+ background: transparent;
360
391
  line-height: 1;
361
392
  text-align: center;
362
393
  }
@@ -369,44 +400,51 @@ h1,
369
400
  }
370
401
 
371
402
  .source-filter-button:hover,
372
- .source-filter-button[aria-expanded="true"] { background: transparent; }
403
+ .source-filter-button[aria-expanded="true"] { background: var(--color-background-button-secondary-hover); }
373
404
  .source-filter-button[aria-expanded="true"] .filter-chevron { transform: rotate(180deg); }
374
405
 
375
406
  .source-menu {
376
407
  position: absolute;
377
408
  top: calc(100% + 6px);
378
409
  z-index: 20;
379
- border: 1px solid var(--color-border-heavy);
380
- border-radius: var(--radius-md);
410
+ border: 0;
411
+ border-radius: 16px;
381
412
  background: var(--color-background-elevated-primary-opaque);
382
- box-shadow: var(--shadow-xl);
413
+ box-shadow: 0 8px 32px var(--color-border-heavy);
383
414
  }
384
415
 
385
416
  .source-menu[hidden] { display: none; }
386
417
 
418
+ /* 透明边框保留固定底部留白,不随列表内容滚走。 */
419
+ #source-menu {
420
+ border-bottom: 8px solid transparent;
421
+ padding-bottom: 0;
422
+ }
423
+
424
+
387
425
  .source-menu {
388
426
  left: 0;
389
- width: 240px;
390
- max-height: min(342px, calc(100vh - 108px));
391
- padding: 5px;
427
+ width: min(260px, calc(100vw - 32px));
428
+ max-height: min(400px, calc(100vh - 96px));
429
+ padding: 6px;
392
430
  overflow-y: auto;
393
431
  }
394
432
 
395
433
  .source-option {
396
434
  width: 100%;
397
- min-height: 32px;
435
+ min-height: 36px;
398
436
  border: 0;
399
- border-radius: 7px;
437
+ border-radius: 10px;
400
438
  display: grid;
401
439
  grid-template-columns: 16px minmax(0, 1fr) auto;
402
440
  align-items: center;
403
441
  gap: 7px;
404
- padding: 5px 8px;
442
+ padding: 8px 10px;
405
443
  color: var(--color-text-foreground-secondary);
406
444
  background: transparent;
407
445
  cursor: pointer;
408
446
  text-align: left;
409
- font-size: var(--text-xs);
447
+ font-size: var(--text-sm);
410
448
  }
411
449
 
412
450
  .source-option:hover,
@@ -430,74 +468,18 @@ h1,
430
468
  background: var(--color-border);
431
469
  }
432
470
 
433
- .density-control {
434
- height: 28px;
435
- border-radius: 8px;
436
- display: flex;
437
- align-items: center;
438
- gap: 6px;
439
- padding: 0 4px 0 7px;
440
- color: var(--color-text-foreground-tertiary);
441
- }
442
-
443
- .density-icon {
444
- width: 14px;
445
- height: 14px;
446
- flex: 0 0 auto;
447
- }
448
-
449
- .density-slider {
450
- width: 92px;
451
- height: 18px;
452
- margin: 0;
453
- appearance: none;
454
- border: 0;
455
- outline: 0;
456
- background: transparent;
457
- cursor: pointer;
458
- }
459
-
460
- .density-slider::-webkit-slider-runnable-track {
461
- height: 4px;
462
- border: 0;
463
- border-radius: 999px;
464
- background: var(--color-border-heavy);
465
- }
466
-
467
- .density-slider::-webkit-slider-thumb {
468
- width: 10px;
469
- height: 10px;
470
- margin-top: -3px;
471
- appearance: none;
472
- border: 0;
473
- border-radius: 50%;
474
- background: var(--color-text-foreground-secondary);
475
- }
476
-
477
- .density-slider:hover::-webkit-slider-thumb {
478
- background: var(--color-text-foreground);
479
- }
480
-
481
- .density-slider::-moz-range-track {
482
- height: 4px;
483
- border: 0;
484
- border-radius: 999px;
485
- background: var(--color-border-heavy);
486
- }
487
-
488
- .density-slider::-moz-range-thumb {
489
- width: 10px;
490
- height: 10px;
491
- border: 0;
492
- border-radius: 50%;
493
- background: var(--color-text-foreground-secondary);
494
- }
495
-
496
- .density-button-value {
497
- min-width: 10px;
498
- font-size: 10px;
499
- text-align: center;
471
+ .density-control { display: flex; align-items: center; }
472
+ .density-icon { width: 14px; height: 14px; flex: 0 0 auto; }
473
+ .source-filter-button, .density-trigger {
474
+ font-size: var(--text-sm);
475
+ font-weight: 400;
476
+ color: var(--color-icon-tertiary);
500
477
  }
478
+ .density-trigger { padding-inline: 8px; }
479
+ .density-menu { left: auto; right: 0; width: 76px; }
480
+ .density-menu .source-option { display: flex; justify-content: space-between; }
481
+ .density-menu .source-option[aria-selected="true"]::after { content: "✓"; }
482
+ .density-menu .source-option:focus-visible { outline-offset: -2px; }
501
483
 
502
484
  .group-button[aria-pressed="true"] {
503
485
  color: var(--color-text-foreground);
@@ -576,7 +558,7 @@ h1,
576
558
  .icon-button:focus-visible,
577
559
  .toolbar-button:focus-visible,
578
560
  .source-option:focus-visible,
579
- .density-slider:focus-visible,
561
+ .density-trigger:focus-visible,
580
562
  .image-card:focus-visible,
581
563
  .thread-board:focus-visible {
582
564
  outline: 2px solid var(--color-border-focus);
@@ -585,8 +567,8 @@ h1,
585
567
 
586
568
  .image-grid {
587
569
  --image-grid-gap: 16px;
588
- --grid-columns: 3;
589
- padding: 18px 20px 36px;
570
+ --grid-columns: 4;
571
+ padding: 0 var(--library-gutter) 48px;
590
572
  display: grid;
591
573
  grid-template-columns: repeat(var(--grid-columns), minmax(0, 1fr));
592
574
  grid-auto-rows: 1px;
@@ -602,29 +584,30 @@ h1,
602
584
 
603
585
  .image-card,
604
586
  .thread-board {
587
+ position: relative;
605
588
  width: 100%;
606
589
  margin: 0 0 var(--image-grid-gap);
607
590
  padding: 0;
608
591
  overflow: hidden;
609
- border: 1px solid var(--color-border);
610
- border-radius: var(--radius-lg);
592
+ border: 1px solid var(--library-card-border);
593
+ border-radius: var(--library-card-radius);
594
+ box-shadow: var(--library-card-shadow);
611
595
  display: block;
612
596
  color: var(--color-text-foreground);
613
- background: var(--color-token-bg-secondary);
597
+ background: var(--color-token-main-surface-primary);
614
598
  cursor: pointer;
615
599
  text-align: left;
616
600
  transition: background-color 120ms ease, border-color 120ms ease, transform 120ms ease;
617
601
  }
618
602
 
619
- .image-card:hover,
620
- .image-card.is-selected,
621
- .thread-board:hover {
622
- border-color: var(--color-border-heavy);
623
- background: var(--color-token-list-hover-background);
603
+ .image-card.is-wide {
604
+ --library-card-shadow: 0 4px 16px 0 light-dark(rgb(0 0 0 / 7%), rgb(0 0 0 / 20%));
624
605
  }
625
606
 
626
- .image-card:hover,
627
- .thread-board:hover { transform: translateY(-1px); }
607
+ .image-card.is-selected {
608
+ outline: 2px solid var(--color-border-focus);
609
+ outline-offset: 3px;
610
+ }
628
611
 
629
612
  .image-card img {
630
613
  width: 100%;
@@ -678,14 +661,14 @@ h1,
678
661
  }
679
662
 
680
663
  .thread-board-caption {
681
- min-height: 72px;
682
- padding: 8px 10px 9px;
683
- border-top: 1px solid var(--color-border);
664
+ min-height: 80px;
665
+ padding: 12px 16px;
666
+ border-top: 0;
684
667
  display: flex;
685
668
  flex-direction: column;
686
669
  justify-content: center;
687
670
  gap: 2px;
688
- background: var(--color-background-panel);
671
+ background: var(--color-token-main-surface-primary);
689
672
  font-size: var(--text-xs);
690
673
  white-space: nowrap;
691
674
  }
@@ -707,18 +690,30 @@ h1,
707
690
  }
708
691
 
709
692
  .card-caption {
710
- min-height: 54px;
711
- padding: 7px 10px 8px;
712
- border-top: 1px solid var(--color-border);
693
+ position: absolute;
694
+ inset: auto 10px 10px;
695
+ min-height: 48px;
696
+ padding: 8px 12px;
697
+ border: 1px solid var(--color-border-subtle);
698
+ border-radius: var(--radius-lg);
713
699
  display: flex;
714
700
  flex-direction: column;
715
- align-items: stretch;
716
- justify-content: center;
717
701
  gap: 2px;
718
- background: var(--color-background-panel);
702
+ background: color-mix(in srgb, var(--color-token-main-surface-primary) 94%, transparent);
703
+ backdrop-filter: blur(12px);
719
704
  font-size: var(--text-xs);
720
705
  font-variant-numeric: tabular-nums;
721
706
  white-space: nowrap;
707
+ opacity: 0;
708
+ pointer-events: none;
709
+ transition: opacity 120ms ease;
710
+ }
711
+
712
+ .image-card:hover .card-caption,
713
+ .image-card:focus-visible .card-caption { opacity: 1; }
714
+
715
+ @media (hover: none) {
716
+ .card-caption { opacity: 1; }
722
717
  }
723
718
 
724
719
  .source-value {
@@ -809,15 +804,18 @@ h1,
809
804
  }
810
805
 
811
806
  .drawer-open .image-grid {
812
- --image-grid-gap: 12px;
807
+ --image-grid-gap: 16px;
808
+ padding: 0 20px 20px;
813
809
  grid-template-columns: 1fr;
814
810
  }
815
811
  .drawer-open .image-card .card-caption { display: none; }
812
+ .drawer-open .library-header { padding-inline: 20px; }
813
+ .drawer-open .library-header h1 { font-size: var(--text-heading-sm); }
816
814
 
817
815
  .drawer-header {
818
816
  flex: 0 0 auto;
819
817
  justify-content: space-between;
820
- padding: 0 9px 0 16px;
818
+ padding: 0 var(--library-detail-gutter);
821
819
  border-bottom: 0;
822
820
  }
823
821
 
@@ -829,18 +827,17 @@ h1,
829
827
  }
830
828
 
831
829
  .drawer-figure {
832
- min-height: 180px;
833
830
  margin: 0;
834
- padding: 16px;
831
+ padding: 0;
835
832
  display: grid;
836
833
  place-items: center;
837
- background: var(--color-token-bg-primary);
834
+ background: transparent;
838
835
  }
839
836
 
840
837
  /* Native-token image editor: tokens arrive from RuntimeHost with the active Codex theme. */
841
- .image-editor { position: relative; background: var(--color-token-bg-primary); }
838
+ .image-editor { position: relative; margin: 0 var(--library-detail-gutter) 8px; border-radius: var(--library-card-radius); background: transparent; }
842
839
  .image-editor [hidden] { display: none !important; }
843
- .image-editor-controls { position: sticky; z-index: 6; top: 0; background: var(--color-token-bg-primary); }
840
+ .image-editor-controls { position: sticky; z-index: 6; top: 0; border-radius: var(--library-card-radius) var(--library-card-radius) 0 0; background: transparent; }
844
841
  .image-editor-toolbar { position: relative; display: flex; justify-content: center; min-height: 48px; padding: 8px 16px; }
845
842
  .image-edit-actions, .image-edit-mode { display: flex; min-width: 0; align-items: center; gap: 2px; padding: 2px; overflow: hidden; border-radius: 9999px; background: color-mix(in srgb, var(--color-surface-tertiary) 95%, transparent); box-shadow: 0 0 0 1px var(--color-border-subtle), var(--shadow-md); backdrop-filter: blur(4px); }
846
843
  .image-edit-action, .image-edit-mode button { display: inline-flex; height: 28px; align-items: center; justify-content: center; gap: 4px; border: 1px solid transparent; border-radius: 999px; padding: 0 6px; background: transparent; color: var(--color-text-foreground); font-family: var(--font-sans-default); font-size: var(--text-base); font-weight: var(--font-weight-normal); line-height: 18px; white-space: nowrap; cursor: pointer; }
@@ -870,7 +867,7 @@ h1,
870
867
  .image-menu-separator { height: 1px; margin: 0 8px; background: var(--color-border); }
871
868
  .image-zoom-menu { width: 136px; padding: 6px; border-radius: 10px; }
872
869
  .image-zoom-menu button { border-radius: 6px; padding: 5px 5px 5px 8px; line-height: 20px; }
873
- .image-editor-stage { position: relative; overflow: auto; touch-action: none; }
870
+ .image-editor-stage { position: relative; overflow: auto; border-radius: var(--library-card-radius); touch-action: none; }
874
871
  .image-editor-stage img { transform-origin: center; transition: transform 120ms ease-out; }
875
872
  .image-edit-mask, .image-comment-layer { position: absolute; inset: 0; width: 100%; height: 100%; }
876
873
  .image-edit-mask { cursor: crosshair; opacity: .5; color: var(--color-text-accent); }
@@ -900,6 +897,8 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
900
897
  @media (max-width: 520px) { .image-edit-action span { display: none; } .image-edit-action { width: 28px; padding: 0; } }
901
898
 
902
899
  .drawer-figure img {
900
+ width: auto;
901
+ height: auto;
903
902
  max-width: 100%;
904
903
  max-height: min(68vh, 720px);
905
904
  display: block;
@@ -908,10 +907,13 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
908
907
  }
909
908
 
910
909
  .detail-section {
911
- padding: 16px;
912
- border-top: 1px solid var(--color-border);
910
+ margin: 0 var(--library-detail-gutter);
911
+ padding: 24px 0;
912
+ border-top: 0;
913
913
  }
914
914
 
915
+ .detail-section + .detail-section { border-top: 1px solid var(--color-border-subtle); }
916
+
915
917
  .detail-section h3 {
916
918
  margin-bottom: 10px;
917
919
  color: var(--color-text-foreground);
@@ -946,7 +948,7 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
946
948
  white-space: pre-wrap;
947
949
  color: var(--color-text-foreground-secondary);
948
950
  font-size: var(--text-sm);
949
- line-height: 1.55;
951
+ line-height: 1.75;
950
952
  }
951
953
 
952
954
  .drawer-prompt.is-loading,
@@ -979,10 +981,10 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
979
981
 
980
982
  .drawer-actions {
981
983
  min-height: 56px;
982
- padding: 10px 12px;
984
+ padding: 10px var(--library-detail-gutter);
983
985
  flex: 0 0 auto;
984
986
  display: grid;
985
- grid-template-columns: repeat(2, minmax(0, 200px));
987
+ grid-template-columns: repeat(2, minmax(0, 144px));
986
988
  justify-content: end;
987
989
  gap: 12px;
988
990
  border-top: 1px solid var(--color-border);
@@ -997,6 +999,12 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
997
999
 
998
1000
  .source-button { width: 100%; }
999
1001
  .save-button { width: 100%; }
1002
+ .drawer-actions button { min-height: 34px; padding-block: 6px; border-radius: 999px; }
1003
+ .library-header .rescan-button,
1004
+ .toolbar-actions .group-button,
1005
+ .drawer-close { width: 36px; min-height: 36px; border-radius: 999px; }
1006
+ /* 补偿热区与 SVG 内部留白,让叉号本身贴齐图片区域右缘。 */
1007
+ .drawer-close { margin-right: -14px; }
1000
1008
 
1001
1009
  .source-action.is-disabled .source-button {
1002
1010
  pointer-events: none;
@@ -1062,16 +1070,21 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
1062
1070
  }
1063
1071
 
1064
1072
  @container (max-width: 520px) {
1065
- .library-toolbar { padding-left: 8px; }
1066
- .density-slider { width: 64px; }
1067
- .density-button-value { display: none; }
1073
+ .library-header { gap: 8px; }
1074
+ .library-toolbar { gap: 4px; }
1075
+ .source-filter-button { max-width: 130px; padding-inline: 10px; }
1076
+ .filter-source-icon, .filter-count, .density-icon { display: none; }
1077
+ .toolbar-actions { gap: 2px; }
1078
+ .density-control { padding: 0; }
1068
1079
  .image-grid { grid-template-columns: 1fr; }
1069
1080
  }
1070
1081
 
1071
1082
  @media (max-width: 520px) {
1072
- .image-grid {
1073
- padding: 10px;
1074
- }
1083
+ :root { --library-gutter: 16px; --library-detail-gutter: 16px; --library-card-radius: 16px; }
1084
+ .library-header, .drawer-header { height: 60px; }
1085
+ .library-header h1 { font-size: 20px; }
1086
+ .image-grid { --image-grid-gap: 16px; padding: 0 16px 16px; }
1087
+ .drawer-figure { padding: 0; }
1075
1088
  }
1076
1089
 
1077
1090
  @media (prefers-reduced-motion: reduce) {
@@ -1082,3 +1095,20 @@ button.image-comment-marker { pointer-events: auto; cursor: pointer; }
1082
1095
  transition-duration: 0.01ms !important;
1083
1096
  }
1084
1097
  }
1098
+
1099
+ /* 浮条锚定内容区,既不占据网格空间,也不随图片滚动。 */
1100
+ .library-feed { position: relative; display: flex; flex: 1; min-height: 0; }
1101
+ .library-feed > .library-scroll { width: 100%; }
1102
+ .new-images-chip {
1103
+ position: absolute; z-index: 5; top: 12px; left: 50%; transform: translateX(-50%);
1104
+ display: flex; align-items: center; gap: 8px;
1105
+ min-height: 36px; padding: 8px 16px; border: 1px solid var(--color-border);
1106
+ border-radius: 999px; background: var(--color-surface-elevated-secondary);
1107
+ color: var(--color-text-foreground); font: 500 13px/18px var(--font-sans-default);
1108
+ box-shadow: 0 2px 6px #0000000a, 0 8px 24px #00000014;
1109
+ white-space: nowrap; cursor: pointer; -webkit-app-region: no-drag;
1110
+ }
1111
+ .new-images-chip:hover { background: var(--color-background-panel); }
1112
+ .new-images-chip:focus-visible { outline: 2px solid var(--color-border-focus); outline-offset: 3px; }
1113
+ .new-images-arrow { font-size: 18px; line-height: 18px; }
1114
+ .new-images-chip[hidden], .drawer-open .new-images-chip, .thread-context .new-images-chip { display: none; }
@@ -10,6 +10,7 @@ Codex Composer 原生模型选择器的轻量增强功能。它通过同级
10
10
  - 收藏常用 `provider/model`,保持原目录顺序;
11
11
  - 较长的模型列表保持紧凑、可滚动;
12
12
  - 所有模型共用 Slider,动态读取模型支持的思考档位;
13
+ - 同时兼容旧版 reasoning 回调与新版 power selection 控制器契约;
13
14
  - 沿用原生面板的间距、重置入口;仅实际支持 Fast 时显示闪电按钮;
14
15
  - Chat/Temporary Chat 完全使用原生模型选择器,不注入增强面板或拦截模型菜单。
15
16
 
@@ -19,7 +20,18 @@ Codex Composer 原生模型选择器的轻量增强功能。它通过同级
19
20
  npm test
20
21
  ```
21
22
 
22
- 真实 UI 仅在隔离 profile 中验证:
23
+ 真实 UI 仅在隔离 profile 中验证。先显式启动独立 Codex 实例:
24
+
25
+ ```bash
26
+ open -na /Applications/ChatGPT.app --args \
27
+ --user-data-dir="$HOME/.codex-model-slider/codex-profile" \
28
+ --remote-debugging-address=127.0.0.1 \
29
+ --remote-debugging-port=9233 \
30
+ --remote-allow-origins=http://127.0.0.1:9233 \
31
+ --no-first-run
32
+ ```
33
+
34
+ 再启动只加载 Model Slider 的 RuntimeHost:
23
35
 
24
36
  ```bash
25
37
  CODEX_FEATURES_ROOT="$PWD/features" \