clay-server 5.2.0-beta.9 → 5.2.1-beta.1

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 (109) hide show
  1. package/README.md +0 -4
  2. package/lib/clay-product-control-tools.js +1 -0
  3. package/lib/clay-product-control.js +14 -11
  4. package/lib/clay-vendor-usage.js +44 -0
  5. package/lib/github-star-count.js +147 -0
  6. package/lib/notes-checklist.js +43 -1
  7. package/lib/notes.js +2 -1
  8. package/lib/project-session-notes.js +33 -8
  9. package/lib/project-sessions.js +63 -24
  10. package/lib/project-start-protocol.js +29 -0
  11. package/lib/project-vendor-login.js +2 -0
  12. package/lib/project.js +5 -1
  13. package/lib/public/app.js +30 -18
  14. package/lib/public/css/command-palette.css +12 -2
  15. package/lib/public/css/contextual-clay.css +1 -1
  16. package/lib/public/css/filebrowser.css +4 -5
  17. package/lib/public/css/mate-loading-scene.css +21 -0
  18. package/lib/public/css/messages.css +30 -11
  19. package/lib/public/css/overlays.css +67 -256
  20. package/lib/public/css/project-mate-creation.css +5 -6
  21. package/lib/public/css/project-start.css +108 -0
  22. package/lib/public/css/projects-hub.css +53 -14
  23. package/lib/public/css/right-workbench.css +28 -0
  24. package/lib/public/css/settings-shell.css +103 -0
  25. package/lib/public/css/sidebar.css +7 -0
  26. package/lib/public/css/title-bar.css +99 -0
  27. package/lib/public/index.html +54 -66
  28. package/lib/public/modules/account-transport-settings.js +8 -2
  29. package/lib/public/modules/admin-settings-email.js +7 -2
  30. package/lib/public/modules/admin-settings-invitations.js +2 -2
  31. package/lib/public/modules/admin-settings-projects.js +2 -2
  32. package/lib/public/modules/admin-settings-ui.js +20 -4
  33. package/lib/public/modules/admin-settings-users.js +4 -4
  34. package/lib/public/modules/app-home-hub.js +2 -1
  35. package/lib/public/modules/app-messages.js +10 -2
  36. package/lib/public/modules/app-projects.js +1 -407
  37. package/lib/public/modules/app-rate-limit.js +12 -1
  38. package/lib/public/modules/clay-tool-presentation.js +1 -0
  39. package/lib/public/modules/contextual-clay.js +3 -1
  40. package/lib/public/modules/github-star.js +66 -0
  41. package/lib/public/modules/home-surface-boot.js +0 -1
  42. package/lib/public/modules/mate-loading-scene.js +17 -0
  43. package/lib/public/modules/pair-result-status.js +89 -39
  44. package/lib/public/modules/pane-appearance-bridge.js +59 -0
  45. package/lib/public/modules/profile.js +11 -3
  46. package/lib/public/modules/project-mate-creation-workspace.js +13 -4
  47. package/lib/public/modules/project-session-visibility-settings.js +19 -16
  48. package/lib/public/modules/project-settings-environment.js +12 -1
  49. package/lib/public/modules/project-settings.js +119 -129
  50. package/lib/public/modules/project-start-dialog.js +130 -0
  51. package/lib/public/modules/project-start-folder-state.js +78 -0
  52. package/lib/public/modules/project-start-folder-view.js +190 -0
  53. package/lib/public/modules/project-start-forms.js +66 -0
  54. package/lib/public/modules/project-start-path.js +60 -0
  55. package/lib/public/modules/project-start-state.js +54 -0
  56. package/lib/public/modules/project-start-submit.js +67 -0
  57. package/lib/public/modules/projects-hub-view.js +32 -44
  58. package/lib/public/modules/projects-hub.js +39 -28
  59. package/lib/public/modules/server-settings.js +36 -91
  60. package/lib/public/modules/settings-project-target.js +56 -0
  61. package/lib/public/modules/settings-select.js +1 -1
  62. package/lib/public/modules/settings-shell-registry.js +88 -0
  63. package/lib/public/modules/settings-shell-view.js +104 -0
  64. package/lib/public/modules/settings-shell.js +342 -0
  65. package/lib/public/modules/sidebar-mobile.js +8 -30
  66. package/lib/public/modules/sidebar-projects.js +2 -1
  67. package/lib/public/modules/theme.js +31 -3
  68. package/lib/public/modules/topbar-workbench-controls.js +102 -0
  69. package/lib/public/modules/user-settings-integrations.js +2 -1
  70. package/lib/public/modules/user-settings-layout.js +12 -34
  71. package/lib/public/modules/user-settings-profile.js +1 -1
  72. package/lib/public/modules/user-settings.js +18 -85
  73. package/lib/public/modules/vendor-usage-format.js +93 -0
  74. package/lib/public/modules/vendor-usage-list.js +45 -0
  75. package/lib/public/modules/vendor-usage-model.js +215 -0
  76. package/lib/public/modules/vendor-usage-overview.js +323 -0
  77. package/lib/public/style.css +13 -10
  78. package/lib/public/welcome-art/conversation-desk.png +0 -0
  79. package/lib/public/welcome-art/mate-clay.png +0 -0
  80. package/lib/public/welcome-art/project-clay.png +0 -0
  81. package/lib/sdk-bridge.js +6 -1
  82. package/lib/sdk-message-processor.js +9 -1
  83. package/lib/sdk-quota-snapshot.js +20 -2
  84. package/lib/server-github-stars.js +39 -0
  85. package/lib/server-global-ws.js +21 -17
  86. package/lib/server.js +11 -0
  87. package/lib/session-notes-mcp-server.js +26 -4
  88. package/lib/session-notes-writes.js +88 -0
  89. package/lib/session-visibility.js +20 -8
  90. package/lib/sessions.js +12 -2
  91. package/lib/vendor-usage-acp-readers.js +97 -0
  92. package/lib/vendor-usage-capabilities.js +88 -0
  93. package/lib/vendor-usage-http-readers.js +214 -0
  94. package/lib/vendor-usage-metrics.js +47 -0
  95. package/lib/vendor-usage-native-readers.js +106 -0
  96. package/lib/vendor-usage-overview.js +406 -0
  97. package/lib/vendor-usage-service.js +281 -0
  98. package/lib/ws-schema.js +4 -2
  99. package/lib/yoke/adapters/claude.js +12 -0
  100. package/lib/yoke/adapters/codex-query-contract.js +1 -0
  101. package/lib/yoke/adapters/codex.js +45 -12
  102. package/lib/yoke/claude-hook-installer.js +1 -0
  103. package/lib/yoke/codex-dynamic-tool-names.js +80 -0
  104. package/lib/yoke/codex-model-catalog.js +37 -3
  105. package/lib/yoke/muse-services.js +16 -3
  106. package/lib/yoke/providers/claude-model-descriptions.js +22 -2
  107. package/lib/yoke/vendor-registry.js +6 -2
  108. package/package.json +2 -1
  109. package/lib/public/modules/server-settings-navigation.js +0 -39
@@ -0,0 +1,103 @@
1
+ /* Unified full-screen settings shell. Personal, Project and Server panes keep
2
+ their ids (so the shared settings-ui primitives still apply) and mount into
3
+ the shell content; their former modal chrome is neutralised here. */
4
+ #settings-shell {
5
+ position: fixed; inset: 0; z-index: 600; display: flex; flex-direction: column;
6
+ background: var(--bg); color: var(--text);
7
+ }
8
+ #settings-shell.hidden { display: none; }
9
+ #settings-shell [hidden], #settings-shell .hidden { display: none !important; }
10
+ #settings-shell :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
11
+
12
+ /* --- Header: close and scope tabs --- */
13
+ .settings-shell-header {
14
+ flex: 0 0 auto; display: flex; align-items: center; gap: 12px; min-height: 48px;
15
+ padding: calc(var(--safe-top) + 6px) 16px 6px; border-bottom: 1px solid var(--border-subtle); background: var(--sidebar-bg);
16
+ }
17
+ .settings-shell-close {
18
+ display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px 0 8px; border: 1px solid var(--border);
19
+ border-radius: 8px; background: var(--bg); color: var(--text-secondary); font: inherit; font-size: 13px; cursor: pointer;
20
+ }
21
+ .settings-shell-close:hover { color: var(--text); border-color: var(--text-dimmer); }
22
+ .settings-shell-close svg { width: 16px; height: 16px; }
23
+ .settings-shell-close kbd { font: inherit; font-size: 11px; color: var(--text-dimmer); padding-left: 4px; }
24
+ .settings-scope-tabs { display: inline-flex; gap: 2px; padding: 3px; border: 1px solid var(--border); border-radius: 9px; background: var(--bg-alt); }
25
+ .settings-scope-tab {
26
+ min-width: 76px; height: 28px; padding: 0 12px; border: 0; border-radius: 6px; background: none;
27
+ color: var(--text-muted); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
28
+ }
29
+ .settings-scope-tab:hover { color: var(--text); }
30
+ .settings-scope-tab.active { background: var(--bg); color: var(--text); box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
31
+
32
+ /* --- Body: navigation + content --- */
33
+ .settings-shell-body { flex: 1 1 auto; min-height: 0; display: flex; }
34
+ .settings-shell-nav { flex: 0 0 240px; width: 240px; overflow-y: auto; background: var(--sidebar-bg); border-right: 1px solid var(--border-subtle); }
35
+ .settings-shell-nav-inner { padding: 20px 12px 32px 14px; }
36
+ .settings-scope-head { display: flex; flex-direction: column; gap: 2px; padding: 0 10px 12px; margin-bottom: 8px; border-bottom: 1px solid var(--border-subtle); }
37
+ .settings-scope-head strong { font-size: 14px; color: var(--text); }
38
+ .settings-scope-head small { font-size: 12px; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
39
+ .settings-scope-hint { font-size: 12px; line-height: 1.35; color: var(--text-muted); }
40
+ .settings-project-picker { padding: 0 4px 12px; }
41
+ .settings-project-picker .settings-label { display: block; margin: 0 0 6px 6px; font-size: 12px; color: var(--text-muted); }
42
+ .settings-project-picker .settings-picker { display: block; width: 100%; }
43
+ .settings-project-picker .settings-picker-menu { right: auto; left: 0; width: 100%; max-width: none; }
44
+ .settings-project-picker select { width: 100%; }
45
+ .settings-shell-nav .settings-nav-item { min-height: 32px; padding: 6px 10px; font-size: 13px; }
46
+ .settings-shell-nav .settings-nav-item.active { background: rgba(var(--overlay-rgb), .08); color: var(--text); }
47
+ .settings-shell-nav .settings-nav-item:focus-visible { outline-offset: -2px; }
48
+ .settings-shell-nav .settings-nav-dropdown { display: none; }
49
+ .settings-shell-content { flex: 1 1 auto; min-width: 0; overflow-y: auto; padding: 28px 40px calc(var(--safe-bottom) + 56px); }
50
+ .settings-shell-status { max-width: 760px; margin: 0 0 16px; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-alt); color: var(--text-secondary); font-size: 13px; }
51
+ .settings-shell-status[data-state="error"] { border-color: color-mix(in srgb, var(--error) 40%, var(--border)); color: var(--error); }
52
+
53
+ /* --- Panes: neutralise the former modal/overlay chrome --- */
54
+ #settings-shell .settings-pane { position: static; inset: auto; z-index: auto; display: block; width: 100%; max-width: 760px; margin: 0; padding: 0; background: none; backdrop-filter: none; animation: none; overflow: visible; }
55
+ #settings-shell .settings-pane.hidden { display: none !important; }
56
+ #user-settings .us-modal, #project-settings .ps-modal {
57
+ position: static; display: block; width: auto; height: auto; border: 0; border-radius: 0; background: none; box-shadow: none; animation: none; overflow: visible;
58
+ }
59
+ #user-settings .us-modal-body, #project-settings .project-settings-layout { display: block; height: auto; overflow: visible; background: none; }
60
+ #user-settings .us-modal-content, #project-settings .project-settings-content, #server-settings .server-settings-content {
61
+ max-width: none; padding: 0; background: none; overflow: visible;
62
+ }
63
+ #project-settings .project-settings-content-inner, #server-settings .server-settings-content-inner { padding: 0; }
64
+ #server-settings .server-settings-layout { display: block; height: auto; background: none; }
65
+ #server-settings .server-settings-layout::after { display: none; }
66
+ #project-settings .ps-section h2, #user-settings .us-section h2, #server-settings .server-settings-section h2 { margin-top: 0; }
67
+ #project-settings.ps-no-target .ps-section { display: none; }
68
+ #project-settings .settings-empty { padding: 24px 0; }
69
+
70
+ /* --- Inline subviews (admin editors, avatar crop): replace the page's list in place --- */
71
+ .has-subview > :not(h2):not(.settings-subview) { display: none !important; }
72
+ .admin-subview, .avatar-positioner-inline { display: block; position: static; padding: 0; background: none; }
73
+ .admin-subview .admin-modal {
74
+ position: static; width: auto; max-width: 640px; max-height: none; margin: 0; border: 1px solid var(--border);
75
+ border-radius: 10px; background: var(--bg); box-shadow: none;
76
+ }
77
+ .admin-subview .admin-modal-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--border-subtle); }
78
+ .admin-subview .admin-modal-header h3 { margin: 0; font-size: 14px; }
79
+ .admin-subview .admin-modal-body { padding: 14px 16px; overflow: visible; max-height: none; }
80
+ .admin-subview .admin-modal-footer { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border-subtle); }
81
+ .avatar-positioner-inline .avatar-positioner-container { position: relative; display: flex; flex-direction: column; align-items: center; gap: 12px; max-width: 360px; padding: 16px; border: 1px solid var(--border); border-radius: 10px; background: var(--bg); box-shadow: none; }
82
+
83
+ /* --- Narrow screens: tabs in the header, page select replaces the nav list --- */
84
+ @media (max-width: 800px) {
85
+ .settings-shell-header { padding-left: 10px; padding-right: 10px; gap: 8px; }
86
+ .settings-shell-close span, .settings-shell-close kbd { display: none; }
87
+ .settings-shell-close { width: 32px; padding: 0; justify-content: center; }
88
+ .settings-scope-tabs { flex: 1 1 auto; min-width: 0; }
89
+ .settings-scope-tab { flex: 1 1 0; min-width: 0; padding: 0 6px; }
90
+ .settings-shell-body { flex-direction: column; }
91
+ .settings-shell-nav { flex: 0 0 auto; width: 100%; max-height: 40%; border-right: 0; border-bottom: 1px solid var(--border-subtle); }
92
+ .settings-shell-nav-inner { padding: 10px 12px; display: grid; gap: 8px; }
93
+ .settings-scope-head { display: none; }
94
+ .settings-project-picker { padding: 0; }
95
+ .settings-project-picker .settings-picker { display: none; }
96
+ .settings-project-picker select { height: 36px; }
97
+ .settings-shell-nav-items { display: none; }
98
+ .settings-shell-nav .settings-nav-dropdown { display: block; width: 100%; height: 36px; margin: 0; }
99
+ .settings-shell-content { padding: 18px 14px calc(var(--safe-bottom) + 40px); }
100
+ }
101
+ @media (prefers-reduced-motion: reduce) {
102
+ #settings-shell * { transition: none !important; animation: none !important; }
103
+ }
@@ -1392,6 +1392,13 @@ body:not(.home-active) #icon-strip-hint-mate { display: none; }
1392
1392
  .user-island-profile:active { transform: translateY(1px); }
1393
1393
  .user-island-profile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
1394
1394
 
1395
+ .user-island-quick-controls {
1396
+ display: flex;
1397
+ align-items: center;
1398
+ justify-content: center;
1399
+ gap: 4px;
1400
+ }
1401
+
1395
1402
  .cursor-share-toggle {
1396
1403
  position: relative;
1397
1404
  width: var(--account-rail-cursor-target, 28px);
@@ -93,6 +93,10 @@
93
93
  right: 10px;
94
94
  top: 50%;
95
95
  transform: translateY(-50%);
96
+ /* The transform makes this group its own stacking context, so its popovers
97
+ are ordered by this value. Sit above chat layers but below contextual Clay
98
+ (160), the mobile overlays and modals. */
99
+ z-index: 150;
96
100
  display: flex;
97
101
  align-items: center;
98
102
  gap: 2px;
@@ -116,6 +120,22 @@
116
120
 
117
121
  #server-settings-btn.active { color: var(--text); }
118
122
 
123
+ /* Browser, Terminal and sticky-note visibility live beside Notifications and
124
+ Settings on desktop. Match those compact top-bar buttons; the same nodes keep
125
+ their own IDs, state and handlers (see topbar-workbench-controls.js). */
126
+ .top-bar-actions :is(#shared-browser-toggle-btn, #terminal-toggle-btn, #sticky-notes-toggle-btn) {
127
+ position: relative;
128
+ padding: 3px;
129
+ border: 0;
130
+ border-radius: 6px;
131
+ }
132
+ .top-bar-actions :is(#shared-browser-toggle-btn, #terminal-toggle-btn, #sticky-notes-toggle-btn) .lucide { width: 14px; height: 14px; }
133
+ .top-bar-actions :is(#shared-browser-toggle-btn, #terminal-toggle-btn, #sticky-notes-toggle-btn):hover { color: var(--text-secondary); background: rgba(var(--overlay-rgb), 0.06); border: 0; }
134
+ .top-bar-actions #shared-browser-toggle-btn:disabled:hover { background: none; }
135
+ /* These controls belong to a session: keep them out of the project-less shell and while the title bar is replaced by another view. */
136
+ body.projects-shell .top-bar-actions :is(#shared-browser-toggle-btn, #terminal-toggle-btn, #sticky-notes-toggle-btn),
137
+ #top-bar.title-bar-hidden .top-bar-actions :is(#shared-browser-toggle-btn, #terminal-toggle-btn, #sticky-notes-toggle-btn) { display: none; }
138
+
119
139
  /* --- Theme toggle pill switch (light/dark) --- */
120
140
  .theme-toggle {
121
141
  display: flex;
@@ -906,3 +926,82 @@
906
926
  .rate-limit-popover { font-size: 11px; padding: 6px 10px; }
907
927
  .header-context { width: 50px; }
908
928
  }
929
+
930
+ /* --- GitHub Star link (desktop only, beside the brand) --- */
931
+ .top-bar-star {
932
+ display: flex;
933
+ align-items: center;
934
+ gap: 6px;
935
+ flex: 0 0 auto;
936
+ white-space: nowrap;
937
+ }
938
+
939
+ .top-bar-star-pill {
940
+ display: inline-flex;
941
+ align-items: stretch;
942
+ height: 20px;
943
+ border: 1px solid var(--border-subtle);
944
+ border-radius: 6px;
945
+ background: rgba(var(--overlay-rgb), 0.03);
946
+ color: var(--text-muted);
947
+ font-size: 11px;
948
+ font-weight: 600;
949
+ line-height: 18px;
950
+ text-decoration: none;
951
+ overflow: hidden;
952
+ transition: background 0.15s, border-color 0.15s, color 0.15s;
953
+ }
954
+
955
+ .top-bar-star-pill:hover {
956
+ background: rgba(var(--overlay-rgb), 0.08);
957
+ border-color: var(--border);
958
+ color: var(--text-secondary);
959
+ }
960
+
961
+ .top-bar-star-pill:active { transform: translateY(1px); }
962
+
963
+ .top-bar-star-pill:focus-visible {
964
+ outline: 2px solid var(--accent);
965
+ outline-offset: 2px;
966
+ }
967
+
968
+ .top-bar-star-mark {
969
+ align-self: center;
970
+ width: 12px;
971
+ height: 12px;
972
+ margin: 0 4px 0 6px;
973
+ fill: currentColor;
974
+ }
975
+
976
+ .top-bar-star-label { padding-right: 6px; }
977
+
978
+ .top-bar-star-count {
979
+ padding: 0 6px;
980
+ border-left: 1px solid var(--border-subtle);
981
+ font-variant-numeric: tabular-nums;
982
+ }
983
+
984
+ .top-bar-star-count.hidden { display: none; }
985
+
986
+ @media (max-width: 790px) {
987
+ .top-bar-star-long { display: none; }
988
+ }
989
+
990
+ /* The CTA yields to functional controls sharing the left group: the install
991
+ pill shortens the label first (and takes the pill when space is tight); a
992
+ visible update notice takes the whole CTA. */
993
+ .top-bar-left-pills:has(.top-bar-install-btn:not(.hidden)) .top-bar-star-long { display: none; }
994
+ .top-bar-left-pills:has(#update-pill-wrap:not(.hidden)) .top-bar-star { display: none; }
995
+
996
+ @media (max-width: 1100px) {
997
+ .top-bar-left-pills:has(.top-bar-install-btn:not(.hidden)) .top-bar-star { display: none; }
998
+ }
999
+
1000
+ @media (max-width: 768px) {
1001
+ .top-bar-star { display: none; }
1002
+ }
1003
+
1004
+ @media (prefers-reduced-motion: reduce) {
1005
+ .top-bar-star-pill { transition: none; }
1006
+ .top-bar-star-pill:active { transform: none; }
1007
+ }
@@ -60,6 +60,9 @@ body { background: transparent; color: inherit; }
60
60
  <div id="top-bar">
61
61
  <div class="top-bar-left-pills">
62
62
  <a class="top-bar-brand-link" href="https://github.com/chadbyte/clay" target="_blank" rel="noopener noreferrer" aria-label="Clay Studio repository"><span class="top-bar-brand-wordmark" aria-hidden="true"></span></a>
63
+ <div class="top-bar-star" id="github-star">
64
+ <a class="top-bar-star-pill" id="github-star-link" href="https://github.com/chadbyte/clay" target="_blank" rel="noopener noreferrer" aria-label="Star Clay on GitHub"><svg class="top-bar-star-mark" viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg><span class="top-bar-star-label">Star<span class="top-bar-star-long"> on GitHub</span></span><span class="top-bar-star-count hidden" id="github-star-count"></span></a>
65
+ </div>
63
66
  <button id="pwa-install-pill" class="top-bar-install-btn hidden" title="Open as app"><i data-lucide="download"></i> Open as app</button>
64
67
  <div id="update-pill-wrap" class="top-bar-update hidden">
65
68
  <button id="update-pill" class="top-bar-update-btn"><i data-lucide="arrow-up-circle"></i> <span id="update-version"></span> is available. Update now</button>
@@ -74,9 +77,12 @@ body { background: transparent; color: inherit; }
74
77
  <!-- Pill badges -->
75
78
  <div id="skip-perms-pill" class="top-bar-pill pill-error hidden"><i data-lucide="shield-off"></i> <span>Skip perms</span></div>
76
79
  <div id="client-count" class="top-bar-pill pill-accent hidden"><i data-lucide="users"></i> <span id="client-count-text"></span></div>
77
- <button id="share-pill" title="Share"><i data-lucide="share-2"></i></button>
80
+ <!-- Right workbench controls: same nodes and handlers as before; app JS returns them to the title bar on mobile. -->
81
+ <button type="button" id="shared-browser-toggle-btn" class="hidden" title="Browser" aria-label="Browser" aria-controls="shared-browser-panel" aria-expanded="false" disabled><i data-lucide="globe"></i></button>
82
+ <button id="terminal-toggle-btn" title="Terminal"><i data-lucide="square-terminal"></i><span id="terminal-count" class="hidden"></span></button>
83
+ <button type="button" id="sticky-notes-toggle-btn" aria-label="Hide sticky notes" aria-pressed="false" title="Hide sticky notes"><i data-lucide="eye-off"></i></button>
78
84
  <button id="notif-center-btn" title="Notifications"><i data-lucide="bell"></i><span id="notif-center-badge" class="notif-badge hidden">0</span></button>
79
- <button id="server-settings-btn" title="Server settings"><i data-lucide="settings"></i></button>
85
+ <button id="server-settings-btn" title="Settings" aria-label="Settings" aria-expanded="false"><i data-lucide="settings"></i></button>
80
86
  </div>
81
87
  </div>
82
88
 
@@ -322,9 +328,6 @@ body { background: transparent; color: inherit; }
322
328
  </button>
323
329
  <button id="debate-pdf-btn" class="hidden" title="Export debate as PDF"><i data-lucide="download"></i></button>
324
330
  <button id="find-in-session-btn" title="Search in session (Ctrl+F)"><i data-lucide="search"></i></button>
325
- <button type="button" id="sticky-notes-toggle-btn" aria-label="Hide sticky notes" aria-pressed="false" title="Hide sticky notes"><i data-lucide="eye-off"></i></button>
326
- <button type="button" id="shared-browser-toggle-btn" class="hidden" title="Browser" aria-label="Browser" aria-controls="shared-browser-panel" aria-expanded="false" disabled><i data-lucide="globe"></i></button>
327
- <button id="terminal-toggle-btn" title="Terminal"><i data-lucide="square-terminal"></i><span id="terminal-count" class="hidden"></span></button>
328
331
  </div>
329
332
  </div>
330
333
  <div id="main-panels">
@@ -657,13 +660,10 @@ body { background: transparent; color: inherit; }
657
660
  </div>
658
661
  </div>
659
662
  <div id="project-settings" class="hidden">
660
- <div class="ps-modal" role="dialog" aria-modal="true" aria-labelledby="ps-modal-title">
661
- <header class="ps-modal-header"><div><h2 id="ps-modal-title">Project settings</h2><span id="ps-nav-title"></span></div><button class="settings-btn-sm" id="project-settings-close" aria-label="Close project settings"><i data-lucide="x"></i></button></header>
663
+ <div class="ps-modal">
662
664
  <div class="project-settings-layout">
663
- <nav class="project-settings-nav" aria-label="Project settings">
664
- <div class="project-settings-nav-inner"><select id="ps-nav-dropdown" class="settings-nav-dropdown" aria-label="Settings page"></select><div class="server-settings-nav-items"></div></div>
665
- </nav>
666
665
  <div class="project-settings-content"><div class="project-settings-content-inner">
666
+ <div class="settings-empty" id="ps-empty" hidden><h2 tabindex="-1">No project selected</h2><p id="ps-empty-text" class="settings-hint"></p></div>
667
667
  <section class="ps-section active" data-section="profile">
668
668
  <h2>General</h2><p class="ps-section-desc">Identify this project in your workspace.</p>
669
669
  <div class="ps-project-identity">
@@ -680,8 +680,8 @@ body { background: transparent; color: inherit; }
680
680
  <div class="settings-field" id="ps-session-visibility-default-field" style="display:none">
681
681
  <label class="settings-label" for="ps-session-visibility-default">New session visibility</label>
682
682
  <div class="settings-hint">Applies to new project conversations and Issue Start work sessions. Existing sessions, hidden work, and delegated workflows keep their current visibility.</div>
683
+ <div class="settings-hint hidden" id="ps-session-visibility-default-owner-hint">Only the project owner can change this setting. Administrators can view it here but cannot change it.</div>
683
684
  <div class="settings-hint hidden" id="ps-session-visibility-default-inherited-hint">This worktree inherits the setting from its parent project. Change it there.</div>
684
- <div class="settings-hint hidden" id="ps-session-visibility-default-non-current-hint">Open this project to change this setting.</div>
685
685
  <select class="ps-select" id="ps-session-visibility-default">
686
686
  <option value="private">Private</option>
687
687
  <option value="shared">Shared with project members</option>
@@ -737,11 +737,16 @@ body { background: transparent; color: inherit; }
737
737
  <span class="user-island-cta hidden">Personalize your name</span>
738
738
  </div>
739
739
  </button>
740
- <button id="cursor-share-toggle" class="cursor-share-toggle" type="button" aria-pressed="false" aria-label="Cursor sharing unavailable" disabled>
741
- <i data-lucide="mouse-pointer-2" class="cursor-share-icon" aria-hidden="true"></i>
742
- </button>
740
+ <div class="user-island-quick-controls">
741
+ <button id="cursor-share-toggle" class="cursor-share-toggle" type="button" aria-pressed="false" aria-label="Cursor sharing unavailable" disabled>
742
+ <i data-lucide="mouse-pointer-2" class="cursor-share-icon" aria-hidden="true"></i>
743
+ </button>
744
+ <button id="appearance-mode-toggle" class="cursor-share-toggle" type="button" aria-label="Switch to light mode" title="Switch to light mode">
745
+ <i data-lucide="sun" class="cursor-share-icon" aria-hidden="true"></i>
746
+ </button>
747
+ </div>
743
748
  <div class="user-island-actions">
744
- <button id="user-settings-btn" title="User settings"><i data-lucide="settings"></i></button>
749
+ <button id="user-settings-btn" title="Personal settings" aria-label="Personal settings" aria-expanded="false"><i data-lucide="settings"></i></button>
745
750
  </div>
746
751
  </div>
747
752
 
@@ -780,19 +785,31 @@ body { background: transparent; color: inherit; }
780
785
  </div>
781
786
  </div>
782
787
 
783
- <!-- === User Settings (modal dialog) === -->
788
+ <!-- === Unified settings shell (full screen): Personal, Project and Server panes mount into it === -->
789
+ <div id="settings-shell" class="hidden" role="region" aria-label="Settings">
790
+ <header class="settings-shell-header">
791
+ <button type="button" id="settings-shell-close" class="settings-shell-close" aria-label="Close settings"><i data-lucide="arrow-left" aria-hidden="true"></i><span>Back</span><kbd>Esc</kbd></button>
792
+ <div class="settings-scope-tabs" id="settings-scope-tabs" role="group" aria-label="Settings scope"></div>
793
+ </header>
794
+ <div class="settings-shell-body">
795
+ <nav class="settings-shell-nav" aria-label="Settings navigation">
796
+ <div class="settings-shell-nav-inner">
797
+ <div class="settings-scope-head"><strong id="settings-scope-title">Settings</strong><small id="settings-server-name" hidden></small><span id="settings-scope-hint" class="settings-scope-hint"></span></div>
798
+ <div class="settings-project-picker" id="settings-project-picker" hidden><label class="settings-label" for="settings-project-select">Project</label><select id="settings-project-select" class="ps-select" aria-label="Project"></select></div>
799
+ <select id="settings-page-select" class="settings-nav-dropdown" aria-label="Settings page"></select>
800
+ <div class="settings-shell-nav-items" id="settings-page-nav"></div>
801
+ </div>
802
+ </nav>
803
+ <main class="settings-shell-content" id="settings-shell-content">
804
+ <p id="settings-shell-status" class="settings-shell-status" role="status" hidden></p>
805
+ </main>
806
+ </div>
807
+ </div>
808
+
809
+ <!-- === Personal settings pane === -->
784
810
  <div id="user-settings" class="hidden">
785
- <div class="confirm-backdrop" id="user-settings-backdrop"></div>
786
811
  <div class="us-modal">
787
- <div class="us-modal-header">
788
- <span class="us-modal-title">User Settings</span>
789
- <button class="us-modal-close" id="user-settings-close" title="Close"><i data-lucide="x"></i></button>
790
- </div>
791
812
  <div class="us-modal-body">
792
- <nav class="us-modal-nav">
793
- <select id="user-settings-nav-dropdown" class="settings-nav-dropdown"></select>
794
- <div class="us-modal-nav-items"></div>
795
- </nav>
796
813
  <div class="us-modal-content">
797
814
 
798
815
  <div class="us-section" data-section="us-notifications">
@@ -1031,16 +1048,8 @@ body { background: transparent; color: inherit; }
1031
1048
  </div>
1032
1049
 
1033
1050
  <!-- === Server Settings (full-screen overlay) === -->
1034
- <div id="server-settings" class="hidden" role="dialog" aria-modal="true" aria-label="Server settings">
1051
+ <div id="server-settings" class="hidden">
1035
1052
  <div class="server-settings-layout">
1036
- <nav class="server-settings-nav" aria-label="Server settings pages">
1037
- <div class="server-settings-nav-inner">
1038
- <div class="server-settings-nav-header">Server settings<small id="settings-server-name"></small></div>
1039
- <select id="settings-nav-dropdown" class="settings-nav-dropdown" aria-label="Settings page"></select>
1040
- <div class="server-settings-nav-items" id="settings-page-nav"></div>
1041
- <button class="settings-nav-item" id="settings-personal-link">Personal notifications ↗</button>
1042
- </div>
1043
- </nav>
1044
1053
  <div class="server-settings-content"><div class="server-settings-content-inner">
1045
1054
  <p id="settings-access-status" role="status">Checking administrator access…</p>
1046
1055
  <div class="server-settings-section active" data-section="overview">
@@ -1248,7 +1257,7 @@ body { background: transparent; color: inherit; }
1248
1257
  <div class="settings-hint settings-restart-error hidden" id="settings-restart-error" style="margin-top: 8px;"></div>
1249
1258
  </div>
1250
1259
  </div>
1251
- </div><section class="settings-operation settings-danger-operation"><div class="settings-danger-entry"><div class="settings-danger-entry-copy"><h3>Danger zone</h3><p>Shut down Clay for everyone. Active work stops; restarting requires access to the host.</p></div><button type="button" class="settings-btn-sm settings-btn-danger" id="settings-shutdown-review" aria-expanded="false" aria-controls="settings-shutdown-flow"><i data-lucide="power" aria-hidden="true"></i>Review shutdown…</button></div><div id="settings-shutdown-flow" hidden role="group" aria-labelledby="settings-shutdown-title"><h4 id="settings-shutdown-title">Shut down server</h4><p class="settings-hint">Stops Clay, interrupts active work and disconnects everyone. You will need shell or service-manager access to start it again.</p><label class="settings-label" for="settings-shutdown-input">Type shutdown to continue</label><div class="settings-shutdown-input-row"><input type="text" id="settings-shutdown-input" autocomplete="off" spellcheck="false"><button class="settings-btn-sm settings-btn-danger" id="settings-shutdown-btn" disabled>Shut down…</button></div><p id="settings-shutdown-error" class="settings-hint hidden" role="status"></p><button type="button" class="settings-btn-sm" id="settings-shutdown-back">Back</button></div></section></div></div></div><div class="server-settings-close-col"><button id="server-settings-close" class="server-settings-close-btn" aria-label="Close server settings"><i data-lucide="x"></i><span>ESC</span></button></div></div></div>
1260
+ </div><section class="settings-operation settings-danger-operation"><div class="settings-danger-entry"><div class="settings-danger-entry-copy"><h3>Danger zone</h3><p>Shut down Clay for everyone. Active work stops; restarting requires access to the host.</p></div><button type="button" class="settings-btn-sm settings-btn-danger" id="settings-shutdown-review" aria-expanded="false" aria-controls="settings-shutdown-flow"><i data-lucide="power" aria-hidden="true"></i>Review shutdown…</button></div><div id="settings-shutdown-flow" hidden role="group" aria-labelledby="settings-shutdown-title"><h4 id="settings-shutdown-title">Shut down server</h4><p class="settings-hint">Stops Clay, interrupts active work and disconnects everyone. You will need shell or service-manager access to start it again.</p><label class="settings-label" for="settings-shutdown-input">Type shutdown to continue</label><div class="settings-shutdown-input-row"><input type="text" id="settings-shutdown-input" autocomplete="off" spellcheck="false"><button class="settings-btn-sm settings-btn-danger" id="settings-shutdown-btn" disabled>Shut down…</button></div><p id="settings-shutdown-error" class="settings-hint hidden" role="status"></p><button type="button" class="settings-btn-sm" id="settings-shutdown-back">Back</button></div></section></div></div></div></div></div>
1252
1261
 
1253
1262
  <div id="paste-modal" class="hidden" role="dialog" aria-modal="true" aria-labelledby="paste-modal-title">
1254
1263
  <div class="confirm-backdrop"></div>
@@ -1358,37 +1367,16 @@ body { background: transparent; color: inherit; }
1358
1367
  </div>
1359
1368
  </div>
1360
1369
 
1361
- <div id="add-project-modal" class="hidden">
1362
- <div class="confirm-backdrop"></div>
1363
- <div class="confirm-dialog add-project-dialog">
1364
- <div class="add-project-title">Add project</div>
1365
- <div id="add-project-removed" class="hidden"></div>
1366
- <div class="add-project-modes">
1367
- <button class="add-project-mode-btn active" data-mode="existing">Existing directory</button>
1368
- <button class="add-project-mode-btn" data-mode="create">New project</button>
1369
- <button class="add-project-mode-btn" data-mode="clone">Clone from GitHub</button>
1370
- </div>
1371
- <div class="add-project-body">
1372
- <div class="add-project-panel active" data-panel="existing">
1373
- <div class="add-project-input-wrap">
1374
- <span id="add-project-prefix" class="add-project-prefix hidden"></span>
1375
- <input type="text" id="add-project-input" placeholder="/" autocomplete="off" spellcheck="false">
1376
- <div id="add-project-suggestions" class="hidden"></div>
1377
- </div>
1378
- </div>
1379
- <div class="add-project-panel" data-panel="create">
1380
- <input type="text" id="add-project-create-input" placeholder="Project name" autocomplete="off" spellcheck="false">
1381
- </div>
1382
- <div class="add-project-panel" data-panel="clone">
1383
- <input type="text" id="add-project-clone-input" placeholder="https://github.com/user/repo" autocomplete="off" spellcheck="false">
1384
- <div id="add-project-clone-progress" class="hidden"><span class="clone-spinner"></span><span id="add-project-clone-text">Cloning...</span></div>
1385
- </div>
1386
- <div id="add-project-error" class="hidden"></div>
1387
- </div>
1388
- <div class="confirm-actions">
1389
- <button class="confirm-btn confirm-cancel" id="add-project-cancel">Cancel</button>
1390
- <button class="confirm-btn confirm-ok" id="add-project-ok">Add</button>
1391
- </div>
1370
+ <div id="project-start-modal" class="hidden">
1371
+ <div class="project-start-backdrop"></div>
1372
+ <div class="project-start-dialog" role="dialog" aria-modal="true" aria-labelledby="project-start-title" aria-describedby="project-start-subtitle" tabindex="-1">
1373
+ <header class="project-start-header">
1374
+ <button type="button" class="project-start-icon-btn" id="project-start-back" aria-label="Back to choices" hidden><i data-lucide="arrow-left"></i></button>
1375
+ <h2 id="project-start-title">Start a project</h2>
1376
+ <button type="button" class="project-start-icon-btn" id="project-start-close" aria-label="Close"><i data-lucide="x"></i></button>
1377
+ </header>
1378
+ <p class="project-start-subtitle" id="project-start-subtitle">Start something new, or pick up where you left off.</p>
1379
+ <div class="project-start-body" id="project-start-body"></div>
1392
1380
  </div>
1393
1381
  </div>
1394
1382
 
@@ -33,8 +33,14 @@ export function initAccountTransportSettings() {
33
33
  '<div class="settings-form-actions"><button class="settings-btn-sm">Save connection settings</button></div></form><p class="settings-hint" role="status"></p>';
34
34
  anchor.after(section);
35
35
  section.querySelectorAll('[name=origin],[name=proxies]').forEach(function (input) { input.oninput = function () {
36
- var state = Object.assign({}, store.get('accountTransport'), { dirty: true, error: '' });
37
- setSettingsDraft('accountTransport', true); store.set({ accountTransport: state }); render(state);
36
+ // A draft is the form differing from the saved values, so a manual revert clears it.
37
+ var saved = store.get('accountTransport') || {};
38
+ var origin = section.querySelector('[name=origin]').value.trim();
39
+ var proxies = section.querySelector('[name=proxies]').value.split(/\s+/).filter(Boolean);
40
+ var dirty = origin !== (saved.origin || '') || proxies.join('\n') !== (saved.trustedProxies || []).join('\n');
41
+ var state = Object.assign({}, saved, { dirty: dirty, error: '' });
42
+ if (dirty) setSettingsDraft('accountTransport', true); else clearSettingsDraft('accountTransport');
43
+ store.set({ accountTransport: state }); render(state);
38
44
  }; });
39
45
  section.querySelector('form').onsubmit = async function (event) {
40
46
  event.preventDefault(); var password = section.querySelector('[name=password]');
@@ -96,8 +96,13 @@ function renderSmtpTab(body, cfg) {
96
96
 
97
97
  body.innerHTML = html;
98
98
  clearSettingsDraft('smtp');
99
- body.oninput = function () { setSettingsDraft('smtp', true); };
100
- body.onchange = function () { setSettingsDraft('smtp', true); };
99
+ // The draft is the form differing from what was rendered, so reverting a field clears it.
100
+ var fields = Array.from(body.querySelectorAll('input, select, textarea'));
101
+ function fieldValue(field) { return field.type === 'checkbox' ? field.checked : field.value; }
102
+ var baseline = fields.map(fieldValue);
103
+ function syncDraft() { setSettingsDraft('smtp', fields.some(function (field, index) { return fieldValue(field) !== baseline[index]; })); }
104
+ body.oninput = syncDraft;
105
+ body.onchange = syncDraft;
101
106
  refreshIcons(body);
102
107
 
103
108
  var errorEl = body.querySelector("#smtp-error");
@@ -1,7 +1,7 @@
1
1
  import { store } from './store.js';
2
2
  import { iconHtml, refreshIcons } from './icons.js';
3
3
  import { showToast, copyToClipboard, escapeHtml } from './utils.js';
4
- import { apiGet, apiPost, apiPut, apiDelete, showConfirmDialog, showConfirmResetPin, prepareAdminModal } from './admin-settings-ui.js';
4
+ import { apiGet, apiPost, apiPut, apiDelete, showConfirmDialog, showConfirmResetPin, prepareAdminModal, mountAdminSubview } from './admin-settings-ui.js';
5
5
  // --- Invites ---
6
6
  export function loadInvitesTab(body) {
7
7
  apiGet("/api/admin/invites").then(function (data) {
@@ -138,7 +138,7 @@ function showEmailInvitePrompt(body) {
138
138
  '<button class="admin-modal-cancel">Cancel</button>' +
139
139
  '</div></div>';
140
140
  modal.innerHTML = html;
141
- document.body.appendChild(modal);
141
+ mountAdminSubview(modal);
142
142
  prepareAdminModal(modal);
143
143
  refreshIcons(modal);
144
144
 
@@ -1,7 +1,7 @@
1
1
  import { store } from './store.js';
2
2
  import { iconHtml, refreshIcons } from './icons.js';
3
3
  import { showToast, copyToClipboard, escapeHtml } from './utils.js';
4
- import { apiGet, apiPost, apiPut, apiDelete, showConfirmDialog, showConfirmResetPin, prepareAdminModal } from './admin-settings-ui.js';
4
+ import { apiGet, apiPost, apiPut, apiDelete, showConfirmDialog, showConfirmResetPin, prepareAdminModal, mountAdminSubview } from './admin-settings-ui.js';
5
5
  // --- Projects ---
6
6
  export function loadProjectsTab(body) {
7
7
  var projectList = store.get('projectsHubList') || [];
@@ -168,7 +168,7 @@ function showProjectUsersModal(slug, parentBody) {
168
168
  html += '</div>';
169
169
 
170
170
  modal.innerHTML = html;
171
- document.body.appendChild(modal);
171
+ mountAdminSubview(modal);
172
172
  prepareAdminModal(modal);
173
173
  refreshIcons(modal);
174
174
 
@@ -14,13 +14,29 @@ export function apiPost(url, body) { return request(url, 'POST', body || {}); }
14
14
  export function apiPut(url, body) { return request(url, 'PUT', body); }
15
15
  export function apiDelete(url) { return request(url, 'DELETE'); }
16
16
 
17
+ // Editors open inline in the active Server settings page (a subview with its
18
+ // own Back/Cancel path) instead of over the page. Only destructive
19
+ // confirmations remain overlay dialogs.
20
+ export function mountAdminSubview(modal) {
21
+ var host = document.querySelector('#server-settings .server-settings-section.active');
22
+ if (!host) { document.body.appendChild(modal); return; }
23
+ modal.className = 'admin-subview settings-subview';
24
+ host.classList.add('has-subview');
25
+ host.appendChild(modal);
26
+ var observer = new MutationObserver(function () {
27
+ if (!host.querySelector('.settings-subview')) { host.classList.remove('has-subview'); observer.disconnect(); }
28
+ });
29
+ observer.observe(host, { childList: true });
30
+ }
31
+
17
32
  export function prepareAdminModal(modal) {
18
33
  if (modal.dataset.prepared) return;
19
34
  modal.dataset.prepared = 'true';
20
35
  var previous = document.activeElement;
21
- var restore = isolateSettingsDialog(modal);
36
+ var inline = modal.classList.contains('settings-subview');
37
+ var restore = inline ? function () {} : isolateSettingsDialog(modal);
22
38
  var dialog = modal.querySelector('.admin-modal');
23
- dialog.setAttribute('role', 'dialog'); dialog.setAttribute('aria-modal', 'true');
39
+ dialog.setAttribute('role', inline ? 'region' : 'dialog'); if (!inline) dialog.setAttribute('aria-modal', 'true');
24
40
  var title = dialog.querySelector('h3'); dialog.setAttribute('aria-label', title ? title.textContent : 'Confirm action');
25
41
  var dirty = false;
26
42
  modal.addEventListener('input', function () { dirty = true; });
@@ -37,7 +53,7 @@ export function prepareAdminModal(modal) {
37
53
  modal.addEventListener('keydown', function (event) {
38
54
  event.stopPropagation();
39
55
  if (event.key === 'Escape') { event.preventDefault(); if (dirty) cancel(event); else modal.remove(); }
40
- trapSettingsFocus(event, modal);
56
+ if (!inline) trapSettingsFocus(event, modal);
41
57
  });
42
58
  modal.querySelectorAll('.admin-smtp-row').forEach(function (row) {
43
59
  var label = row.querySelector('label'); var input = row.querySelector('input, select');
@@ -49,7 +65,7 @@ export function prepareAdminModal(modal) {
49
65
  var closeObserver = new MutationObserver(function () {
50
66
  if (!modal.isConnected) { closeObserver.disconnect(); restore(); if (previous && previous.isConnected) previous.focus(); }
51
67
  });
52
- closeObserver.observe(document.body, { childList: true });
68
+ closeObserver.observe(inline ? modal.parentElement : document.body, { childList: true });
53
69
  var focus = modal.querySelector('input:not([type=hidden]), .admin-modal-cancel, button');
54
70
  if (focus) focus.focus();
55
71
  }
@@ -1,7 +1,7 @@
1
1
  import { store } from './store.js';
2
2
  import { iconHtml, refreshIcons } from './icons.js';
3
3
  import { showToast, copyToClipboard, escapeHtml } from './utils.js';
4
- import { apiGet, apiPost, apiPut, apiDelete, showConfirmDialog, showConfirmResetPin, prepareAdminModal } from './admin-settings-ui.js';
4
+ import { apiGet, apiPost, apiPut, apiDelete, showConfirmDialog, showConfirmResetPin, prepareAdminModal, mountAdminSubview } from './admin-settings-ui.js';
5
5
  // --- Users ---
6
6
  export function loadUsersTab(body) {
7
7
  apiGet("/api/admin/users").then(function (data) {
@@ -163,7 +163,7 @@ function showPermissionsModal(user, body) {
163
163
  '</div></div>';
164
164
 
165
165
  modal.innerHTML = html;
166
- document.body.appendChild(modal);
166
+ mountAdminSubview(modal);
167
167
  prepareAdminModal(modal);
168
168
  refreshIcons(modal);
169
169
 
@@ -222,7 +222,7 @@ function showAddUserModal(body) {
222
222
  '<button class="admin-modal-cancel">Cancel</button>' +
223
223
  '</div></div>';
224
224
  modal.innerHTML = html;
225
- document.body.appendChild(modal);
225
+ mountAdminSubview(modal);
226
226
  prepareAdminModal(modal);
227
227
  refreshIcons(modal);
228
228
 
@@ -299,7 +299,7 @@ function showTempPinModal(user, tempPin) {
299
299
  '<button class="admin-modal-cancel">Close</button>' +
300
300
  '</div></div>';
301
301
  modal.innerHTML = html;
302
- document.body.appendChild(modal);
302
+ mountAdminSubview(modal);
303
303
  prepareAdminModal(modal);
304
304
  refreshIcons(modal);
305
305
 
@@ -3,7 +3,8 @@
3
3
  import { showProjectsHub, hideProjectsHub } from './projects-hub.js';
4
4
  import { store } from './store.js';
5
5
  import { getWs } from './ws-ref.js';
6
- import { getCachedProjects, openAddProjectModal, switchProject } from './app-projects.js';
6
+ import { getCachedProjects, switchProject } from './app-projects.js';
7
+ import { openAddProjectModal } from './project-start-dialog.js';
7
8
  import { chooseProjectActivationTarget, homeProjectCreationState } from './project-activation.js';
8
9
  import { mateAvatarUrl } from './avatar.js';
9
10
  import { exitDmMode } from './app-dm.js';