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
+}