frdel commited on
Commit
06c8c46
·
1 Parent(s): 3167019

frontend components refactor cleanup

Browse files
webui/components/messages/action-buttons/simple-action-buttons.js CHANGED
@@ -2,7 +2,7 @@
2
  import { store as speechStore } from "/components/chat/speech/speech-store.js";
3
 
4
  // Extract text content from different message types
5
- function getTextContent(element) {
6
  // Get all children except action buttons
7
  const textParts = [];
8
  // Loop through all child elements
@@ -15,7 +15,7 @@ function getTextContent(element) {
15
  continue;
16
  }
17
  // Get text content from the child
18
- const text = child.innerText || "";
19
  if (text.trim()) {
20
  textParts.push(text.trim());
21
  }
 
2
  import { store as speechStore } from "/components/chat/speech/speech-store.js";
3
 
4
  // Extract text content from different message types
5
+ function getTextContent(element,html=false) {
6
  // Get all children except action buttons
7
  const textParts = [];
8
  // Loop through all child elements
 
15
  continue;
16
  }
17
  // Get text content from the child
18
+ const text = (html ? child.innerHTML : child.innerText) || "";
19
  if (text.trim()) {
20
  textParts.push(text.trim());
21
  }
webui/components/projects/project-selector.html CHANGED
@@ -7,7 +7,7 @@
7
  </head>
8
 
9
  <body>
10
- <div x-data>
11
  <template x-if="$store.projects">
12
  <div>
13
  <template x-if="$store.selectedProject">
@@ -18,7 +18,7 @@
18
  </template>
19
  </div>
20
  </template>
21
- </div>
22
  </body>
23
 
24
  </html>
 
7
  </head>
8
 
9
  <body>
10
+ <!-- <div x-data>
11
  <template x-if="$store.projects">
12
  <div>
13
  <template x-if="$store.selectedProject">
 
18
  </template>
19
  </div>
20
  </template>
21
+ </div> -->
22
  </body>
23
 
24
  </html>
webui/components/sidebar/bottom/preferences/preferences-panel.html CHANGED
@@ -16,42 +16,42 @@
16
  </svg>
17
  </h3>
18
  <ul class="config-list collapse show" id="pref-list">
19
- <li x-data x-init="$watch('$store.preferences.autoScroll', v => $store.preferences.applyAutoScroll(v))">
20
  <span>Autoscroll</span>
21
  <label class="switch">
22
  <input id="auto-scroll-switch" type="checkbox" x-model="$store.preferences.autoScroll">
23
  <span class="slider"></span>
24
  </label>
25
  </li>
26
- <li x-data x-init="$watch('$store.preferences.darkMode', v => $store.preferences.applyDarkMode(v))">
27
  <span class="switch-label">Dark mode</span>
28
  <label class="switch">
29
  <input type="checkbox" x-model="$store.preferences.darkMode">
30
  <span class="slider"></span>
31
  </label>
32
  </li>
33
- <li x-data x-init="$watch('$store.preferences.speech', v => $store.preferences.applySpeech(v))">
34
  <span class="switch-label">Speech</span>
35
  <label class="switch">
36
  <input type="checkbox" x-model="$store.preferences.speech">
37
  <span class="slider"></span>
38
  </label>
39
  </li>
40
- <li x-data x-init="$watch('$store.preferences.showThoughts', v => $store.preferences.applyShowThoughts(v))">
41
  <span>Show thoughts</span>
42
  <label class="switch">
43
  <input type="checkbox" x-model="$store.preferences.showThoughts">
44
  <span class="slider"></span>
45
  </label>
46
  </li>
47
- <li x-data x-init="$watch('$store.preferences.showJson', v => $store.preferences.applyShowJson(v))">
48
  <span>Show JSON</span>
49
  <label class="switch">
50
  <input type="checkbox" x-model="$store.preferences.showJson">
51
  <span class="slider"></span>
52
  </label>
53
  </li>
54
- <li x-data x-init="$watch('$store.preferences.showUtils', v => $store.preferences.applyShowUtils(v))">
55
  <span>Show utility messages</span>
56
  <label class="switch">
57
  <input type="checkbox" x-model="$store.preferences.showUtils">
 
16
  </svg>
17
  </h3>
18
  <ul class="config-list collapse show" id="pref-list">
19
+ <li x-data>
20
  <span>Autoscroll</span>
21
  <label class="switch">
22
  <input id="auto-scroll-switch" type="checkbox" x-model="$store.preferences.autoScroll">
23
  <span class="slider"></span>
24
  </label>
25
  </li>
26
+ <li x-data>
27
  <span class="switch-label">Dark mode</span>
28
  <label class="switch">
29
  <input type="checkbox" x-model="$store.preferences.darkMode">
30
  <span class="slider"></span>
31
  </label>
32
  </li>
33
+ <li x-data>
34
  <span class="switch-label">Speech</span>
35
  <label class="switch">
36
  <input type="checkbox" x-model="$store.preferences.speech">
37
  <span class="slider"></span>
38
  </label>
39
  </li>
40
+ <li x-data>
41
  <span>Show thoughts</span>
42
  <label class="switch">
43
  <input type="checkbox" x-model="$store.preferences.showThoughts">
44
  <span class="slider"></span>
45
  </label>
46
  </li>
47
+ <li x-data>
48
  <span>Show JSON</span>
49
  <label class="switch">
50
  <input type="checkbox" x-model="$store.preferences.showJson">
51
  <span class="slider"></span>
52
  </label>
53
  </li>
54
+ <li x-data>
55
  <span>Show utility messages</span>
56
  <label class="switch">
57
  <input type="checkbox" x-model="$store.preferences.showUtils">
webui/components/sidebar/bottom/preferences/preferences-store.js CHANGED
@@ -1,14 +1,63 @@
1
  import { createStore } from "/js/AlpineStore.js";
 
 
2
 
3
  // Preferences store centralizes user preference toggles and side-effects
4
  const model = {
5
  // UI toggles (initialized with safe defaults, loaded from localStorage in init)
6
- autoScroll: true,
7
- darkMode: true,
8
- speech: false,
9
- showThoughts: true,
10
- showJson: false,
11
- showUtils: false,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  // Initialize preferences and apply current state
14
  init() {
@@ -16,68 +65,69 @@ const model = {
16
  // Load persisted preferences with safe fallbacks
17
  try {
18
  const storedDarkMode = localStorage.getItem("darkMode");
19
- this.darkMode = storedDarkMode !== "false";
20
  } catch {
21
- this.darkMode = true; // Default to dark mode if localStorage is unavailable
22
  }
23
 
24
  try {
25
  const storedSpeech = localStorage.getItem("speech");
26
- this.speech = storedSpeech === "true";
27
  } catch {
28
- this.speech = false; // Default to speech off if localStorage is unavailable
29
  }
30
 
31
  // Apply all preferences
32
- this.applyDarkMode(this.darkMode);
33
- this.applyAutoScroll(this.autoScroll);
34
- this.applySpeech(this.speech);
35
- this.applyShowThoughts(this.showThoughts);
36
- this.applyShowJson(this.showJson);
37
- this.applyShowUtils(this.showUtils);
38
  } catch (e) {
39
  console.error("Failed to initialize preferences store", e);
40
  }
41
  },
42
 
43
- // Side-effect appliers delegate to existing global handlers for parity
44
- applyAutoScroll(value = this.autoScroll) {
45
- if (typeof globalThis.toggleAutoScroll === "function") {
46
- globalThis.toggleAutoScroll(value);
47
- }
48
  },
49
 
50
- applyDarkMode(value = this.darkMode) {
51
- if (typeof globalThis.toggleDarkMode === "function") {
52
- globalThis.toggleDarkMode(value);
 
 
 
 
53
  }
 
54
  },
55
 
56
- applySpeech(value = this.speech) {
57
- if (typeof globalThis.toggleSpeech === "function") {
58
- globalThis.toggleSpeech(value);
59
- }
60
  },
61
 
62
- applyShowThoughts(value = this.showThoughts) {
63
- if (typeof globalThis.toggleThoughts === "function") {
64
- globalThis.toggleThoughts(value);
65
- }
 
 
66
  },
67
 
68
- applyShowJson(value = this.showJson) {
69
- if (typeof globalThis.toggleJson === "function") {
70
- globalThis.toggleJson(value);
71
- }
72
  },
73
 
74
- applyShowUtils(value = this.showUtils) {
75
- if (typeof globalThis.toggleUtils === "function") {
76
- globalThis.toggleUtils(value);
77
- }
 
 
78
  },
79
  };
80
 
81
  export const store = createStore("preferences", model);
82
-
83
-
 
1
  import { createStore } from "/js/AlpineStore.js";
2
+ import * as css from "/js/css.js";
3
+ import { store as speechStore } from "/components/chat/speech/speech-store.js";
4
 
5
  // Preferences store centralizes user preference toggles and side-effects
6
  const model = {
7
  // UI toggles (initialized with safe defaults, loaded from localStorage in init)
8
+ get autoScroll() {
9
+ return this._autoScroll;
10
+ },
11
+ set autoScroll(value) {
12
+ this._autoScroll = value;
13
+ this._applyAutoScroll(value);
14
+ },
15
+ _autoScroll: true,
16
+
17
+ get darkMode() {
18
+ return this._darkMode;
19
+ },
20
+ set darkMode(value) {
21
+ this._darkMode = value;
22
+ this._applyDarkMode(value);
23
+ },
24
+ _darkMode: true,
25
+
26
+ get speech() {
27
+ return this._speech;
28
+ },
29
+ set speech(value) {
30
+ this._speech = value;
31
+ this._applySpeech(value);
32
+ },
33
+ _speech: false,
34
+
35
+ get showThoughts() {
36
+ return this._showThoughts;
37
+ },
38
+ set showThoughts(value) {
39
+ this._showThoughts = value;
40
+ this._applyShowThoughts(value);
41
+ },
42
+ _showThoughts: true,
43
+
44
+ get showJson() {
45
+ return this._showJson;
46
+ },
47
+ set showJson(value) {
48
+ this._showJson = value;
49
+ this._applyShowJson(value);
50
+ },
51
+ _showJson: false,
52
+
53
+ get showUtils() {
54
+ return this._showUtils;
55
+ },
56
+ set showUtils(value) {
57
+ this._showUtils = value;
58
+ this._applyShowUtils(value);
59
+ },
60
+ _showUtils: false,
61
 
62
  // Initialize preferences and apply current state
63
  init() {
 
65
  // Load persisted preferences with safe fallbacks
66
  try {
67
  const storedDarkMode = localStorage.getItem("darkMode");
68
+ this._darkMode = storedDarkMode !== "false";
69
  } catch {
70
+ this._darkMode = true; // Default to dark mode if localStorage is unavailable
71
  }
72
 
73
  try {
74
  const storedSpeech = localStorage.getItem("speech");
75
+ this._speech = storedSpeech === "true";
76
  } catch {
77
+ this._speech = false; // Default to speech off if localStorage is unavailable
78
  }
79
 
80
  // Apply all preferences
81
+ this._applyDarkMode(this._darkMode);
82
+ this._applyAutoScroll(this._autoScroll);
83
+ this._applySpeech(this._speech);
84
+ this._applyShowThoughts(this._showThoughts);
85
+ this._applyShowJson(this._showJson);
86
+ this._applyShowUtils(this._showUtils);
87
  } catch (e) {
88
  console.error("Failed to initialize preferences store", e);
89
  }
90
  },
91
 
92
+ _applyAutoScroll(value) {
93
+ // nothing for now
 
 
 
94
  },
95
 
96
+ _applyDarkMode(value) {
97
+ if (value) {
98
+ document.body.classList.remove("light-mode");
99
+ document.body.classList.add("dark-mode");
100
+ } else {
101
+ document.body.classList.remove("dark-mode");
102
+ document.body.classList.add("light-mode");
103
  }
104
+ localStorage.setItem("darkMode", value);
105
  },
106
 
107
+ _applySpeech(value) {
108
+ localStorage.setItem("speech", value);
109
+ if (!value) speechStore.stopAudio();
 
110
  },
111
 
112
+ _applyShowThoughts(value) {
113
+ css.toggleCssProperty(
114
+ ".msg-thoughts",
115
+ "display",
116
+ value ? undefined : "none"
117
+ );
118
  },
119
 
120
+ _applyShowJson(value) {
121
+ css.toggleCssProperty(".msg-json", "display", value ? "block" : "none");
 
 
122
  },
123
 
124
+ _applyShowUtils(value) {
125
+ css.toggleCssProperty(
126
+ ".message-util",
127
+ "display",
128
+ value ? undefined : "none"
129
+ );
130
  },
131
  };
132
 
133
  export const store = createStore("preferences", model);
 
 
webui/components/sidebar/left-sidebar.html CHANGED
@@ -1,30 +1,36 @@
1
  <html>
 
2
  <head>
3
  <script type="module">
4
  import { store as sidebarStore } from "/components/sidebar/sidebar-store.js";
5
  </script>
6
  <!-- Wrapper composes existing sidebar components -->
7
  </head>
 
8
  <body>
9
- <div id="left-panel" class="panel" x-data :class="{'hidden': !$store.sidebar.isOpen}">
10
- <!--Sidebar upper elements-->
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
 
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-->
25
- <div class="left-panel-bottom">
26
- <x-component path="sidebar/bottom/sidebar-bottom.html"></x-component>
27
- </div>
28
  </div>
29
 
30
  <style>
@@ -42,21 +48,25 @@
42
  color: var(--color-text);
43
  box-shadow: 1px 0 5px rgba(0, 0, 0, 0.3);
44
  user-select: none;
45
- -webkit-user-select: none; /* Safari compatibility */
46
- height: 100vh; /* Ensure full height */
47
- overflow: hidden; /* Prevent overall panel overflow */
 
 
 
48
  }
49
 
50
  /* Ensure component host behaves like the original direct children for flex layout */
51
- #left-panel > .left-panel-top,
52
- #left-panel > .left-panel-bottom {
53
- display: flex;
54
- flex-direction: column;
55
  }
56
 
57
- #left-panel > .left-panel-top {
58
- flex: 1;
59
- min-height: 0; /* allow inner flex children to shrink properly */
 
60
  }
61
 
62
  #left-panel.hidden {
@@ -64,11 +74,13 @@
64
  }
65
 
66
  .left-panel-top {
67
- flex: 1 1 auto; /* Take available space */
 
68
  display: -webkit-flex;
69
  display: flex;
70
  flex-direction: column;
71
- min-height: 0; /* Critical for allowing flex children to shrink */
 
72
  overflow: hidden;
73
  justify-content: space-between;
74
  margin-top: 3.5rem;
@@ -76,13 +88,16 @@
76
  scrollbar-width: none;
77
  -ms-overflow-style: none;
78
  }
 
79
  .left-panel-top::-webkit-scrollbar {
80
  width: 0px;
81
  }
 
82
  .left-panel-bottom {
83
  position: relative;
84
  flex-shrink: 0;
85
- flex-grow: 0; /* Prevent bottom from growing */
 
86
  }
87
 
88
  /* Chats section container inside sidebar */
@@ -91,7 +106,8 @@
91
  display: flex;
92
  flex-direction: column;
93
  min-height: 0;
94
- flex: 1 1 auto; /* Take all available space */
 
95
  max-height: 100%;
96
  overflow: hidden;
97
  }
@@ -102,19 +118,21 @@
102
  display: flex;
103
  flex-direction: column;
104
  min-height: 0;
105
- flex: 0 0 auto; /* Shrink to content, no reserved space */
106
- max-height: 40%; /* Limit to 40% of viewport height when expanded */
 
 
107
  margin-top: 0;
108
  padding-top: var(--spacing-md);
109
  overflow: hidden;
110
  }
111
-
112
  /* Flatten wrapper elements to maintain flex chain for inner scroll containers */
113
- #chats-section > x-component,
114
- #chats-section > x-component > div[x-data],
115
- #tasks-section > x-component,
116
- #tasks-section > x-component > div[x-data],
117
- #tasks-section > x-component > div[x-data] > div[x-data] {
118
  display: contents;
119
  }
120
 
@@ -125,10 +143,12 @@
125
  flex: 1;
126
  min-height: 0;
127
  }
 
128
  /* During the collapsing transition, allow height animation to control size */
129
  #tasks-section .collapsing {
130
  flex: 0 0 auto !important;
131
  }
 
132
  /* Common section header styling (Chats, Tasks) - matching Preferences style */
133
  .section-header {
134
  display: flex;
@@ -137,23 +157,25 @@
137
  gap: 6px;
138
  margin: 0 0 0.5rem 0;
139
  padding: 0;
140
- -webkit-user-select: none; /* Safari compatibility */
 
141
  user-select: none;
142
  font-size: var(--font-size-normal);
143
  }
144
-
145
  /* Collapsible section headers (Tasks) */
146
  .section-header-collapsible {
147
  cursor: pointer;
148
  }
149
-
150
  @media (max-width: 768px) {
151
  #left-panel {
152
  position: fixed;
153
  left: 0;
154
  top: 0;
155
  bottom: 0;
156
- width: 250px !important; /* Force width */
 
157
  min-width: 250px;
158
  z-index: 1003;
159
  transition: all var(--transition-speed) ease-in-out;
@@ -165,9 +187,17 @@
165
  }
166
 
167
  @media (max-height: 600px) {
168
- #chats-section { min-height: 100%; }
169
- .left-panel-top { overflow-y: auto; -webkit-scroll-behavior: smooth; scroll-behavior: smooth; }
 
 
 
 
 
 
 
170
  }
171
  </style>
172
  </body>
173
- </html>
 
 
1
  <html>
2
+
3
  <head>
4
  <script type="module">
5
  import { store as sidebarStore } from "/components/sidebar/sidebar-store.js";
6
  </script>
7
  <!-- Wrapper composes existing sidebar components -->
8
  </head>
9
+
10
  <body>
11
+ <div x-data>
12
+ <template x-if="$store.sidebar">
13
+ <div id="left-panel" class="panel" x-data :class="{'hidden': !$store.sidebar.isOpen}">
14
+ <!--Sidebar upper elements-->
15
+ <div class="left-panel-top">
16
+ <!-- Top Section: Header Icons + Quick Actions -->
17
+ <x-component path="sidebar/top-section/sidebar-top.html"></x-component>
18
+ <!-- Chats List -->
19
+ <div class="config-section" id="chats-section">
20
+ <x-component path="sidebar/chats/chats-list.html"></x-component>
21
+ </div>
22
 
23
+ <!-- Tasks List -->
24
+ <div class="config-section" id="tasks-section">
25
+ <x-component path="sidebar/tasks/tasks-list.html"></x-component>
26
+ </div>
27
+ </div>
28
+ <!--Sidebar lower elements-->
29
+ <div class="left-panel-bottom">
30
+ <x-component path="sidebar/bottom/sidebar-bottom.html"></x-component>
31
+ </div>
32
  </div>
33
+ </template>
 
 
 
 
34
  </div>
35
 
36
  <style>
 
48
  color: var(--color-text);
49
  box-shadow: 1px 0 5px rgba(0, 0, 0, 0.3);
50
  user-select: none;
51
+ -webkit-user-select: none;
52
+ /* Safari compatibility */
53
+ height: 100vh;
54
+ /* Ensure full height */
55
+ overflow: hidden;
56
+ /* Prevent overall panel overflow */
57
  }
58
 
59
  /* Ensure component host behaves like the original direct children for flex layout */
60
+ #left-panel>.left-panel-top,
61
+ #left-panel>.left-panel-bottom {
62
+ display: flex;
63
+ flex-direction: column;
64
  }
65
 
66
+ #left-panel>.left-panel-top {
67
+ flex: 1;
68
+ min-height: 0;
69
+ /* allow inner flex children to shrink properly */
70
  }
71
 
72
  #left-panel.hidden {
 
74
  }
75
 
76
  .left-panel-top {
77
+ flex: 1 1 auto;
78
+ /* Take available space */
79
  display: -webkit-flex;
80
  display: flex;
81
  flex-direction: column;
82
+ min-height: 0;
83
+ /* Critical for allowing flex children to shrink */
84
  overflow: hidden;
85
  justify-content: space-between;
86
  margin-top: 3.5rem;
 
88
  scrollbar-width: none;
89
  -ms-overflow-style: none;
90
  }
91
+
92
  .left-panel-top::-webkit-scrollbar {
93
  width: 0px;
94
  }
95
+
96
  .left-panel-bottom {
97
  position: relative;
98
  flex-shrink: 0;
99
+ flex-grow: 0;
100
+ /* Prevent bottom from growing */
101
  }
102
 
103
  /* Chats section container inside sidebar */
 
106
  display: flex;
107
  flex-direction: column;
108
  min-height: 0;
109
+ flex: 1 1 auto;
110
+ /* Take all available space */
111
  max-height: 100%;
112
  overflow: hidden;
113
  }
 
118
  display: flex;
119
  flex-direction: column;
120
  min-height: 0;
121
+ flex: 0 0 auto;
122
+ /* Shrink to content, no reserved space */
123
+ max-height: 40%;
124
+ /* Limit to 40% of viewport height when expanded */
125
  margin-top: 0;
126
  padding-top: var(--spacing-md);
127
  overflow: hidden;
128
  }
129
+
130
  /* Flatten wrapper elements to maintain flex chain for inner scroll containers */
131
+ #chats-section>x-component,
132
+ #chats-section>x-component>div[x-data],
133
+ #tasks-section>x-component,
134
+ #tasks-section>x-component>div[x-data],
135
+ #tasks-section>x-component>div[x-data]>div[x-data] {
136
  display: contents;
137
  }
138
 
 
143
  flex: 1;
144
  min-height: 0;
145
  }
146
+
147
  /* During the collapsing transition, allow height animation to control size */
148
  #tasks-section .collapsing {
149
  flex: 0 0 auto !important;
150
  }
151
+
152
  /* Common section header styling (Chats, Tasks) - matching Preferences style */
153
  .section-header {
154
  display: flex;
 
157
  gap: 6px;
158
  margin: 0 0 0.5rem 0;
159
  padding: 0;
160
+ -webkit-user-select: none;
161
+ /* Safari compatibility */
162
  user-select: none;
163
  font-size: var(--font-size-normal);
164
  }
165
+
166
  /* Collapsible section headers (Tasks) */
167
  .section-header-collapsible {
168
  cursor: pointer;
169
  }
170
+
171
  @media (max-width: 768px) {
172
  #left-panel {
173
  position: fixed;
174
  left: 0;
175
  top: 0;
176
  bottom: 0;
177
+ width: 250px !important;
178
+ /* Force width */
179
  min-width: 250px;
180
  z-index: 1003;
181
  transition: all var(--transition-speed) ease-in-out;
 
187
  }
188
 
189
  @media (max-height: 600px) {
190
+ #chats-section {
191
+ min-height: 100%;
192
+ }
193
+
194
+ .left-panel-top {
195
+ overflow-y: auto;
196
+ -webkit-scroll-behavior: smooth;
197
+ scroll-behavior: smooth;
198
+ }
199
  }
200
  </style>
201
  </body>
202
+
203
+ </html>
webui/index.html CHANGED
@@ -99,7 +99,9 @@
99
  <script type="module" src="index.js"></script>
100
 
101
  <!-- Bootstrap JS (only for logic, importing bundled CSS => UI conflicts) -->
102
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
 
 
103
 
104
  <!-- Then load Alpine.js -->
105
  <!-- <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> -->
@@ -133,15 +135,19 @@
133
  </script>
134
  </head>
135
 
136
- <body class="dark-mode device-pointer">
137
  <div class="container">
138
  <!-- Sidebar Overlay -->
139
- <div id="sidebar-overlay" class="sidebar-overlay" x-data :class="{'visible': $store.sidebar.isOpen && $store.sidebar.isMobile()}" @click="$store.sidebar.close()"></div>
 
 
 
 
140
  <!-- Left Sidebar (Header Icons, Quick Actions, Tabs, Chats, Tasks) -->
141
  <x-component path="sidebar/left-sidebar.html"></x-component>
142
-
143
  <!-- Right Panel (Message History and Input Section) -->
144
- <div id="right-panel" class="panel" :class="{'expanded': !$store.sidebar.isOpen}">
145
  <!-- Time and Date -->
146
  <div id="time-date-container">
147
  <div id="time-date"></div>
 
99
  <script type="module" src="index.js"></script>
100
 
101
  <!-- Bootstrap JS (only for logic, importing bundled CSS => UI conflicts) -->
102
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
103
+ integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
104
+ crossorigin="anonymous"></script>
105
 
106
  <!-- Then load Alpine.js -->
107
  <!-- <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> -->
 
135
  </script>
136
  </head>
137
 
138
+ <body class="dark-mode device-pointer" x-data>
139
  <div class="container">
140
  <!-- Sidebar Overlay -->
141
+ <template x-if="$store.sidebar">
142
+ <div id="sidebar-overlay" class="sidebar-overlay" x-data
143
+ :class="{'visible': $store.sidebar.isOpen && $store.sidebar.isMobile()}"
144
+ @click="$store.sidebar.close()"></div>
145
+ </template>
146
  <!-- Left Sidebar (Header Icons, Quick Actions, Tabs, Chats, Tasks) -->
147
  <x-component path="sidebar/left-sidebar.html"></x-component>
148
+
149
  <!-- Right Panel (Message History and Input Section) -->
150
+ <div id="right-panel" class="panel" >
151
  <!-- Time and Date -->
152
  <div id="time-date-container">
153
  <div id="time-date"></div>
webui/index.js CHANGED
@@ -21,9 +21,6 @@ globalThis.resetCounter = 0; // Used by stores and getChatBasedId
21
  let skipOneSpeech = false;
22
  let connectionStatus = undefined; // undefined = not checked yet, true = connected, false = disconnected
23
 
24
- export function getAutoScroll() {
25
- return autoScroll;
26
- }
27
 
28
  // Sidebar toggle logic is now handled by sidebar-store.js
29
 
@@ -175,7 +172,7 @@ setInterval(updateUserTime, 1000);
175
  function setMessage(id, type, heading, content, temp, kvps = null) {
176
  const result = msgs.setMessage(id, type, heading, content, temp, kvps);
177
  const chatHistoryEl = document.getElementById("chat-history");
178
- if (autoScroll && chatHistoryEl) {
179
  chatHistoryEl.scrollTop = chatHistoryEl.scrollHeight;
180
  }
181
  return result;
@@ -480,61 +477,6 @@ export const getChatBasedId = function (id) {
480
  return context + "-" + globalThis.resetCounter + "-" + id;
481
  };
482
 
483
- globalThis.toggleAutoScroll = async function (_autoScroll) {
484
- autoScroll = _autoScroll;
485
- };
486
-
487
- globalThis.toggleJson = async function (showJson) {
488
- css.toggleCssProperty(".msg-json", "display", showJson ? "block" : "none");
489
- };
490
-
491
- globalThis.toggleThoughts = async function (showThoughts) {
492
- css.toggleCssProperty(
493
- ".msg-thoughts",
494
- "display",
495
- showThoughts ? undefined : "none"
496
- );
497
- };
498
-
499
- globalThis.toggleUtils = async function (showUtils) {
500
- css.toggleCssProperty(
501
- ".message-util",
502
- "display",
503
- showUtils ? undefined : "none"
504
- );
505
- };
506
-
507
- globalThis.toggleDarkMode = function (isDark) {
508
- if (isDark) {
509
- document.body.classList.remove("light-mode");
510
- document.body.classList.add("dark-mode");
511
- } else {
512
- document.body.classList.remove("dark-mode");
513
- document.body.classList.add("light-mode");
514
- }
515
- console.log("Dark mode:", isDark);
516
- localStorage.setItem("darkMode", isDark);
517
- };
518
-
519
- globalThis.toggleSpeech = function (isOn) {
520
- console.log("Speech:", isOn);
521
- localStorage.setItem("speech", isOn);
522
- if (!isOn) speechStore.stopAudio();
523
- };
524
-
525
- globalThis.nudge = async function () {
526
- await inputStore.nudge();
527
- };
528
-
529
- globalThis.restart = async function () {
530
- await chatsStore.restart();
531
- };
532
-
533
- // Modify this part
534
- document.addEventListener("DOMContentLoaded", () => {
535
- const isDarkMode = localStorage.getItem("darkMode") !== "false";
536
- toggleDarkMode(isDarkMode);
537
- });
538
 
539
  globalThis.loadChats = async function () {
540
  await chatsStore.loadChats();
 
21
  let skipOneSpeech = false;
22
  let connectionStatus = undefined; // undefined = not checked yet, true = connected, false = disconnected
23
 
 
 
 
24
 
25
  // Sidebar toggle logic is now handled by sidebar-store.js
26
 
 
172
  function setMessage(id, type, heading, content, temp, kvps = null) {
173
  const result = msgs.setMessage(id, type, heading, content, temp, kvps);
174
  const chatHistoryEl = document.getElementById("chat-history");
175
+ if (preferencesStore.autoScroll && chatHistoryEl) {
176
  chatHistoryEl.scrollTop = chatHistoryEl.scrollHeight;
177
  }
178
  return result;
 
477
  return context + "-" + globalThis.resetCounter + "-" + id;
478
  };
479
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
 
481
  globalThis.loadChats = async function () {
482
  await chatsStore.loadChats();