@oddessentials/agent-guild 0.21.0 → 0.22.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.
- package/README.md +5 -0
- package/package.json +1 -1
- package/web/app.js +116 -4
- package/web/index.html +14 -0
- package/web/skins/gnomeland/skin.css +2 -2
- package/web/skins/grove/skin.css +2 -2
- package/web/skins/guild/skin.css +2 -2
- package/web/skins/orbital/skin.css +2 -2
- package/web/styles.css +18 -2
package/README.md
CHANGED
|
@@ -124,6 +124,11 @@ vX.Y.Z** switches over when you are ready. The version badge opens
|
|
|
124
124
|
|
|
125
125
|
<img src="docs/images/whats-new.webp" alt="The What's new panel listing the release notes of each version">
|
|
126
126
|
|
|
127
|
+
**Keep notes at hand.** **Notes** in the top bar opens a notepad for prompts,
|
|
128
|
+
commands and to-dos, even while a terminal is open. It saves up to 100,000
|
|
129
|
+
characters as you type and keeps them in this browser, never on the manager;
|
|
130
|
+
every tab of the page shows the same notes.
|
|
131
|
+
|
|
127
132
|
**Appearance.** The Appearance menu in the top bar picks a skin and light or
|
|
128
133
|
dark mode, without a reload. **Guild** is the default fantasy look;
|
|
129
134
|
**Professional** is a plain business look with no characters; **Orbital**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oddessentials/agent-guild",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Launch and watch AI coding-assistant terminal sessions from one local web page. A bundled session manager owns the terminals so the page can close and reconnect.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/web/app.js
CHANGED
|
@@ -16,6 +16,7 @@ const GITHUB_ACCOUNT_KEY = 'agentGuild.githubAccount';
|
|
|
16
16
|
const CLONE_PARENT_KEY = 'agentGuild.cloneParent';
|
|
17
17
|
const SESSION_ORDER_KEY = 'agentGuild.sessionOrder';
|
|
18
18
|
const SOUND_KEY = 'agentGuild.sound';
|
|
19
|
+
const NOTES_KEY = 'agentGuild.notes';
|
|
19
20
|
const RELEASES_URL = 'https://github.com/oddessentials/agent-guild/releases';
|
|
20
21
|
const isMac = /Mac|iPhone|iPad/.test(navigator.platform || navigator.userAgent);
|
|
21
22
|
const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
@@ -63,7 +64,7 @@ const state = {
|
|
|
63
64
|
// ---- storage (may be unavailable, e.g. blocked site data) -----------------
|
|
64
65
|
|
|
65
66
|
function load(key) { try { return localStorage.getItem(key); } catch { return null; } }
|
|
66
|
-
function save(key, value) { try { value === null ? localStorage.removeItem(key) : localStorage.setItem(key, value); } catch {
|
|
67
|
+
function save(key, value) { try { value === null ? localStorage.removeItem(key) : localStorage.setItem(key, value); return true; } catch { return false; } }
|
|
67
68
|
|
|
68
69
|
// ---- helpers --------------------------------------------------------------
|
|
69
70
|
|
|
@@ -87,6 +88,12 @@ function toast(message, ms = 5000, action = null) {
|
|
|
87
88
|
toastTimer = setTimeout(() => { el.hidden = true; }, ms);
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Handles a click, but not the second click of a double-click, which lands on whatever the first one
|
|
93
|
+
* opened or uncovered: Close over Notes, or Stop manager under a panel's Close.
|
|
94
|
+
*/
|
|
95
|
+
const firstClick = (run) => (e) => { if (e.detail < 2) run(); };
|
|
96
|
+
|
|
90
97
|
function setConnection(kind, label) {
|
|
91
98
|
const el = $('connection');
|
|
92
99
|
el.className = `connection ${kind}`;
|
|
@@ -294,6 +301,99 @@ function placeAppearanceMenu() {
|
|
|
294
301
|
menu.style.right = `${Math.max(8, Math.round(innerWidth - box.right))}px`;
|
|
295
302
|
}
|
|
296
303
|
|
|
304
|
+
// ---- notes ----------------------------------------------------------------
|
|
305
|
+
|
|
306
|
+
/** Notes share the page's storage with every other setting, so they stay far below the browser's limit for it. */
|
|
307
|
+
const NOTES_LIMIT = 100000;
|
|
308
|
+
const NOTES_STATUS = {
|
|
309
|
+
saved: 'Saved in this browser as you type',
|
|
310
|
+
long: `Not saved: notes hold up to ${NOTES_LIMIT.toLocaleString('en-US')} characters. Shorten them to save.`,
|
|
311
|
+
refused: 'Not saved: the browser’s storage for this page is full or turned off. Copy what you need before you close the page.',
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* `saved`: the notes as this page last read or wrote them in storage. `status`: whether the text in the
|
|
315
|
+
* panel is saved, too `long` or `refused`; `shown`: the status the line under the title shows.
|
|
316
|
+
* `pressedOutside`: the last press on the panel was on its backdrop.
|
|
317
|
+
*/
|
|
318
|
+
const notesView = { saved: '', status: 'saved', shown: 'saved', pressedOutside: false };
|
|
319
|
+
|
|
320
|
+
/** Shows notes another tab saved since this page last read or wrote them. Saved notes win over text this page could not save. */
|
|
321
|
+
function refreshNotes() {
|
|
322
|
+
let text;
|
|
323
|
+
// Unlike load(), a read that fails is not taken for empty notes.
|
|
324
|
+
try { text = localStorage.getItem(NOTES_KEY) ?? ''; } catch { return; }
|
|
325
|
+
if (text === notesView.saved) return;
|
|
326
|
+
notesView.saved = text;
|
|
327
|
+
notesView.status = 'saved';
|
|
328
|
+
$('notes-text').value = text;
|
|
329
|
+
renderNotesStatus();
|
|
330
|
+
guardLeaving();
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Saves the notes on every change; emptying them removes the saved copy. */
|
|
334
|
+
function saveNotes() {
|
|
335
|
+
const text = $('notes-text').value;
|
|
336
|
+
if (text.length > NOTES_LIMIT) notesView.status = 'long';
|
|
337
|
+
else if (!save(NOTES_KEY, text || null)) notesView.status = 'refused';
|
|
338
|
+
else {
|
|
339
|
+
notesView.status = 'saved';
|
|
340
|
+
notesView.saved = text;
|
|
341
|
+
}
|
|
342
|
+
renderNotesStatus();
|
|
343
|
+
guardLeaving();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/** The line under the title is a live region, so it is rewritten only when the status changes. */
|
|
347
|
+
function renderNotesStatus() {
|
|
348
|
+
if (notesView.shown === notesView.status) return;
|
|
349
|
+
notesView.shown = notesView.status;
|
|
350
|
+
const sub = $('notes-sub');
|
|
351
|
+
sub.textContent = NOTES_STATUS[notesView.status];
|
|
352
|
+
sub.classList.toggle('warn', notesView.status !== 'saved');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** Another tab saved the notes, or cleared this page's storage. */
|
|
356
|
+
function notesStored(e) {
|
|
357
|
+
if (e.key === NOTES_KEY || e.key === null) refreshNotes();
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function openNotes() {
|
|
361
|
+
hideTip();
|
|
362
|
+
refreshNotes();
|
|
363
|
+
// Saving an empty note changes nothing, but shows at once when the browser keeps nothing.
|
|
364
|
+
if (notesView.status === 'saved' && !$('notes-text').value) saveNotes();
|
|
365
|
+
const dialog = $('notes');
|
|
366
|
+
if (!dialog.open) dialog.showModal();
|
|
367
|
+
$('notes-text').focus();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function closeNotes() {
|
|
371
|
+
if ($('notes').open) $('notes').close();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/** Focus goes back to the Notes button in every browser, never to the page itself. */
|
|
375
|
+
function notesClosed() {
|
|
376
|
+
$('notes-open').focus();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** The second press of a double-click on Notes lands in the panel, where it must not take the focus from the text. */
|
|
380
|
+
const keepFocus = (e) => { if (e.detail > 1 && e.target !== $('notes-text')) e.preventDefault(); };
|
|
381
|
+
|
|
382
|
+
/** Whether a press or click on the panel was on its backdrop, outside the sheet. */
|
|
383
|
+
function isOutsideNotes(e) {
|
|
384
|
+
const box = e.currentTarget.getBoundingClientRect();
|
|
385
|
+
return e.target === e.currentTarget && (e.clientX < box.left || e.clientX >= box.right || e.clientY < box.top || e.clientY >= box.bottom);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function notesPressed(e) {
|
|
389
|
+
notesView.pressedOutside = isOutsideNotes(e);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** Only a press and a release both outside close the notes: a drag into or out of them selects text. */
|
|
393
|
+
function notesClicked(e) {
|
|
394
|
+
if (notesView.pressedOutside && isOutsideNotes(e)) closeNotes();
|
|
395
|
+
}
|
|
396
|
+
|
|
297
397
|
// ---- upgrading the manager ------------------------------------------------
|
|
298
398
|
|
|
299
399
|
function renderUpgrade() {
|
|
@@ -2858,7 +2958,9 @@ function confirmLeaving(event) {
|
|
|
2858
2958
|
|
|
2859
2959
|
function guardLeaving() {
|
|
2860
2960
|
const running = state.connected && [...state.sessions.values()].some((s) => s.status === 'running');
|
|
2861
|
-
|
|
2961
|
+
// Notes that could not be saved are lost with the page.
|
|
2962
|
+
const unsaved = notesView.status !== 'saved' && $('notes-text').value !== '';
|
|
2963
|
+
if (running || unsaved) addEventListener('beforeunload', confirmLeaving);
|
|
2862
2964
|
else removeEventListener('beforeunload', confirmLeaving);
|
|
2863
2965
|
}
|
|
2864
2966
|
|
|
@@ -3761,6 +3863,16 @@ document.addEventListener('keydown', (e) => {
|
|
|
3761
3863
|
}, true);
|
|
3762
3864
|
addEventListener('scroll', () => { if (tipFor) hideTip(); }, true);
|
|
3763
3865
|
addEventListener('resize', () => { if (tipFor) hideTip(); });
|
|
3866
|
+
$('notes-open').addEventListener('click', firstClick(openNotes));
|
|
3867
|
+
$('notes-close').addEventListener('click', firstClick(closeNotes));
|
|
3868
|
+
$('notes').addEventListener('mousedown', keepFocus);
|
|
3869
|
+
$('notes').addEventListener('pointerdown', notesPressed);
|
|
3870
|
+
$('notes').addEventListener('click', notesClicked);
|
|
3871
|
+
$('notes').addEventListener('close', notesClosed);
|
|
3872
|
+
$('notes-text').addEventListener('input', saveNotes);
|
|
3873
|
+
addEventListener('storage', notesStored);
|
|
3874
|
+
// On load, and again for a page back from the back/forward cache, which may have missed another tab's notes.
|
|
3875
|
+
addEventListener('pageshow', refreshNotes);
|
|
3764
3876
|
$('news-all').addEventListener('click', openNews);
|
|
3765
3877
|
$('news-close').addEventListener('click', closeNews);
|
|
3766
3878
|
$('news-fresh').addEventListener('click', showFreshNews);
|
|
@@ -3843,8 +3955,8 @@ $('models-more').addEventListener('click', () => {
|
|
|
3843
3955
|
renderModels();
|
|
3844
3956
|
$('models-list').children[before]?.querySelector('.model-toggle')?.focus();
|
|
3845
3957
|
});
|
|
3846
|
-
$('stop-manager').addEventListener('click', () => stopManager());
|
|
3847
|
-
$('restart-manager').addEventListener('click', () => stopManager({ restart: true }));
|
|
3958
|
+
$('stop-manager').addEventListener('click', firstClick(() => stopManager()));
|
|
3959
|
+
$('restart-manager').addEventListener('click', firstClick(() => stopManager({ restart: true })));
|
|
3848
3960
|
$('copy-command').addEventListener('click', copyCommand);
|
|
3849
3961
|
$('upgrade').addEventListener('click', upgradeManager);
|
|
3850
3962
|
$('appearance-menu').addEventListener('change', (e) => {
|
package/web/index.html
CHANGED
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
<label class="choice" title="Plays when the session manager stops, remains unavailable after a brief recovery check, or a new Agent Guild update is discovered. Click or type on this page to allow playback."><input id="sound" type="checkbox" name="sound"><span class="sound-alerts">Alert sounds</span></label>
|
|
42
42
|
</fieldset>
|
|
43
43
|
</div>
|
|
44
|
+
<button id="notes-open" class="btn notes-open" type="button" aria-haspopup="dialog">Notes</button>
|
|
44
45
|
<button id="restart-manager" class="btn restart-manager" type="button" hidden>Restart manager</button>
|
|
45
46
|
<button id="stop-manager" class="btn danger stop-manager" type="button" hidden title="Stop the session manager. This ends every session.">Stop manager</button>
|
|
46
47
|
</div>
|
|
@@ -179,6 +180,19 @@
|
|
|
179
180
|
<p id="changelog-status" class="news-status" hidden></p>
|
|
180
181
|
</dialog>
|
|
181
182
|
|
|
183
|
+
<dialog id="notes" class="news-panel notes-panel" aria-labelledby="notes-title">
|
|
184
|
+
<div class="news-bar">
|
|
185
|
+
<div class="news-heading">
|
|
186
|
+
<h2 id="notes-title">Notes</h2>
|
|
187
|
+
<p id="notes-sub" class="sub" aria-live="polite">Saved in this browser as you type</p>
|
|
188
|
+
</div>
|
|
189
|
+
<button id="notes-close" class="btn" type="button">Close</button>
|
|
190
|
+
</div>
|
|
191
|
+
<div class="news-body">
|
|
192
|
+
<textarea id="notes-text" class="notes-text" aria-labelledby="notes-title" aria-describedby="notes-sub" autocomplete="off" placeholder="Prompts, commands, to-dos: anything you want to keep at hand"></textarea>
|
|
193
|
+
</div>
|
|
194
|
+
</dialog>
|
|
195
|
+
|
|
182
196
|
<dialog id="history" class="models history" aria-labelledby="history-title">
|
|
183
197
|
<div class="models-bar">
|
|
184
198
|
<span id="history-icon" class="provider-icon small"></span>
|
|
@@ -243,7 +243,7 @@
|
|
|
243
243
|
}
|
|
244
244
|
.btn.primary:hover { filter: brightness(1.08); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), inset 0 0 0 1px rgba(233, 196, 122, 0.6), 0 5px 16px rgba(40, 70, 30, 0.35); }
|
|
245
245
|
.btn.danger:hover { border-color: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 14%, transparent); }
|
|
246
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select { background: var(--panel-strong); }
|
|
246
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select, .notes-text { background: var(--panel-strong); }
|
|
247
247
|
|
|
248
248
|
.models, .news-panel, .auth, .news-latest, .appearance-menu { background: var(--panel-strong); backdrop-filter: blur(16px); }
|
|
249
249
|
.models, .news-panel { box-shadow: var(--dialog-shadow); }
|
|
@@ -362,7 +362,7 @@
|
|
|
362
362
|
.btn.primary { border-color: #6a8f3a; background: linear-gradient(#55924a, #35662f); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 0 0 1px rgba(233, 196, 122, 0.3), 0 0 16px rgba(110, 170, 80, 0.3); }
|
|
363
363
|
.btn.danger { color: #f59a8c; }
|
|
364
364
|
.btn.danger:hover { border-color: #b8402f; box-shadow: 0 0 12px rgba(240, 123, 106, 0.3); }
|
|
365
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select { border-color: #4a3824; background: rgba(10, 7, 4, 0.7); }
|
|
365
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select, .notes-text { border-color: #4a3824; background: rgba(10, 7, 4, 0.7); }
|
|
366
366
|
|
|
367
367
|
.models::backdrop, .news-panel::backdrop { background: rgba(6, 4, 2, 0.66); }
|
|
368
368
|
.terminal-panel { border-color: #5a4226; box-shadow: 0 0 0 1px rgba(233, 196, 122, 0.06), 0 30px 80px rgba(0, 0, 0, 0.7); }
|
package/web/skins/grove/skin.css
CHANGED
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
}
|
|
245
245
|
.btn.primary:hover { filter: brightness(1.07); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 6px 20px rgba(45, 107, 69, 0.36); }
|
|
246
246
|
.btn.danger:hover { border-color: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 14%, transparent); }
|
|
247
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select { background: var(--paper-strong); }
|
|
247
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select, .notes-text { background: var(--paper-strong); }
|
|
248
248
|
|
|
249
249
|
.models, .news-panel, .auth, .news-latest, .appearance-menu { background: var(--paper-strong); backdrop-filter: blur(16px); }
|
|
250
250
|
.models, .news-panel { box-shadow: var(--dialog-shadow); }
|
|
@@ -371,7 +371,7 @@
|
|
|
371
371
|
.btn.primary { background: linear-gradient(135deg, #4a8c5e, #2a6340); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 0 18px rgba(80, 160, 105, 0.35); }
|
|
372
372
|
.btn.danger { color: #ff9a8e; }
|
|
373
373
|
.btn.danger:hover { border-color: #b8443a; box-shadow: 0 0 12px rgba(240, 122, 108, 0.3); }
|
|
374
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select { border-color: #2e4a3d; background: rgba(4, 10, 8, 0.7); }
|
|
374
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select, .notes-text { border-color: #2e4a3d; background: rgba(4, 10, 8, 0.7); }
|
|
375
375
|
|
|
376
376
|
.models::backdrop, .news-panel::backdrop { background: rgba(2, 6, 5, 0.66); }
|
|
377
377
|
.terminal-panel { border-color: #2e4a3d; box-shadow: 0 0 0 1px rgba(140, 210, 160, 0.06), 0 30px 80px rgba(0, 0, 0, 0.7); }
|
package/web/skins/guild/skin.css
CHANGED
|
@@ -376,7 +376,7 @@
|
|
|
376
376
|
.btn.primary:hover { border-color: var(--gold); filter: brightness(1.08); }
|
|
377
377
|
.btn.danger { color: #ff9a94; }
|
|
378
378
|
.btn.danger:hover { border-color: #b8524d; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 0 12px rgba(239, 107, 102, 0.3); }
|
|
379
|
-
.cwd input, .auth input { border-color: #4a3d25; background: rgba(12, 13, 17, 0.8); }
|
|
379
|
+
.cwd input, .auth input, .notes-text { border-color: #4a3d25; background: rgba(12, 13, 17, 0.8); }
|
|
380
380
|
.auth {
|
|
381
381
|
background: var(--card-bg);
|
|
382
382
|
border: 1px solid #4a3d25; box-shadow: inset 0 0 0 1px rgba(232, 196, 124, 0.06), 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
@@ -480,7 +480,7 @@
|
|
|
480
480
|
}
|
|
481
481
|
.btn.primary:hover { border-color: #b8892f; filter: brightness(1.08); }
|
|
482
482
|
.btn.danger:hover { border-color: #c4625d; }
|
|
483
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input {
|
|
483
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .notes-text {
|
|
484
484
|
border-color: #dccba5; background: #fffdf8; box-shadow: inset 0 1px 2px rgba(70, 48, 12, 0.06);
|
|
485
485
|
}
|
|
486
486
|
.auth { border-color: #e4d6b6; box-shadow: var(--card-shadow); }
|
|
@@ -246,7 +246,7 @@
|
|
|
246
246
|
}
|
|
247
247
|
.btn.primary:hover { filter: brightness(1.08); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 6px 20px rgba(122, 79, 232, 0.4); }
|
|
248
248
|
.btn.danger:hover { border-color: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 14%, transparent); }
|
|
249
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select { background: var(--glass-strong); }
|
|
249
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select, .notes-text { background: var(--glass-strong); }
|
|
250
250
|
|
|
251
251
|
.models, .news-panel, .auth, .news-latest, .appearance-menu { background: var(--glass-strong); backdrop-filter: blur(16px); }
|
|
252
252
|
.models, .news-panel { box-shadow: var(--dialog-shadow); }
|
|
@@ -367,7 +367,7 @@
|
|
|
367
367
|
.btn.primary { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.22), 0 0 18px rgba(106, 92, 240, 0.45); }
|
|
368
368
|
.btn.danger { color: #ff8c9c; }
|
|
369
369
|
.btn.danger:hover { border-color: #c23a52; box-shadow: 0 0 12px rgba(255, 107, 129, 0.3); }
|
|
370
|
-
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select { border-color: #26355c; background: rgba(4, 7, 16, 0.7); }
|
|
370
|
+
.cwd input, .auth input, .history-tools input[type="search"], .history-form input, .github-fields input, .github-fields select, .notes-text { border-color: #26355c; background: rgba(4, 7, 16, 0.7); }
|
|
371
371
|
|
|
372
372
|
.models::backdrop, .news-panel::backdrop { background: rgba(2, 4, 10, 0.66); }
|
|
373
373
|
.terminal-panel { border-color: #2a3a66; box-shadow: 0 0 0 1px rgba(120, 170, 255, 0.06), 0 30px 80px rgba(0, 0, 0, 0.7); }
|
package/web/styles.css
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
--icon-github: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z'/%3E%3C/svg%3E");
|
|
30
30
|
--icon-info: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 10.8v6.2' stroke-width='2.4'/%3E%3Ccircle cx='12' cy='7.3' r='1.2' fill='black' stroke='none'/%3E%3C/svg%3E");
|
|
31
31
|
--icon-grip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='black'%3E%3Ccircle cx='9' cy='5.5' r='1.9'/%3E%3Ccircle cx='15' cy='5.5' r='1.9'/%3E%3Ccircle cx='9' cy='12' r='1.9'/%3E%3Ccircle cx='15' cy='12' r='1.9'/%3E%3Ccircle cx='9' cy='18.5' r='1.9'/%3E%3Ccircle cx='15' cy='18.5' r='1.9'/%3E%3C/svg%3E");
|
|
32
|
+
--icon-notes: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 4.5h14v9.5l-5.5 5.5H5z'/%3E%3Cpath d='M13.5 19.5V14H19M8.5 9h7M8.5 12.5h4'/%3E%3C/svg%3E");
|
|
32
33
|
font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
33
34
|
font-size: 15px;
|
|
34
35
|
color-scheme: light;
|
|
@@ -336,13 +337,14 @@ main { max-width: 1200px; margin: 0 auto; padding: 26px 16px 56px; display: grid
|
|
|
336
337
|
.btn.danger { color: var(--danger); }
|
|
337
338
|
.btn.danger:hover { border-color: var(--danger); }
|
|
338
339
|
.btn:disabled { opacity: 0.6; cursor: progress; }
|
|
339
|
-
.stop-manager, .restart-manager, .appearance, .upgrade { white-space: nowrap; }
|
|
340
|
-
.appearance::before, .appearance-menu .choice > span::before {
|
|
340
|
+
.stop-manager, .restart-manager, .appearance, .notes-open, .upgrade { white-space: nowrap; }
|
|
341
|
+
.appearance::before, .notes-open::before, .appearance-menu .choice > span::before {
|
|
341
342
|
content: ""; display: inline-block; width: 1em; height: 1em; margin-right: 0.4em; vertical-align: -0.15em;
|
|
342
343
|
background: currentColor; mask: var(--icon-sun) center / contain no-repeat;
|
|
343
344
|
}
|
|
344
345
|
:root[data-theme="dark"] .appearance::before, .appearance-menu .choice > .mode-dark::before { mask-image: var(--icon-moon); }
|
|
345
346
|
.appearance-menu .choice > .sound-alerts::before { mask-image: var(--icon-sound); }
|
|
347
|
+
.notes-open::before { mask-image: var(--icon-notes); }
|
|
346
348
|
.appearance::after { margin-left: 0.45em; transform: rotate(90deg); transition: transform 0.15s var(--ease); }
|
|
347
349
|
.appearance:has(+ :popover-open)::after { transform: rotate(-90deg); }
|
|
348
350
|
.appearance-menu {
|
|
@@ -547,6 +549,20 @@ a.news-link:visited { color: var(--muted); }
|
|
|
547
549
|
.changelog-changes li::marker { color: var(--muted); }
|
|
548
550
|
.changelog-changes code { font-size: 0.8rem; padding: 0 4px; border-radius: 4px; background: var(--surface-2); }
|
|
549
551
|
|
|
552
|
+
/* Notes: the News side sheet, holding one text field that skins style with their other fields. */
|
|
553
|
+
.notes-panel .news-body { display: flex; flex-direction: column; padding-top: 12px; }
|
|
554
|
+
.notes-text {
|
|
555
|
+
flex: 1; min-height: 8em; margin: 0; padding: 10px 12px; resize: none;
|
|
556
|
+
border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); color: var(--text);
|
|
557
|
+
font: inherit; font-size: 0.9rem; line-height: 1.55;
|
|
558
|
+
}
|
|
559
|
+
.notes-text:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
|
|
560
|
+
.notes-panel .sub.warn { color: var(--warn); }
|
|
561
|
+
@media (pointer: coarse) {
|
|
562
|
+
/* iOS zooms in on a field with smaller text when it takes focus. */
|
|
563
|
+
.notes-text { font-size: 16px; }
|
|
564
|
+
}
|
|
565
|
+
|
|
550
566
|
.history-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 10px 14px 0; }
|
|
551
567
|
.history-tools input[type="search"] {
|
|
552
568
|
flex: 1 1 220px; min-width: 0; padding: 7px 10px; border-radius: var(--radius); border: 1px solid var(--border);
|