solid-chat 0.0.5 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +20 -5
- package/index.html +144 -247
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -26,7 +26,7 @@ const MIME_TYPES = {
|
|
|
26
26
|
'.ttf': 'font/ttf'
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
let port = parseInt(process.argv[2]) || 3333
|
|
30
30
|
|
|
31
31
|
const server = createServer((req, res) => {
|
|
32
32
|
let filePath = join(ROOT, req.url === '/' ? 'index.html' : req.url)
|
|
@@ -61,9 +61,10 @@ const server = createServer((req, res) => {
|
|
|
61
61
|
}
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
function startServer(p) {
|
|
65
|
+
server.listen(p, () => {
|
|
66
|
+
const url = `http://localhost:${p}`
|
|
67
|
+
console.log(`
|
|
67
68
|
╭─────────────────────────────────────╮
|
|
68
69
|
│ │
|
|
69
70
|
│ Solid Chat running at: │
|
|
@@ -73,5 +74,19 @@ server.listen(port, () => {
|
|
|
73
74
|
│ │
|
|
74
75
|
╰─────────────────────────────────────╯
|
|
75
76
|
`)
|
|
76
|
-
|
|
77
|
+
open(url)
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
server.on('error', (err) => {
|
|
82
|
+
if (err.code === 'EADDRINUSE') {
|
|
83
|
+
console.log(`Port ${port} in use, trying ${port + 1}...`)
|
|
84
|
+
port++
|
|
85
|
+
startServer(port)
|
|
86
|
+
} else {
|
|
87
|
+
console.error('Server error:', err.message)
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
77
90
|
})
|
|
91
|
+
|
|
92
|
+
startServer(port)
|
package/index.html
CHANGED
|
@@ -28,244 +28,98 @@
|
|
|
28
28
|
<link rel="manifest" href="manifest.json">
|
|
29
29
|
|
|
30
30
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
31
|
-
<style>
|
|
32
|
-
:root {
|
|
33
|
-
--gradient-start: #667eea;
|
|
34
|
-
--gradient-end: #9f7aea;
|
|
35
|
-
--bg: #f7f8fc;
|
|
36
|
-
--text: #2d3748;
|
|
37
|
-
--text-muted: #a0aec0;
|
|
38
|
-
--accent: #805ad5;
|
|
39
|
-
}
|
|
40
31
|
|
|
32
|
+
<!-- Theme CSS - loaded dynamically -->
|
|
33
|
+
<link id="theme-css" rel="stylesheet" href="themes/wave.css">
|
|
34
|
+
|
|
35
|
+
<style>
|
|
36
|
+
/* Base styles that don't change between themes */
|
|
41
37
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
42
38
|
|
|
43
39
|
body {
|
|
44
40
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
45
41
|
background: var(--bg);
|
|
46
42
|
color: var(--text);
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.app-header {
|
|
51
|
-
background: linear-gradient(135deg, var(--gradient-start), var(--gradient-end));
|
|
52
|
-
color: white;
|
|
53
|
-
padding: 16px 24px;
|
|
54
|
-
box-shadow: 0 4px 20px rgba(102, 126, 234, 0.3);
|
|
55
|
-
display: flex;
|
|
56
|
-
align-items: center;
|
|
57
|
-
gap: 16px;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.app-header h1 {
|
|
61
|
-
font-size: 1.25rem;
|
|
62
|
-
font-weight: 600;
|
|
63
|
-
margin-bottom: 2px;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
.app-header p {
|
|
67
|
-
font-size: 0.8rem;
|
|
68
|
-
opacity: 0.9;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
.app-header button {
|
|
72
|
-
padding: 6px 14px;
|
|
73
|
-
background: rgba(255,255,255,0.2);
|
|
74
|
-
color: white;
|
|
75
|
-
border: 1px solid rgba(255,255,255,0.3);
|
|
76
|
-
border-radius: 6px;
|
|
77
|
-
font-size: 12px;
|
|
78
|
-
font-weight: 500;
|
|
79
|
-
cursor: pointer;
|
|
80
|
-
transition: background 0.2s;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
.app-header button:hover {
|
|
84
|
-
background: rgba(255,255,255,0.3);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.app-header input {
|
|
88
|
-
padding: 6px 10px;
|
|
89
|
-
border: 1px solid rgba(255,255,255,0.3);
|
|
90
|
-
border-radius: 6px;
|
|
91
|
-
font-size: 12px;
|
|
92
|
-
background: rgba(255,255,255,0.15);
|
|
93
|
-
color: white;
|
|
94
|
-
width: 140px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.app-header input::placeholder {
|
|
98
|
-
color: rgba(255,255,255,0.7);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
#chatContainer {
|
|
102
|
-
background: white;
|
|
103
|
-
overflow: hidden;
|
|
104
|
-
height: 100%;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.placeholder {
|
|
108
|
-
display: flex;
|
|
109
|
-
flex-direction: column;
|
|
110
|
-
align-items: center;
|
|
111
|
-
justify-content: center;
|
|
112
|
-
height: 100%;
|
|
113
|
-
color: var(--text-muted);
|
|
114
|
-
text-align: center;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.placeholder-icon {
|
|
118
|
-
font-size: 64px;
|
|
119
|
-
margin-bottom: 16px;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.placeholder h2 {
|
|
123
|
-
color: var(--text);
|
|
124
|
-
margin-bottom: 8px;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.loading-spinner {
|
|
128
|
-
width: 40px;
|
|
129
|
-
height: 40px;
|
|
130
|
-
border: 3px solid #e0e0e0;
|
|
131
|
-
border-top-color: var(--primary);
|
|
132
|
-
border-radius: 50%;
|
|
133
|
-
animation: spin 0.8s linear infinite;
|
|
134
|
-
margin-bottom: 16px;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
@keyframes spin {
|
|
138
|
-
to { transform: rotate(360deg); }
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
@keyframes fadeInUp {
|
|
142
|
-
from {
|
|
143
|
-
opacity: 0;
|
|
144
|
-
transform: translate(-50%, 20px);
|
|
145
|
-
}
|
|
146
|
-
to {
|
|
147
|
-
opacity: 1;
|
|
148
|
-
transform: translate(-50%, 0);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.error {
|
|
153
|
-
background: #fff3f3;
|
|
154
|
-
border: 1px solid #ffcdd2;
|
|
155
|
-
color: #c62828;
|
|
156
|
-
padding: 16px;
|
|
157
|
-
border-radius: 8px;
|
|
158
|
-
margin-top: 16px;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/* App layout with sidebar */
|
|
162
|
-
.app-layout {
|
|
163
|
-
display: flex;
|
|
164
|
-
height: calc(100vh - 68px);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
.sidebar {
|
|
168
|
-
width: 320px;
|
|
169
|
-
flex-shrink: 0;
|
|
170
|
-
height: 100%;
|
|
171
|
-
overflow: hidden;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
.main-content {
|
|
175
|
-
flex: 1;
|
|
43
|
+
height: 100vh;
|
|
176
44
|
overflow: hidden;
|
|
177
|
-
background: var(--bg);
|
|
178
|
-
height: 100%;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/* Mobile hamburger */
|
|
182
|
-
.mobile-menu-btn {
|
|
183
|
-
display: none;
|
|
184
|
-
width: 40px;
|
|
185
|
-
height: 40px;
|
|
186
|
-
background: rgba(255,255,255,0.2);
|
|
187
|
-
border: none;
|
|
188
|
-
border-radius: 8px;
|
|
189
|
-
color: white;
|
|
190
|
-
font-size: 24px;
|
|
191
|
-
cursor: pointer;
|
|
192
|
-
align-items: center;
|
|
193
|
-
justify-content: center;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
.sidebar-overlay {
|
|
197
|
-
display: none;
|
|
198
|
-
position: fixed;
|
|
199
|
-
top: 0;
|
|
200
|
-
left: 0;
|
|
201
|
-
right: 0;
|
|
202
|
-
bottom: 0;
|
|
203
|
-
background: rgba(0,0,0,0.5);
|
|
204
|
-
z-index: 99;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
@media (max-width: 768px) {
|
|
208
|
-
.mobile-menu-btn {
|
|
209
|
-
display: flex;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.sidebar {
|
|
213
|
-
position: fixed;
|
|
214
|
-
top: 0;
|
|
215
|
-
left: -320px;
|
|
216
|
-
height: 100vh;
|
|
217
|
-
z-index: 100;
|
|
218
|
-
transition: left 0.3s ease;
|
|
219
|
-
box-shadow: 4px 0 20px rgba(0,0,0,0.2);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
.sidebar.open {
|
|
223
|
-
left: 0;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
.sidebar-overlay.open {
|
|
227
|
-
display: block;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.app-layout {
|
|
231
|
-
height: calc(100vh - 68px);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
.main-content {
|
|
235
|
-
width: 100%;
|
|
236
|
-
}
|
|
237
45
|
}
|
|
238
46
|
</style>
|
|
239
47
|
</head>
|
|
240
48
|
<body>
|
|
241
49
|
|
|
242
|
-
<
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
<div id="headerLoginArea" style="margin-left: auto; display: flex; align-items: center; gap: 8px;">
|
|
249
|
-
<button id="soundToggle" title="Toggle notification sound" style="background: none; border: none; font-size: 18px; cursor: pointer; padding: 4px;">🔔</button>
|
|
250
|
-
<span id="userStatus" style="font-size: 13px; opacity: 0.9;">Loading...</span>
|
|
251
|
-
<span id="loginArea"></span>
|
|
50
|
+
<div class="app-wrapper">
|
|
51
|
+
<div class="app-banner">
|
|
52
|
+
<div class="brand">
|
|
53
|
+
<h1>Solid Chat</h1>
|
|
54
|
+
<p>Decentralized messaging</p>
|
|
55
|
+
</div>
|
|
252
56
|
</div>
|
|
253
|
-
</header>
|
|
254
57
|
|
|
255
|
-
<div class="sidebar-overlay" id="sidebarOverlay"></div>
|
|
58
|
+
<div class="sidebar-overlay" id="sidebarOverlay"></div>
|
|
59
|
+
|
|
60
|
+
<div class="app-container">
|
|
61
|
+
<!-- Left Panel - Chat List -->
|
|
62
|
+
<aside class="left-panel" id="leftPanel">
|
|
63
|
+
<div class="panel-header">
|
|
64
|
+
<div class="header-left">
|
|
65
|
+
<div class="user-avatar" id="userAvatar">S</div>
|
|
66
|
+
<div>
|
|
67
|
+
<div class="header-title">Solid Chat <span class="header-version" id="appVersion"></span></div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="header-actions">
|
|
71
|
+
<button class="icon-btn" id="soundToggle" title="Toggle notification sound">🔔</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
256
74
|
|
|
257
|
-
<div class="
|
|
258
|
-
<aside class="sidebar" id="sidebar"></aside>
|
|
75
|
+
<div class="sidebar" id="sidebar"></div>
|
|
259
76
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
77
|
+
<div class="sidebar-footer">
|
|
78
|
+
<select id="sidebarThemeSelect" class="sidebar-theme-select" title="Switch theme">
|
|
79
|
+
<option value="wave">Wave</option>
|
|
80
|
+
<option value="solid">Solid</option>
|
|
81
|
+
<option value="telegram">Telegram</option>
|
|
82
|
+
<option value="signal">Signal</option>
|
|
83
|
+
</select>
|
|
266
84
|
</div>
|
|
267
|
-
</
|
|
268
|
-
|
|
85
|
+
</aside>
|
|
86
|
+
|
|
87
|
+
<!-- Right Panel - Chat -->
|
|
88
|
+
<main class="right-panel">
|
|
89
|
+
<div class="content-header">
|
|
90
|
+
<div class="header-left">
|
|
91
|
+
<button class="mobile-menu-btn" id="mobileMenuBtn">☰</button>
|
|
92
|
+
<span id="userStatus" class="user-status">Loading...</span>
|
|
93
|
+
</div>
|
|
94
|
+
<div class="header-right" id="headerLoginArea">
|
|
95
|
+
<div class="theme-switcher">
|
|
96
|
+
<select id="themeSelect" title="Switch theme">
|
|
97
|
+
<option value="wave">Wave</option>
|
|
98
|
+
<option value="solid">Solid</option>
|
|
99
|
+
<option value="telegram">Telegram</option>
|
|
100
|
+
<option value="signal">Signal</option>
|
|
101
|
+
</select>
|
|
102
|
+
</div>
|
|
103
|
+
<span id="loginArea"></span>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div class="chat-area">
|
|
108
|
+
<div id="chatContainer">
|
|
109
|
+
<div class="placeholder" id="placeholder">
|
|
110
|
+
<div class="placeholder-icon">💬</div>
|
|
111
|
+
<h2>Welcome to Solid Chat</h2>
|
|
112
|
+
<p>Send and receive messages from your Solid POD.<br>Your data stays with you, always.<br><br>Select a chat from the sidebar or add a new one.</p>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</main>
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div class="status-badge" id="statusBadge">
|
|
121
|
+
<div class="status-dot"></div>
|
|
122
|
+
<span>Connected</span>
|
|
269
123
|
</div>
|
|
270
124
|
|
|
271
125
|
<!-- Load rdflib and Solid auth -->
|
|
@@ -276,6 +130,54 @@
|
|
|
276
130
|
import { longChatPane } from './src/longChatPane.js'
|
|
277
131
|
import { chatListPane, addChat, updateChatPreview } from './src/chatListPane.js'
|
|
278
132
|
|
|
133
|
+
// Theme management
|
|
134
|
+
const THEMES = {
|
|
135
|
+
wave: { name: 'Wave', file: 'themes/wave.css' },
|
|
136
|
+
solid: { name: 'Solid', file: 'themes/solid.css' },
|
|
137
|
+
telegram: { name: 'Telegram', file: 'themes/telegram.css' },
|
|
138
|
+
signal: { name: 'Signal', file: 'themes/signal.css' }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function loadTheme(themeName) {
|
|
142
|
+
const theme = THEMES[themeName] || THEMES.wave
|
|
143
|
+
const themeLink = document.getElementById('theme-css')
|
|
144
|
+
themeLink.href = theme.file
|
|
145
|
+
localStorage.setItem('solidchat-theme', themeName)
|
|
146
|
+
|
|
147
|
+
// Update selects
|
|
148
|
+
const select = document.getElementById('themeSelect')
|
|
149
|
+
if (select) select.value = themeName
|
|
150
|
+
const sidebarSelect = document.getElementById('sidebarThemeSelect')
|
|
151
|
+
if (sidebarSelect) sidebarSelect.value = themeName
|
|
152
|
+
|
|
153
|
+
// Update title based on theme
|
|
154
|
+
const titles = { wave: 'Wave', solid: 'Solid Chat', telegram: 'Telegram', signal: 'Signal' }
|
|
155
|
+
document.title = titles[themeName] || 'Solid Chat'
|
|
156
|
+
document.querySelector('.header-title').innerHTML = `${titles[themeName]} <span class="header-version" id="appVersion"></span>`
|
|
157
|
+
|
|
158
|
+
// Reload version
|
|
159
|
+
fetch('./package.json')
|
|
160
|
+
.then(r => r.json())
|
|
161
|
+
.then(pkg => {
|
|
162
|
+
const el = document.getElementById('appVersion')
|
|
163
|
+
if (el) el.textContent = `v${pkg.version}`
|
|
164
|
+
})
|
|
165
|
+
.catch(() => {})
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function initTheme() {
|
|
169
|
+
const saved = localStorage.getItem('solidchat-theme') || 'solid'
|
|
170
|
+
loadTheme(saved)
|
|
171
|
+
|
|
172
|
+
document.getElementById('themeSelect').addEventListener('change', (e) => {
|
|
173
|
+
loadTheme(e.target.value)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
document.getElementById('sidebarThemeSelect').addEventListener('change', (e) => {
|
|
177
|
+
loadTheme(e.target.value)
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
279
181
|
// Wait for libraries to be available
|
|
280
182
|
async function waitForLibraries() {
|
|
281
183
|
return new Promise((resolve) => {
|
|
@@ -299,17 +201,19 @@ const placeholder = document.getElementById('placeholder')
|
|
|
299
201
|
const userStatus = document.getElementById('userStatus')
|
|
300
202
|
const loginArea = document.getElementById('loginArea')
|
|
301
203
|
const sidebar = document.getElementById('sidebar')
|
|
204
|
+
const leftPanel = document.getElementById('leftPanel')
|
|
302
205
|
const mobileMenuBtn = document.getElementById('mobileMenuBtn')
|
|
303
206
|
const sidebarOverlay = document.getElementById('sidebarOverlay')
|
|
207
|
+
const statusBadge = document.getElementById('statusBadge')
|
|
304
208
|
|
|
305
209
|
// Mobile menu toggle
|
|
306
210
|
mobileMenuBtn.addEventListener('click', () => {
|
|
307
|
-
|
|
211
|
+
leftPanel.classList.toggle('open')
|
|
308
212
|
sidebarOverlay.classList.toggle('open')
|
|
309
213
|
})
|
|
310
214
|
|
|
311
215
|
sidebarOverlay.addEventListener('click', () => {
|
|
312
|
-
|
|
216
|
+
leftPanel.classList.remove('open')
|
|
313
217
|
sidebarOverlay.classList.remove('open')
|
|
314
218
|
})
|
|
315
219
|
|
|
@@ -341,14 +245,18 @@ async function handleAuthRedirect() {
|
|
|
341
245
|
function updateAuthUI(isLoggedIn) {
|
|
342
246
|
if (isLoggedIn && currentWebId) {
|
|
343
247
|
const shortId = currentWebId.split('//')[1]?.split('/')[0] || currentWebId
|
|
344
|
-
userStatus.innerHTML = `Logged in as <
|
|
345
|
-
loginArea.innerHTML = `<button id="logoutBtn">Logout</button>`
|
|
248
|
+
userStatus.innerHTML = `Logged in as <a href="${currentWebId}" target="_blank">${shortId}</a>`
|
|
249
|
+
loginArea.innerHTML = `<button class="btn btn-secondary" id="logoutBtn">Logout</button>`
|
|
346
250
|
document.getElementById('logoutBtn').addEventListener('click', handleLogout)
|
|
251
|
+
|
|
252
|
+
// Update avatar with user initial
|
|
253
|
+
const initial = shortId.charAt(0).toUpperCase()
|
|
254
|
+
document.getElementById('userAvatar').textContent = initial
|
|
347
255
|
} else {
|
|
348
256
|
userStatus.textContent = 'Not logged in'
|
|
349
257
|
loginArea.innerHTML = `
|
|
350
|
-
<input type="text" id="idpInput" placeholder="e.g. solidweb.org"
|
|
351
|
-
<button id="loginBtn">Login</button>
|
|
258
|
+
<input type="text" class="input-field" id="idpInput" placeholder="e.g. solidweb.org">
|
|
259
|
+
<button class="btn btn-primary" id="loginBtn">Login</button>
|
|
352
260
|
`
|
|
353
261
|
document.getElementById('loginBtn').addEventListener('click', handleLogin)
|
|
354
262
|
document.getElementById('idpInput').addEventListener('keydown', (e) => {
|
|
@@ -706,7 +614,7 @@ async function loadChat(uri) {
|
|
|
706
614
|
}
|
|
707
615
|
|
|
708
616
|
// Close mobile sidebar if open
|
|
709
|
-
|
|
617
|
+
leftPanel.classList.remove('open')
|
|
710
618
|
sidebarOverlay.classList.remove('open')
|
|
711
619
|
|
|
712
620
|
chatContainer.innerHTML = `
|
|
@@ -989,19 +897,6 @@ function showToast(message) {
|
|
|
989
897
|
const toast = document.createElement('div')
|
|
990
898
|
toast.className = 'toast'
|
|
991
899
|
toast.textContent = message
|
|
992
|
-
toast.style.cssText = `
|
|
993
|
-
position: fixed;
|
|
994
|
-
bottom: 24px;
|
|
995
|
-
left: 50%;
|
|
996
|
-
transform: translateX(-50%);
|
|
997
|
-
background: #1e1e2e;
|
|
998
|
-
color: white;
|
|
999
|
-
padding: 12px 24px;
|
|
1000
|
-
border-radius: 8px;
|
|
1001
|
-
font-size: 14px;
|
|
1002
|
-
z-index: 9999;
|
|
1003
|
-
animation: fadeInUp 0.3s ease;
|
|
1004
|
-
`
|
|
1005
900
|
document.body.appendChild(toast)
|
|
1006
901
|
|
|
1007
902
|
setTimeout(() => {
|
|
@@ -1016,13 +911,8 @@ window.solidChat = { createChat, copyShareLink, getMyPodRoot }
|
|
|
1016
911
|
|
|
1017
912
|
// Initialize: handle auth redirect first, then render sidebar
|
|
1018
913
|
async function init() {
|
|
1019
|
-
//
|
|
1020
|
-
|
|
1021
|
-
.then(r => r.json())
|
|
1022
|
-
.then(pkg => {
|
|
1023
|
-
document.getElementById('appVersion').textContent = `v${pkg.version}`
|
|
1024
|
-
})
|
|
1025
|
-
.catch(() => {})
|
|
914
|
+
// Initialize theme
|
|
915
|
+
initTheme()
|
|
1026
916
|
|
|
1027
917
|
// Set initial sound button state
|
|
1028
918
|
updateSoundButton()
|
|
@@ -1047,6 +937,13 @@ async function init() {
|
|
|
1047
937
|
})
|
|
1048
938
|
sidebar.appendChild(sidebarElement)
|
|
1049
939
|
|
|
940
|
+
// Move theme selector above Discover Chats button
|
|
941
|
+
const discoverBtn = sidebar.querySelector('.discover-btn')
|
|
942
|
+
const themeSelect = document.getElementById('sidebarThemeSelect')
|
|
943
|
+
if (discoverBtn && themeSelect) {
|
|
944
|
+
discoverBtn.parentNode.insertBefore(themeSelect.parentNode, discoverBtn)
|
|
945
|
+
}
|
|
946
|
+
|
|
1050
947
|
// Check for ?chat= deep link first, then ?uri= (legacy), then default
|
|
1051
948
|
const deepLinkedChat = await handleDeepLink()
|
|
1052
949
|
if (deepLinkedChat) {
|