levix-bot 2.1.1 → 2.2.0

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.
@@ -9,89 +9,287 @@
9
9
  <link rel="apple-touch-icon" href="/brand/apple-touch-icon.png" />
10
10
  <link rel="stylesheet" href="/dashboard.css" />
11
11
  </head>
12
- <body>
12
+ <body class="dashboard-page">
13
13
  <div class="shell">
14
14
  <aside class="sidebar" id="sidebar">
15
- <div class="brand">
15
+ <a
16
+ class="brand"
17
+ href="#overview"
18
+ aria-label="<%= brand.name %> overview"
19
+ >
16
20
  <img src="/brand/mark.svg" alt="" />
17
- <div>
21
+ <div class="brand-copy">
18
22
  <div class="brand-name"><%= brand.name %></div>
19
- <div class="brand-tag"><%= brand.tagline %></div>
23
+ <div class="brand-tag">Private control room</div>
20
24
  </div>
21
- </div>
25
+ <span class="brand-pulse" aria-hidden="true"
26
+ ><i></i><i></i><i></i
27
+ ></span>
28
+ </a>
22
29
 
23
- <nav class="nav">
30
+ <nav class="nav" aria-label="Primary navigation">
24
31
  <a href="#overview" data-view="overview">
25
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
32
+ <svg
33
+ viewBox="0 0 24 24"
34
+ fill="none"
35
+ stroke="currentColor"
36
+ stroke-width="2"
37
+ >
38
+ <rect x="3" y="3" width="7" height="7" rx="1" />
39
+ <rect x="14" y="3" width="7" height="7" rx="1" />
40
+ <rect x="3" y="14" width="7" height="7" rx="1" />
41
+ <rect x="14" y="14" width="7" height="7" rx="1" />
42
+ </svg>
26
43
  Overview
27
44
  </a>
28
45
  <a href="#connection" data-view="connection">
29
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 20a8 8 0 1 0-7-4l-1 4 4-1a8 8 0 0 0 4 1z"/></svg>
46
+ <svg
47
+ viewBox="0 0 24 24"
48
+ fill="none"
49
+ stroke="currentColor"
50
+ stroke-width="2"
51
+ >
52
+ <path d="M12 20a8 8 0 1 0-7-4l-1 4 4-1a8 8 0 0 0 4 1z" />
53
+ </svg>
30
54
  Connection
31
55
  </a>
32
56
 
33
57
  <div class="nav-label">Control</div>
34
58
  <a href="#commands" data-view="commands">
35
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
59
+ <svg
60
+ viewBox="0 0 24 24"
61
+ fill="none"
62
+ stroke="currentColor"
63
+ stroke-width="2"
64
+ >
65
+ <polyline points="4 17 10 11 4 5" />
66
+ <line x1="12" y1="19" x2="20" y2="19" />
67
+ </svg>
36
68
  Commands
37
69
  </a>
38
70
  <a href="#ai" data-view="ai">
39
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v3M12 18v3M3 12h3M18 12h3"/><circle cx="12" cy="12" r="4"/></svg>
71
+ <svg
72
+ viewBox="0 0 24 24"
73
+ fill="none"
74
+ stroke="currentColor"
75
+ stroke-width="2"
76
+ >
77
+ <path d="M12 3v3M12 18v3M3 12h3M18 12h3" />
78
+ <circle cx="12" cy="12" r="4" />
79
+ </svg>
40
80
  AI &amp; memory
41
81
  </a>
42
82
  <a href="#groups" data-view="groups">
43
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="9" cy="8" r="3"/><circle cx="17" cy="9" r="2.5"/><path d="M3 19a6 6 0 0 1 12 0M15 19a5 5 0 0 1 6-4"/></svg>
83
+ <svg
84
+ viewBox="0 0 24 24"
85
+ fill="none"
86
+ stroke="currentColor"
87
+ stroke-width="2"
88
+ >
89
+ <circle cx="9" cy="8" r="3" />
90
+ <circle cx="17" cy="9" r="2.5" />
91
+ <path d="M3 19a6 6 0 0 1 12 0M15 19a5 5 0 0 1 6-4" />
92
+ </svg>
44
93
  Groups
45
94
  </a>
46
95
  <a href="#roles" data-view="roles">
47
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3l7 4v5c0 4-3 7-7 9-4-2-7-5-7-9V7z"/></svg>
96
+ <svg
97
+ viewBox="0 0 24 24"
98
+ fill="none"
99
+ stroke="currentColor"
100
+ stroke-width="2"
101
+ >
102
+ <path d="M12 3l7 4v5c0 4-3 7-7 9-4-2-7-5-7-9V7z" />
103
+ </svg>
48
104
  Roles
49
105
  </a>
50
106
 
51
107
  <div class="nav-label">Data</div>
52
108
  <a href="#data" data-view="data">
53
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="6" rx="8" ry="3"/><path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6"/><path d="M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3"/></svg>
109
+ <svg
110
+ viewBox="0 0 24 24"
111
+ fill="none"
112
+ stroke="currentColor"
113
+ stroke-width="2"
114
+ >
115
+ <ellipse cx="12" cy="6" rx="8" ry="3" />
116
+ <path d="M4 6v12c0 1.7 3.6 3 8 3s8-1.3 8-3V6" />
117
+ <path d="M4 12c0 1.7 3.6 3 8 3s8-1.3 8-3" />
118
+ </svg>
54
119
  Tables
55
120
  </a>
56
121
  <a href="#settings" data-view="settings">
57
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19 12a7 7 0 0 0-.1-1l2-1.5-2-3.4-2.3 1a7 7 0 0 0-1.7-1L14.5 3h-4l-.4 2.6a7 7 0 0 0-1.7 1l-2.3-1-2 3.4L6 11a7 7 0 0 0 0 2l-2 1.5 2 3.4 2.3-1a7 7 0 0 0 1.7 1l.4 2.6h4l.4-2.6a7 7 0 0 0 1.7-1l2.3 1 2-3.4-2-1.5c.1-.3.1-.7.1-1z"/></svg>
122
+ <svg
123
+ viewBox="0 0 24 24"
124
+ fill="none"
125
+ stroke="currentColor"
126
+ stroke-width="2"
127
+ >
128
+ <circle cx="12" cy="12" r="3" />
129
+ <path
130
+ d="M19 12a7 7 0 0 0-.1-1l2-1.5-2-3.4-2.3 1a7 7 0 0 0-1.7-1L14.5 3h-4l-.4 2.6a7 7 0 0 0-1.7 1l-2.3-1-2 3.4L6 11a7 7 0 0 0 0 2l-2 1.5 2 3.4 2.3-1a7 7 0 0 0 1.7 1l.4 2.6h4l.4-2.6a7 7 0 0 0 1.7-1l2.3 1 2-3.4-2-1.5c.1-.3.1-.7.1-1z"
131
+ />
132
+ </svg>
58
133
  Settings
59
134
  </a>
60
135
  </nav>
61
136
 
62
137
  <div class="sidebar-foot">
63
- <%= brand.name %> · built by <%= brand.developer %><br />
64
- <a href="<%= brand.repo %>" target="_blank" rel="noopener noreferrer">Source &amp; docs</a>
138
+ <div class="local-note">
139
+ <span class="local-note-icon" aria-hidden="true"></span>
140
+ <span
141
+ ><strong>Self-hosted</strong>Your workspace, on your server.</span
142
+ >
143
+ </div>
144
+ <div class="sidebar-credit flex">
145
+ <div class="c1">
146
+ &copy; <%= brand.copyrightYear %>
147
+ <a href="<%= brand.developerSite %>"><%= brand.developer %></a>
148
+ (<a href="<%= brand.studioSite %>"><%= brand.studio %></a>)
149
+ </div>
150
+ <a
151
+ href="<%= brand.repo %>"
152
+ target="_blank"
153
+ rel="noopener noreferrer"
154
+ >Source &amp; docs ↗</a
155
+ >
156
+ </div>
65
157
  </div>
66
158
  </aside>
67
159
 
68
- <button class="sidebar-backdrop" id="sidebar-backdrop" type="button" aria-label="Close navigation"></button>
160
+ <button
161
+ class="sidebar-backdrop"
162
+ id="sidebar-backdrop"
163
+ type="button"
164
+ aria-label="Close navigation"
165
+ ></button>
69
166
 
70
167
  <div class="main">
71
168
  <header class="topbar">
72
- <button class="btn btn-icon menu-btn" id="menu-btn" type="button" aria-label="Open navigation" aria-controls="sidebar" aria-expanded="false">☰</button>
73
- <h1 id="page-title">Overview</h1>
169
+ <button
170
+ class="btn btn-icon menu-btn"
171
+ id="menu-btn"
172
+ type="button"
173
+ aria-label="Open navigation"
174
+ aria-controls="sidebar"
175
+ aria-expanded="false"
176
+ >
177
+ <svg viewBox="0 0 24 24" aria-hidden="true">
178
+ <path d="M4 7h16M4 12h16M4 17h16" />
179
+ </svg>
180
+ </button>
181
+ <div class="page-heading">
182
+ <span>Levix workspace</span>
183
+ <h1 id="page-title">Overview</h1>
184
+ </div>
74
185
  <div class="spacer"></div>
75
- <span class="pill" id="status-pill"><span class="dot"></span>Checking…</span>
76
- <button class="btn btn-icon" id="refresh-btn" type="button" aria-label="Refresh current view">⟳</button>
77
- <button class="btn btn-icon" id="theme-btn" type="button" aria-label="Switch color theme">☀</button>
78
- <form action="/logout" method="post">
79
- <button type="submit" class="btn btn-sm">Log out</button>
80
- </form>
186
+ <div class="topbar-actions">
187
+ <span class="pill" id="status-pill"
188
+ ><span class="dot"></span>Checking…</span
189
+ >
190
+ <div class="icon-cluster">
191
+ <button
192
+ class="btn btn-icon"
193
+ id="refresh-btn"
194
+ type="button"
195
+ aria-label="Refresh current view"
196
+ title="Refresh current view"
197
+ >
198
+ <svg viewBox="0 0 24 24" aria-hidden="true">
199
+ <path d="M20 11a8 8 0 1 0-2.34 5.66M20 4v7h-7" />
200
+ </svg>
201
+ </button>
202
+ <button
203
+ class="btn btn-icon theme-toggle"
204
+ id="theme-btn"
205
+ type="button"
206
+ aria-label="Switch color theme"
207
+ title="Switch color theme"
208
+ >
209
+ <svg class="sun-icon" viewBox="0 0 24 24" aria-hidden="true">
210
+ <circle cx="12" cy="12" r="3.5" />
211
+ <path
212
+ d="M12 2v2M12 20v2M4.93 4.93l1.42 1.42M17.65 17.65l1.42 1.42M2 12h2M20 12h2M4.93 19.07l1.42-1.42M17.65 6.35l1.42-1.42"
213
+ />
214
+ </svg>
215
+ <svg class="moon-icon" viewBox="0 0 24 24" aria-hidden="true">
216
+ <path
217
+ d="M20 15.4A8.5 8.5 0 0 1 8.6 4a8.5 8.5 0 1 0 11.4 11.4z"
218
+ />
219
+ </svg>
220
+ </button>
221
+ </div>
222
+ <form action="/logout" method="post" class="logout-form">
223
+ <button type="submit" class="btn btn-sm logout-btn">
224
+ <span>Log out</span>
225
+ <svg viewBox="0 0 24 24" aria-hidden="true">
226
+ <path
227
+ d="M10 17l5-5-5-5M15 12H3M14 3h5a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-5"
228
+ />
229
+ </svg>
230
+ </button>
231
+ </form>
232
+ </div>
81
233
  </header>
82
234
 
83
235
  <main class="content">
84
236
  <!-- Overview ---------------------------------------------------->
85
237
  <section class="view" id="view-overview">
86
- <div class="section-head">
87
- <h2>Overview</h2>
88
- <p>What the bot is doing right now.</p>
238
+ <div class="overview-hero">
239
+ <div class="hero-copy">
240
+ <span class="eyebrow">Personal assistant operations</span>
241
+ <h2>Your conversations,<br /><em>under one calm roof.</em></h2>
242
+ <p>
243
+ Watch the live connection, shape how Levix responds, and
244
+ manage the details that keep every chat moving.
245
+ </p>
246
+ <div class="hero-actions">
247
+ <a class="btn btn-primary" href="#connection">
248
+ Manage connection
249
+ <svg viewBox="0 0 24 24" aria-hidden="true">
250
+ <path d="M5 12h14M13 6l6 6-6 6" />
251
+ </svg>
252
+ </a>
253
+ <a class="text-link" href="#settings"
254
+ >Tune workspace <span aria-hidden="true">↗</span></a
255
+ >
256
+ </div>
257
+ </div>
258
+ <div class="signal-stage" aria-hidden="true">
259
+ <div class="signal-orbit orbit-one"></div>
260
+ <div class="signal-orbit orbit-two"></div>
261
+ <div class="signal-core">
262
+ <img src="/brand/mark.svg" alt="" />
263
+ </div>
264
+ <span class="signal-node node-one"></span>
265
+ <span class="signal-node node-two"></span>
266
+ <span class="signal-node node-three"></span>
267
+ <div class="signal-label">
268
+ <span>Always within reach</span
269
+ ><strong>One private workspace</strong>
270
+ </div>
271
+ </div>
272
+ </div>
273
+
274
+ <div class="section-head section-head-split">
275
+ <div>
276
+ <span class="eyebrow">Workspace pulse</span>
277
+ <h2>At a glance</h2>
278
+ <p>The essentials from your running assistant.</p>
279
+ </div>
280
+ <span class="section-note">Refreshes every 15 seconds</span>
89
281
  </div>
90
282
 
91
283
  <div class="stats" id="stat-cards"></div>
92
284
 
93
- <div class="card">
94
- <div class="card-head"><h2>Runtime</h2></div>
285
+ <div class="card runtime-card">
286
+ <div class="card-head">
287
+ <div>
288
+ <span class="eyebrow">Runtime</span>
289
+ <h2>System signals</h2>
290
+ </div>
291
+ <span class="source">Current process</span>
292
+ </div>
95
293
  <div class="grid-2" id="overview-info"></div>
96
294
  </div>
97
295
  </section>
@@ -99,35 +297,56 @@
99
297
  <!-- Connection -------------------------------------------------->
100
298
  <section class="view" id="view-connection">
101
299
  <div class="section-head">
300
+ <span class="eyebrow">Live link</span>
102
301
  <h2>Connection</h2>
103
- <p>Start or stop the WhatsApp session, and link or unlink an account.</p>
302
+ <p>
303
+ Start or stop the WhatsApp session, and link or unlink an
304
+ account.
305
+ </p>
104
306
  </div>
105
307
 
106
- <div class="card">
308
+ <div class="card session-card">
107
309
  <div class="card-head">
108
- <h2>Session</h2>
310
+ <div>
311
+ <span class="eyebrow">WhatsApp</span>
312
+ <h2>Session</h2>
313
+ </div>
109
314
  <div class="spacer"></div>
110
315
  <span id="conn-state"></span>
111
316
  </div>
112
317
 
113
- <div class="hint" id="conn-detail"></div>
318
+ <div class="hint session-detail" id="conn-detail"></div>
114
319
 
115
320
  <div class="hint" id="conn-proxy"></div>
116
321
 
117
- <div class="inline" style="margin-top:12px">
118
- <button class="btn btn-primary" id="start-btn">Start session</button>
119
- <button class="btn" id="reconnect-btn">Reconnect to apply</button>
120
- <button class="btn" id="stop-btn">Stop session</button>
121
- <button class="btn btn-danger" id="unlink-btn">Unlink account</button>
122
- <button class="btn" id="restart-btn">Restart bot</button>
322
+ <div class="inline action-cluster">
323
+ <button class="btn btn-primary" id="start-btn" type="button">
324
+ Start session
325
+ </button>
326
+ <button class="btn" id="reconnect-btn" type="button">
327
+ Reconnect to apply
328
+ </button>
329
+ <button class="btn" id="stop-btn" type="button">
330
+ Stop session
331
+ </button>
332
+ <button class="btn btn-danger" id="unlink-btn" type="button">
333
+ Unlink account
334
+ </button>
335
+ <button class="btn" id="restart-btn" type="button">
336
+ Restart bot
337
+ </button>
123
338
  </div>
124
- <div class="hint" style="margin-top:8px">
125
- Levix runs whether or not WhatsApp is connected. Starting the session is
126
- the only thing that opens a connection; restart only comes back on its own
127
- under a supervisor (pm2, systemd, Docker).
339
+ <div class="callout">
340
+ <span class="callout-icon" aria-hidden="true">i</span>
341
+ <p>
342
+ Levix runs whether or not WhatsApp is connected. Starting the
343
+ session is the only thing that opens a connection; restart
344
+ only comes back on its own under a supervisor (pm2, systemd,
345
+ Docker).
346
+ </p>
128
347
  </div>
129
348
 
130
- <div id="qr-panel" style="display:none">
349
+ <div id="qr-panel" style="display: none">
131
350
  <div class="qr-box">
132
351
  <div class="qr-frame" id="qr-frame"></div>
133
352
  <div class="hint" id="qr-note">Waiting for a QR code…</div>
@@ -144,28 +363,48 @@
144
363
  <!-- Commands ---------------------------------------------------->
145
364
  <section class="view" id="view-commands">
146
365
  <div class="section-head">
366
+ <span class="eyebrow">Behavior</span>
147
367
  <h2>Commands</h2>
148
- <p>Rename triggers, change who may run what, switch commands off.</p>
368
+ <p>
369
+ Rename triggers, change who may run what, switch commands off.
370
+ </p>
149
371
  </div>
150
372
 
151
- <div class="card">
373
+ <div class="card compact-card">
152
374
  <div class="card-head"><h2>Prefix</h2></div>
153
- <div class="inline">
154
- <input type="text" id="prefix-input" maxlength="3" style="max-width:90px" />
155
- <button class="btn btn-primary" id="prefix-save">Save</button>
156
- <span class="hint">The character every command starts with, e.g. <code>!ping</code>.</span>
375
+ <div class="inline prefix-control">
376
+ <label class="sr-only" for="prefix-input">Command prefix</label>
377
+ <input type="text" id="prefix-input" maxlength="3" />
378
+ <button class="btn btn-primary" id="prefix-save" type="button">
379
+ Save prefix
380
+ </button>
381
+ <span class="hint"
382
+ >The character every command starts with, e.g.
383
+ <code>!ping</code>.</span
384
+ >
157
385
  </div>
158
386
  </div>
159
387
 
160
388
  <div class="card">
161
389
  <div class="toolbar">
162
- <input type="text" id="cmd-search" placeholder="Search commands…" />
163
- <select id="cmd-filter">
390
+ <label class="search-field">
391
+ <span class="sr-only">Search commands</span>
392
+ <svg viewBox="0 0 24 24" aria-hidden="true">
393
+ <circle cx="11" cy="11" r="7" />
394
+ <path d="m20 20-4-4" />
395
+ </svg>
396
+ <input
397
+ type="text"
398
+ id="cmd-search"
399
+ placeholder="Search commands…"
400
+ />
401
+ </label>
402
+ <select id="cmd-filter" aria-label="Filter commands by type">
164
403
  <option value="all">All commands</option>
165
404
  <option value="general">General</option>
166
405
  <option value="group">Group</option>
167
406
  </select>
168
- <div class="spacer" style="flex:1"></div>
407
+ <div class="spacer" style="flex: 1"></div>
169
408
  <span class="hint">Changes apply to the next message.</span>
170
409
  </div>
171
410
 
@@ -181,7 +420,9 @@
181
420
  </tr>
182
421
  </thead>
183
422
  <tbody id="cmd-body">
184
- <tr><td colspan="5"><div class="loading">Loading…</div></td></tr>
423
+ <tr>
424
+ <td colspan="5"><div class="loading">Loading…</div></td>
425
+ </tr>
185
426
  </tbody>
186
427
  </table>
187
428
  </div>
@@ -191,20 +432,30 @@
191
432
  <!-- AI ---------------------------------------------------------->
192
433
  <section class="view" id="view-ai">
193
434
  <div class="section-head">
435
+ <span class="eyebrow">Intelligence</span>
194
436
  <h2>AI &amp; memory</h2>
195
- <p>The prompt the model gets, and everything it has been told to remember.</p>
437
+ <p>
438
+ The prompt the model gets, and everything it has been told to
439
+ remember.
440
+ </p>
196
441
  </div>
197
442
 
198
443
  <div class="card">
199
444
  <div class="card-head">
200
445
  <h2>System prompt</h2>
201
446
  <div class="spacer"></div>
202
- <span class="hint"><code id="persona-file">ai-persona.md</code></span>
447
+ <span class="hint"
448
+ ><code id="persona-file">ai-persona.md</code></span
449
+ >
203
450
  </div>
204
451
  <textarea id="persona-body" spellcheck="false"></textarea>
205
- <div class="inline" style="margin-top:12px">
206
- <button class="btn btn-primary" id="persona-save">Save prompt</button>
207
- <span class="hint">Applies to the next message — no restart.</span>
452
+ <div class="inline form-actions">
453
+ <button class="btn btn-primary" id="persona-save" type="button">
454
+ Save prompt
455
+ </button>
456
+ <span class="hint"
457
+ >Applies to the next message — no restart.</span
458
+ >
208
459
  </div>
209
460
  </div>
210
461
 
@@ -212,15 +463,34 @@
212
463
  <div class="card-head"><h2>Long-term memory</h2></div>
213
464
  <div class="inline" id="memory-list"></div>
214
465
 
215
- <div id="memory-editor" style="display:none;margin-top:16px">
466
+ <div
467
+ id="memory-editor"
468
+ class="memory-editor"
469
+ style="display: none"
470
+ >
216
471
  <div class="card-head">
217
472
  <h2>Editing <code id="memory-scope"></code></h2>
218
473
  </div>
219
474
  <textarea id="memory-content" spellcheck="false"></textarea>
220
- <div class="inline" style="margin-top:12px">
221
- <button class="btn btn-primary" id="memory-save">Save</button>
222
- <button class="btn btn-danger" id="memory-delete">Delete file</button>
223
- <span class="hint">Plain Markdown — a line starting with <code>-</code> is one memory.</span>
475
+ <div class="inline form-actions">
476
+ <button
477
+ class="btn btn-primary"
478
+ id="memory-save"
479
+ type="button"
480
+ >
481
+ Save memory
482
+ </button>
483
+ <button
484
+ class="btn btn-danger"
485
+ id="memory-delete"
486
+ type="button"
487
+ >
488
+ Delete file
489
+ </button>
490
+ <span class="hint"
491
+ >Plain Markdown — a line starting with <code>-</code> is one
492
+ memory.</span
493
+ >
224
494
  </div>
225
495
  </div>
226
496
  </div>
@@ -229,8 +499,12 @@
229
499
  <!-- Groups ------------------------------------------------------>
230
500
  <section class="view" id="view-groups">
231
501
  <div class="section-head">
502
+ <span class="eyebrow">Moderation</span>
232
503
  <h2>Groups</h2>
233
- <p>Moderation settings per group. Same values the <code>!group</code> commands change.</p>
504
+ <p>
505
+ Moderation settings per group. Same values the
506
+ <code>!group</code> commands change.
507
+ </p>
234
508
  </div>
235
509
  <div id="groups-list"><div class="loading">Loading…</div></div>
236
510
  </section>
@@ -238,19 +512,32 @@
238
512
  <!-- Roles ------------------------------------------------------->
239
513
  <section class="view" id="view-roles">
240
514
  <div class="section-head">
515
+ <span class="eyebrow">Access</span>
241
516
  <h2>Roles</h2>
242
- <p>Bot-level roles. An owner can do everything; an admin counts as an admin in every chat.</p>
517
+ <p>
518
+ Bot-level roles. An owner can do everything; an admin counts as
519
+ an admin in every chat.
520
+ </p>
243
521
  </div>
244
522
 
245
523
  <div class="card">
246
524
  <div class="card-head"><h2>Add someone</h2></div>
247
- <div class="inline">
248
- <input type="text" id="role-number" placeholder="201234567890" style="max-width:220px" />
249
- <select id="role-kind" style="max-width:140px">
525
+ <div class="inline role-control">
526
+ <label class="sr-only" for="role-number">Phone number</label>
527
+ <input
528
+ type="text"
529
+ id="role-number"
530
+ placeholder="201234567890"
531
+ inputmode="numeric"
532
+ />
533
+ <label class="sr-only" for="role-kind">Role</label>
534
+ <select id="role-kind">
250
535
  <option value="admin">Admin</option>
251
536
  <option value="owner">Owner</option>
252
537
  </select>
253
- <button class="btn btn-primary" id="role-add">Add</button>
538
+ <button class="btn btn-primary" id="role-add" type="button">
539
+ Add person
540
+ </button>
254
541
  <span class="hint">International format, digits only.</span>
255
542
  </div>
256
543
  </div>
@@ -259,7 +546,13 @@
259
546
  <div class="card-head"><h2>Owners</h2></div>
260
547
  <div class="table-wrap">
261
548
  <table>
262
- <thead><tr><th>Number</th><th>Name</th><th></th></tr></thead>
549
+ <thead>
550
+ <tr>
551
+ <th>Number</th>
552
+ <th>Name</th>
553
+ <th></th>
554
+ </tr>
555
+ </thead>
263
556
  <tbody id="owners-body"></tbody>
264
557
  </table>
265
558
  </div>
@@ -269,7 +562,13 @@
269
562
  <div class="card-head"><h2>Admins</h2></div>
270
563
  <div class="table-wrap">
271
564
  <table>
272
- <thead><tr><th>Number</th><th>Name</th><th></th></tr></thead>
565
+ <thead>
566
+ <tr>
567
+ <th>Number</th>
568
+ <th>Name</th>
569
+ <th></th>
570
+ </tr>
571
+ </thead>
273
572
  <tbody id="admins-body"></tbody>
274
573
  </table>
275
574
  </div>
@@ -279,18 +578,75 @@
279
578
  <!-- Data -------------------------------------------------------->
280
579
  <section class="view" id="view-data">
281
580
  <div class="section-head">
581
+ <span class="eyebrow">Stored records</span>
282
582
  <h2>Tables</h2>
283
- <p>What the bot has stored: debts, warnings, notes, todo lists, known users.</p>
583
+ <p>
584
+ What the bot has stored: debts, warnings, notes, todo lists,
585
+ known users.
586
+ </p>
284
587
  </div>
285
588
 
286
589
  <div class="card">
287
- <div class="toolbar" id="data-tabs">
288
- <button class="btn btn-sm btn-primary" data-table="debts">Debts</button>
289
- <button class="btn btn-sm" data-table="warnings">Warnings</button>
290
- <button class="btn btn-sm" data-table="notes">Notes</button>
291
- <button class="btn btn-sm" data-table="todos">Todos</button>
292
- <button class="btn btn-sm" data-table="users">Users</button>
293
- <button class="btn btn-sm" data-table="schedules">Schedules</button>
590
+ <div
591
+ class="toolbar data-tabs"
592
+ id="data-tabs"
593
+ role="tablist"
594
+ aria-label="Stored data tables"
595
+ >
596
+ <button
597
+ class="btn btn-sm btn-primary"
598
+ data-table="debts"
599
+ type="button"
600
+ role="tab"
601
+ aria-selected="true"
602
+ >
603
+ Debts
604
+ </button>
605
+ <button
606
+ class="btn btn-sm"
607
+ data-table="warnings"
608
+ type="button"
609
+ role="tab"
610
+ aria-selected="false"
611
+ >
612
+ Warnings
613
+ </button>
614
+ <button
615
+ class="btn btn-sm"
616
+ data-table="notes"
617
+ type="button"
618
+ role="tab"
619
+ aria-selected="false"
620
+ >
621
+ Notes
622
+ </button>
623
+ <button
624
+ class="btn btn-sm"
625
+ data-table="todos"
626
+ type="button"
627
+ role="tab"
628
+ aria-selected="false"
629
+ >
630
+ Todos
631
+ </button>
632
+ <button
633
+ class="btn btn-sm"
634
+ data-table="users"
635
+ type="button"
636
+ role="tab"
637
+ aria-selected="false"
638
+ >
639
+ Users
640
+ </button>
641
+ <button
642
+ class="btn btn-sm"
643
+ data-table="schedules"
644
+ type="button"
645
+ role="tab"
646
+ aria-selected="false"
647
+ >
648
+ Schedules
649
+ </button>
294
650
  </div>
295
651
  <div id="data-table"><div class="loading">Loading…</div></div>
296
652
  </div>
@@ -299,27 +655,41 @@
299
655
  <!-- Settings ---------------------------------------------------->
300
656
  <section class="view" id="view-settings">
301
657
  <div class="section-head">
658
+ <span class="eyebrow">Workspace</span>
302
659
  <h2>Settings</h2>
303
660
  <p>
304
- This page is the only place the bot is configured — there is no config file.
305
- Clear a field to go back to its default.
661
+ This page is the only place the bot is configured — there is no
662
+ config file. Clear a field to go back to its default.
306
663
  </p>
307
664
  </div>
308
665
 
309
- <div class="card">
666
+ <div class="card security-card">
310
667
  <div class="card-head"><h2>Control panel password</h2></div>
311
- <div class="inline" style="margin-bottom:8px">
312
- <input type="password" id="pw-current" placeholder="Current password"
313
- autocomplete="current-password" />
314
- </div>
315
- <div class="inline" style="margin-bottom:8px">
316
- <input type="password" id="pw-next" placeholder="New password"
317
- autocomplete="new-password" />
318
- <button class="btn btn-sm btn-primary" id="pw-save">Change</button>
668
+ <div class="password-grid">
669
+ <label class="field">
670
+ <span>Current password</span>
671
+ <input
672
+ type="password"
673
+ id="pw-current"
674
+ autocomplete="current-password"
675
+ />
676
+ </label>
677
+ <label class="field">
678
+ <span>New password</span>
679
+ <input
680
+ type="password"
681
+ id="pw-next"
682
+ autocomplete="new-password"
683
+ />
684
+ </label>
685
+ <button class="btn btn-primary" id="pw-save" type="button">
686
+ Change password
687
+ </button>
319
688
  </div>
320
689
  <div class="hint">
321
- This password is the only thing between the internet and a linked WhatsApp
322
- account. It is stored as a hash — nobody, including this page, can read it back.
690
+ This password is the only thing between the internet and a
691
+ linked WhatsApp account. It is stored as a hash — nobody,
692
+ including this page, can read it back.
323
693
  </div>
324
694
  </div>
325
695