minecodex 2.0.2 → 2.0.3

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 (101) hide show
  1. package/DESIGN.md +149 -0
  2. package/apps/dashboard/DESIGN.md +45 -0
  3. package/features/images/DESIGN.md +71 -0
  4. package/features/images/README.md +2 -0
  5. package/features/images/codex-feature.json +2 -1
  6. package/features/images/src/adapters/codex/cloud-import.mjs +52 -0
  7. package/features/images/src/adapters/codex/image-prompt.mjs +22 -0
  8. package/features/images/src/adapters/codex/library-api.mjs +55 -0
  9. package/features/images/src/adapters/codex/library-viewer.mjs +18 -0
  10. package/features/images/src/adapters/codex/prompt-resolver-source.mjs +8 -0
  11. package/features/images/src/backend/cloud-library.mjs +10 -0
  12. package/features/images/src/domain/library-prompt.mjs +7 -0
  13. package/features/images/src/library-prompt-page.mjs +7 -75
  14. package/features/images/src/library-prompt-source.mjs +10 -0
  15. package/features/images/web/app.js +9 -9
  16. package/features/images/web/styles.css +219 -219
  17. package/features/model-slider/DESIGN.md +34 -0
  18. package/features/model-slider/src/adapters/codex/controller.mjs +93 -0
  19. package/features/model-slider/src/domain/model-rules.mjs +143 -0
  20. package/features/model-slider/src/frontend/install.mjs +2110 -0
  21. package/features/model-slider/src/injection-source.mjs +10 -0
  22. package/features/notes/DESIGN.md +13 -15
  23. package/features/notes/README.md +7 -1
  24. package/features/notes/assets/icons/book-open-nav-fill.svg +1 -0
  25. package/features/notes/codex-feature.json +5 -1
  26. package/features/notes/src/{default-prompts.mjs → backend/default-prompts.mjs} +1 -1
  27. package/features/notes/src/{product.mjs → backend/product.mjs} +1 -1
  28. package/features/notes/src/{quick-prompts-server.mjs → backend/quick-prompts-server.mjs} +2 -2
  29. package/features/notes/src/{quick-prompts-page.mjs → frontend/entry.mjs} +64 -257
  30. package/features/notes/src/frontend/icons.json +13 -0
  31. package/features/notes/src/frontend/styles.css +110 -0
  32. package/features/notes/src/main.mjs +2 -2
  33. package/features/notes/vendor/phosphor-LICENSE +21 -0
  34. package/features/session-status/DESIGN.md +7 -7
  35. package/features/session-status/README.md +4 -0
  36. package/features/session-status/codex-feature.json +1 -1
  37. package/features/session-status/src/adapters/codex/context-usage.mjs +39 -0
  38. package/features/session-status/src/adapters/codex/session-log.mjs +81 -0
  39. package/features/session-status/src/adapters/codex/session-reader.mjs +106 -0
  40. package/features/session-status/src/domain/session-stats.mjs +141 -0
  41. package/features/session-status/src/injection-source.mjs +6 -0
  42. package/features/session-status/src/session-status.mjs +41 -101
  43. package/features/sidebar-focus/DESIGN.md +6 -5
  44. package/features/sidebar-focus/codex-feature.json +2 -1
  45. package/features/sidebar-focus/src/adapters/codex/renderer.mjs +28 -0
  46. package/features/sidebar-focus/src/injection-source.mjs +6 -0
  47. package/features/sidebar-focus/src/sidebar-focus.mjs +19 -66
  48. package/features/sites/DESIGN.md +60 -0
  49. package/features/sites/README.md +27 -0
  50. package/features/sites/codex-feature.json +28 -0
  51. package/features/sites/src/adapters/codex/catalog.mjs +26 -0
  52. package/features/sites/src/adapters/codex/renderer.mjs +83 -0
  53. package/features/sites/src/backend/discovery.mjs +73 -0
  54. package/features/sites/src/backend/project-sites.mjs +34 -0
  55. package/features/sites/src/backend/site-launcher.mjs +54 -0
  56. package/features/sites/src/backend/sites-preview.mjs +53 -0
  57. package/features/sites/src/backend/sites-service.mjs +162 -0
  58. package/features/sites/src/domain/site.mjs +40 -0
  59. package/features/sites/src/frontend/entry.mjs +383 -0
  60. package/features/sites/src/frontend/icons.json +12 -0
  61. package/features/sites/src/frontend/styles.css +72 -0
  62. package/features/sites/src/injection-source.mjs +7 -0
  63. package/features/sites/vendor/lucide-LICENSE +35 -0
  64. package/features/unread-inbox/DESIGN.md +6 -2
  65. package/features/unread-inbox/codex-feature.json +2 -1
  66. package/features/unread-inbox/src/adapters/codex/renderer.mjs +66 -0
  67. package/features/unread-inbox/src/injection-source.mjs +6 -0
  68. package/features/unread-inbox/src/unread-inbox.mjs +34 -89
  69. package/features/usage-meter/DESIGN.md +9 -9
  70. package/features/usage-meter/README.md +2 -1
  71. package/features/usage-meter/codex-feature.json +3 -3
  72. package/features/usage-meter/src/adapters/codex/renderer.mjs +61 -0
  73. package/features/usage-meter/src/injection-source.mjs +6 -0
  74. package/features/usage-meter/src/usage-meter.mjs +27 -66
  75. package/package.json +17 -4
  76. package/packages/cli/src/config.mjs +2 -1
  77. package/packages/codex-adapter/README.md +15 -0
  78. package/packages/codex-adapter/package.json +1 -0
  79. package/packages/codex-adapter/src/renderer/environment.mjs +53 -0
  80. package/packages/runtime-host/README.md +27 -0
  81. package/packages/runtime-host/src/codex-injection.mjs +32 -2393
  82. package/packages/runtime-host/src/codex-runtime.mjs +21 -3
  83. package/packages/runtime-host/src/feature-registry.mjs +28 -3
  84. package/packages/ui/DESIGN.md +31 -0
  85. package/packages/ui/package.json +8 -0
  86. package/packages/ui/src/components/button.mjs +21 -0
  87. package/packages/ui/src/components/composer-menu.mjs +18 -0
  88. package/packages/ui/src/components/dialog.mjs +55 -0
  89. package/packages/ui/src/components/navigation-rail.mjs +77 -0
  90. package/packages/ui/src/components/page.mjs +8 -0
  91. package/packages/ui/src/components/tooltip.mjs +96 -0
  92. package/packages/ui/src/foundation/layers.mjs +14 -0
  93. package/packages/ui/src/foundation/surfaces.mjs +34 -0
  94. package/packages/ui/src/install.mjs +22 -0
  95. package/packages/ui/src/native/navigation-rail.mjs +33 -0
  96. package/packages/ui/src/native/theme.mjs +35 -0
  97. package/packages/{runtime-host/src/codex-design-contract.mjs → ui/src/native/tokens.mjs} +67 -24
  98. package/packages/runtime-host/src/cloud-images.mjs +0 -123
  99. package/packages/runtime-host/src/feature-tooltips.mjs +0 -65
  100. package/packages/runtime-host/src/session-status-reader.mjs +0 -340
  101. /package/features/notes/src/{prompt-schema.mjs → backend/prompt-schema.mjs} +0 -0
@@ -1,154 +1,13 @@
1
- const ICONS = {
2
- prompt:
3
- '<svg\n class="lucide lucide-book-open"\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="-1.5 -1.5 27 27"\n fill="none"\n stroke="currentColor"\n stroke-width="1.5"\n stroke-linecap="round"\n stroke-linejoin="round"\n>\n <path vector-effect="non-scaling-stroke" d="M12 7v14" />\n <path vector-effect="non-scaling-stroke" d="M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" />\n</svg>',
4
- chevron:
5
- '<!-- @license lucide-static v0.577.0 - ISC -->\n<svg\n class="lucide lucide-chevron-down"\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n stroke="currentColor"\n stroke-width="2"\n stroke-linecap="round"\n stroke-linejoin="round"\n>\n <path d="m6 9 6 6 6-6" />\n</svg>\n',
6
- search:
7
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path fill-rule="evenodd" clip-rule="evenodd" d="M7.32849 1.91016C10.2877 1.91016 12.6867 4.30938 12.6869 7.26855C12.6869 8.57363 12.2192 9.7688 11.4437 10.6982L14.0433 13.2979C14.2481 13.5028 14.2481 13.8351 14.0433 14.04C13.8384 14.245 13.5062 14.2449 13.3011 14.04L10.6957 11.4346C9.77536 12.1793 8.60462 12.627 7.32849 12.627C4.36931 12.6268 1.97009 10.2278 1.97009 7.26855C1.97027 4.30949 4.36942 1.91033 7.32849 1.91016ZM7.32849 2.96094C4.94932 2.96111 3.02105 4.88939 3.02087 7.26855C3.02087 9.64787 4.94921 11.577 7.32849 11.5771C9.70792 11.5771 11.6371 9.64798 11.6371 7.26855C11.6369 4.88928 9.70781 2.96094 7.32849 2.96094Z" fill="currentColor"/></svg>',
8
- "arrow-down-wide-narrow":
9
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M4.66722 3.14218C4.95711 3.14225 5.19261 3.37767 5.19261 3.66757V11.6295L6.95824 9.82578C7.16093 9.61896 7.49327 9.61573 7.70043 9.81796C7.90753 10.0208 7.91092 10.353 7.70824 10.5602L5.27953 13.0406L5.2141 13.1012C4.89729 13.3642 4.43507 13.3645 4.1184 13.1012L4.05297 13.0406L1.62523 10.5602C1.4228 10.353 1.42608 10.0207 1.63304 9.81796C1.8401 9.61558 2.17245 9.61912 2.37523 9.82578L4.14183 11.6295V3.66757C4.14183 3.37762 4.37727 3.14218 4.66722 3.14218Z" fill="currentColor"/> <path d="M10.7854 2.98203C11.1021 2.71876 11.5643 2.719 11.8811 2.98203L11.9465 3.04257L14.3752 5.52304C14.5779 5.73021 14.5745 6.06242 14.3674 6.26523C14.1603 6.46786 13.828 6.46437 13.6252 6.25742L11.8586 4.45175V12.3336C11.8584 12.6233 11.623 12.859 11.3332 12.859C11.0436 12.8588 10.8081 12.6232 10.8078 12.3336V4.45371L9.04222 6.25742C8.83948 6.46447 8.50723 6.46775 8.30004 6.26523C8.093 6.06236 8.08941 5.73017 8.29222 5.52304L10.72 3.04257L10.7854 2.98203Z" fill="currentColor"/></svg>',
10
- check:
11
- '<!-- @license lucide-static v0.577.0 - ISC -->\n<svg\n class="lucide lucide-check"\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n stroke="currentColor"\n stroke-width="2"\n stroke-linecap="round"\n stroke-linejoin="round"\n>\n <path d="M20 6 9 17l-5-5" />\n</svg>\n',
12
- x: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M10.962 4.29539C11.1669 4.09057 11.4992 4.09076 11.7042 4.29539C11.9092 4.50039 11.9091 4.83255 11.7042 5.03758L8.74229 7.99949L11.7052 10.9624C11.9097 11.1673 11.9097 11.4996 11.7052 11.7046C11.5003 11.9095 11.168 11.9093 10.963 11.7046L8.0001 8.74168L5.03721 11.7046C4.83216 11.9093 4.49994 11.9095 4.29502 11.7046C4.09047 11.4996 4.09045 11.1673 4.29502 10.9624L7.25791 7.99949L4.296 5.03758C4.09101 4.83255 4.09099 4.5004 4.296 4.29539C4.50105 4.09079 4.8333 4.09054 5.03819 4.29539L8.0001 7.2573L10.962 4.29539Z" fill="currentColor"/></svg>',
13
- back: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M9.87117 11.6289C10.0762 11.8339 10.0762 12.166 9.87117 12.3711C9.66614 12.5761 9.334 12.5761 9.12898 12.3711L5.36433 8.60641C5.0296 8.27129 5.0296 7.72863 5.36433 7.39351L9.12898 3.62887C9.334 3.42384 9.66614 3.42384 9.87117 3.62887C10.0762 3.83389 10.0762 4.16603 9.87117 4.37105L6.24226 7.99996L9.87117 11.6289Z" fill="currentColor"/></svg>',
14
- settings:
15
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path fill-rule="evenodd" clip-rule="evenodd" d="M6.33374 8.97461C7.54786 8.97484 8.56163 9.83236 8.80347 10.9746H13.3337C13.6235 10.9749 13.8591 11.2102 13.8591 11.5C13.8591 11.7898 13.6235 12.0251 13.3337 12.0254H8.80347C8.56163 13.1676 7.54786 14.0252 6.33374 14.0254C5.11907 14.0254 4.10455 13.1673 3.86304 12.0244L2.66675 12.0254C2.37691 12.0253 2.14138 11.7899 2.14136 11.5C2.14136 11.2102 2.37693 10.9748 2.66675 10.9746H3.86304C4.10491 9.83221 5.11941 8.97461 6.33374 8.97461ZM6.33374 10.0254C5.51912 10.0254 4.85913 10.6854 4.85913 11.5C4.85913 12.3146 5.51912 12.9746 6.33374 12.9746C7.14814 12.9743 7.80835 12.3145 7.80835 11.5C7.80835 10.6855 7.14814 10.0257 6.33374 10.0254Z" fill="currentColor"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.66675 1.97461C10.881 1.97461 11.8935 2.83236 12.1355 3.97461H13.3328C13.6227 3.97459 13.8581 4.21005 13.8582 4.5C13.8581 4.78993 13.6227 5.02537 13.3328 5.02539H12.1365C11.8946 6.16774 10.881 7.02539 9.66675 7.02539C8.45245 7.02539 7.43893 6.16774 7.19702 5.02539H2.66675C2.3768 5.02539 2.14136 4.78995 2.14136 4.5C2.14136 4.21005 2.3768 3.97461 2.66675 3.97461H7.19702C7.43893 2.83226 8.45245 1.97461 9.66675 1.97461ZM9.66675 3.02539C8.85213 3.02539 8.19214 3.68538 8.19214 4.5C8.19214 5.31462 8.85213 5.97461 9.66675 5.97461C10.4814 5.97461 11.1414 5.31462 11.1414 4.5C11.1414 3.68538 10.4814 3.02539 9.66675 3.02539Z" fill="currentColor"/></svg>',
16
- drag: '<svg\n xmlns="http://www.w3.org/2000/svg"\n width="24"\n height="24"\n viewBox="0 0 24 24"\n fill="none"\n stroke="currentColor"\n stroke-width="2"\n stroke-linecap="round"\n stroke-linejoin="round"\n>\n <path d="M4 5h16" />\n <path d="M4 12h16" />\n <path d="M4 19h16" />\n</svg>\n',
17
- "prompt-nav":
18
- '<svg\n class="lucide lucide-book-open"\n xmlns="http://www.w3.org/2000/svg"\n width="20"\n height="20"\n viewBox="-1.5 -1.5 27 27"\n fill="none"\n stroke="currentColor"\n stroke-width="1.8"\n stroke-linecap="round"\n stroke-linejoin="round"\n>\n <path d="M12 7v14 M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" />\n</svg>',
19
- };
1
+ const ICONS = config.resources.icons;
20
2
  const MARKER = "data-minecodex-quick-prompts";
21
3
  const zh = () => (document.documentElement.lang || navigator.language || "en").toLowerCase().startsWith("zh");
22
4
  const text = (en, cn) => (zh() ? cn : en);
23
5
  const style = document.createElement("style");
24
- style.textContent = `
25
- [${MARKER}=page] .pm-title-control { display:flex; align-items:stretch; min-height:40px; border:1px solid var(--color-border-primary-outline); border-radius:var(--radius-lg); background:var(--color-background-primary-soft); overflow:hidden; }
26
- [${MARKER}=page] .pm-title-control:focus-within { border-color:var(--color-ring); }
27
- [${MARKER}=page] .pm-title-control>.pm-emoji-trigger { display:flex; flex:none; align-items:center; justify-content:center; width:40px; padding:0; border-inline-end:1px solid var(--color-border); }
28
- [${MARKER}=page] .pm-title-control>.pm-emoji-trigger:hover { background:var(--color-background-primary-ghost-hover); }
29
- [${MARKER}=page] .pm-title-control>.pm-emoji-trigger:focus-visible { outline-offset:-3px; }
30
- [${MARKER}=page] .pm-editor .pm-title-control>input { flex:1; min-width:0; border:0; border-radius:0; background:transparent; padding:8px 10px; outline:none; box-shadow:none; }
31
-
32
- [${MARKER}=panel] { position:fixed; z-index:50; zoom:var(--codex-window-zoom,1); transform:translateY(-100%); box-sizing:border-box; display:flex; flex-direction:column; overflow:hidden; padding:var(--spacing); border:1px solid var(--color-border); border-radius:var(--radius-suggestion-menu,var(--radius-2xl)); background:var(--color-surface-elevated-secondary); color:var(--color-text-primary); font-family:var(--font-sans-default); font-size:var(--text-sm); line-height:1.43; }
33
- [${MARKER}=panel] *, [${MARKER}=button] { box-sizing:border-box; }
34
- [${MARKER}=panel] button { cursor:var(--cursor-interaction,pointer); }
35
- [${MARKER}=panel] button:disabled { opacity:.4; cursor:default; }
36
- [${MARKER}=panel] button:focus-visible, [${MARKER}=panel] input:focus-visible, [${MARKER}=panel] textarea:focus-visible { outline:2px solid var(--color-ring,var(--color-text-secondary)); outline-offset:-2px; }
37
- [${MARKER}=panel] svg { width:16px; height:16px; flex:none; }
38
- [${MARKER}=panel] .qp-header { display:flex; align-items:center; justify-content:space-between; padding:var(--spacing) var(--padding-row-x,8px); color:var(--color-text-tertiary); flex:none; }
39
- [${MARKER}=panel] .qp-scroll { overflow-y:auto; min-height:0; padding-bottom:var(--spacing); }
40
- [${MARKER}=panel] .qp-row { display:flex; align-items:center; min-width:0; border-radius:var(--suggestion-menu-item-radius,var(--radius-xl)); }
41
- [${MARKER}=panel] .qp-row:hover, [${MARKER}=panel] .qp-row:focus-within { background:var(--color-background-primary-ghost-hover); }
42
- [${MARKER}=panel] .qp-select { display:flex; flex:1; align-items:center; min-width:0; gap:calc(var(--spacing)*1.5); text-align:left; padding:var(--suggestion-menu-item-padding,var(--app-menu-item-padding,var(--padding-row-y,5px) var(--padding-row-x,8px))); border-radius:inherit; }
43
- [${MARKER}=panel] .qp-title { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
44
- [${MARKER}=panel] .qp-preview { flex:1; min-width:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:var(--color-text-tertiary); }
45
- [${MARKER}=panel] .qp-empty { padding:calc(var(--spacing)*3) var(--padding-row-x,8px); color:var(--color-text-tertiary); }
46
- [${MARKER}=panel] .qp-command { padding:var(--spacing) calc(var(--spacing)*2); border-radius:var(--radius-xl); }
47
- [${MARKER}=panel] .qp-command:hover { background:var(--color-background-primary-ghost-hover); }
48
- [${MARKER}=panel] .qp-error { color:var(--color-text-danger,var(--color-text-primary)); padding:var(--spacing) var(--padding-row-x,8px); }
49
- .qp-symbol { display:inline-flex; width:20px; height:20px; flex:none; align-items:center; justify-content:center; font-size:18px; line-height:1; color:var(--prompt-icon-light,var(--color-text-secondary)); }
50
- .qp-symbol svg { width:20px; height:20px; }
51
- .dark .qp-symbol, [data-theme=dark] .qp-symbol { color:var(--prompt-icon-dark,var(--color-text-secondary)); }
52
- [${MARKER}=page] { position:fixed; z-index:20; overflow:auto; border-radius:var(--radius-xl-base); background:var(--color-surface); color:var(--color-text-primary); font-family:var(--font-sans-default); font-size:var(--text-sm); line-height:var(--text-sm--line-height); }
53
- [${MARKER}=page] * { box-sizing:border-box; }
54
- [${MARKER}=page] button { cursor:var(--cursor-interaction,pointer); }
55
- [${MARKER}=page] button:disabled { opacity:.35; cursor:default; }
56
- [${MARKER}=page] button:focus-visible, [${MARKER}=page] input:focus-visible, [${MARKER}=page] textarea:focus-visible { outline:2px solid var(--color-text-secondary); outline-offset:2px; }
57
- [${MARKER}=page] .pm-wrap { max-width:1440px; margin:auto; padding:28px 48px 48px; }
58
- [${MARKER}=page] .pm-heading { display:flex; align-items:center; justify-content:space-between; gap:16px; min-height:36px; margin-bottom:24px; }
59
- [${MARKER}=page] h1 { font-size:var(--text-heading-lg); font-weight:var(--font-weight-medium); line-height:1.2; margin:0; }
60
- [${MARKER}=page] h2 { font-size:var(--text-base,14px); font-weight:600; margin:24px 0 12px; }
61
- [${MARKER}=page] .pm-header-actions { display:flex; align-items:center; gap:8px; }
62
- [${MARKER}=page] .pm-tab-row { display:flex; align-items:center; gap:8px; margin-bottom:24px; }
63
- [${MARKER}=page] .pm-tab-row .pm-tabs { margin-bottom:0; min-width:0; }
64
- [${MARKER}=page] .pm-icon { display:flex; align-items:center; justify-content:center; width:32px; height:32px; flex:none; padding:0; border-radius:var(--radius-full); color:var(--color-text-secondary); }
65
- [${MARKER}=page] .pm-icon[hidden] { display:none; }
66
- [${MARKER}=page] .pm-icon svg { width:16px; height:16px; }
67
- [${MARKER}=page] .pm-icon:hover, [${MARKER}=page] .pm-icon[aria-expanded=true], [${MARKER}=page] .pm-icon[aria-pressed=true] { background:var(--color-background-primary-ghost-hover); color:var(--color-text-primary); }
68
- [${MARKER}=page] .pm-popup { position:fixed; z-index:30; width:200px; padding:var(--app-menu-gutter,var(--spacing)); border-radius:var(--radius-2xl); background:color-mix(in srgb,var(--color-surface-elevated-secondary) 90%,transparent); box-shadow:0 0 0 .5px var(--color-border),var(--shadow-xl-spread,0 8px 16px -4px rgba(0,0,0,.12)); backdrop-filter:blur(4px); }
69
- [${MARKER}=page] .pm-popup button { width:100%; min-height:var(--app-menu-item-height,30px); display:flex; align-items:center; justify-content:space-between; gap:16px; padding:var(--app-menu-item-padding,5px 8px); border-radius:var(--radius-xl); text-align:left; }
70
- [${MARKER}=page] .pm-popup button:hover, [${MARKER}=page] .pm-popup button:focus-visible { background:var(--color-background-primary-ghost-hover); }
71
- [${MARKER}=page] .pm-popup svg { width:16px; height:16px; }
72
- [${MARKER}=page] .pm-command { display:inline-flex; align-items:center; justify-content:center; gap:6px; min-height:32px; padding:6px 12px; border-radius:var(--radius-full,999px); color:inherit; white-space:nowrap; }
73
- [${MARKER}=page] .pm-command:hover { background:var(--color-background-primary-ghost-hover); }
74
- [${MARKER}=page] .pm-primary { background:var(--color-background-primary-solid); color:var(--color-text-primary-solid); }
75
- [${MARKER}=page] .pm-primary:hover { background:var(--color-background-primary-solid-hover); }
76
- [${MARKER}=page] .pm-tabs { display:flex; gap:4px; overflow:auto; padding-bottom:4px; margin-bottom:24px; }
77
- [${MARKER}=page] .pm-tab { display:flex; align-items:center; gap:6px; flex:none; height:36px; border-radius:999px; padding:0 16px; font-weight:500; color:var(--color-text-secondary); }
78
- [${MARKER}=page] .pm-tab:hover, [${MARKER}=page] .pm-tab[aria-selected=true] { background:var(--color-background-primary-ghost-hover); color:var(--color-text-primary); }
79
- [${MARKER}=page] input, [${MARKER}=page] textarea { font:inherit; color:inherit; background:transparent; border:1px solid var(--color-border); border-radius:var(--radius-lg,12px); padding:8px 12px; }
80
- [${MARKER}=page] .pm-list { display:flex; flex-direction:column; gap:4px; }
81
- [${MARKER}=page] .pm-row { display:flex; align-items:center; gap:12px; padding:16px 12px; border-radius:var(--radius-xl,16px); }
82
- [${MARKER}=page] .pm-row:hover { background:var(--color-background-primary-ghost-hover); }
83
- [${MARKER}=page] .pm-info { flex:1; min-width:0; text-align:left; }
84
- [${MARKER}=page] .pm-title { font-weight:500; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }
85
- [${MARKER}=page] .pm-preview { color:var(--color-text-secondary); overflow:hidden; white-space:nowrap; text-overflow:ellipsis; margin-top:3px; }
86
- [${MARKER}=page] .pm-stats { color:var(--color-text-tertiary); min-width:130px; text-align:right; font-variant-numeric:tabular-nums; font-size:var(--text-xs,12px); }
87
- [${MARKER}=page] .pm-count { color:var(--color-text-secondary); }
88
- [${MARKER}=page] .pm-empty { color:var(--color-text-tertiary); padding:48px 0; text-align:center; }
89
- [${MARKER}=page] .pm-form { display:flex; flex-direction:column; gap:16px; }
90
- [${MARKER}=page] .pm-field { display:flex; flex-direction:column; gap:6px; color:var(--color-text-secondary); }
91
- [${MARKER}=page] .pm-field textarea { min-height:220px; resize:vertical; color:var(--color-text-primary); }
92
- [${MARKER}=page] .pm-footer { display:flex; justify-content:flex-end; gap:8px; margin-top:8px; }
93
- [${MARKER}=page] .pm-grid { display:flex; flex-wrap:wrap; gap:4px; }
94
- [${MARKER}=page] .pm-choice { width:36px; height:36px; border-radius:10px; display:flex; justify-content:center; align-items:center; }
95
- [${MARKER}=page] .pm-choice[aria-pressed=true] { background:var(--color-background-primary-ghost-hover); outline:1px solid var(--color-text-secondary); }
96
- [${MARKER}=page] .pm-swatch { width:18px; height:18px; border-radius:50%; background:currentColor; }
97
- [${MARKER}=page] .pm-error { color:var(--color-text-danger,var(--color-text-primary)); margin:12px 0; }
98
- [${MARKER}=page] .pm-editor h2 { margin-top:0; }
99
- @media(max-width:800px) { [${MARKER}=page] .pm-wrap { padding:24px 30px; } [${MARKER}=page] .pm-stats { min-width:90px; } }
100
- [${MARKER}=page] .pm-modal-layer { position:fixed; inset:0; z-index:60; display:grid; place-items:center; padding:24px; background:var(--color-background-overlay,rgba(0,0,0,.16)); }
101
- [${MARKER}=page] .pm-editor { position:relative; top:auto; width:440px; max-width:calc(100vw - 48px); max-height:calc(100vh - 64px); margin:0; padding:20px; overflow:auto; border:0; border-radius:var(--radius-3xl,25px); background:color-mix(in srgb,var(--color-surface-elevated-secondary) 90%,transparent); box-shadow:0 0 0 .5px var(--color-border),var(--shadow-lg); backdrop-filter:blur(24px); }
102
- [${MARKER}=page] .pm-prompt-editor { width:520px; }
103
- [${MARKER}=page] .pm-modal-heading { display:flex; align-items:center; gap:8px; margin:0 0 16px; }
104
- [${MARKER}=page] .pm-modal-heading h2 { flex:1; font-size:var(--text-lg,18px); font-weight:600; line-height:28px; margin:0; }
105
- [${MARKER}=page] .pm-modal-heading .pm-icon { width:28px; height:28px; }
106
- [${MARKER}=page] .pm-editor .pm-row { min-height:44px; padding:8px; gap:10px; border-radius:var(--radius-lg); }
107
- [${MARKER}=page] .pm-editor .pm-form { gap:12px; }
108
- [${MARKER}=page] .pm-editor .pm-field { gap:8px; color:var(--color-text-primary); }
109
- [${MARKER}=page] .pm-editor input, [${MARKER}=page] .pm-editor textarea { border-radius:var(--radius-md); padding:8px 10px; background:var(--color-background-primary-soft,rgba(0,0,0,.025)); }
110
- [${MARKER}=page] .pm-editor .pm-footer { margin-top:20px; gap:12px; }
111
- [${MARKER}=page] .pm-editor .pm-footer .pm-command { border-radius:var(--radius-button-action,999px); min-height:32px; padding:6px 16px; background:var(--color-background-primary-ghost-hover); }
112
- [${MARKER}=page] .pm-editor .pm-footer .pm-primary { background:var(--color-background-primary-solid); color:var(--color-text-primary-solid); }
113
- [${MARKER}=page] .pm-editor .pm-footer .pm-primary:hover { background:var(--color-background-primary-solid-hover); }
114
- [${MARKER}=page] .pm-grid { gap:4px; }
115
- [${MARKER}=page] .pm-choice { width:36px; height:36px; border-radius:var(--radius-lg); }
116
- [${MARKER}=page] .pm-choice svg { width:20px; height:20px; }
117
- [${MARKER}=page] .pm-choice[aria-pressed=true] { outline:none; box-shadow:inset 0 0 0 1px var(--color-border); }
118
- [${MARKER}=page] .pm-search-inline { display:flex; align-items:center; width:clamp(150px,22vw,300px); height:32px; padding:0 12px; gap:8px; border:1px solid var(--color-border-primary-outline,var(--color-border)); border-radius:var(--radius-full); background:transparent; }
119
- [${MARKER}=page] .pm-search-inline input { min-width:0; width:100%; padding:0; border:0; background:transparent; outline:none; }
120
- [${MARKER}=page] .pm-search-inline>svg { width:16px; height:16px; flex:none; color:var(--color-text-tertiary); }
121
- [${MARKER}=page] .pm-list>h2 { color:var(--color-text-tertiary); font-size:var(--text-sm,13px); font-weight:500; }
122
- [${MARKER}=page] .pm-stats { min-width:64px; }
123
- [${MARKER}=page] .pm-modal-heading>.pm-icon:first-child { margin-left:-11px; }
124
- [${MARKER}=page] .pm-modal-heading>.pm-icon:last-child { margin-right:-10px; }
125
- [${MARKER}=page] .pm-editor input:focus, [${MARKER}=page] .pm-editor textarea:focus, [${MARKER}=page] .pm-popup input:focus { outline:none; box-shadow:none; border-color:var(--color-ring,var(--color-border-primary-outline)); }
126
- [${MARKER}=page] .pm-editor .pm-footer .pm-danger { color:var(--color-text-danger); background:var(--color-background-danger-soft-alpha); }
127
- [${MARKER}=page] .pm-editor .pm-footer .pm-danger:hover { background:var(--color-background-danger-soft-alpha-hover); }
128
- [${MARKER}=page] .pm-confirm-description { color:var(--color-text-secondary); line-height:1.6; }
129
- [${MARKER}=page] .pm-select { display:flex; align-items:center; gap:8px; min-height:36px; padding:8px 10px; background:var(--color-background-primary-soft); border:1px solid var(--color-border); border-radius:var(--radius-md); text-align:left; }
130
- [${MARKER}=page] .pm-select>svg { width:16px; height:16px; }
131
- [${MARKER}=page] .pm-option-label { flex:1; }
132
- [${MARKER}=page] .pm-empty-state { display:flex; flex-direction:column; align-items:center; justify-content:center; min-height:340px; gap:8px; text-align:center; }
133
- [${MARKER}=page] .pm-empty-art { font-size:var(--text-5xl,48px); line-height:1; margin-bottom:8px; }
134
- [${MARKER}=page] .pm-empty-title { font-size:var(--text-lg,18px); line-height:24px; font-weight:500; }
135
- [${MARKER}=page] .pm-empty-description { color:var(--color-text-secondary); }
136
- [${MARKER}=page] .pm-empty-state>.pm-command { margin-top:24px; }
137
- [${MARKER}=page] .pm-drag { cursor:grab; color:var(--color-text-tertiary); }
138
- [${MARKER}=page] .pm-drag:active { cursor:grabbing; }
139
- [${MARKER}=page] .pm-drop-placeholder { flex:none; border:1px dashed var(--color-border-primary-outline,var(--color-border)); border-radius:var(--radius-xl); background:var(--color-background-primary-ghost-hover); box-sizing:border-box; }
140
- [${MARKER}=page] .pm-dragging { position:absolute; opacity:0; pointer-events:none; }
141
- [${MARKER}=page] .pm-popup { z-index:70; max-height:calc(100vh - 32px); overflow:auto; }
142
- [${MARKER}=page] .pm-symbol-picker { width:320px; padding:12px; display:flex; flex-direction:column; gap:12px; }
143
- [${MARKER}=page] .pm-symbol-picker>input { width:100%; flex:none; border-radius:var(--radius-full); }
144
- [${MARKER}=page] .pm-emoji-grid { display:grid; grid-template-columns:repeat(8,minmax(0,1fr)); gap:4px; max-height:264px; overflow:auto; }
145
- [${MARKER}=page] .pm-emoji-grid .pm-emoji-choice { width:32px; height:32px; min-height:32px; padding:0; display:flex; justify-content:center; font-size:22px; border-radius:var(--radius-lg); }
146
- [${MARKER}=page] .pm-emoji-choice[aria-pressed=true] { background:var(--color-background-primary-ghost-hover); }
147
- `;
6
+ style.textContent = config.resources.styles;
148
7
  document.head.append(style);
149
8
  let button = null;
150
9
  let addButton = null;
151
- let composerCard = null;
10
+ let composerRoot = null;
152
11
  let composerThread = null;
153
12
  let panel = null;
154
13
  let items = [];
@@ -210,13 +69,8 @@ function showError(error) {
210
69
  panel.append(message);
211
70
  }
212
71
  function position() {
213
- if (!panel || !composerCard?.isConnected) return;
214
- const rect = composerCard.getBoundingClientRect();
215
- const zoom = Number.parseFloat(getComputedStyle(panel).zoom) || 1;
216
- panel.style.left = `${rect.left / zoom}px`;
217
- panel.style.top = `${(rect.top - 4) / zoom}px`;
218
- panel.style.width = `${rect.width / zoom}px`;
219
- panel.style.maxHeight = `${Math.max(0, Math.min(400, (rect.top - 16) / zoom))}px`;
72
+ if (!panel || !composerRoot?.isConnected) return;
73
+ config.ui.composerMenu(panel, addButton);
220
74
  }
221
75
  function close(restoreFocus = false) {
222
76
  generation++;
@@ -251,7 +105,7 @@ async function loadList() {
251
105
  }
252
106
  }
253
107
  const COLORS = {
254
- black: ["var(--color-text-secondary)", "var(--color-text-secondary)"],
108
+ black: ["var(--mcx-color-text-secondary)", "var(--mcx-color-text-secondary)"],
255
109
  blue: ["#0285ff", "#339cff"],
256
110
  green: ["#04b84c", "#40c977"],
257
111
  orange: ["#fb6a22", "#ff8549"],
@@ -352,6 +206,7 @@ function open() {
352
206
  if (addButton.getAttribute("aria-expanded") === "true") addButton.click();
353
207
  panel = element("div");
354
208
  panel.setAttribute(MARKER, "panel");
209
+ config.ui.surface(panel, "composer-menu");
355
210
  panel.setAttribute("role", "dialog");
356
211
  panel.setAttribute("aria-label", text("Quick Prompts", "快捷提示词"));
357
212
  document.body.append(panel);
@@ -360,37 +215,34 @@ function open() {
360
215
  position();
361
216
  void loadList();
362
217
  }
218
+ function isOpenComposerMenu(node) {
219
+ return node.getAttribute("aria-expanded") === "true"
220
+ && node.checkVisibility({ visibilityProperty: true })
221
+ && (node.getAttribute("data-composer-navigation-target") === "add-context"
222
+ || node.getAttribute("aria-haspopup") === "menu");
223
+ }
363
224
  function sync() {
364
225
  if (disposed || signal.aborted) return;
365
226
  syncNavigation();
366
- const add = [
367
- ...document.querySelectorAll("[data-codex-composer-root] button"),
368
- ].find(
369
- (node) =>
370
- node.getAttribute("data-composer-navigation-target") === "add-context",
371
- );
372
- const card = add?.closest("[data-codex-composer-root]");
373
- const thread =
374
- card
375
- ?.querySelector("[data-above-composer-conversation-id]")
376
- ?.getAttribute("data-above-composer-conversation-id") ?? null;
227
+ const nativeComposer = config.codex.composer(null,{threadOnly:false});
228
+ const add = nativeComposer?.add;
229
+ const card = nativeComposer?.root;
230
+ const thread = nativeComposer?.threadId ?? null;
377
231
  if (thread !== composerThread) {
378
232
  close();
379
233
  composerThread = thread;
380
234
  }
381
- if (add !== addButton || card !== composerCard) {
235
+ if (add !== addButton || card !== composerRoot) {
382
236
  close();
383
237
  button?.remove();
384
238
  button = null;
385
239
  addButton = add;
386
- composerCard = card;
240
+ composerRoot = card;
387
241
  }
388
242
  if (!add) return;
389
243
  if (
390
244
  panel &&
391
- [...card.querySelectorAll("button[aria-expanded=true]")].some(
392
- (node) => node !== button,
393
- )
245
+ [...card.querySelectorAll("button")].some(isOpenComposerMenu)
394
246
  )
395
247
  close();
396
248
  if (!button) {
@@ -442,10 +294,10 @@ let searchText = "";
442
294
  let editor = null;
443
295
  let pageFocus = null;
444
296
  const hiddenSurfaces = new Map();
445
- const nativeNavigationSelection = new Map();
297
+ let navigationRail = null;
446
298
 
447
- function pageControl(label, handler, primary = false) {
448
- return control(label, handler, `pm-command${primary ? " pm-primary" : ""}`);
299
+ function pageControl(label, handler, primary = false, tone = "secondary") {
300
+ return config.ui.action(control(label, handler, `pm-command${primary ? " pm-primary" : ""}`), primary ? "primary" : tone);
449
301
  }
450
302
  function pageError(error) {
451
303
  if (!page) return;
@@ -456,7 +308,7 @@ function pageError(error) {
456
308
  }
457
309
  function positionPage() {
458
310
  if (!page) return;
459
- const rail = document.querySelector("[data-app-navigation-rail]");
311
+ const rail = config.codex.rail();
460
312
  if (!rail) {
461
313
  closePage();
462
314
  return;
@@ -468,30 +320,10 @@ function positionPage() {
468
320
  page.style.bottom = "4px";
469
321
  }
470
322
  function syncNavigationSelection() {
471
- if (!page) return;
472
- for (const node of document.querySelectorAll('[data-app-navigation-rail] [data-sidebar-destination][data-selected], [data-app-navigation-rail] [data-sidebar-destination][aria-current="page"]')) {
473
- if (!nativeNavigationSelection.has(node)) {
474
- nativeNavigationSelection.set(node, new Map(
475
- ["data-selected", "aria-current", "data-suppress-active-style"].map(name => [name, node.getAttribute(name)]),
476
- ));
477
- }
478
- node.removeAttribute("data-selected");
479
- node.removeAttribute("aria-current");
480
- node.setAttribute("data-suppress-active-style", "");
481
- }
482
- if (navButton && !navButton.hasAttribute("data-selected")) navButton.setAttribute("data-selected", "");
483
- if (navButton?.getAttribute("aria-current") !== "page") navButton?.setAttribute("aria-current", "page");
323
+ navigationRail?.select(Boolean(page));
484
324
  }
485
325
  function restoreNavigationSelection() {
486
- // 退出覆盖页时还原原生状态,随后由原生路由接管新的选择。
487
- for (const [node, attributes] of nativeNavigationSelection) {
488
- if (!node.isConnected) continue;
489
- for (const [name, value] of attributes) {
490
- if (value === null) node.removeAttribute(name);
491
- else node.setAttribute(name, value);
492
- }
493
- }
494
- nativeNavigationSelection.clear();
326
+ navigationRail?.select(false);
495
327
  }
496
328
  function closePage(restoreFocus = false) {
497
329
  dragState?.cancel();
@@ -530,6 +362,7 @@ function openPage() {
530
362
  pageFocus = document.activeElement;
531
363
  page = element("section");
532
364
  page.setAttribute(MARKER, "page");
365
+ config.ui.page(page);
533
366
  page.setAttribute("aria-label", text("Prompts", "提示词"));
534
367
  document.body.append(page);
535
368
  // 只隔离主内容的焦点,保留导航栏与原生窗口控件。
@@ -571,6 +404,7 @@ function makePagePopup(trigger, className, role, matchTriggerWidth = false) {
571
404
  popupTrigger = trigger;
572
405
  trigger.setAttribute("aria-expanded", "true");
573
406
  pagePopup = element("div", `pm-popup ${className}`);
407
+ config.ui.surface(pagePopup, "dropdown");
574
408
  pagePopup.setAttribute("role", role);
575
409
  pagePopup.setAttribute("aria-label", trigger.getAttribute("aria-label"));
576
410
  (editorLayer ?? page).append(pagePopup);
@@ -983,9 +817,12 @@ function field(label, input) {
983
817
  }
984
818
  let editorLayer = null;
985
819
  let editorReturnFocus = null;
820
+ let editorFocusCleanup = null;
986
821
  function closeEditor(restoreFocus = true) {
987
822
  dragState?.cancel();
988
823
  closePagePopup();
824
+ editorFocusCleanup?.();
825
+ editorFocusCleanup = null;
989
826
  editorLayer?.remove();
990
827
  editorLayer = null;
991
828
  editor = null;
@@ -999,7 +836,11 @@ function editorShell(title, back = null) {
999
836
  if (!editorLayer) {
1000
837
  editorReturnFocus = document.activeElement;
1001
838
  editorLayer = element("div", "pm-modal-layer");
1002
- page.append(editorLayer);
839
+ editorLayer.setAttribute(MARKER, "modal");
840
+ config.ui.overlay(editorLayer);
841
+ // 弹窗遮罩覆盖整个窗口,避免受页面与侧栏的层级约束。
842
+ config.ui.mount(editorLayer, "modal");
843
+ editorFocusCleanup = config.ui.trapFocus(() => editor, { onClose:()=>closeEditor(), isBlocked:()=>Boolean(pagePopup) });
1003
844
  page.querySelector(".pm-wrap").inert = true;
1004
845
  }
1005
846
  editorLayer.replaceChildren();
@@ -1008,48 +849,15 @@ function editorShell(title, back = null) {
1008
849
  editor.setAttribute("aria-modal", "true");
1009
850
  editor.setAttribute("aria-label", title);
1010
851
  editor.tabIndex = -1;
1011
- const heading = element("div", "pm-modal-heading");
1012
- if (back) heading.append(pageIcon(text("Back", "返回"), "back", back));
1013
- heading.append(
1014
- element("h2", "", title),
1015
- pageIcon(text("Close", "关闭"), "x", () => closeEditor()),
1016
- );
1017
- editor.append(heading);
852
+ const heading = config.ui.heading(editor, {
853
+ title, closeLabel:text("Close", "关闭"), onClose:()=>closeEditor(),
854
+ back:back ? pageIcon(text("Back", "返回"), "back", back) : null,
855
+ });
856
+ heading.classList.add("pm-modal-heading");
1018
857
  editorLayer.append(editor);
1019
858
  editor.focus();
1020
859
  return editor;
1021
860
  }
1022
- document.addEventListener(
1023
- "keydown",
1024
- (event) => {
1025
- if (!editorLayer || !editor || pagePopup) return;
1026
- if (event.key === "Escape") {
1027
- event.preventDefault();
1028
- event.stopImmediatePropagation();
1029
- closeEditor();
1030
- }
1031
- if (event.key === "Tab") {
1032
- const controls = [
1033
- ...editor.querySelectorAll(
1034
- 'button:not(:disabled),input,select,textarea,[tabindex="0"]',
1035
- ),
1036
- ].filter((x) => x.getBoundingClientRect().width);
1037
- const first = controls[0],
1038
- last = controls.at(-1);
1039
- if (
1040
- event.shiftKey &&
1041
- (document.activeElement === first || document.activeElement === editor)
1042
- ) {
1043
- event.preventDefault();
1044
- last?.focus();
1045
- } else if (!event.shiftKey && document.activeElement === last) {
1046
- event.preventDefault();
1047
- first?.focus();
1048
- }
1049
- }
1050
- },
1051
- { signal, capture: true },
1052
- );
1053
861
  function editPrompt(item = null) {
1054
862
  const target = editorShell(
1055
863
  item ? text("Edit prompt", "编辑提示词") : text("New prompt", "新建提示词"),
@@ -1134,7 +942,7 @@ function editPrompt(item = null) {
1134
942
  field(text("Category", "分类"), categoryButton),
1135
943
  field(text("Prompt", "提示词"), body),
1136
944
  );
1137
- const footer = element("div", "pm-footer");
945
+ const footer = config.ui.footer(element("div", "pm-footer"));
1138
946
  if (item) {
1139
947
  const remove = pageControl(text("Delete", "删除"), async () => {
1140
948
  if (remove.dataset.confirm !== "true") {
@@ -1151,13 +959,13 @@ function editPrompt(item = null) {
1151
959
  pageError(error);
1152
960
  }
1153
961
  });
1154
- remove.classList.add("pm-danger");
962
+ config.ui.action(remove, "danger");
1155
963
  remove.style.marginRight = "auto";
1156
964
  footer.append(remove);
1157
965
  }
1158
966
  const save = pageControl(text("Save", "保存"), () => {}, true);
1159
967
  save.type = "submit";
1160
- footer.append(pageControl(text("Cancel", "取消"), renderPage), save);
968
+ footer.append(pageControl(text("Cancel", "取消"), renderPage, false, "ghost"), save);
1161
969
  form.append(footer);
1162
970
  target.append(form);
1163
971
  form.addEventListener("submit", async (event) => {
@@ -1265,7 +1073,7 @@ function openEmojiPicker(trigger, selected, refresh) {
1265
1073
  }
1266
1074
  function manageCategories() {
1267
1075
  const target = editorShell(text("Categories", "分类"));
1268
- const footer = element("div", "pm-footer");
1076
+ const footer = config.ui.footer(element("div", "pm-footer"));
1269
1077
  footer.append(
1270
1078
  pageControl(text("New category", "新建分类"), () => editCategory(), true),
1271
1079
  );
@@ -1347,7 +1155,7 @@ function editCategory(category = null) {
1347
1155
  element("div", "", text("Color", "颜色")),
1348
1156
  colors,
1349
1157
  );
1350
- const footer = element("div", "pm-footer");
1158
+ const footer = config.ui.footer(element("div", "pm-footer"));
1351
1159
  if (category) {
1352
1160
  const remove = pageControl(text("Delete", "删除"), () => {
1353
1161
  const count = items.filter(
@@ -1379,25 +1187,25 @@ function editCategory(category = null) {
1379
1187
  ),
1380
1188
  ),
1381
1189
  );
1382
- const actions = element("div", "pm-footer");
1190
+ const actions = config.ui.footer(element("div", "pm-footer"));
1383
1191
  const confirm = pageControl(
1384
1192
  text("Delete", "删除"),
1385
1193
  () => void destroy(confirm),
1386
1194
  );
1387
- confirm.classList.add("pm-danger");
1195
+ config.ui.action(confirm, "danger");
1388
1196
  actions.append(
1389
- pageControl(text("Cancel", "取消"), () => editCategory(category)),
1197
+ pageControl(text("Cancel", "取消"), () => editCategory(category), false, "ghost"),
1390
1198
  confirm,
1391
1199
  );
1392
1200
  confirmation.append(actions);
1393
1201
  });
1394
- remove.classList.add("pm-danger");
1202
+ config.ui.action(remove, "danger");
1395
1203
  remove.style.marginRight = "auto";
1396
1204
  footer.append(remove);
1397
1205
  }
1398
1206
  const save = pageControl(text("Save", "保存"), () => {}, true);
1399
1207
  save.type = "submit";
1400
- footer.append(pageControl(text("Cancel", "取消"), manageCategories), save);
1208
+ footer.append(pageControl(text("Cancel", "取消"), manageCategories, false, "ghost"), save);
1401
1209
  form.append(footer);
1402
1210
  target.append(form);
1403
1211
  form.addEventListener("submit", async (event) => {
@@ -1427,26 +1235,17 @@ function editCategory(category = null) {
1427
1235
  }
1428
1236
  // 原生导航挂载与卸载
1429
1237
  function syncNavigation() {
1430
- const rail = document.querySelector("[data-app-navigation-rail]");
1238
+ const rail = config.codex.rail();
1431
1239
  if (!rail) {
1432
1240
  navButton?.remove();
1433
1241
  navButton = null;
1434
1242
  if (page) closePage();
1435
1243
  return;
1436
1244
  }
1437
- const source =
1438
- rail.querySelector('[data-sidebar-destination="builtin:projects"]') ??
1439
- rail.querySelector('[data-sidebar-destination="builtin:library"]');
1440
- if (!source) return;
1441
- // 固定扩展区是独立容器;不依赖 Projects 的固定状态或文字。
1442
- const scroll = rail.querySelector(".overflow-y-auto");
1443
- if (!scroll) return;
1444
- let group = [...scroll.children].find(
1445
- (node) =>
1446
- node !== ownNavGroup &&
1447
- node.classList.contains("flex-col") &&
1448
- node.classList.contains("shrink-0"),
1449
- );
1245
+ const slot = config.codex.railSlot(ownNavGroup);
1246
+ if (!slot) return;
1247
+ const { template:source, scroll } = slot;
1248
+ let group = slot.group;
1450
1249
  if (!group) {
1451
1250
  if (!ownNavGroup) {
1452
1251
  ownNavGroup = element("div", "flex shrink-0 flex-col items-center gap-2");
@@ -1456,6 +1255,7 @@ function syncNavigation() {
1456
1255
  group = ownNavGroup;
1457
1256
  }
1458
1257
  if (!navButton?.isConnected) {
1258
+ navigationRail?.restore();
1459
1259
  navButton = source.cloneNode(false);
1460
1260
  navButton.removeAttribute("id");
1461
1261
  navButton.removeAttribute("title");
@@ -1472,6 +1272,9 @@ function syncNavigation() {
1472
1272
  glyph.setAttribute("aria-hidden", "true");
1473
1273
  inner.append(glyph, element("span", "sr-only", text("Prompts", "提示词")));
1474
1274
  navButton.append(inner);
1275
+ navigationRail = config.ui.navigationRail(navButton, {
1276
+ defaultIcon:glyph, selectedIcon:icon("prompt-nav-selected"),
1277
+ });
1475
1278
  navButton.addEventListener("click", openPage);
1476
1279
  }
1477
1280
  if (navButton.parentElement !== group || navButton !== group.lastElementChild)
@@ -1513,6 +1316,10 @@ observer.observe(document.documentElement, {
1513
1316
  "aria-expanded",
1514
1317
  "data-selected",
1515
1318
  "aria-current",
1319
+ "class",
1320
+ "hidden",
1321
+ "inert",
1322
+ "aria-hidden",
1516
1323
  ],
1517
1324
  });
1518
1325
  document.addEventListener(
@@ -0,0 +1,13 @@
1
+ {
2
+ "prompt": "<svg\n class=\"lucide lucide-book-open\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"-1.5 -1.5 27 27\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n>\n <path vector-effect=\"non-scaling-stroke\" d=\"M12 7v14\" />\n <path vector-effect=\"non-scaling-stroke\" d=\"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z\" />\n</svg>",
3
+ "chevron": "<!-- @license lucide-static v0.577.0 - ISC -->\n<svg\n class=\"lucide lucide-chevron-down\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n>\n <path d=\"m6 9 6 6 6-6\" />\n</svg>\n",
4
+ "search": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M7.32849 1.91016C10.2877 1.91016 12.6867 4.30938 12.6869 7.26855C12.6869 8.57363 12.2192 9.7688 11.4437 10.6982L14.0433 13.2979C14.2481 13.5028 14.2481 13.8351 14.0433 14.04C13.8384 14.245 13.5062 14.2449 13.3011 14.04L10.6957 11.4346C9.77536 12.1793 8.60462 12.627 7.32849 12.627C4.36931 12.6268 1.97009 10.2278 1.97009 7.26855C1.97027 4.30949 4.36942 1.91033 7.32849 1.91016ZM7.32849 2.96094C4.94932 2.96111 3.02105 4.88939 3.02087 7.26855C3.02087 9.64787 4.94921 11.577 7.32849 11.5771C9.70792 11.5771 11.6371 9.64798 11.6371 7.26855C11.6369 4.88928 9.70781 2.96094 7.32849 2.96094Z\" fill=\"currentColor\"/></svg>",
5
+ "arrow-down-wide-narrow": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><path d=\"M4.66722 3.14218C4.95711 3.14225 5.19261 3.37767 5.19261 3.66757V11.6295L6.95824 9.82578C7.16093 9.61896 7.49327 9.61573 7.70043 9.81796C7.90753 10.0208 7.91092 10.353 7.70824 10.5602L5.27953 13.0406L5.2141 13.1012C4.89729 13.3642 4.43507 13.3645 4.1184 13.1012L4.05297 13.0406L1.62523 10.5602C1.4228 10.353 1.42608 10.0207 1.63304 9.81796C1.8401 9.61558 2.17245 9.61912 2.37523 9.82578L4.14183 11.6295V3.66757C4.14183 3.37762 4.37727 3.14218 4.66722 3.14218Z\" fill=\"currentColor\"/> <path d=\"M10.7854 2.98203C11.1021 2.71876 11.5643 2.719 11.8811 2.98203L11.9465 3.04257L14.3752 5.52304C14.5779 5.73021 14.5745 6.06242 14.3674 6.26523C14.1603 6.46786 13.828 6.46437 13.6252 6.25742L11.8586 4.45175V12.3336C11.8584 12.6233 11.623 12.859 11.3332 12.859C11.0436 12.8588 10.8081 12.6232 10.8078 12.3336V4.45371L9.04222 6.25742C8.83948 6.46447 8.50723 6.46775 8.30004 6.26523C8.093 6.06236 8.08941 5.73017 8.29222 5.52304L10.72 3.04257L10.7854 2.98203Z\" fill=\"currentColor\"/></svg>",
6
+ "check": "<!-- @license lucide-static v0.577.0 - ISC -->\n<svg\n class=\"lucide lucide-check\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n>\n <path d=\"M20 6 9 17l-5-5\" />\n</svg>\n",
7
+ "x": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><path d=\"M10.962 4.29539C11.1669 4.09057 11.4992 4.09076 11.7042 4.29539C11.9092 4.50039 11.9091 4.83255 11.7042 5.03758L8.74229 7.99949L11.7052 10.9624C11.9097 11.1673 11.9097 11.4996 11.7052 11.7046C11.5003 11.9095 11.168 11.9093 10.963 11.7046L8.0001 8.74168L5.03721 11.7046C4.83216 11.9093 4.49994 11.9095 4.29502 11.7046C4.09047 11.4996 4.09045 11.1673 4.29502 10.9624L7.25791 7.99949L4.296 5.03758C4.09101 4.83255 4.09099 4.5004 4.296 4.29539C4.50105 4.09079 4.8333 4.09054 5.03819 4.29539L8.0001 7.2573L10.962 4.29539Z\" fill=\"currentColor\"/></svg>",
8
+ "back": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><path d=\"M9.87117 11.6289C10.0762 11.8339 10.0762 12.166 9.87117 12.3711C9.66614 12.5761 9.334 12.5761 9.12898 12.3711L5.36433 8.60641C5.0296 8.27129 5.0296 7.72863 5.36433 7.39351L9.12898 3.62887C9.334 3.42384 9.66614 3.42384 9.87117 3.62887C10.0762 3.83389 10.0762 4.16603 9.87117 4.37105L6.24226 7.99996L9.87117 11.6289Z\" fill=\"currentColor\"/></svg>",
9
+ "settings": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M6.33374 8.97461C7.54786 8.97484 8.56163 9.83236 8.80347 10.9746H13.3337C13.6235 10.9749 13.8591 11.2102 13.8591 11.5C13.8591 11.7898 13.6235 12.0251 13.3337 12.0254H8.80347C8.56163 13.1676 7.54786 14.0252 6.33374 14.0254C5.11907 14.0254 4.10455 13.1673 3.86304 12.0244L2.66675 12.0254C2.37691 12.0253 2.14138 11.7899 2.14136 11.5C2.14136 11.2102 2.37693 10.9748 2.66675 10.9746H3.86304C4.10491 9.83221 5.11941 8.97461 6.33374 8.97461ZM6.33374 10.0254C5.51912 10.0254 4.85913 10.6854 4.85913 11.5C4.85913 12.3146 5.51912 12.9746 6.33374 12.9746C7.14814 12.9743 7.80835 12.3145 7.80835 11.5C7.80835 10.6855 7.14814 10.0257 6.33374 10.0254Z\" fill=\"currentColor\"/> <path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M9.66675 1.97461C10.881 1.97461 11.8935 2.83236 12.1355 3.97461H13.3328C13.6227 3.97459 13.8581 4.21005 13.8582 4.5C13.8581 4.78993 13.6227 5.02537 13.3328 5.02539H12.1365C11.8946 6.16774 10.881 7.02539 9.66675 7.02539C8.45245 7.02539 7.43893 6.16774 7.19702 5.02539H2.66675C2.3768 5.02539 2.14136 4.78995 2.14136 4.5C2.14136 4.21005 2.3768 3.97461 2.66675 3.97461H7.19702C7.43893 2.83226 8.45245 1.97461 9.66675 1.97461ZM9.66675 3.02539C8.85213 3.02539 8.19214 3.68538 8.19214 4.5C8.19214 5.31462 8.85213 5.97461 9.66675 5.97461C10.4814 5.97461 11.1414 5.31462 11.1414 4.5C11.1414 3.68538 10.4814 3.02539 9.66675 3.02539Z\" fill=\"currentColor\"/></svg>",
10
+ "drag": "<svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n>\n <path d=\"M4 5h16\" />\n <path d=\"M4 12h16\" />\n <path d=\"M4 19h16\" />\n</svg>\n",
11
+ "prompt-nav": "<svg\n class=\"lucide lucide-book-open\"\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"20\"\n height=\"20\"\n viewBox=\"-1.5 -1.5 27 27\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.8\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n>\n <path d=\"M12 7v14 M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z\" />\n</svg>",
12
+ "prompt-nav-selected": "<svg width=\"20\" height=\"20\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\"><path d=\"M240,56V200a8,8,0,0,1-8,8H160a24,24,0,0,0-24,23.94,7.9,7.9,0,0,1-5.12,7.55A8,8,0,0,1,120,232a24,24,0,0,0-24-24H24a8,8,0,0,1-8-8V56a8,8,0,0,1,8-8H88a32,32,0,0,1,32,32v87.73a8.17,8.17,0,0,0,7.47,8.25,8,8,0,0,0,8.53-8V80a32,32,0,0,1,32-32h64A8,8,0,0,1,240,56Z\"/></svg>"
13
+ }