Spaces:
Paused
Paused
Commit ·
32b833d
1
Parent(s): 3c970e3
fix: sidebar, welcome screen and UX
Browse files- webui/components/sidebar/bottom/preferences/preferences-panel.html +7 -3
- webui/components/sidebar/sidebar-store.js +40 -0
- webui/components/sidebar/tasks/tasks-list.html +6 -2
- webui/components/sidebar/top-section/header-icons.html +1 -3
- webui/components/welcome/welcome-screen.html +56 -78
- webui/index.css +14 -0
- webui/index.html +12 -10
- webui/index.js +38 -15
webui/components/sidebar/bottom/preferences/preferences-panel.html
CHANGED
|
@@ -9,13 +9,17 @@
|
|
| 9 |
<template x-if="$store.preferences">
|
| 10 |
<div class="pref-section">
|
| 11 |
<span>
|
| 12 |
-
<h3 class="pref-header"
|
|
|
|
|
|
|
|
|
|
| 13 |
Preferences
|
| 14 |
<svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
|
| 15 |
<path d="M8 4l8 8-8 8" />
|
| 16 |
</svg>
|
| 17 |
</h3>
|
| 18 |
-
<ul class="config-list collapse
|
|
|
|
| 19 |
<li x-data>
|
| 20 |
<span>Autoscroll</span>
|
| 21 |
<label class="switch">
|
|
@@ -89,7 +93,7 @@
|
|
| 89 |
flex-direction: column;
|
| 90 |
gap: 1px;
|
| 91 |
}
|
| 92 |
-
#
|
| 93 |
opacity: 0.8;
|
| 94 |
}
|
| 95 |
.pref-section .switch-label,
|
|
|
|
| 9 |
<template x-if="$store.preferences">
|
| 10 |
<div class="pref-section">
|
| 11 |
<span>
|
| 12 |
+
<h3 class="pref-header"
|
| 13 |
+
data-bs-toggle="collapse"
|
| 14 |
+
@click="$store.sidebar.toggleSection('preferences')"
|
| 15 |
+
x-effect="!$store.sidebar.isSectionOpen('preferences') ? $el.classList.add('collapsed') : $el.classList.remove('collapsed')">
|
| 16 |
Preferences
|
| 17 |
<svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
|
| 18 |
<path d="M8 4l8 8-8 8" />
|
| 19 |
</svg>
|
| 20 |
</h3>
|
| 21 |
+
<ul class="config-list collapse" id="preferences-collapse"
|
| 22 |
+
x-effect="(() => { const c = bootstrap.Collapse.getOrCreateInstance($el, { toggle: false }); $store.sidebar.isSectionOpen('preferences') ? c.show() : c.hide(); })()">
|
| 23 |
<li x-data>
|
| 24 |
<span>Autoscroll</span>
|
| 25 |
<label class="switch">
|
|
|
|
| 93 |
flex-direction: column;
|
| 94 |
gap: 1px;
|
| 95 |
}
|
| 96 |
+
#preferences-collapse li {
|
| 97 |
opacity: 0.8;
|
| 98 |
}
|
| 99 |
.pref-section .switch-label,
|
webui/components/sidebar/sidebar-store.js
CHANGED
|
@@ -5,17 +5,57 @@ const model = {
|
|
| 5 |
isOpen: true,
|
| 6 |
_initialized: false,
|
| 7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
// Initialize the store by setting up a resize listener
|
| 9 |
// Guard ensures this runs only once, even if called from multiple components
|
| 10 |
init() {
|
| 11 |
if (this._initialized) return;
|
| 12 |
this._initialized = true;
|
| 13 |
|
|
|
|
| 14 |
this.handleResize();
|
| 15 |
this.resizeHandler = () => this.handleResize();
|
| 16 |
window.addEventListener("resize", this.resizeHandler);
|
| 17 |
},
|
| 18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
// Cleanup method for lifecycle management
|
| 20 |
destroy() {
|
| 21 |
if (this.resizeHandler) {
|
|
|
|
| 5 |
isOpen: true,
|
| 6 |
_initialized: false,
|
| 7 |
|
| 8 |
+
// Centralized collapse state for all sidebar sections (persisted in localStorage)
|
| 9 |
+
sectionStates: {
|
| 10 |
+
tasks: false, // default: collapsed
|
| 11 |
+
preferences: false // default: collapsed
|
| 12 |
+
},
|
| 13 |
+
|
| 14 |
// Initialize the store by setting up a resize listener
|
| 15 |
// Guard ensures this runs only once, even if called from multiple components
|
| 16 |
init() {
|
| 17 |
if (this._initialized) return;
|
| 18 |
this._initialized = true;
|
| 19 |
|
| 20 |
+
this.loadSectionStates();
|
| 21 |
this.handleResize();
|
| 22 |
this.resizeHandler = () => this.handleResize();
|
| 23 |
window.addEventListener("resize", this.resizeHandler);
|
| 24 |
},
|
| 25 |
|
| 26 |
+
// Load section collapse states from localStorage
|
| 27 |
+
loadSectionStates() {
|
| 28 |
+
try {
|
| 29 |
+
const stored = localStorage.getItem('sidebarSections');
|
| 30 |
+
if (stored) {
|
| 31 |
+
this.sectionStates = { ...this.sectionStates, ...JSON.parse(stored) };
|
| 32 |
+
}
|
| 33 |
+
} catch (e) {
|
| 34 |
+
console.error('Failed to load sidebar section states', e);
|
| 35 |
+
}
|
| 36 |
+
},
|
| 37 |
+
|
| 38 |
+
// Persist section states to localStorage
|
| 39 |
+
persistSectionStates() {
|
| 40 |
+
try {
|
| 41 |
+
localStorage.setItem('sidebarSections', JSON.stringify(this.sectionStates));
|
| 42 |
+
} catch (e) {
|
| 43 |
+
console.error('Failed to persist section states', e);
|
| 44 |
+
}
|
| 45 |
+
},
|
| 46 |
+
|
| 47 |
+
// Check if a section should be open (used by x-init in templates)
|
| 48 |
+
isSectionOpen(name) {
|
| 49 |
+
return this.sectionStates[name] === true;
|
| 50 |
+
},
|
| 51 |
+
|
| 52 |
+
// Toggle and persist a section's open state (drives Bootstrap programmatically via components)
|
| 53 |
+
toggleSection(name) {
|
| 54 |
+
if (!(name in this.sectionStates)) return;
|
| 55 |
+
this.sectionStates[name] = !this.sectionStates[name];
|
| 56 |
+
this.persistSectionStates();
|
| 57 |
+
},
|
| 58 |
+
|
| 59 |
// Cleanup method for lifecycle management
|
| 60 |
destroy() {
|
| 61 |
if (this.resizeHandler) {
|
webui/components/sidebar/tasks/tasks-list.html
CHANGED
|
@@ -8,13 +8,17 @@
|
|
| 8 |
<div class="tasks-list-root">
|
| 9 |
<template x-if="$store.tasks">
|
| 10 |
<div x-data class="tasks-list-inner">
|
| 11 |
-
<h3 class="section-header section-header-collapsible"
|
|
|
|
|
|
|
|
|
|
| 12 |
Tasks
|
| 13 |
<svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
|
| 14 |
<path d="M8 4l8 8-8 8" />
|
| 15 |
</svg>
|
| 16 |
</h3>
|
| 17 |
-
<div class="collapse
|
|
|
|
| 18 |
<div class="tasks-list-body">
|
| 19 |
<div class="tasks-list-container" x-data>
|
| 20 |
<ul class="config-list tasks-config-list" x-show="$store.tasks.tasks.length > 0">
|
|
|
|
| 8 |
<div class="tasks-list-root">
|
| 9 |
<template x-if="$store.tasks">
|
| 10 |
<div x-data class="tasks-list-inner">
|
| 11 |
+
<h3 class="section-header section-header-collapsible"
|
| 12 |
+
data-bs-toggle="collapse"
|
| 13 |
+
@click="$store.sidebar.toggleSection('tasks')"
|
| 14 |
+
x-effect="!$store.sidebar.isSectionOpen('tasks') ? $el.classList.add('collapsed') : $el.classList.remove('collapsed')">
|
| 15 |
Tasks
|
| 16 |
<svg class="arrow-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
|
| 17 |
<path d="M8 4l8 8-8 8" />
|
| 18 |
</svg>
|
| 19 |
</h3>
|
| 20 |
+
<div class="collapse" id="tasks-collapse"
|
| 21 |
+
x-effect="(() => { const c = bootstrap.Collapse.getOrCreateInstance($el, { toggle: false }); $store.sidebar.isSectionOpen('tasks') ? c.show() : c.hide(); })()">
|
| 22 |
<div class="tasks-list-body">
|
| 23 |
<div class="tasks-list-container" x-data>
|
| 24 |
<ul class="config-list tasks-config-list" x-show="$store.tasks.tasks.length > 0">
|
webui/components/sidebar/top-section/header-icons.html
CHANGED
|
@@ -62,14 +62,12 @@
|
|
| 62 |
}
|
| 63 |
#logo-container a { color: inherit; text-decoration: none; }
|
| 64 |
#logo-container img { border-radius: var(--spacing-xs); width: auto; height: 2.6rem; -webkit-transition: filter 0.3s ease; transition: filter 0.3s ease; }
|
| 65 |
-
#right-panel.expanded #logo-container { margin-left: 4.6rem; }
|
| 66 |
|
| 67 |
.light-mode #logo-container img { -webkit-filter: invert(100%) grayscale(100%); filter: invert(100%) grayscale(100%); }
|
| 68 |
|
| 69 |
@media (max-width: 768px) {
|
| 70 |
.toggle-sidebar-button { position: fixed; left: var(--spacing-md); z-index: 1004; }
|
| 71 |
-
#logo-container {
|
| 72 |
-
#right-panel.expanded #logo-container { margin-left: 4.6rem; }
|
| 73 |
}
|
| 74 |
</style>
|
| 75 |
</body>
|
|
|
|
| 62 |
}
|
| 63 |
#logo-container a { color: inherit; text-decoration: none; }
|
| 64 |
#logo-container img { border-radius: var(--spacing-xs); width: auto; height: 2.6rem; -webkit-transition: filter 0.3s ease; transition: filter 0.3s ease; }
|
|
|
|
| 65 |
|
| 66 |
.light-mode #logo-container img { -webkit-filter: invert(100%) grayscale(100%); filter: invert(100%) grayscale(100%); }
|
| 67 |
|
| 68 |
@media (max-width: 768px) {
|
| 69 |
.toggle-sidebar-button { position: fixed; left: var(--spacing-md); z-index: 1004; }
|
| 70 |
+
#logo-container { -webkit-transition: all 0.3s ease; transition: all 0.3s ease; z-index: 1004; }
|
|
|
|
| 71 |
}
|
| 72 |
</style>
|
| 73 |
</body>
|
webui/components/welcome/welcome-screen.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
| 11 |
<!-- Agent Zero Logo -->
|
| 12 |
<div class="welcome-logo-container">
|
| 13 |
<img
|
| 14 |
-
src="/
|
| 15 |
alt="Agent Zero Logo"
|
| 16 |
class="welcome-logo"
|
| 17 |
/>
|
|
@@ -78,22 +78,10 @@
|
|
| 78 |
</p>
|
| 79 |
</div>
|
| 80 |
</div>
|
| 81 |
-
|
| 82 |
-
<!-- Footer Info -->
|
| 83 |
-
<div class="welcome-footer">
|
| 84 |
-
<p>Agent Zero Framework • Open Source AI Assistant</p>
|
| 85 |
-
</div>
|
| 86 |
</div>
|
| 87 |
</template>
|
| 88 |
</div>
|
| 89 |
|
| 90 |
-
<script>
|
| 91 |
-
document.addEventListener("alpine:init", () => {
|
| 92 |
-
const s = Alpine.store("welcomeStore");
|
| 93 |
-
if (s && typeof s.init === "function") s.init();
|
| 94 |
-
});
|
| 95 |
-
</script>
|
| 96 |
-
|
| 97 |
<style>
|
| 98 |
/* Welcome Screen Styles */
|
| 99 |
.welcome-container {
|
|
@@ -101,38 +89,43 @@
|
|
| 101 |
flex-direction: column;
|
| 102 |
align-items: center;
|
| 103 |
justify-content: center;
|
| 104 |
-
padding:
|
| 105 |
text-align: center;
|
| 106 |
background: var(--color-background);
|
| 107 |
color: var(--color-text);
|
| 108 |
-
min-height:
|
| 109 |
}
|
| 110 |
-
|
| 111 |
.welcome-logo-container {
|
| 112 |
display: flex;
|
| 113 |
justify-content: center;
|
| 114 |
align-items: center;
|
| 115 |
-
margin-bottom: 1.5rem;
|
| 116 |
}
|
| 117 |
|
| 118 |
.welcome-logo {
|
| 119 |
-
width:
|
| 120 |
-
height:
|
| 121 |
-
filter: brightness(1);
|
| 122 |
}
|
| 123 |
|
| 124 |
-
/*
|
|
|
|
|
|
|
|
|
|
| 125 |
.dark-mode .welcome-logo {
|
| 126 |
-
filter:
|
| 127 |
}
|
| 128 |
|
| 129 |
.welcome-title {
|
| 130 |
font-size: 2rem;
|
| 131 |
-
font-weight:
|
| 132 |
-
margin
|
| 133 |
color: var(--color-text);
|
| 134 |
}
|
| 135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
.welcome-subtitle {
|
| 137 |
font-size: 1rem;
|
| 138 |
margin-bottom: 2rem;
|
|
@@ -163,32 +156,19 @@
|
|
| 163 |
flex-direction: column;
|
| 164 |
align-items: center;
|
| 165 |
text-align: center;
|
| 166 |
-
min-height:
|
| 167 |
justify-content: center;
|
| 168 |
}
|
| 169 |
|
| 170 |
.welcome-action-card:hover {
|
| 171 |
-
border-color: var(--color-accent);
|
| 172 |
background: var(--color-message-bg);
|
| 173 |
-
transform: translateY(-2px);
|
| 174 |
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
| 175 |
-
}
|
| 176 |
-
|
| 177 |
-
.dark-mode .welcome-action-card:hover {
|
| 178 |
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
| 179 |
}
|
| 180 |
|
| 181 |
.welcome-action-icon {
|
| 182 |
font-size: 2rem;
|
| 183 |
-
margin-bottom: 0
|
| 184 |
-
color: var(--color-accent);
|
| 185 |
-
}
|
| 186 |
-
|
| 187 |
-
.welcome-action-title {
|
| 188 |
-
font-size: 1.1rem;
|
| 189 |
-
font-weight: 500;
|
| 190 |
-
margin-bottom: 0.4rem;
|
| 191 |
-
color: var(--color-text);
|
| 192 |
}
|
| 193 |
|
| 194 |
.welcome-action-description {
|
|
@@ -197,12 +177,6 @@
|
|
| 197 |
line-height: 1.3;
|
| 198 |
}
|
| 199 |
|
| 200 |
-
.welcome-footer {
|
| 201 |
-
margin-top: 1.5rem;
|
| 202 |
-
opacity: 0.7;
|
| 203 |
-
font-size: 0.8rem;
|
| 204 |
-
}
|
| 205 |
-
|
| 206 |
/* Light mode adjustments */
|
| 207 |
.light-mode .welcome-title {
|
| 208 |
color: #2d2d2d;
|
|
@@ -226,37 +200,41 @@
|
|
| 226 |
|
| 227 |
/* Responsive design */
|
| 228 |
@media (max-width: 768px) {
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
| 257 |
-
|
| 258 |
-
|
| 259 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 260 |
}
|
| 261 |
</style>
|
| 262 |
</body>
|
|
|
|
| 11 |
<!-- Agent Zero Logo -->
|
| 12 |
<div class="welcome-logo-container">
|
| 13 |
<img
|
| 14 |
+
src="./public/darkSymbol.svg"
|
| 15 |
alt="Agent Zero Logo"
|
| 16 |
class="welcome-logo"
|
| 17 |
/>
|
|
|
|
| 78 |
</p>
|
| 79 |
</div>
|
| 80 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
</div>
|
| 82 |
</template>
|
| 83 |
</div>
|
| 84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
<style>
|
| 86 |
/* Welcome Screen Styles */
|
| 87 |
.welcome-container {
|
|
|
|
| 89 |
flex-direction: column;
|
| 90 |
align-items: center;
|
| 91 |
justify-content: center;
|
| 92 |
+
padding: 3%;
|
| 93 |
text-align: center;
|
| 94 |
background: var(--color-background);
|
| 95 |
color: var(--color-text);
|
| 96 |
+
min-height: 100vh;
|
| 97 |
}
|
| 98 |
+
/* Welcome container styles */
|
| 99 |
.welcome-logo-container {
|
| 100 |
display: flex;
|
| 101 |
justify-content: center;
|
| 102 |
align-items: center;
|
|
|
|
| 103 |
}
|
| 104 |
|
| 105 |
.welcome-logo {
|
| 106 |
+
width: 7rem;
|
| 107 |
+
height: 7rem;
|
|
|
|
| 108 |
}
|
| 109 |
|
| 110 |
+
/* Themes adjustments for logo */
|
| 111 |
+
.light-mode .welcome-logo {
|
| 112 |
+
filter: invert(0.5);
|
| 113 |
+
}
|
| 114 |
.dark-mode .welcome-logo {
|
| 115 |
+
filter: invert(0.8);
|
| 116 |
}
|
| 117 |
|
| 118 |
.welcome-title {
|
| 119 |
font-size: 2rem;
|
| 120 |
+
font-weight: 400;
|
| 121 |
+
margin: var(--spacing-xs) 0 0 0;
|
| 122 |
color: var(--color-text);
|
| 123 |
}
|
| 124 |
|
| 125 |
+
.welcome-action-title {
|
| 126 |
+
margin-bottom: 0;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
.welcome-subtitle {
|
| 130 |
font-size: 1rem;
|
| 131 |
margin-bottom: 2rem;
|
|
|
|
| 156 |
flex-direction: column;
|
| 157 |
align-items: center;
|
| 158 |
text-align: center;
|
| 159 |
+
min-height: 10rem;
|
| 160 |
justify-content: center;
|
| 161 |
}
|
| 162 |
|
| 163 |
.welcome-action-card:hover {
|
| 164 |
+
border-color: var(--color-accent-dark);
|
| 165 |
background: var(--color-message-bg);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
}
|
| 167 |
|
| 168 |
.welcome-action-icon {
|
| 169 |
font-size: 2rem;
|
| 170 |
+
margin-bottom: 0;
|
| 171 |
+
color: var(--color-accent-dark);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
}
|
| 173 |
|
| 174 |
.welcome-action-description {
|
|
|
|
| 177 |
line-height: 1.3;
|
| 178 |
}
|
| 179 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
/* Light mode adjustments */
|
| 181 |
.light-mode .welcome-title {
|
| 182 |
color: #2d2d2d;
|
|
|
|
| 200 |
|
| 201 |
/* Responsive design */
|
| 202 |
@media (max-width: 768px) {
|
| 203 |
+
.welcome-container {
|
| 204 |
+
padding: 1rem;
|
| 205 |
+
padding-top: 3rem;
|
| 206 |
+
}
|
| 207 |
+
.welcome-logo {
|
| 208 |
+
width: 5rem;
|
| 209 |
+
height: 5rem;
|
| 210 |
+
}
|
| 211 |
+
.welcome-logo-container {
|
| 212 |
+
margin-top: 2rem;
|
| 213 |
+
}
|
| 214 |
+
.welcome-title {
|
| 215 |
+
font-size: 1.5rem;
|
| 216 |
+
margin: 0 !important;
|
| 217 |
+
}
|
| 218 |
+
.welcome-subtitle {
|
| 219 |
+
font-size: 1rem;
|
| 220 |
+
margin-top: var(--spacing-xs);
|
| 221 |
+
margin-bottom: 0;
|
| 222 |
+
}
|
| 223 |
+
.welcome-actions {
|
| 224 |
+
grid-template-columns: 1fr;
|
| 225 |
+
gap: 1rem;
|
| 226 |
+
margin-bottom: 2rem;
|
| 227 |
+
}
|
| 228 |
+
.welcome-action-card {
|
| 229 |
+
padding: 1.5rem;
|
| 230 |
+
min-height: 120px;
|
| 231 |
+
}
|
| 232 |
+
.welcome-action-icon {
|
| 233 |
+
font-size: 2rem;
|
| 234 |
+
}
|
| 235 |
+
.welcome-action-title {
|
| 236 |
+
font-size: 1.1rem;
|
| 237 |
+
}
|
| 238 |
}
|
| 239 |
</style>
|
| 240 |
</body>
|
webui/index.css
CHANGED
|
@@ -164,9 +164,23 @@ img {
|
|
| 164 |
transition: margin-left var(--transition-speed) ease-in-out;
|
| 165 |
}
|
| 166 |
|
|
|
|
| 167 |
#right-panel.expanded {
|
| 168 |
margin-left: 0;
|
| 169 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
|
| 171 |
#time-date-container {
|
| 172 |
z-index: 1000;
|
|
|
|
| 164 |
transition: margin-left var(--transition-speed) ease-in-out;
|
| 165 |
}
|
| 166 |
|
| 167 |
+
/* Scrollbar styles for right panel */
|
| 168 |
#right-panel.expanded {
|
| 169 |
margin-left: 0;
|
| 170 |
}
|
| 171 |
+
div#right-panel::-webkit-scrollbar {
|
| 172 |
+
width: 6px;
|
| 173 |
+
}
|
| 174 |
+
div#right-panel::-webkit-scrollbar-track {
|
| 175 |
+
background: transparent;
|
| 176 |
+
}
|
| 177 |
+
div#right-panel::-webkit-scrollbar-thumb {
|
| 178 |
+
background-color: rgba(155, 155, 155, 0.3);
|
| 179 |
+
border-radius: 6px;
|
| 180 |
+
}
|
| 181 |
+
div#right-panel::-webkit-scrollbar-thumb:hover {
|
| 182 |
+
background-color: rgba(155, 155, 155, 0.5);
|
| 183 |
+
}
|
| 184 |
|
| 185 |
#time-date-container {
|
| 186 |
z-index: 1000;
|
webui/index.html
CHANGED
|
@@ -128,8 +128,6 @@
|
|
| 128 |
|
| 129 |
<!-- Non-module scripts after Alpine.js -->
|
| 130 |
<script type="text/javascript" src="js/settings.js"></script>
|
| 131 |
-
<script type="text/javascript" src="js/file_browser.js"></script>
|
| 132 |
-
<script type="module" src="js/tunnel.js"></script>
|
| 133 |
<script>
|
| 134 |
// Expose git info for sidebar component
|
| 135 |
globalThis.gitinfo = { version: "{{version_no}}", commit_time: "{{version_time}}" };
|
|
@@ -139,10 +137,11 @@
|
|
| 139 |
<body class="dark-mode device-pointer" x-data>
|
| 140 |
<div class="container">
|
| 141 |
<!-- Sidebar Overlay -->
|
| 142 |
-
<
|
| 143 |
-
<
|
| 144 |
-
:class="{'visible': $store.sidebar.isOpen && $store.sidebar.isMobile()}"
|
| 145 |
-
|
|
|
|
| 146 |
</template>
|
| 147 |
<!-- Left Sidebar (Header Icons, Quick Actions, Tabs, Chats, Tasks) -->
|
| 148 |
<x-component path="sidebar/left-sidebar.html"></x-component>
|
|
@@ -190,10 +189,13 @@
|
|
| 190 |
<button class="toast__copy" style="display: none;">Copy</button>
|
| 191 |
<button class="toast__close">Close</button>
|
| 192 |
</div>
|
| 193 |
-
<!--
|
| 194 |
-
<x-
|
| 195 |
-
|
| 196 |
-
|
|
|
|
|
|
|
|
|
|
| 197 |
</div>
|
| 198 |
</div>
|
| 199 |
<div id="settingsModal" x-data="settingsModalProxy">
|
|
|
|
| 128 |
|
| 129 |
<!-- Non-module scripts after Alpine.js -->
|
| 130 |
<script type="text/javascript" src="js/settings.js"></script>
|
|
|
|
|
|
|
| 131 |
<script>
|
| 132 |
// Expose git info for sidebar component
|
| 133 |
globalThis.gitinfo = { version: "{{version_no}}", commit_time: "{{version_time}}" };
|
|
|
|
| 137 |
<body class="dark-mode device-pointer" x-data>
|
| 138 |
<div class="container">
|
| 139 |
<!-- Sidebar Overlay -->
|
| 140 |
+
<div id="sidebar-overlay" x-data>
|
| 141 |
+
<template x-if="$store.sidebar">
|
| 142 |
+
<div class="sidebar-overlay" :class="{'visible': $store.sidebar.isOpen && $store.sidebar.isMobile()}" @click="$store.sidebar.close()"></div>
|
| 143 |
+
</template>
|
| 144 |
+
</div>
|
| 145 |
</template>
|
| 146 |
<!-- Left Sidebar (Header Icons, Quick Actions, Tabs, Chats, Tasks) -->
|
| 147 |
<x-component path="sidebar/left-sidebar.html"></x-component>
|
|
|
|
| 189 |
<button class="toast__copy" style="display: none;">Copy</button>
|
| 190 |
<button class="toast__close">Close</button>
|
| 191 |
</div>
|
| 192 |
+
<!-- Chat Input Area -->
|
| 193 |
+
<div x-show="!$store.welcomeStore || !$store.welcomeStore.isVisible">
|
| 194 |
+
<!-- Progress Bar -->
|
| 195 |
+
<x-component path="chat/input/progress.html"></x-component>
|
| 196 |
+
<!-- Input Section -->
|
| 197 |
+
<x-component path="chat/input/chat-bar.html"></x-component>
|
| 198 |
+
</div>
|
| 199 |
</div>
|
| 200 |
</div>
|
| 201 |
<div id="settingsModal" x-data="settingsModalProxy">
|
webui/index.js
CHANGED
|
@@ -331,26 +331,37 @@ async function poll() {
|
|
| 331 |
// Check if this context exists in the chats list
|
| 332 |
const contextExists = chatsStore.contains(context);
|
| 333 |
|
| 334 |
-
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
}
|
|
|
|
|
|
|
| 341 |
}
|
| 342 |
-
|
| 343 |
-
tasksStore.setSelected(context);
|
| 344 |
} else {
|
| 345 |
-
|
| 346 |
-
|
| 347 |
-
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
| 351 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
}
|
| 353 |
}
|
|
|
|
| 354 |
|
| 355 |
lastLogVersion = response.log_version;
|
| 356 |
lastLogGuid = response.log_guid;
|
|
@@ -617,6 +628,18 @@ document.addEventListener("DOMContentLoaded", function () {
|
|
| 617 |
chatHistory.addEventListener("scroll", updateAfterScroll);
|
| 618 |
}
|
| 619 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 620 |
// Start polling for updates
|
| 621 |
startPolling();
|
| 622 |
});
|
|
|
|
| 331 |
// Check if this context exists in the chats list
|
| 332 |
const contextExists = chatsStore.contains(context);
|
| 333 |
|
| 334 |
+
if (!contextExists) {
|
| 335 |
+
if (chatsStore.contexts.length > 0) {
|
| 336 |
+
// If it doesn't exist in the list but other contexts do, fall back to the first
|
| 337 |
+
const firstChatId = chatsStore.firstId();
|
| 338 |
+
if (firstChatId) {
|
| 339 |
+
setContext(firstChatId);
|
| 340 |
+
chatsStore.setSelected(firstChatId);
|
| 341 |
+
}
|
| 342 |
+
} else if (typeof deselectChat === "function") {
|
| 343 |
+
// No contexts remain – clear state so the welcome screen can surface
|
| 344 |
+
deselectChat();
|
| 345 |
}
|
| 346 |
+
} else {
|
| 347 |
+
tasksStore.setSelected(context);
|
| 348 |
}
|
|
|
|
|
|
|
| 349 |
} else {
|
| 350 |
+
const welcomeStore =
|
| 351 |
+
globalThis.Alpine && typeof globalThis.Alpine.store === "function"
|
| 352 |
+
? globalThis.Alpine.store("welcomeStore")
|
| 353 |
+
: null;
|
| 354 |
+
const welcomeVisible = Boolean(welcomeStore && welcomeStore.isVisible);
|
| 355 |
+
|
| 356 |
+
// No context selected, try to select the first available item unless welcome screen is active
|
| 357 |
+
if (!welcomeVisible && contexts.length > 0) {
|
| 358 |
+
const firstChatId = chatsStore.firstId();
|
| 359 |
+
if (firstChatId) {
|
| 360 |
+
setContext(firstChatId);
|
| 361 |
+
chatsStore.setSelected(firstChatId);
|
| 362 |
}
|
| 363 |
}
|
| 364 |
+
}
|
| 365 |
|
| 366 |
lastLogVersion = response.log_version;
|
| 367 |
lastLogGuid = response.log_guid;
|
|
|
|
| 628 |
chatHistory.addEventListener("scroll", updateAfterScroll);
|
| 629 |
}
|
| 630 |
|
| 631 |
+
// Restore previously selected context (if any) before polling begins
|
| 632 |
+
let storedContext = null;
|
| 633 |
+
try {
|
| 634 |
+
storedContext = localStorage.getItem("lastSelectedChat");
|
| 635 |
+
} catch (_e) {
|
| 636 |
+
storedContext = null;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
if (storedContext && storedContext !== "null" && storedContext !== "") {
|
| 640 |
+
setContext(storedContext);
|
| 641 |
+
}
|
| 642 |
+
|
| 643 |
// Start polling for updates
|
| 644 |
startPolling();
|
| 645 |
});
|