ui: streamline sidebar buttons, add dropdown component

3clyp50 committed Dec 29, 2025 at 15:03 UTC d4587e0b7794534d5d93a5ab564a3212aed794f1
10 files changed +394 -67
webui/components/dropdown/dropdown.html new
+69
@@ -0,0 +1,69 @@
1 +<!--
2 + Reusable Dropdown Component
3 +
4 + Usage:
5 + <x-component data-component="ui/dropdown" data-props='{"id": "my-dropdown"}'>
6 + <template x-slot:trigger>
7 + <button>Click me</button>
8 + </template>
9 + <template x-slot:menu>
10 + <button class="dropdown-item" @click="...">Item 1</button>
11 + <div class="dropdown-separator"></div>
12 + <button class="dropdown-item" @click="...">Item 2</button>
13 + </template>
14 + </x-component>
15 +
16 + Or use the simpler inline approach with x-data:
17 + <div class="dropdown" x-data="{ open: false }" @click.outside="open = false">
18 + <button class="dropdown-trigger" @click="open = !open">...</button>
19 + <div class="dropdown-menu" x-show="open" x-transition>...</div>
20 + </div>
21 +-->
22 +<html>
23 +<head>
24 + <!-- Dropdown uses global styles from index.css -->
25 +</head>
26 +<body>
27 + <div
28 + class="dropdown"
29 + x-data="{
30 + open: false,
31 + toggle() { this.open = !this.open; },
32 + close() { this.open = false; }
33 + }"
34 + @click.outside="close()"
35 + @keydown.escape.window="close()"
36 + >
37 + <!-- Trigger slot -->
38 + <div class="dropdown-trigger-wrapper" @click="toggle()">
39 + <slot name="trigger">
40 + <button class="dropdown-trigger" type="button">
41 + <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
42 + <path d="M6 9l6 6 6-6"/>
43 + </svg>
44 + </button>
45 + </slot>
46 + </div>
47 +
48 + <!-- Menu slot -->
49 + <div
50 + class="dropdown-menu"
51 + x-show="open"
52 + @click="close()"
53 + >
54 + <slot name="menu">
55 + <!-- Default empty menu -->
56 + </slot>
57 + </div>
58 + </div>
59 +
60 + <style>
61 + /* Component-specific styles (layout helpers) */
62 + .dropdown-trigger-wrapper {
63 + display: contents;
64 + }
65 +
66 + </style>
67 +</body>
68 +</html>
69 +
webui/components/modals/memory/memory-dashboard-store.js renamed
+2 -2
@@ -53,7 +53,7 @@ const memoryDashboardStore = {
53 pollingEnabled: false,
54
55 async openModal() {
56 - await openModal("settings/memory/memory-dashboard.html");
56 + await openModal("modals/memory/memory-dashboard.html");
57 },
58
59 init() {
@@ -451,7 +451,7 @@ ${memory.content_full}
451 this.editMode = false;
452 this.editMemoryBackup = null;
453 // Use global modal system
454 - openModal("settings/memory/memory-detail-modal.html");
454 + openModal("modals/memory/memory-detail-modal.html");
455 },
456
457 closeMemoryDetails() {
webui/components/modals/memory/memory-dashboard.html renamed
+1 -1
@@ -3,7 +3,7 @@
3 <head>
4 <title>Memory Dashboard</title>
5 <script type="module">
6 - import { store } from "/components/settings/memory/memory-dashboard-store.js";
6 + import { store } from "/components/modals/memory/memory-dashboard-store.js";
7 </script>
8 </head>
9
webui/components/modals/memory/memory-detail-modal.html renamed
webui/components/settings/agent/memory.html
+1 -1
@@ -34,7 +34,7 @@
34 <div class="field-control">
35 <button
36 class="btn btn-field"
37 - @click="$store.settingsStore.handleFieldButton({ id: 'memory_dashboard' })"
37 + @click="openModal('modals/memory/memory-dashboard.html');"
38 >
39 Open Dashboard
40 </button>
webui/components/settings/settings-store.js
+11 -13
@@ -6,6 +6,15 @@ import { store as notificationStore } from "/components/notifications/notificati
6 const VIEW_MODE_STORAGE_KEY = "settingsActiveTab";
7 const DEFAULT_TAB = "agent";
8
9 +// Field button actions (field id -> modal path)
10 +const FIELD_BUTTON_MODAL_BY_ID = Object.freeze({
11 + mcp_servers_config: "settings/mcp/client/mcp-servers.html",
12 + backup_create: "settings/backup/backup.html",
13 + backup_restore: "settings/backup/restore.html",
14 + show_a2a_connection: "settings/a2a/a2a-connection.html",
15 + external_api_examples: "settings/external/api-examples.html",
16 +});
17 +
18 // Helper for toasts
19 function toast(text, type = "info", timeout = 5000) {
20 notificationStore.addFrontendToastOnly(type, text, "", timeout / 1000);
@@ -146,19 +155,8 @@ const model = {
155 // Field helpers for external components
156 // Handle button field clicks (opens sub-modals)
157 async handleFieldButton(field) {
149 - if (field.id === "mcp_servers_config") {
150 - window.openModal("settings/mcp/client/mcp-servers.html");
151 - } else if (field.id === "backup_create") {
152 - window.openModal("settings/backup/backup.html");
153 - } else if (field.id === "backup_restore") {
154 - window.openModal("settings/backup/restore.html");
155 - } else if (field.id === "show_a2a_connection") {
156 - window.openModal("settings/a2a/a2a-connection.html");
157 - } else if (field.id === "external_api_examples") {
158 - window.openModal("settings/external/api-examples.html");
159 - } else if (field.id === "memory_dashboard") {
160 - window.openModal("settings/memory/memory-dashboard.html");
161 - }
158 + const modalPath = FIELD_BUTTON_MODAL_BY_ID[field?.id];
159 + if (modalPath) window.openModal(modalPath);
160 },
161
162 // Open settings modal from external callers
webui/components/sidebar/top-section/header-icons.html
+35 -8
@@ -2,18 +2,14 @@
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 </script>
7 </head>
8 <body>
9 <div class="icons-section" id="hide-button" x-data>
10 <!-- Sidebar Toggle Button -->
11 <button id="toggle-sidebar" class="toggle-sidebar-button" @click="$store.sidebar.toggle()" aria-label="Toggle Sidebar" aria-expanded="false">
11 - <span aria-hidden="true">
12 - <!-- Hamburger Icon -->
13 - <svg id="sidebar-hamburger-svg" xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="CurrentColor">
14 - <path d="M3 13h18v-2H3v2zm0 4h18v-2H3v2zm0-8h18V7H3v2z"></path>
15 - </svg>
16 - </span>
12 + <span class="material-symbols-outlined" aria-hidden="true">menu</span>
13 </button>
14
15 <div id="logo-container">
@@ -21,6 +17,13 @@
17 <img src="./public/splash.jpg" alt="a0" width="22" height="22">
18 </a>
19 </div>
20 +
21 + <!-- New Chat Button -->
22 + <button id="newChat" @click="$store.chats.newChat()" aria-label="New Chat">
23 + <svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 110 135" width="32" height="32">
24 + <path d="m38.3 81.3 3.2-9.1 3.1-9v-.1c0-.2.1-.3.2-.4.1-.2.2-.3.3-.4L82.4 25c1.6-1.6 3.7-2.4 5.7-2.4h.2c2 0 4 .8 5.6 2.4l3.7 3.7.1.2c1.5 1.6 2.2 3.6 2.2 5.6v.2c0 2-.8 4-2.4 5.6l-.1.1-3.8 3.6-.1.1-.1.1-32.9 33-.1.1q-.45.45-.9.6l-9.1 3.2h-.1l-9.1 3.1c-1.2.4-2.5-.2-2.9-1.4q-.3-.75 0-1.5m7.5-7.6-1.6 4.6 4.6-1.6 5.7-2-3.4-3.4-3.3-3.3zm4.2-9.9 4.3 4.3 4.3 4.3 30-30-8.6-8.5zm35.7-35.7-2.5 2.5 8.6 8.6 2.4-2.4.1-.1c.6-.6 1-1.5 1-2.3v-.1c0-.9-.3-1.8-1-2.4l-3.7-3.7c-.6-.6-1.5-1-2.3-1h-.1c-.9-.1-1.8.3-2.5.9m.4 44.1c0-1.3 1-2.3 2.3-2.3s2.3 1 2.3 2.3V101c0 3.2-1.3 6.1-3.4 8.2s-5 3.4-8.2 3.4H21.6c-3.2 0-6.1-1.3-8.2-3.4s-3.4-5-3.4-8.2V43.4c0-3.2 1.3-6.1 3.4-8.2s5-3.4 8.2-3.4h28.8c1.3 0 2.3 1 2.3 2.3s-1 2.3-2.3 2.3H21.6c-1.9 0-3.7.8-4.9 2-1.3 1.3-2 3-2 4.9v57.6c0 1.9.8 3.6 2 4.9 1.3 1.3 3 2 4.9 2h57.6c1.9 0 3.7-.8 4.9-2 1.3-1.3 2-3 2-4.9z" style="fill:currentColor"></path>
25 + </svg>
26 + </button>
27 </div>
28
29
@@ -45,8 +48,12 @@
48 }
49 .toggle-sidebar-button:hover { background-color: var(--color-secondary); opacity: 1; }
50 .toggle-sidebar-button:active { opacity: 0.5; }
48 - #sidebar-hamburger-svg { -webkit-transition: all var(--transition-speed) ease; transition: all var(--transition-speed) ease; }
49 - .toggle-sidebar-button:active #sidebar-hamburger-svg { -webkit-transform: scaleY(0.8); transform: scaleY(0.8); }
51 + .toggle-sidebar-button .material-symbols-outlined {
52 + font-size: 22px;
53 + -webkit-transition: all var(--transition-speed) ease;
54 + transition: all var(--transition-speed) ease;
55 + }
56 + .toggle-sidebar-button:active .material-symbols-outlined { -webkit-transform: scaleY(0.8); transform: scaleY(0.8); }
57
58 #logo-container {
59 display: -webkit-flex;
@@ -65,6 +72,26 @@
72
73 .light-mode #logo-container img { -webkit-filter: invert(100%) grayscale(100%); filter: invert(100%) grayscale(100%); }
74
75 + /* New Chat Button */
76 + #newChat {
77 + display: flex;
78 + flex-wrap: nowrap;
79 + background-color: transparent;
80 + border: none;
81 + align-items: center;
82 + position: absolute;
83 + left: 12rem;
84 + top: var(--spacing-md);
85 + z-index: 1004;
86 + opacity: 0.6;
87 + cursor: pointer;
88 + -webkit-transition: all 0.1s ease-in-out, left var(--transition-speed) ease-in-out;
89 + transition: all 0.1s ease-in-out, left var(--transition-speed) ease-in-out;
90 + }
91 + #newChat:hover { opacity: 0.85; transform: scale(1.04); }
92 + #newChat:active { opacity: 0.5; transform: scale(0.98); }
93 + #newChat svg { color: var(--color-text); }
94 +
95 @media (max-width: 768px) {
96 .toggle-sidebar-button { position: fixed; left: var(--spacing-md); z-index: 1004; }
97 #logo-container { -webkit-transition: all 0.3s ease; transition: all 0.3s ease; z-index: 1004; }
webui/components/sidebar/top-section/quick-actions.html
+159 -41
@@ -7,67 +7,181 @@
7 </head>
8
9 <body>
10 - <div class="config-section" x-data>
11 - <button class="config-button" id="resetChat" @click="$store.chats.resetChat()">Reset Chat</button>
12 - <button class="config-button" id="newChat" @click="$store.chats.newChat()">New Chat</button>
13 - <button class="config-button" id="loadChats" @click="$store.chats.loadChats()">Load Chat</button>
14 - <button class="config-button" id="loadChat" @click="$store.chats.saveChat()">Save Chat</button>
15 - <button class="config-button" id="restart" @click="$store.chats.restart()">Restart</button>
16 - <button class="config-button" id="settings" @click="openModal('settings/settings.html')"><svg
17 - xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="-5.0 -17.0 110.0 135.0" fill="currentColor" width="24"
18 - height="24">
19 - <path
20 - d="m52.301 90.102h-4.1016c-3 0-5 0-6.8984-1.3984-1.8984-1.3984-2.5-3.3008-3.5-6.1016l-1.1016-3.6016c-0.19922-0.60156-0.69922-1.1992-1.3984-1.6016l-1.1016-0.60156c-0.60156-0.30078-1.5-0.39844-2.3008-0.19922l-4.3008 1.1992c-3.1016 0.89844-5.1016 1.5-7.3984 0.5-2.3008-0.89844-3.3984-2.8008-5-5.6016l-1.8008-3.1016c-1.5-2.5-2.5-4.3008-2.3008-6.6992 0.19922-2.3984 1.6016-3.8008 3.6016-6.1016l3.8008-4.1992c0.19922-0.19922 0.60156-1.3984 0.60156-2.6016 0-1.1016-0.5-2.3008-0.80078-2.6992l-3.6016-4c-2-2.1992-3.3008-3.6992-3.6016-6.1016-0.19922-2.3984 0.80078-4.1992 2.3008-6.6992l1.8008-3.1016c1.6016-2.8008 2.6992-4.6016 5-5.6016 2.3008-0.89844 4.3008-0.39844 7.3984 0.5l4.3984 1.1992c0.69922 0.10156 1.5 0 2.3008-0.30078l1.1016-0.60156c0.5-0.30078 1-0.89844 1.3008-1.6992l1.1992-3.5c0.89844-2.8008 1.6016-4.6992 3.5-6.1016 1.8984-1.3984 3.8984-1.3984 6.8984-1.3984h4.1016c3 0 5 0 6.8984 1.3984 1.8984 1.3984 2.5 3.1992 3.5 6.1016l1.1992 3.6016c0.19922 0.60156 0.69922 1.1992 1.3984 1.6016l1.1016 0.60156c0.60156 0.30078 1.5 0.39844 2.3008 0.19922l4.3008-1.1992c3.1016-0.89844 5.1016-1.5 7.3984-0.5 2.3008 0.89844 3.3984 2.8008 5 5.5l1.8008 3.1016c1.3984 2.5 2.5 4.3008 2.3008 6.6992-0.19922 2.3984-1.6016 3.8008-3.6016 6.1016l-3.9961 4.4062c-0.19922 0.19922-0.60156 1.3984-0.60156 2.6016 0 1.1016 0.5 2.3008 0.80078 2.6992l3.6016 4c2 2.1992 3.3008 3.6992 3.6016 6.1016 0.19922 2.3984-0.80078 4.1992-2.3008 6.6992l-1.8008 3.1016c-1.6016 2.8008-2.6992 4.6016-5 5.6016-2.3008 0.89844-4.3984 0.39844-7.3984-0.5l-4.3984-1.1992c-0.69922-0.10156-1.5 0-2.3008 0.30078l-1.1016 0.60156c-0.5 0.30078-1 0.89844-1.3008 1.6992l-1.1992 3.5c-0.89844 2.8008-1.6016 4.6992-3.5 6.1016-1.8008 1.293-3.8008 1.293-6.8008 1.293zm-6.6016-7.3008c0.5 0.10156 1.6016 0.10156 2.6016 0.10156h4.1016c1 0 2 0 2.6016-0.10156 0.19922-0.5 0.60156-1.5 0.89844-2.3984l1.1992-3.6016c0.89844-2.3008 2.3984-4.1992 4.3984-5.3984l1.3984-0.80078c2.3984-1.3008 5.1016-1.6016 7.6016-1l4.6016 1.3008c1 0.30078 2.1016 0.60156 2.6992 0.69922 0.30078-0.5 0.89844-1.5 1.3984-2.3984l1.8008-3.1016c0.5-0.80078 1-1.8008 1.1992-2.3008-0.30078-0.39844-1-1.1992-1.6992-2l-3.8008-4.1992c-1.6016-2-2.5-4.8008-2.5-7.3984 0-2.6016 0.89844-5.3984 2.3008-7.3008l3.8984-4.3984c0.69922-0.69922 1.3984-1.5 1.6992-2-0.19922-0.5-0.80078-1.3984-1.1992-2.3008l-1.8984-3.1016c-0.5-0.89844-1.1016-1.8984-1.3984-2.3984-0.60156 0.10156-1.6992 0.39844-2.6992 0.69922l-4.3984 1.3008c-2.6992 0.60156-5.3008 0.30078-7.6016-0.89844l-1.4023-0.80469c-2.1016-1.3984-3.6016-3.1992-4.3984-5.3984l-1.3008-3.8008c-0.30078-0.89844-0.60156-1.8984-0.89844-2.3984-0.5-0.10156-1.6016-0.10156-2.6016-0.10156h-4.1016c-1 0-2 0-2.6016 0.10156-0.19922 0.5-0.60156 1.5-0.89844 2.3984l-1.1992 3.6016c-0.89844 2.3008-2.3984 4.1992-4.3984 5.3984l-1.3984 0.80078c-2.3984 1.3008-5.1016 1.6016-7.6016 1l-4.6016-1.3008c-1-0.30078-2.1016-0.60156-2.6992-0.69922-0.30078 0.5-0.89844 1.5-1.3984 2.3984l-1.8008 3.1016c-0.5 0.80078-1 1.8008-1.1992 2.3008 0.30078 0.39844 1 1.1992 1.6992 2l3.8008 4.1992c1.6016 2 2.5 4.8008 2.5 7.3984 0 2.6016-0.89844 5.3984-2.3008 7.3008l-3.8984 4.3984c-0.69922 0.69922-1.3984 1.5-1.6992 2 0.19922 0.5 0.80078 1.3984 1.1992 2.3008l1.8008 3.1016c0.5 0.89844 1.1016 1.8984 1.3984 2.3984 0.60156-0.10156 1.6992-0.39844 2.6992-0.69922l4.3984-1.1992c2.6992-0.60156 5.3008-0.30078 7.6016 0.89844l1.3984 0.80078c2.1016 1.3008 3.6016 3.1992 4.3984 5.3984l1.3008 3.8008c0.5 0.80078 0.80078 1.8008 1 2.3008z">
21 - </path>
22 - <path
23 - d="m50.301 66.5c-9 0-16.398-7.3008-16.398-16.398 0-9.1016 7.3008-16.398 16.398-16.398 9.1016 0 16.398 7.3008 16.398 16.398 0 9.0977-7.3984 16.398-16.398 16.398zm0-25.5c-5 0-9.1016 4.1016-9.1016 9.1016s4.1016 9.1016 9.1016 9.1016 9.1016-4.1016 9.1016-9.1016c-0.003906-5-4.1016-9.1016-9.1016-9.1016z">
24 - </path>
25 - </svg>Settings</button>
26 - <button class="config-button" id="scheduler" @click="openModal('modals/scheduler/scheduler-modal.html')">
27 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" width="24" height="24">
28 - <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67V7z"/>
29 - </svg>Scheduler</button>
30 - <button class="config-button" id="memory-dash"
31 - @click="openModal('settings/memory/memory-dashboard.html');">Memory</button>
32 - <button class="config-button" id="dashboard" @click="deselectChat()">Dashboard</button>
10 + <div class="wrapper" x-data="{ dropdownOpen: false }" @click.outside="dropdownOpen = false" @keydown.escape.window="dropdownOpen = false">
11 + <div id="quick-actions">
12 + <!-- Dashboard -->
13 + <button class="config-button" id="dashboard" @click="deselectChat()" title="Dashboard">
14 + <span class="material-symbols-outlined">dashboard</span>
15 + </button>
16
17 + <!-- Memory -->
18 + <button class="config-button" id="memory-dash" @click="openModal('modals/memory/memory-dashboard.html')" title="Memory">
19 + <span class="material-symbols-outlined">psychology</span>
20 + </button>
21 +
22 + <!-- Scheduler -->
23 + <button class="config-button" id="scheduler" @click="openModal('modals/scheduler/scheduler-modal.html')" title="Scheduler">
24 + <span class="material-symbols-outlined">schedule</span>
25 + </button>
26 +
27 + <!-- Settings -->
28 + <button class="config-button" id="settings" @click="openModal('settings/settings.html')" title="Settings">
29 + <span class="material-symbols-outlined">settings</span>
30 + </button>
31 +
32 + <!-- Dropdown Toggle -->
33 + <button class="config-button dropdown-toggle" @click="dropdownOpen = !dropdownOpen" title="More options">
34 + <span class="material-symbols-outlined" :class="dropdownOpen ? 'rotated' : ''">expand_more</span>
35 + </button>
36 + </div>
37 +
38 + <!-- Dropdown Menu -->
39 + <div class="dropdown-menu quick-actions-dropdown"
40 + x-show="dropdownOpen">
41 +
42 + <div class="dropdown-header">Navigation</div>
43 +
44 + <button class="dropdown-item" @click="deselectChat(); dropdownOpen = false">
45 + <span class="material-symbols-outlined">dashboard</span>
46 + <span>Dashboard</span>
47 + </button>
48 +
49 + <button class="dropdown-item" @click="openModal('modals/memory/memory-dashboard.html'); dropdownOpen = false">
50 + <span class="material-symbols-outlined">psychology</span>
51 + <span>Memories</span>
52 + </button>
53 +
54 + <button class="dropdown-item" @click="openModal('modals/scheduler/scheduler-modal.html'); dropdownOpen = false">
55 + <span class="material-symbols-outlined">schedule</span>
56 + <span>Scheduler</span>
57 + </button>
58 +
59 + <button class="dropdown-item" @click="openModal('settings/settings.html'); dropdownOpen = false">
60 + <span class="material-symbols-outlined">settings</span>
61 + <span>Settings</span>
62 + </button>
63 +
64 + <div class="dropdown-separator"></div>
65 + <div class="dropdown-header">Chat Actions</div>
66 +
67 + <button class="dropdown-item" @click="$store.chats.newChat(); dropdownOpen = false">
68 + <span class="material-symbols-outlined">add_comment</span>
69 + <span>New Chat</span>
70 + </button>
71 +
72 + <button class="dropdown-item" @click="$store.chats.loadChats(); dropdownOpen = false">
73 + <span class="material-symbols-outlined">folder_open</span>
74 + <span>Load Chat</span>
75 + </button>
76 +
77 + <button class="dropdown-item" @click="$store.chats.saveChat(); dropdownOpen = false">
78 + <span class="material-symbols-outlined">save</span>
79 + <span>Save Chat</span>
80 + </button>
81 +
82 + <div class="dropdown-separator"></div>
83 +
84 + <button class="dropdown-item" @click="$store.chats.restart(); dropdownOpen = false">
85 + <span class="material-symbols-outlined">restart_alt</span>
86 + <span>Restart A0</span>
87 + </button>
88 +
89 + </div>
90 </div>
91 </body>
92 +
93 <style>
37 - .config-button {
94 + /* Wrapper container for icon toolbar */
95 + .wrapper {
96 + position: relative;
97 + padding: 0.2rem;
98 + border-radius: 0.6rem;
99 background-color: var(--color-background);
39 - border: 0.1rem solid var(--color-border);
40 - border-radius: var(--spacing-xs);
100 + }
101 +
102 + /* Icon toolbar layout */
103 + #quick-actions {
104 + display: flex;
105 + flex-direction: row;
106 + flex-wrap: nowrap;
107 + width: 100%;
108 + justify-content: space-between;
109 + padding: 0;
110 + gap: 0;
111 + }
112 +
113 + /* Config button - icon only style */
114 + .config-button {
115 + background-color: var(--color-panel);
116 + border: 0.05rem solid var(--color-border);
117 + border-radius: 6px;
118 cursor: pointer;
42 - display: inline;
43 - font-family: "Rubik", Arial, Helvetica, sans-serif;
44 - font-size: var(--font-size-small);
119 + display: flex;
120 + align-items: center;
121 + justify-content: center;
122 opacity: 0.8;
46 - text-wrap: nowrap;
47 - width: calc(50% - var(--spacing-xs));
48 - float: left;
49 - margin: 0 var(--spacing-xs) var(--spacing-xs) 0;
50 - padding: var(--spacing-sm) 0.75rem;
51 - max-height: 2.3rem;
52 - -webkit-transition: all var(--transition-speed), transform 0.1s ease-in-out;
123 + padding: var(--spacing-xs);
124 + flex: 1;
125 + min-width: 0;
126 transition: all var(--transition-speed), transform 0.1s ease-in-out;
127 }
128
129 + .config-button .material-symbols-outlined {
130 + font-size: 22px;
131 + transition: transform 0.2s ease;
132 + }
133 +
134 + .config-button .material-symbols-outlined.rotated {
135 + transform: rotate(180deg);
136 + }
137 +
138 + /* Connected button borders */
139 + .config-button:not(:last-child) {
140 + margin-right: -1px;
141 + border-right: 1px solid var(--color-border);
142 + }
143 +
144 + .config-button:first-child {
145 + border-top-right-radius: 0;
146 + border-bottom-right-radius: 0;
147 + }
148 +
149 + .config-button:last-child {
150 + border-top-left-radius: 0;
151 + border-bottom-left-radius: 0;
152 + }
153 +
154 + .config-button:not(:first-child):not(:last-child) {
155 + border-radius: 0;
156 + }
157 +
158 .config-button:hover {
159 background-color: var(--color-secondary);
160 opacity: 1;
161 + z-index: 1;
162 + position: relative;
163 }
164
165 .config-button:active {
166 opacity: 0.5;
167 + transform: scale(0.95);
168 }
169
65 - #settings,
66 - #scheduler {
67 - display: flex;
68 - align-items: center;
170 + /* Dropdown specific positioning */
171 + .quick-actions-dropdown {
172 + position: absolute;
173 + top: 100%;
174 + left: 0;
175 + right: 0;
176 + margin-top: var(--spacing-xs);
177 + }
178 +
179 + /* Dropdown item icon sizing */
180 + .dropdown-item .material-symbols-outlined {
181 + font-size: 18px;
182 }
183
184 + /* Light mode */
185 .light-mode .config-button {
186 background-color: var(--color-background);
187 color: #333333;
@@ -80,6 +194,10 @@
194 .light-mode .config-button:active {
195 background-color: #bdc0cb;
196 }
197 +
198 + /* Transition helpers */
199 + .-translate-y-1 { transform: translateY(-0.25rem); }
200 + .translate-y-0 { transform: translateY(0); }
201 </style>
202
85 -</html>
\ No newline at end of file
203 +</html>
webui/components/welcome/welcome-store.js
+1 -1
@@ -1,7 +1,7 @@
1 import { createStore } from "/js/AlpineStore.js";
2 import { getContext } from "/index.js";
3 import { store as chatsStore } from "/components/sidebar/chats/chats-store.js";
4 -import { store as memoryStore } from "/components/settings/memory/memory-dashboard-store.js";
4 +import { store as memoryStore } from "/components/modals/memory/memory-dashboard-store.js";
5 import { store as projectsStore } from "/components/projects/projects-store.js";
6
7 const model = {
webui/index.css
+115
@@ -1254,3 +1254,118 @@ nav ul li a img {
1254 box-sizing: border-box;
1255 flex-shrink: 0;
1256 }
1257 +
1258 +/* ========================================
1259 + Global Dropdown Component Styles
1260 + ======================================== */
1261 +
1262 +/* Dropdown container - position relative for absolute menu */
1263 +.dropdown {
1264 + position: relative;
1265 + display: inline-block;
1266 +}
1267 +
1268 +/* Dropdown trigger button */
1269 +.dropdown-trigger {
1270 + display: flex;
1271 + align-items: center;
1272 + justify-content: center;
1273 + cursor: pointer;
1274 + background: transparent;
1275 + border: none;
1276 + color: var(--color-text);
1277 + padding: var(--spacing-xs);
1278 + transition: all var(--transition-speed) ease;
1279 +}
1280 +
1281 +.dropdown-trigger:hover {
1282 + opacity: 1;
1283 +}
1284 +
1285 +.dropdown-trigger:active {
1286 + opacity: 0.5;
1287 +}
1288 +
1289 +/* Dropdown menu */
1290 +.dropdown-menu {
1291 + position: absolute;
1292 + top: 100%;
1293 + right: 0;
1294 + min-width: 180px;
1295 + max-height: 400px;
1296 + overflow-y: auto;
1297 + background-color: var(--color-panel);
1298 + border: 1px solid var(--color-border);
1299 + border-radius: 0.5rem;
1300 + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
1301 + z-index: 1010;
1302 + padding: var(--spacing-xs) 0;
1303 + margin-top: var(--spacing-xs);
1304 +}
1305 +
1306 +.dropdown-menu.left {
1307 + left: 0;
1308 + right: auto;
1309 +}
1310 +
1311 +/* Dropdown menu items */
1312 +.dropdown-item {
1313 + display: flex;
1314 + align-items: center;
1315 + gap: var(--spacing-sm);
1316 + width: 100%;
1317 + padding: var(--spacing-sm) var(--spacing-md);
1318 + background: transparent;
1319 + border: none;
1320 + color: var(--color-text);
1321 + font-family: var(--font-family-main);
1322 + font-size: var(--font-size-small);
1323 + text-align: left;
1324 + opacity: 0.8;
1325 + cursor: pointer;
1326 + transition: background-color 0.15s ease;
1327 + white-space: nowrap;
1328 +}
1329 +
1330 +.dropdown-item:hover {
1331 + background-color: var(--color-background-hover);
1332 + opacity: 1;
1333 + transform: translateX(-2px);
1334 +}
1335 +
1336 +.dropdown-item:active {
1337 + opacity: 0.7;
1338 +}
1339 +
1340 +.dropdown-item svg {
1341 + width: 18px;
1342 + height: 18px;
1343 + flex-shrink: 0;
1344 + opacity: 0.8;
1345 +}
1346 +
1347 +/* Dropdown separator */
1348 +.dropdown-separator {
1349 + height: 1px;
1350 + background-color: var(--color-border);
1351 + margin: var(--spacing-xs) 0;
1352 +}
1353 +
1354 +/* Dropdown header/label */
1355 +.dropdown-header {
1356 + padding: var(--spacing-xs) var(--spacing-md);
1357 + font-size: 0.7rem;
1358 + color: var(--color-primary);
1359 + text-transform: uppercase;
1360 + letter-spacing: 0.05em;
1361 + opacity: 0.8;
1362 +}
1363 +
1364 +/* Light mode adjustments */
1365 +.light-mode .dropdown-menu {
1366 + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
1367 +}
1368 +
1369 +.light-mode .dropdown-item:hover {
1370 + background-color: var(--color-secondary);
1371 +}