main
html 447 lines 15.2 KB
Raw
1 <html>
2 <head>
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 import { store as chatInputStore } from "/components/chat/input/input-store.js";
8 </script>
9 </head>
10 <body>
11 <div
12 class="sidebar-header-stack"
13 x-data
14 @click.window="$store.sidebar.menuClick($event, $refs.headerPanel)"
15 @keydown.escape.window="$store.sidebar.menuClose()"
16 >
17 <!-- Fixed panel that expands on hover -->
18 <div
19 id="sidebar-header-panel"
20 class="sidebar-header-panel"
21 x-ref="headerPanel"
22 :class="{ 'sidebar-header-panel-open': $store.sidebar.headOpen() }"
23 >
24 <div id="logo-bar">
25 <a href="https://github.com/agent0ai/agent-zero" target="_blank" rel="noopener noreferrer" aria-label="Agent Zero on GitHub">
26 <div class="logo-container">
27 <span id="a0-logo" class="logo-expanded" role="img" aria-label="Agent Zero"></span>
28 <!-- Placeholder for the single 'A' logo asset -->
29 <span id="a0-logo-collapsed" class="logo-collapsed" role="img" aria-label="Agent Zero"></span>
30 </div>
31 </a>
32 </div>
33
34 <div class="icons-section" id="hide-button">
35 <!-- Sidebar Toggle Button -->
36 <button id="toggle-sidebar" class="toggle-sidebar-button" @click="$store.sidebar.toggle()" aria-label="Toggle Sidebar" aria-expanded="false">
37 <x-icon aria-hidden="true" name="menu"></x-icon>
38 </button>
39
40 <button class="config-button header-action-button" id="header-dashboard" @click="deselectChat()" title="Dashboard" aria-label="Dashboard" tabindex="-1">
41 <x-icon aria-hidden="true" name="home"></x-icon>
42 </button>
43
44 <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">
45 <x-icon aria-hidden="true" name="extension"></x-icon>
46 </button>
47
48 <button class="config-button header-action-button" id="header-settings" @click="openModal('settings/settings.html')" title="Settings" aria-label="Settings" tabindex="-1">
49 <x-icon aria-hidden="true" name="settings"></x-icon>
50 </button>
51
52 <button
53 class="config-button header-action-button dropdown-toggle"
54 id="header-more"
55 x-ref="menuButton"
56 @click="$store.sidebar.menuToggle($refs.menuButton)"
57 title="More options"
58 aria-label="More options"
59 tabindex="-1"
60 >
61 <x-icon aria-hidden="true" :class="$store.sidebar.menuOpen ? 'rotated' : ''" name="expand_more"></x-icon>
62 </button>
63 </div>
64
65 <!-- Stop propagation so @click.window menuClick does not treat in-menu clicks as outside the header panel (fixed menu + confirm flow). -->
66 <div
67 class="dropdown-menu quick-actions-dropdown"
68 x-show="$store.sidebar.menuOpen"
69 :style="$store.sidebar.dropdownStyle"
70 @click.stop
71 >
72 <div id="sidebar-quick-actions-dropdown-slot-start"></div>
73
74 <div class="dropdown-header">Navigation</div>
75
76 <button class="dropdown-item" @click="deselectChat(); $store.sidebar.menuClose()">
77 <x-icon name="home"></x-icon>
78 <span>Dashboard</span>
79 </button>
80
81 <button class="dropdown-item" @click="$store.projects.openProjectsModal(); $store.sidebar.menuClose()">
82 <x-icon name="snippet_folder"></x-icon>
83 <span>Projects</span>
84 </button>
85
86 <button id="sidebar-files-dropdown" class="dropdown-item" @click="$store.chatInput.browseFiles(); $store.sidebar.menuClose()">
87 <x-icon name="folder"></x-icon>
88 <span>Files</span>
89 </button>
90
91 <button class="dropdown-item" @click="ensureModalOpen('settings/tunnel/remote-link.html'); $store.sidebar.menuClose()">
92 <x-icon name="share"></x-icon>
93 <span>Remote Control</span>
94 </button>
95
96 <button class="dropdown-item" @click="open('https://space-agent.ai/', '_blank', 'noopener,noreferrer'); $store.sidebar.menuClose()">
97 <x-icon name="rocket_launch"></x-icon>
98 <span>Space Agent</span>
99 </button>
100
101 <button class="dropdown-item" @click="openModal('components/modals/scheduler/scheduler-modal.html'); $store.sidebar.menuClose()">
102 <x-icon name="schedule"></x-icon>
103 <span>Tasks</span>
104 </button>
105
106 <button class="dropdown-item" @click="openModal('settings/settings.html'); $store.sidebar.menuClose()">
107 <x-icon name="settings"></x-icon>
108 <span>Settings</span>
109 </button>
110
111 <div class="dropdown-separator"></div>
112
113 <button
114 type="button"
115 class="dropdown-item quick-actions-accordion-toggle"
116 :class="{ 'is-open': $store.sidebar.isSectionOpen('chatActions') }"
117 :aria-expanded="$store.sidebar.isSectionOpen('chatActions').toString()"
118 @click="$store.sidebar.toggleSection('chatActions')"
119 >
120 <span class="quick-actions-accordion-label">
121 <x-icon name="forum"></x-icon>
122 <span>Chat Actions</span>
123 </span>
124 <x-icon class="quick-actions-accordion-chevron" name="expand_more"></x-icon>
125 </button>
126
127 <div class="quick-actions-accordion-panel" x-show="$store.sidebar.isSectionOpen('chatActions')" style="display: none;">
128 <button class="dropdown-item" @click="$store.chats.newChat(); $store.sidebar.menuClose()">
129 <x-icon name="chat_add_on"></x-icon>
130 <span>New Chat</span>
131 </button>
132
133 <button class="dropdown-item" @click="$store.chats.loadChats(); $store.sidebar.menuClose()">
134 <x-icon name="folder_open"></x-icon>
135 <span>Load Chat</span>
136 </button>
137
138 <button class="dropdown-item" x-show="$store.chats.selected" @click="$store.chats.saveChat(); $store.sidebar.menuClose()">
139 <x-icon name="save"></x-icon>
140 <span>Save Chat</span>
141 </button>
142
143 <button class="dropdown-item" x-show="$store.chats.selected" @click="$confirmClick($event, () => { $store.chats.resetChat(); $store.sidebar.menuClose() })">
144 <x-icon name="delete_sweep"></x-icon>
145 <span>Clear Chat</span>
146 </button>
147 </div>
148
149 <div class="dropdown-separator"></div>
150
151 <button class="dropdown-item" x-show="$store.chats.loggedIn" @click="$confirmClick($event, () => { $store.chats.logout(); $store.sidebar.menuClose() })">
152 <x-icon name="logout"></x-icon>
153 <span>Logout</span>
154 </button>
155
156 <button class="dropdown-item" @click="$confirmClick($event, () => { $store.chats.restart(); $store.sidebar.menuClose() })">
157 <x-icon name="restart_alt"></x-icon>
158 <span>Restart A0</span>
159 </button>
160
161 <div id="sidebar-quick-actions-dropdown-slot-end"></div>
162 </div>
163 </div>
164 </div>
165
166
167 <style>
168 :root {
169 --header-panel-expanded-width: calc(250px - (var(--spacing-md) * 2));
170 /* Padding left (0.625rem) + hamburger width (2.2rem) + padding right (0.625rem) = 3.45rem */
171 --header-panel-collapsed-width: 3.45rem;
172 }
173
174 /* Shell: fixed panel with hover expansion */
175 .sidebar-header-panel {
176 position: fixed;
177 top: var(--spacing-md);
178 left: var(--spacing-md);
179 width: var(--header-panel-collapsed-width);
180 box-sizing: border-box;
181 z-index: 1004;
182 display: flex;
183 flex-direction: column;
184 align-items: flex-start;
185 padding: var(--spacing-xs) var(--spacing-sm);
186 background-color: var(--color-chat-background);
187 border: none;
188 border-radius: 8px;
189 box-shadow: 0 2px 13px 2px rgba(0, 0, 0, 0.35);
190 overflow: hidden;
191 white-space: nowrap;
192 transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1),
193 background-color var(--transition-speed),
194 border-color var(--transition-speed),
195 box-shadow var(--transition-speed);
196 }
197
198 #logo-bar {
199 display: flex;
200 align-items: center;
201 justify-content: flex-start;
202 width: calc(var(--header-panel-expanded-width) - (var(--spacing-sm) * 2));
203 padding-top: var(--spacing-xxs);
204 /* Align logo with the center of the 2.2rem hamburger */
205 padding-left: 0.1rem;
206 }
207
208 #logo-bar a {
209 color: inherit;
210 text-decoration: none;
211 width: min(100%, 11.75rem);
212 }
213
214 .logo-container {
215 position: relative;
216 width: 100%;
217 height: 1.64rem;
218 }
219
220 #a0-logo, #a0-logo-collapsed {
221 position: absolute;
222 top: 0; left: 8px;
223 height: 100%;
224 -webkit-mask-repeat: no-repeat;
225 mask-repeat: no-repeat;
226 background-color: var(--color-text);
227 transition: opacity 0.3s ease;
228 }
229
230 /* Expanded wordmark logo */
231 #a0-logo {
232 width: 100%;
233 left: 8px;
234 -webkit-mask-image: url(/public/a0-fullDark.svg);
235 mask-image: url(/public/a0-fullDark.svg);
236 -webkit-mask-size: contain;
237 mask-size: contain;
238 -webkit-mask-position: left center;
239 mask-position: left center;
240 opacity: 0;
241 }
242
243 /* Collapsed symbol logo placeholder */
244 #a0-logo-collapsed {
245 width: 2.0rem; /* Scale to fit nicely above hamburger */
246 -webkit-mask-image: url(/public/a0-collapsed.svg);
247 mask-image: url(/public/a0-collapsed.svg);
248 -webkit-mask-size: contain;
249 mask-size: contain;
250 -webkit-mask-position: left center;
251 mask-position: left center;
252 opacity: 0.8;
253 }
254
255 #hide-button {
256 display: flex;
257 gap: var(--spacing-xs);
258 width: max-content;
259 margin-top: var(--spacing-xs);
260 }
261
262 /* Toolbar icons */
263 .sidebar-header-panel #hide-button .config-button,
264 .sidebar-header-panel .toggle-sidebar-button {
265 background-color: transparent;
266 border: none;
267 border-radius: 4px;
268 box-shadow: none;
269 flex: 0 0 auto;
270 }
271
272 .sidebar-header-panel #hide-button .config-button {
273 cursor: pointer;
274 display: flex;
275 align-items: center;
276 justify-content: center;
277 padding: var(--spacing-xs);
278 width: 2.2rem;
279 height: 2.2rem;
280 opacity: 0;
281 transform: translateX(-10px);
282 pointer-events: none; /* Disable when collapsed */
283 transition: background-color var(--transition-speed),
284 box-shadow var(--transition-speed),
285 opacity 0.3s ease,
286 transform 0.3s ease;
287 }
288
289 .sidebar-header-panel #hide-button .config-button .material-symbols-outlined {
290 font-size: 22px;
291 transition: transform 0.2s ease;
292 }
293
294 .sidebar-header-panel #hide-button .config-button .material-symbols-outlined.rotated {
295 transform: rotate(180deg);
296 }
297
298 .sidebar-header-panel #hide-button .config-button:hover {
299 background-color: var(--color-background-hover);
300 opacity: 1 !important;
301 box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 18%, transparent);
302 }
303
304 .sidebar-header-panel #hide-button .config-button:active {
305 opacity: 0.5 !important;
306 box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.06);
307 }
308
309 .toggle-sidebar-button {
310 color: var(--color-text);
311 opacity: 0.8;
312 cursor: pointer;
313 display: flex;
314 align-items: center;
315 justify-content: center;
316 width: 2.2rem;
317 height: 2.2rem;
318 padding: var(--spacing-xs);
319 transition: all var(--transition-speed) ease-in-out;
320 }
321
322 .toggle-sidebar-button:hover {
323 background-color: var(--color-background-hover);
324 opacity: 1;
325 box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 18%, transparent);
326 }
327
328 .toggle-sidebar-button:active {
329 opacity: 0.5;
330 box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.06);
331 }
332
333 .toggle-sidebar-button .material-symbols-outlined {
334 font-size: 22px;
335 transition: all var(--transition-speed) ease;
336 }
337
338 .toggle-sidebar-button:active .material-symbols-outlined {
339 transform: scaleY(0.8);
340 }
341
342 .quick-actions-accordion-toggle {
343 justify-content: space-between;
344 }
345
346 .quick-actions-accordion-label {
347 display: inline-flex;
348 align-items: center;
349 gap: var(--spacing-sm);
350 min-width: 0;
351 }
352
353 .quick-actions-accordion-chevron {
354 margin-left: auto;
355 transition: transform 0.15s ease;
356 }
357
358 .quick-actions-accordion-toggle.is-open .quick-actions-accordion-chevron {
359 transform: rotate(180deg);
360 }
361
362 .quick-actions-accordion-panel .dropdown-item {
363 padding-left: calc(var(--spacing-md) + 1.55rem);
364 }
365
366 /* --- Desktop Hover Expand --- */
367 @media (min-width: 769px) {
368 .sidebar-header-panel.sidebar-header-panel-open,
369 .sidebar-header-panel:hover,
370 .sidebar-header-panel:focus-within {
371 width: var(--header-panel-expanded-width);
372 }
373
374 .sidebar-header-panel.sidebar-header-panel-open #a0-logo,
375 .sidebar-header-panel:hover #a0-logo,
376 .sidebar-header-panel:focus-within #a0-logo {
377 opacity: 0.8;
378 }
379
380 .sidebar-header-panel.sidebar-header-panel-open #logo-bar a:hover #a0-logo,
381 .sidebar-header-panel:hover #logo-bar a:hover #a0-logo,
382 .sidebar-header-panel:focus-within #logo-bar a:hover #a0-logo {
383 opacity: 1;
384 }
385
386 .sidebar-header-panel.sidebar-header-panel-open #a0-logo-collapsed,
387 .sidebar-header-panel:hover #a0-logo-collapsed,
388 .sidebar-header-panel:focus-within #a0-logo-collapsed {
389 opacity: 0;
390 }
391
392 .sidebar-header-panel.sidebar-header-panel-open #hide-button .config-button,
393 .sidebar-header-panel:hover #hide-button .config-button,
394 .sidebar-header-panel:focus-within #hide-button .config-button {
395 opacity: 0.8;
396 transform: translateX(0);
397 pointer-events: auto;
398 }
399 }
400
401 /* --- Mobile: open only when header state says so --- */
402 @media (max-width: 768px) {
403 .sidebar-header-panel {
404 transition: all 0.3s ease;
405 }
406
407 .sidebar-header-panel.sidebar-header-panel-open {
408 width: var(--header-panel-expanded-width);
409 }
410
411 .sidebar-header-panel.sidebar-header-panel-open #a0-logo {
412 opacity: 0.8;
413 }
414
415 .sidebar-header-panel.sidebar-header-panel-open #logo-bar a:hover #a0-logo {
416 opacity: 1;
417 }
418
419 .sidebar-header-panel.sidebar-header-panel-open #a0-logo-collapsed {
420 opacity: 0;
421 }
422
423 .sidebar-header-panel.sidebar-header-panel-open #hide-button .config-button {
424 opacity: 0.8 !important;
425 transform: translateX(0) !important;
426 pointer-events: auto !important;
427 }
428 }
429
430 /* Light mode fixes */
431 .light-mode .sidebar-header-panel {
432 background-color: var(--color-background);
433 color: #333333;
434 }
435
436 .light-mode .sidebar-header-panel #hide-button .config-button:hover,
437 .light-mode .sidebar-header-panel .toggle-sidebar-button:hover {
438 background-color: var(--color-background-hover);
439 }
440
441 .light-mode .sidebar-header-panel #hide-button .config-button:active,
442 .light-mode .sidebar-header-panel .toggle-sidebar-button:active {
443 background-color: var(--color-background-hover);
444 }
445 </style>
446 </body>
447 </html>