frontend: quick actions redesign; collapsible wrapper
Alessandro committed
Mar 24, 2026 at 18:06 UTC
1cc055c7d89190fcc32ebc3352afe94b7c304e89
6 files changed
+282
-186
webui/components/sidebar/left-sidebar.html
+22
-19
@@ -10,27 +10,30 @@
10
<body>
11
<div x-data>
12
<template x-if="$store.sidebar">
13
- <div id="left-panel" class="panel" x-data :class="{'hidden': !$store.sidebar.isOpen}">
14
- <x-extension id="sidebar-start"></x-extension>
15
- <!--Sidebar upper elements-->
16
- <div class="left-panel-top no-scrollbar">
17
- <!-- Top Section: Header Icons + Quick Actions -->
18
- <x-component path="sidebar/top-section/sidebar-top.html"></x-component>
19
- <!-- Chats List -->
20
- <div class="config-section" id="chats-section">
21
- <x-component path="sidebar/chats/chats-list.html"></x-component>
13
+ <div class="sidebar-shell">
14
+ <x-component path="sidebar/top-section/header-icons.html"></x-component>
15
+ <div id="left-panel" class="panel" x-data :class="{'hidden': !$store.sidebar.isOpen}">
16
+ <x-extension id="sidebar-start"></x-extension>
17
+ <!--Sidebar upper elements-->
18
+ <div class="left-panel-top no-scrollbar">
19
+ <!-- Top Section: Quick Actions -->
20
+ <x-component path="sidebar/top-section/sidebar-top.html"></x-component>
21
+ <!-- Chats List -->
22
+ <div class="config-section" id="chats-section">
23
+ <x-component path="sidebar/chats/chats-list.html"></x-component>
24
+ </div>
25
+
26
+ <!-- Tasks List -->
27
+ <div class="config-section" id="tasks-section">
28
+ <x-component path="sidebar/tasks/tasks-list.html"></x-component>
29
+ </div>
30
</div>
23
-
24
- <!-- Tasks List -->
25
- <div class="config-section" id="tasks-section">
26
- <x-component path="sidebar/tasks/tasks-list.html"></x-component>
31
+ <!--Sidebar lower elements-->
32
+ <div class="left-panel-bottom">
33
+ <x-component path="sidebar/bottom/sidebar-bottom.html"></x-component>
34
</div>
35
+ <x-extension id="sidebar-end"></x-extension>
36
</div>
29
- <!--Sidebar lower elements-->
30
- <div class="left-panel-bottom">
31
- <x-component path="sidebar/bottom/sidebar-bottom.html"></x-component>
32
- </div>
33
- <x-extension id="sidebar-end"></x-extension>
37
</div>
38
</template>
39
</div>
@@ -85,7 +88,7 @@
88
/* Critical for allowing flex children to shrink */
89
overflow: hidden;
90
justify-content: space-between;
88
- margin-top: 6rem;
91
+ margin-top: 6.5rem;
92
padding: var(--spacing-md) var(--spacing-md) 0 var(--spacing-md);
93
}
94
webui/components/sidebar/sidebar-store.js
+8
-2
@@ -93,10 +93,16 @@ const model = {
93
updateDropdownPosition(triggerElement) {
94
if (!triggerElement) return;
95
const rect = triggerElement.getBoundingClientRect();
96
+ const menuWidth = Math.max(rect.width, 180);
97
+ const viewportPadding = 8;
98
+ const maxLeft = Math.max(
99
+ viewportPadding,
100
+ window.innerWidth - menuWidth - viewportPadding,
101
+ );
102
this.dropdownStyle = {
103
top: `${rect.bottom + 8}px`,
98
- left: `${rect.left}px`,
99
- width: `${rect.width}px`
104
+ left: `${Math.min(Math.max(rect.left, viewportPadding), maxLeft)}px`,
105
+ width: `${menuWidth}px`
106
};
107
},
108
};
webui/components/sidebar/top-section/header-icons.html
+235
-73
@@ -3,79 +3,165 @@
3
<script type="module">
4
import { store as sidebarStore } from "/components/sidebar/sidebar-store.js";
5
import { store as chatsStore } from "/components/sidebar/chats/chats-store.js";
6
+ import { store as projectsStore } from "/components/projects/projects-store.js";
7
</script>
8
</head>
9
<body>
9
- <div class="sidebar-header-stack">
10
- <!--
11
- Single chrome block for logo + toolbar (tokens aligned with .config-button in quick-actions).
12
- Spacer reserves in-flow height so quick-actions clears the fixed overlay (see .left-panel-top margin-top).
13
- -->
14
- <div id="sidebar-header-panel" class="sidebar-header-panel">
10
+ <div
11
+ class="sidebar-header-stack"
12
+ x-data="{ dropdownOpen: false }"
13
+ @click.outside="dropdownOpen = false"
14
+ @keydown.escape.window="dropdownOpen = false"
15
+ x-init="$watch('dropdownOpen', open => open && $nextTick(() => $store.sidebar.updateDropdownPosition($refs.quickActionsToggle)))"
16
+ >
17
+ <!-- Fixed panel that expands on hover -->
18
+ <div id="sidebar-header-panel" class="sidebar-header-panel" :class="{ 'sidebar-header-panel-open': $store.sidebar.isOpen }">
19
<div id="logo-bar">
20
<a href="https://github.com/agent0ai/agent-zero" target="_blank" rel="noopener noreferrer" aria-label="Agent Zero on GitHub">
17
- <span id="a0-logo" role="img" aria-label="Agent Zero"></span>
21
+ <div class="logo-container">
22
+ <span id="a0-logo" class="logo-expanded" role="img" aria-label="Agent Zero"></span>
23
+ <!-- Placeholder for the single 'A' logo asset -->
24
+ <span id="a0-logo-collapsed" class="logo-collapsed" role="img" aria-label="Agent Zero"></span>
25
+ </div>
26
</a>
27
</div>
28
21
- <div class="icons-section" id="hide-button" x-data>
29
+ <div class="icons-section" id="hide-button">
30
<!-- Sidebar Toggle Button -->
31
<button id="toggle-sidebar" class="toggle-sidebar-button" @click="$store.sidebar.toggle()" aria-label="Toggle Sidebar" aria-expanded="false">
32
<span class="material-symbols-outlined" aria-hidden="true">menu</span>
33
</button>
34
27
- <button class="config-button header-action-button" id="header-dashboard" @click="deselectChat()" title="Dashboard" aria-label="Dashboard">
35
+ <button class="config-button header-action-button" id="header-dashboard" @click="deselectChat()" title="Dashboard" aria-label="Dashboard" tabindex="-1">
36
<span class="material-symbols-outlined" aria-hidden="true">home</span>
37
</button>
38
31
- <button class="config-button header-action-button" id="header-plugins" @click="openModal('components/plugins/list/plugin-list.html')" title="Plugins" aria-label="Plugins">
39
+ <button class="config-button header-action-button" id="header-plugins" @click="openModal('components/plugins/list/plugin-list.html')" title="Plugins" aria-label="Plugins" tabindex="-1">
40
<span class="material-symbols-outlined" aria-hidden="true">extension</span>
41
</button>
42
35
- <button class="config-button header-action-button" id="header-settings" @click="openModal('settings/settings.html')" title="Settings" aria-label="Settings">
43
+ <button class="config-button header-action-button" id="header-settings" @click="openModal('settings/settings.html')" title="Settings" aria-label="Settings" tabindex="-1">
44
<span class="material-symbols-outlined" aria-hidden="true">settings</span>
45
</button>
46
+
47
+ <button
48
+ class="config-button header-action-button dropdown-toggle"
49
+ id="header-more"
50
+ x-ref="quickActionsToggle"
51
+ @click="dropdownOpen = !dropdownOpen"
52
+ title="More options"
53
+ aria-label="More options"
54
+ tabindex="-1"
55
+ >
56
+ <span class="material-symbols-outlined" aria-hidden="true" :class="dropdownOpen ? 'rotated' : ''">expand_more</span>
57
+ </button>
58
</div>
39
- </div>
59
60
+ <div class="dropdown-menu quick-actions-dropdown" x-show="dropdownOpen" :style="$store.sidebar.dropdownStyle">
61
+ <div id="sidebar-quick-actions-dropdown-slot-start"></div>
62
+
63
+ <div class="dropdown-header">Navigation</div>
64
+
65
+ <button class="dropdown-item" @click="deselectChat(); dropdownOpen = false">
66
+ <span class="material-symbols-outlined">home</span>
67
+ <span>Dashboard</span>
68
+ </button>
69
+
70
+ <button class="dropdown-item" @click="$store.projects.openProjectsModal(); dropdownOpen = false">
71
+ <span class="material-symbols-outlined">snippet_folder</span>
72
+ <span>Projects</span>
73
+ </button>
74
+
75
+ <button class="dropdown-item" @click="openModal('components/modals/scheduler/scheduler-modal.html'); dropdownOpen = false">
76
+ <span class="material-symbols-outlined">schedule</span>
77
+ <span>Scheduler</span>
78
+ </button>
79
+
80
+ <button class="dropdown-item" @click="openModal('settings/settings.html'); dropdownOpen = false">
81
+ <span class="material-symbols-outlined">settings</span>
82
+ <span>Settings</span>
83
+ </button>
84
+
85
+ <div class="dropdown-separator"></div>
86
+ <div class="dropdown-header">Chat Actions</div>
87
+
88
+ <button class="dropdown-item" @click="$store.chats.newChat(); dropdownOpen = false">
89
+ <span class="material-symbols-outlined">chat_add_on</span>
90
+ <span>New Chat</span>
91
+ </button>
92
+
93
+ <button class="dropdown-item" @click="$store.chats.loadChats(); dropdownOpen = false">
94
+ <span class="material-symbols-outlined">folder_open</span>
95
+ <span>Load Chat</span>
96
+ </button>
97
+
98
+ <button class="dropdown-item" @click="$store.chats.saveChat(); dropdownOpen = false" :disabled="!$store.chats.selected">
99
+ <span class="material-symbols-outlined">save</span>
100
+ <span>Save Chat</span>
101
+ </button>
102
+
103
+ <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.resetChat(); dropdownOpen = false })" :disabled="!$store.chats.selected">
104
+ <span class="material-symbols-outlined">delete_sweep</span>
105
+ <span>Clear Chat</span>
106
+ </button>
107
+
108
+ <div class="dropdown-separator"></div>
109
+
110
+ <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.logout(); dropdownOpen = false })" :disabled="!$store.chats.loggedIn">
111
+ <span class="material-symbols-outlined">logout</span>
112
+ <span>Logout</span>
113
+ </button>
114
+
115
+ <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.restart(); dropdownOpen = false })">
116
+ <span class="material-symbols-outlined">restart_alt</span>
117
+ <span>Restart A0</span>
118
+ </button>
119
+
120
+ <div id="sidebar-quick-actions-dropdown-slot-end"></div>
121
+ </div>
122
+ </div>
123
</div>
124
125
126
<style>
45
- .sidebar-header-stack {
46
- /*
47
- Panel top (viewport) minus .left-panel-top margin-top: flow starts at 5rem; reserve overlap region.
48
- Tuned for: padding + logo 1.47rem + gap + icon row ~2.2rem + padding.
49
- */
50
- --sidebar-header-flow-clearance: calc(1.9rem + (var(--spacing-xs) * 5) + 1.47rem + 2.2rem - 5rem);
127
+ :root {
128
+ --header-panel-expanded-width: calc(250px - (var(--spacing-md) * 2));
129
+ /* Padding left (0.625rem) + hamburger width (2.2rem) + padding right (0.625rem) = 3.45rem */
130
+ --header-panel-collapsed-width: 3.45rem;
131
}
132
53
- /* Shell: same language as .config-button (quick-actions.html) */
133
+ /* Shell: fixed panel with hover expansion */
134
.sidebar-header-panel {
135
position: fixed;
136
top: var(--spacing-md);
137
left: var(--spacing-md);
58
- width: calc(250px - (var(--spacing-md) * 2));
138
+ width: var(--header-panel-collapsed-width);
139
box-sizing: border-box;
140
z-index: 1004;
141
display: flex;
142
flex-direction: column;
63
- align-items: stretch;
143
+ align-items: flex-start;
144
padding: var(--spacing-xs) var(--spacing-sm);
65
- background-color: var(--color-panel);
66
- border: 0.05rem solid var(--color-border);
145
+ background-color: var(--color-chat-background);
146
+ border: none;
147
border-radius: 8px;
68
- transition: background-color var(--transition-speed),
69
- border-color var(--transition-speed), box-shadow var(--transition-speed),
70
- opacity var(--transition-speed) ease-in-out;
148
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
149
+ overflow: hidden;
150
+ white-space: nowrap;
151
+ transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
152
+ background-color var(--transition-speed),
153
+ border-color var(--transition-speed),
154
+ box-shadow var(--transition-speed);
155
}
156
157
#logo-bar {
158
display: flex;
159
align-items: center;
76
- justify-content: center;
77
- width: 100%;
160
+ justify-content: flex-start;
161
+ width: calc(var(--header-panel-expanded-width) - (var(--spacing-sm) * 2));
162
padding-top: var(--spacing-xxs);
163
+ /* Align logo with the center of the 2.2rem hamburger */
164
+ padding-left: 0.1rem;
165
}
166
167
#logo-bar a {
@@ -84,20 +170,62 @@
170
width: min(100%, 11.75rem);
171
}
172
173
+ .logo-container {
174
+ position: relative;
175
+ width: 100%;
176
+ height: 1.64rem;
177
+ }
178
+
179
+ #a0-logo, #a0-logo-collapsed {
180
+ position: absolute;
181
+ top: 0; left: 8px;
182
+ height: 100%;
183
+ -webkit-mask-repeat: no-repeat;
184
+ mask-repeat: no-repeat;
185
+ background-color: var(--color-text);
186
+ transition: opacity 0.3s ease;
187
+ }
188
+
189
+ /* Expanded wordmark logo */
190
+ #a0-logo {
191
+ width: 100%;
192
+ left: 8px;
193
+ -webkit-mask-image: url(/public/a0-fullDark.svg);
194
+ mask-image: url(/public/a0-fullDark.svg);
195
+ -webkit-mask-size: contain;
196
+ mask-size: contain;
197
+ -webkit-mask-position: left center;
198
+ mask-position: left center;
199
+ opacity: 0;
200
+ }
201
+
202
+ /* Collapsed symbol logo placeholder */
203
+ #a0-logo-collapsed {
204
+ width: 2.0rem; /* Scale to fit nicely above hamburger */
205
+ -webkit-mask-image: url(/public/a0-collapsed.svg);
206
+ mask-image: url(/public/a0-collapsed.svg);
207
+ -webkit-mask-size: contain;
208
+ mask-size: contain;
209
+ -webkit-mask-position: left center;
210
+ mask-position: left center;
211
+ opacity: 0.8;
212
+ }
213
+
214
#hide-button {
88
- display: grid;
89
- grid-template-columns: repeat(4, 1fr);
215
+ display: flex;
216
gap: var(--spacing-xs);
91
- width: 100%;
217
+ width: max-content;
218
+ margin-top: var(--spacing-xs);
219
}
220
94
- /* Toolbar icons sit on the panel surface (no nested config-button boxes) */
221
+ /* Toolbar icons */
222
.sidebar-header-panel #hide-button .config-button,
223
.sidebar-header-panel .toggle-sidebar-button {
224
background-color: transparent;
225
border: none;
226
border-radius: 4px;
227
box-shadow: none;
228
+ flex: 0 0 auto;
229
}
230
231
.sidebar-header-panel #hide-button .config-button {
@@ -105,13 +233,16 @@
233
display: flex;
234
align-items: center;
235
justify-content: center;
108
- opacity: 0.8;
236
padding: var(--spacing-xs);
110
- min-width: 0;
111
- min-height: 2.2rem;
237
+ width: 2.2rem;
238
+ height: 2.2rem;
239
+ opacity: 0;
240
+ transform: translateX(-10px);
241
+ pointer-events: none; /* Disable when collapsed */
242
transition: background-color var(--transition-speed),
113
- border-color var(--transition-speed), box-shadow var(--transition-speed),
114
- opacity var(--transition-speed);
243
+ box-shadow var(--transition-speed),
244
+ opacity 0.3s ease,
245
+ transform 0.3s ease;
246
}
247
248
.sidebar-header-panel #hide-button .config-button .material-symbols-outlined {
@@ -119,16 +250,18 @@
250
transition: transform 0.2s ease;
251
}
252
253
+ .sidebar-header-panel #hide-button .config-button .material-symbols-outlined.rotated {
254
+ transform: rotate(180deg);
255
+ }
256
+
257
.sidebar-header-panel #hide-button .config-button:hover {
258
background-color: var(--color-background-hover);
124
- opacity: 1;
259
+ opacity: 1 !important;
260
box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 18%, transparent);
126
- z-index: 1;
127
- position: relative;
261
}
262
263
.sidebar-header-panel #hide-button .config-button:active {
131
- opacity: 0.5;
264
+ opacity: 0.5 !important;
265
box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.06);
266
}
267
@@ -139,10 +272,9 @@
272
display: flex;
273
align-items: center;
274
justify-content: center;
142
- min-width: 0;
143
- min-height: 2.2rem;
275
+ width: 2.2rem;
276
+ height: 2.2rem;
277
padding: var(--spacing-xs);
145
- -webkit-transition: all var(--transition-speed) ease-in-out;
278
transition: all var(--transition-speed) ease-in-out;
279
}
280
@@ -159,37 +291,75 @@
291
292
.toggle-sidebar-button .material-symbols-outlined {
293
font-size: 22px;
162
- -webkit-transition: all var(--transition-speed) ease;
294
transition: all var(--transition-speed) ease;
295
}
296
297
.toggle-sidebar-button:active .material-symbols-outlined {
167
- -webkit-transform: scaleY(0.8);
298
transform: scaleY(0.8);
299
}
300
171
- #a0-logo {
172
- display: block;
173
- width: 100%;
174
- height: 1.64rem;
175
- -webkit-mask-image: url(/public/a0-fullDark.svg);
176
- mask-image: url(/public/a0-fullDark.svg);
177
- -webkit-mask-repeat: no-repeat;
178
- mask-repeat: no-repeat;
179
- -webkit-mask-size: contain;
180
- mask-size: contain;
181
- -webkit-mask-position: left;
182
- mask-position: center;
183
- background-color: var(--color-text);
184
- opacity: 0.8;
185
- -webkit-transition: opacity var(--transition-speed) ease, background-color var(--transition-speed) ease;
186
- transition: opacity var(--transition-speed) ease, background-color var(--transition-speed) ease;
187
- }
301
+ /* --- Desktop Hover Expand --- */
302
+ @media (min-width: 769px) {
303
+ .sidebar-header-panel.sidebar-header-panel-open,
304
+ .sidebar-header-panel:hover,
305
+ .sidebar-header-panel:focus-within {
306
+ width: var(--header-panel-expanded-width);
307
+ }
308
189
- #logo-bar a:hover #a0-logo {
190
- opacity: 1;
309
+ .sidebar-header-panel.sidebar-header-panel-open #a0-logo,
310
+ .sidebar-header-panel:hover #a0-logo,
311
+ .sidebar-header-panel:focus-within #a0-logo {
312
+ opacity: 0.8;
313
+ }
314
+
315
+ .sidebar-header-panel.sidebar-header-panel-open #logo-bar a:hover #a0-logo,
316
+ .sidebar-header-panel:hover #logo-bar a:hover #a0-logo,
317
+ .sidebar-header-panel:focus-within #logo-bar a:hover #a0-logo {
318
+ opacity: 1;
319
+ }
320
+
321
+ .sidebar-header-panel.sidebar-header-panel-open #a0-logo-collapsed,
322
+ .sidebar-header-panel:hover #a0-logo-collapsed,
323
+ .sidebar-header-panel:focus-within #a0-logo-collapsed {
324
+ opacity: 0;
325
+ }
326
+
327
+ .sidebar-header-panel.sidebar-header-panel-open #hide-button .config-button,
328
+ .sidebar-header-panel:hover #hide-button .config-button,
329
+ .sidebar-header-panel:focus-within #hide-button .config-button {
330
+ opacity: 0.8;
331
+ transform: translateX(0);
332
+ pointer-events: auto;
333
+ }
334
}
335
336
+ /* --- Mobile Always Expanded --- */
337
+ @media (max-width: 768px) {
338
+ .sidebar-header-panel {
339
+ width: var(--header-panel-expanded-width);
340
+ transition: all 0.3s ease;
341
+ }
342
+
343
+ #a0-logo {
344
+ opacity: 0.8;
345
+ }
346
+
347
+ #logo-bar a:hover #a0-logo {
348
+ opacity: 1;
349
+ }
350
+
351
+ #a0-logo-collapsed {
352
+ opacity: 0;
353
+ }
354
+
355
+ .sidebar-header-panel #hide-button .config-button {
356
+ opacity: 0.8 !important;
357
+ transform: translateX(0) !important;
358
+ pointer-events: auto !important;
359
+ }
360
+ }
361
+
362
+ /* Light mode fixes */
363
.light-mode .sidebar-header-panel {
364
background-color: var(--color-background);
365
color: #333333;
@@ -204,14 +374,6 @@
374
.light-mode .sidebar-header-panel .toggle-sidebar-button:active {
375
background-color: var(--color-background-hover);
376
}
207
-
208
- @media (max-width: 768px) {
209
- .sidebar-header-panel {
210
- -webkit-transition: all 0.3s ease;
211
- transition: all 0.3s ease;
212
- }
213
- }
377
</style>
378
</body>
379
</html>
217
-
webui/components/sidebar/top-section/quick-actions.html
+11
-89
@@ -1,104 +1,27 @@
1
<html>
2
3
-<head>
4
- <script type="module">
5
- import { store as chatsStore } from "/components/sidebar/chats/chats-store.js";
6
- import { store as projectsStore } from "/components/projects/projects-store.js";
7
- import { store as sidebarStore } from "/components/sidebar/sidebar-store.js";
8
- </script>
9
-</head>
3
+<head></head>
4
5
<body>
12
- <div class="wrapper" x-data="{ dropdownOpen: false }" @click.outside="dropdownOpen = false" @keydown.escape.window="dropdownOpen = false" x-init="$watch('dropdownOpen', v => v && $store.sidebar.updateDropdownPosition($el))">
13
- <div id="quick-actions">
6
+ <div class="quick-actions-surface-host" x-data>
7
+ <template x-teleport="#sidebar-quick-actions-dropdown-slot-start">
8
+ <x-extension id="sidebar-quick-actions-dropdown-start"></x-extension>
9
+ </template>
10
11
+ <div id="quick-actions">
12
<x-extension id="sidebar-quick-actions-main-start"></x-extension>
16
-
13
<x-extension id="sidebar-quick-actions-main-end"></x-extension>
18
-
19
- <!-- Dropdown Toggle -->
20
- <button class="config-button dropdown-toggle" @click="dropdownOpen = !dropdownOpen" title="More options">
21
- <span class="material-symbols-outlined" :class="dropdownOpen ? 'rotated' : ''">expand_more</span>
22
- </button>
14
</div>
15
25
- <!-- Dropdown Menu -->
26
- <div class="dropdown-menu quick-actions-dropdown"
27
- x-show="dropdownOpen"
28
- :style="$store.sidebar.dropdownStyle">
29
-
30
- <x-extension id="sidebar-quick-actions-dropdown-start"></x-extension>
31
-
32
- <div class="dropdown-header">Navigation</div>
33
-
34
- <button class="dropdown-item" @click="deselectChat(); dropdownOpen = false">
35
- <span class="material-symbols-outlined">home</span>
36
- <span>Dashboard</span>
37
- </button>
38
-
39
- <button class="dropdown-item" @click="$store.projects.openProjectsModal(); dropdownOpen = false">
40
- <span class="material-symbols-outlined">snippet_folder</span>
41
- <span>Projects</span>
42
- </button>
43
-
44
- <button class="dropdown-item" @click="openModal('components/modals/scheduler/scheduler-modal.html'); dropdownOpen = false">
45
- <span class="material-symbols-outlined">schedule</span>
46
- <span>Scheduler</span>
47
- </button>
48
-
49
- <button class="dropdown-item" @click="openModal('settings/settings.html'); dropdownOpen = false">
50
- <span class="material-symbols-outlined">settings</span>
51
- <span>Settings</span>
52
- </button>
53
-
54
- <div class="dropdown-separator"></div>
55
- <div class="dropdown-header">Chat Actions</div>
56
-
57
- <button class="dropdown-item" @click="$store.chats.newChat(); dropdownOpen = false">
58
- <span class="material-symbols-outlined">chat_add_on</span>
59
- <span>New Chat</span>
60
- </button>
61
-
62
- <button class="dropdown-item" @click="$store.chats.loadChats(); dropdownOpen = false">
63
- <span class="material-symbols-outlined">folder_open</span>
64
- <span>Load Chat</span>
65
- </button>
66
-
67
- <button class="dropdown-item" @click="$store.chats.saveChat(); dropdownOpen = false" :disabled="!$store.chats.selected">
68
- <span class="material-symbols-outlined">save</span>
69
- <span>Save Chat</span>
70
- </button>
71
-
72
- <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.resetChat(); dropdownOpen = false })" :disabled="!$store.chats.selected">
73
- <span class="material-symbols-outlined">delete_sweep</span>
74
- <span>Clear Chat</span>
75
- </button>
76
-
77
- <div class="dropdown-separator"></div>
78
-
79
-
80
- <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.logout(); dropdownOpen = false })" :disabled="!$store.chats.loggedIn">
81
- <span class="material-symbols-outlined">logout</span>
82
- <span>Logout</span>
83
- </button>
84
-
85
- <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.restart(); dropdownOpen = false })">
86
- <span class="material-symbols-outlined">restart_alt</span>
87
- <span>Restart A0</span>
88
- </button>
89
-
16
+ <template x-teleport="#sidebar-quick-actions-dropdown-slot-end">
17
<x-extension id="sidebar-quick-actions-dropdown-end"></x-extension>
91
- </div>
18
+ </template>
19
</div>
20
</body>
21
22
<style>
96
- /* Wrapper container for icon toolbar */
97
- .wrapper {
98
- position: relative;
99
- border-radius: 0.6rem;
100
- z-index: 100;
101
- /* Ensure dropdown appears above all sidebar content */
23
+ .quick-actions-surface-host {
24
+ display: contents;
25
}
26
27
/* Icon toolbar layout – grid for extension-friendly wrapping */
@@ -111,9 +34,8 @@
34
gap: var(--spacing-xs);
35
}
36
114
- .quick-actions-anchor {
37
+ #quick-actions:not(:has(> x-extension:not(:empty))) {
38
display: none;
116
- pointer-events: none;
39
}
40
41
#quick-actions > x-extension:not(:empty) {
webui/components/sidebar/top-section/sidebar-top.html
+5
-3
@@ -9,9 +9,6 @@
9
<template x-if="$store.sidebar">
10
<div class="sidebar-top-wrapper">
11
<x-extension id="sidebar-top-wrapper-start"></x-extension>
12
- <!-- Header Icons (Toggle + Logo) -->
13
- <x-component path="sidebar/top-section/header-icons.html"></x-component>
14
-
12
<!-- Quick Actions Buttons -->
13
<x-component path="sidebar/top-section/quick-actions.html"></x-component>
14
<x-extension id="sidebar-top-wrapper-end"></x-extension>
@@ -27,6 +24,11 @@
24
flex-direction: column;
25
flex-shrink: 0;
26
}
27
+
28
+ .sidebar-top-wrapper > x-component,
29
+ .sidebar-top-wrapper > x-component > .quick-actions-surface-host {
30
+ display: contents;
31
+ }
32
</style>
33
</body>
34
</html>
webui/public/a0-collapsed.svg
new
+1
@@ -0,0 +1 @@
1
+<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 26" width="16" height="26"><style>.a{fill:#7a7a7a}</style><path class="a" d="m13 19.6c-1.6-2.8-3.3-5.7-5-8.6q-2.6 4.3-5.1 8.7h-2.5c2.5-4.4 7.6-13.1 7.6-13.1 0 0 5.1 8.7 7.6 13.1h-2.6z"/><path class="a" d="m11.2 19.7h-6.5q0.6-1.2 1.2-2.3h4.1q0.6 1.1 1.2 2.3z"/></svg>
\ No newline at end of file