fix: chat list fit-content/grow

- unwrapped chat/tasks list from removed lists-wrapper div - made chat/tasks list scrollable while mantaining the title sticky - when you are at the bottom of the chat list and you create a new chat, the list now scroll up to top thx to the new scrollChatsToTop helper

Alessandro committed Oct 13, 2025 at 03:54 UTC 184fbd1538e6f9e11a284ba45e5b14f8c7007077
4 files changed +132 -144
webui/components/sidebar/chats/chats-list.html
+57 -62
@@ -28,67 +28,62 @@
28 </template>
29 </div>
30
31 + <style>
32 + .chats-list-container .section-header {
33 + position: sticky;
34 + top: 0;
35 + flex-shrink: 0;
36 + z-index: 10;
37 + }
38 + /* Chats list container and items */
39 + .chats-list-container {
40 + display: flex;
41 + flex-direction: column;
42 + flex: 1;
43 + min-height: 0;
44 + margin-top: var(--spacing-md);
45 + }
46 +
47 + .chats-config-list {
48 + flex: 1;
49 + min-height: 0;
50 + overflow: scroll;
51 + scroll-behavior: smooth;
52 + max-height: 100%;
53 + scrollbar-width: none; /* Firefox */
54 + -ms-overflow-style: none; /* IE/Edge */
55 + }
56 + /* Hide scrollbar for Chrome/Safari/Webkit */
57 + .chats-config-list::-webkit-scrollbar {
58 + display: none;
59 + }
60 +
61 + .chat-list-button { display: block; width: 100%; padding: 8px 5px; cursor: pointer; overflow: hidden; position: relative; border-radius: 4px; transition: background-color 0.2s ease-in-out; }
62 + .chat-list-button.has-task-container { padding-top: 6px; padding-bottom: 6px; }
63 + .chat-list-button:hover { background-color: rgba(255, 255, 255, 0.03); }
64 + .light-mode .chat-list-button:hover { background-color: rgba(0, 0, 0, 0.02); }
65 +
66 + .chat-name { display: inline-block; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; padding: 3px 8px; border-radius: 4px; transition: background-color 0.2s; margin-right: 60px; font-size: var(--font-size-small); }
67 + .chat-name:hover { background-color: rgba(255, 255, 255, 0.1); text-decoration: none; }
68 + .light-mode .chat-name:hover { background-color: rgba(0, 0, 0, 0.05); }
69 +
70 + .chat-container { display: flex; align-items: center; position: relative; width: 100%; min-height: 30px; gap: 0; }
71 +
72 + .edit-button { background-color: transparent; border: 1px solid var(--color-border); border-radius: 0.1875rem; color: var(--color-primary); cursor: pointer; padding: 0.125rem 0.5rem; -webkit-transition: all var(--transition-speed) ease-in-out; transition: all var(--transition-speed) ease-in-out; width: 2rem; height: 2rem; }
73 + .edit-button:hover { border-color: var(--color-primary); background-color: #32455690; }
74 + .edit-button:active { background-color: #131a2090; color: rgba(253, 253, 253, 0.35); }
75 + .light-mode .edit-button { border-color: var(--color-primary-light); color: var(--color-primary-light); }
76 + .light-mode .edit-button:hover { background-color: #e4e7f0; }
77 + .light-mode .edit-button:active { background-color: #979fb9; color: rgba(0,0,0,0.35); }
78 +
79 + .empty-list-message { display: flex; justify-content: center; align-items: center; height: 100px; color: var(--color-secondary); text-align: center; opacity: 0.7; font-style: italic; }
80 + .light-mode .empty-list-message { color: var(--color-secondary-light); }
81 +
82 + /* Selected chat accent */
83 + .chat-list-button.font-bold { position: relative; background-color: var(--color-border) 0.05; }
84 + .chat-list-button.font-bold::before { content: ""; position: absolute; left: 0; top: 0; height: 100%; width: 3px; background-color: var(--color-border); border-top-left-radius: 3px; border-bottom-left-radius: 3px; }
85 + .light-mode .chat-list-button.font-bold { background-color: var(--color-border) 0.05; }
86 + .light-mode .chat-list-button.font-bold::before { background-color: var(--color-border); }
87 + </style>
88 </body>
89 </html>
33 -
34 -<style>
35 - /* Chats list container and items */
36 - .chats-list-container {
37 - display: flex;
38 - flex-direction: column;
39 - flex: 1;
40 - min-height: 0;
41 - overflow: hidden;
42 - }
43 -
44 - /* Sticky header for chats list */
45 - .chats-list-container .section-header {
46 - flex-shrink: 0;
47 - z-index: 10;
48 - }
49 -
50 - /* Scrollable config list */
51 - .chats-config-list {
52 - flex: 1;
53 - min-height: 0;
54 - overflow-y: auto;
55 - scroll-behavior: smooth;
56 - max-height: 23vh;
57 - /* Hide scrollbar but keep functionality */
58 - scrollbar-width: none; /* Firefox */
59 - -ms-overflow-style: none; /* IE/Edge */
60 - }
61 - /* Hide scrollbar for Chrome/Safari/Webkit */
62 - .chats-config-list::-webkit-scrollbar {
63 - display: none;
64 - }
65 -
66 - .chat-list-button { display: block; width: 100%; padding: 8px 5px; cursor: pointer; overflow: hidden; position: relative; border-radius: 4px; transition: background-color 0.2s ease-in-out; }
67 - .chat-list-button.has-task-container { padding-top: 6px; padding-bottom: 6px; }
68 - .chat-list-button:hover { background-color: rgba(255, 255, 255, 0.03); }
69 - .light-mode .chat-list-button:hover { background-color: rgba(0, 0, 0, 0.02); }
70 -
71 - .chat-name { display: inline-block; max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; padding: 3px 8px; border-radius: 4px; transition: background-color 0.2s; margin-right: 60px; font-size: var(--font-size-small); }
72 - .chat-name:hover { background-color: rgba(255, 255, 255, 0.1); text-decoration: none; }
73 - .light-mode .chat-name:hover { background-color: rgba(0, 0, 0, 0.05); }
74 -
75 - .chat-container { display: flex; align-items: center; position: relative; width: 100%; min-height: 30px; gap: 0; }
76 -
77 - .edit-button { background-color: transparent; border: 1px solid var(--color-border); border-radius: 0.1875rem; color: var(--color-primary); cursor: pointer; padding: 0.125rem 0.5rem; -webkit-transition: all var(--transition-speed) ease-in-out; transition: all var(--transition-speed) ease-in-out; width: 2rem; height: 2rem; }
78 - .edit-button:hover { border-color: var(--color-primary); background-color: #32455690; }
79 - .edit-button:active { background-color: #131a2090; color: rgba(253, 253, 253, 0.35); }
80 - .light-mode .edit-button { border-color: var(--color-primary-light); color: var(--color-primary-light); }
81 - .light-mode .edit-button:hover { background-color: #e4e7f0; }
82 - .light-mode .edit-button:active { background-color: #979fb9; color: rgba(0,0,0,0.35); }
83 -
84 - .empty-list-message { display: flex; justify-content: center; align-items: center; height: 100px; color: var(--color-secondary); text-align: center; opacity: 0.7; font-style: italic; }
85 - .light-mode .empty-list-message { color: var(--color-secondary-light); }
86 -
87 - /* Selected chat accent */
88 - .chat-list-button.font-bold { position: relative; background-color: var(--color-border) 0.05; }
89 - .chat-list-button.font-bold::before { content: ""; position: absolute; left: 0; top: 0; height: 100%; width: 3px; background-color: var(--color-border); border-top-left-radius: 3px; border-bottom-left-radius: 3px; }
90 - .light-mode .chat-list-button.font-bold { background-color: var(--color-border) 0.05; }
91 - .light-mode .chat-list-button.font-bold::before { background-color: var(--color-border); }
92 -</style>
93 -
94 -
webui/components/sidebar/chats/chats-store.js
+9
@@ -139,6 +139,8 @@ const model = {
139 if (globalThis.updateAfterScroll) {
140 globalThis.updateAfterScroll();
141 }
142 + // UX: scroll-to-top
143 + requestAnimationFrame(() => this._scrollChatsToTop());
144 } catch (e) {
145 if (globalThis.toastFetchError) {
146 globalThis.toastFetchError("Error creating new chat", e);
@@ -146,6 +148,13 @@ const model = {
148 }
149 },
150
151 + // Smoothly scroll the chats list to top if present
152 + _scrollChatsToTop() {
153 + const listEl = document.querySelector('#chats-section .chats-config-list');
154 + if (!listEl) return; // no-op if not in DOM
155 + listEl.scrollTo({ top: 0, behavior: 'smooth' });
156 + },
157 +
158 // Load chats from files
159 async loadChats() {
160 try {
webui/components/sidebar/left-sidebar.html
+13 -24
@@ -11,18 +11,14 @@
11 <div class="left-panel-top">
12 <!-- Top Section: Header Icons + Quick Actions -->
13 <x-component path="sidebar/top-section/sidebar-top.html"></x-component>
14 + <!-- Chats List -->
15 + <div class="config-section" id="chats-section">
16 + <x-component path="sidebar/chats/chats-list.html"></x-component>
17 + </div>
18
15 - <!-- Chats and Tasks Wrapper -->
16 - <div class="lists-wrapper">
17 - <!-- Chats List -->
18 - <div class="config-section" id="chats-section">
19 - <x-component path="sidebar/chats/chats-list.html"></x-component>
20 - </div>
21 -
22 - <!-- Tasks List -->
23 - <div class="config-section" id="tasks-section">
24 - <x-component path="sidebar/tasks/tasks-list.html"></x-component>
25 - </div>
19 + <!-- Tasks List -->
20 + <div class="config-section" id="tasks-section">
21 + <x-component path="sidebar/tasks/tasks-list.html"></x-component>
22 </div>
23 </div>
24 <!--Sidebar lower elements-->
@@ -31,7 +27,6 @@
27 </div>
28 </div>
29
34 -
30 <style>
31 /* Left Panel styles from index.css */
32 #left-panel {
@@ -75,15 +70,6 @@
70 margin-top: 3.5rem;
71 padding: var(--spacing-md) var(--spacing-md) 0 var(--spacing-md);
72 }
78 -
79 - /* Wrapper for Chats and Tasks lists */
80 - .lists-wrapper {
81 - display: flex;
82 - flex-direction: column;
83 - flex: 1;
84 - min-height: 0;
85 - overflow: hidden;
86 - }
73 .left-panel-top::-webkit-scrollbar {
74 width: 0px;
75 }
@@ -105,10 +91,15 @@
91 display: flex;
92 flex-direction: column;
93 min-height: 0;
108 - flex: 0 auto;
94 + flex: 1 1 auto; /* Allow to grow and fill available space */
95 margin-top: var(--spacing-md);
96 overflow: hidden;
97 }
98 + /* Flatten wrapper elements to maintain flex chain for inner scroll containers */
99 + #chats-section, #tasks-section > x-component,
100 + #chats-section, #tasks-section > x-component > div[x-data] {
101 + display: contents;
102 + }
103 /* Tasks section container inside sidebar */
104 #tasks-section {
105 display: -webkit-flex;
@@ -173,5 +164,3 @@
164 </style>
165 </body>
166 </html>
176 -
177 -
webui/components/sidebar/tasks/tasks-list.html
+53 -58
@@ -59,63 +59,58 @@
59 </template>
60 </div>
61
62 + <style>
63 + .tasks-list-container .section-header {
64 + position: sticky;
65 + top: 0;
66 + flex-shrink: 0;
67 + z-index: 10;
68 + }
69 +
70 + .tasks-list-container {
71 + display: flex;
72 + flex-direction: column;
73 + max-height: 100%;
74 + overflow: hidden;
75 + position: relative;
76 + }
77 +
78 + /* Scrollable tasks config list */
79 + .tasks-config-list {
80 + flex: 1;
81 + min-height: 0;
82 + overflow-y: auto;
83 + scroll-behavior: smooth;
84 + scrollbar-width: none; /* Firefox */
85 + -ms-overflow-style: none; /* IE/Edge */
86 + }
87 + /* Hide scrollbar for Chrome/Safari/Webkit */
88 + .tasks-config-list::-webkit-scrollbar {
89 + display: none;
90 + }
91 +
92 + .task-name { display: block; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 3px 0; margin-left: 10px; cursor: pointer; border-radius: 4px; transition: background-color 0.2s; font-size: var(--font-size-small); margin-bottom: 2px; }
93 + .task-name:hover { background-color: rgba(255,255,255,0.1); text-decoration: none; }
94 + .light-mode .task-name:hover { background-color: rgba(0,0,0,0.05); }
95 +
96 + .task-info-line { display: flex; justify-content: space-between; align-items: center; width: 100%; margin-top: 2px; margin-left: 5px; }
97 +
98 + .task-container-vertical { display: flex; flex-direction: column; width: 100%; gap: 6px; }
99 +
100 + /* Scheduler badges (subset used in sidebar) */
101 + .scheduler-status-badge { display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; text-transform: capitalize; white-space: nowrap; }
102 + .scheduler-status-badge-small { font-size: 10px; padding: 2px 6px; margin-right: 5px; min-width: 40px; text-align: center; }
103 + .scheduler-status-idle { background-color: rgba(0, 100, 0, 0.2); color: #2a9d8f; border: 1px solid rgba(42, 157, 143, 0.3); }
104 + .scheduler-status-running { background-color: rgba(0, 60, 120, 0.2); color: #4361ee; border: 1px solid rgba(67, 97, 238, 0.3); }
105 + .scheduler-status-disabled { background-color: rgba(70, 70, 70, 0.2); color: #6c757d; border: 1px solid rgba(108, 117, 125, 0.3); }
106 + .scheduler-status-error { background-color: rgba(120, 0, 0, 0.2); color: #e63946; border: 1px solid rgba(230, 57, 70, 0.3); }
107 + .light-mode .scheduler-status-idle { background-color: rgba(42, 157, 143, 0.1); color: #1a6f65; }
108 + .light-mode .scheduler-status-running { background-color: rgba(67, 97, 238, 0.1); color: #2540b3; }
109 + .light-mode .scheduler-status-disabled { background-color: rgba(108, 117, 125, 0.1); color: #495057; }
110 + .light-mode .scheduler-status-error { background-color: rgba(230, 57, 70, 0.1); color: #c5283d; }
111 +
112 + .empty-list-message { display: flex; justify-content: center; align-items: center; height: 100px; color: var(--color-secondary); text-align: center; opacity: 0.7; font-style: italic; }
113 + .light-mode .empty-list-message { color: var(--color-secondary-light); }
114 + </style>
115 </body>
116 </html>
64 -
65 -<style>
66 - /* Tasks list styling (migrated) */
67 - .tasks-list-container {
68 - display: flex;
69 - flex-direction: column;
70 - max-height: 30vh;
71 - overflow: hidden;
72 - position: relative;
73 - }
74 -
75 - /* Scrollable tasks config list */
76 - .tasks-config-list {
77 - flex: 1;
78 - min-height: 0;
79 - overflow-y: auto;
80 - scroll-behavior: smooth;
81 - max-height: 23vh;
82 - /* Hide scrollbar but keep functionality */
83 - scrollbar-width: none; /* Firefox */
84 - -ms-overflow-style: none; /* IE/Edge */
85 - }
86 - /* Hide scrollbar for Chrome/Safari/Webkit */
87 - .tasks-config-list::-webkit-scrollbar {
88 - display: none;
89 - }
90 -
91 -
92 - .tasks-list-container .section-header {
93 - flex-shrink: 0;
94 - z-index: 10;
95 - }
96 -
97 - .task-name { display: block; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 3px 0; margin-left: 10px; cursor: pointer; border-radius: 4px; transition: background-color 0.2s; font-size: var(--font-size-small); margin-bottom: 2px; }
98 - .task-name:hover { background-color: rgba(255,255,255,0.1); text-decoration: none; }
99 - .light-mode .task-name:hover { background-color: rgba(0,0,0,0.05); }
100 -
101 - .task-info-line { display: flex; justify-content: space-between; align-items: center; width: 100%; margin-top: 2px; margin-left: 5px; }
102 -
103 - .task-container-vertical { display: flex; flex-direction: column; width: 100%; gap: 6px; }
104 -
105 - /* Scheduler badges (subset used in sidebar) */
106 - .scheduler-status-badge { display: inline-block; padding: 4px 8px; border-radius: 4px; font-size: 12px; font-weight: 500; text-transform: capitalize; white-space: nowrap; }
107 - .scheduler-status-badge-small { font-size: 10px; padding: 2px 6px; margin-right: 5px; min-width: 40px; text-align: center; }
108 - .scheduler-status-idle { background-color: rgba(0, 100, 0, 0.2); color: #2a9d8f; border: 1px solid rgba(42, 157, 143, 0.3); }
109 - .scheduler-status-running { background-color: rgba(0, 60, 120, 0.2); color: #4361ee; border: 1px solid rgba(67, 97, 238, 0.3); }
110 - .scheduler-status-disabled { background-color: rgba(70, 70, 70, 0.2); color: #6c757d; border: 1px solid rgba(108, 117, 125, 0.3); }
111 - .scheduler-status-error { background-color: rgba(120, 0, 0, 0.2); color: #e63946; border: 1px solid rgba(230, 57, 70, 0.3); }
112 - .light-mode .scheduler-status-idle { background-color: rgba(42, 157, 143, 0.1); color: #1a6f65; }
113 - .light-mode .scheduler-status-running { background-color: rgba(67, 97, 238, 0.1); color: #2540b3; }
114 - .light-mode .scheduler-status-disabled { background-color: rgba(108, 117, 125, 0.1); color: #495057; }
115 - .light-mode .scheduler-status-error { background-color: rgba(230, 57, 70, 0.1); color: #c5283d; }
116 -
117 - .empty-list-message { display: flex; justify-content: center; align-items: center; height: 100px; color: var(--color-secondary); text-align: center; opacity: 0.7; font-style: italic; }
118 - .light-mode .empty-list-message { color: var(--color-secondary-light); }
119 -</style>
120 -
121 -