From 74865881953c467aa6408bd5369343c989f51be6 Mon Sep 17 00:00:00 2001
From: meetsu <96637888+klNuno@users.noreply.github.com>
Date: Wed, 21 Oct 2026 10:21:49 +0000
Subject: [PATCH 1/2] fix(island): a quiet memory alert by default, and a
setting to turn it off
The memory warning no longer opens the island with a chime: by default it shows as a line in the pill and a slim strip over the deck, the full card a press away. Settings, Island, Memory alert picks Quiet, Panel (the old behaviour) or Off.
---
src/components/island/Island.svelte | 11 ++-
src/components/island/IslandBar.svelte | 10 +-
.../island/settings/IslandSection.svelte | 8 +-
src/components/island/views/MemoryCard.svelte | 98 +++++++++++++++++--
.../island/views/memory-card.svelte.test.ts | 52 ++++++++++
src/lib/companion/companion.test.ts | 3 +
src/lib/companion/prefs.ts | 6 ++
src/lib/island/pill-view.test.ts | 17 +++-
src/lib/island/pill-view.ts | 19 +++-
src/lib/island/pressure.test.ts | 17 +++-
src/lib/island/pressure.ts | 33 +++++++
src/lib/strings.en.ts | 13 ++-
src/lib/strings.fr.ts | 13 ++-
13 files changed, 273 insertions(+), 27 deletions(-)
create mode 100644 src/components/island/views/memory-card.svelte.test.ts
diff --git a/src/components/island/Island.svelte b/src/components/island/Island.svelte
index 429189b..00a7e6d 100644
--- a/src/components/island/Island.svelte
+++ b/src/components/island/Island.svelte
@@ -53,6 +53,7 @@
import { FinishWatch } from '../../lib/island/finished.svelte';
import { posed } from '../../lib/island/posed.svelte';
import { PrWatch } from '../../lib/island/pr-watch.svelte';
+ import { alertPlan } from '../../lib/island/pressure';
import { MemoryWatch } from '../../lib/island/pressure.svelte';
import { QuotaWatch } from '../../lib/island/quotas.svelte';
import { RecapReader } from '../../lib/island/recap.svelte';
@@ -155,8 +156,10 @@
if (!client || demo) return;
return untrack(() => update.follow(client));
});
+ /** Where Settings lets the warning show: by default the pill, the island left closed (`alertPlan`). */
+ const memoryPlan = $derived(alertPlan(companion.prefs.memoryAlert));
/** The warning's cause, not its numbers: a warning calls the island once, not on every read. */
- const memoryCause = $derived(memory.warning ? `${memory.warning.reason}:${memory.warning.threadId ?? ''}` : null);
+ const memoryCause = $derived(memory.warning && memoryPlan.opens ? `${memory.warning.reason}:${memory.warning.threadId ?? ''}` : null);
/** The day's finished threads, read for the tabs that show them, as they show. */
const recap = new RecapReader({ client: () => companion.client, projects: () => companion.projects, leftOut: () => companion.ownThreads });
/** The room between a drop and the island. */
@@ -305,7 +308,7 @@
return untrack(() => frame.call('alarm'));
});
- // The memory guard comes near: the island opens on its card, amber, until it is stopped or set aside.
+ // The memory guard comes near and Settings asks for the panel: the island opens on its card, amber, until it is stopped or set aside.
$effect(() => {
if (!memoryCause) return;
untrack(() => companion.cue('call'));
@@ -318,7 +321,7 @@
* requests come first, and nothing shows over a full-screen app or during
* focus: the card waits for them.
*/
- const away = new AwayWatch({ rows: () => sessions.rows, pr: () => prs.told, warning: () => memory.warning, stopped: () => memory.stopped });
+ const away = new AwayWatch({ rows: () => sessions.rows, pr: () => prs.told, warning: () => (memoryPlan.card ? memory.warning : null), stopped: () => (memoryPlan.card ? memory.stopped : null) });
$effect(() => away.start());
const awayQuotas = new QuotaWatch(() => ({ shown: companion.prefs.quotas, hidden: companion.prefs.hiddenQuotas }));
/** A return older than this was told before the island was drawn again. */
@@ -453,7 +456,7 @@
ondrop={drop}
>
{#if frame.size !== 'open'}
-
{title(warning)}
@@ -88,6 +118,55 @@ .memory.red { --tone: var(--island-danger); } + /* The default: one slim line, the details a press away. */ + .memory.strip { + align-items: center; + gap: 6px; + padding: 4px 6px 4px 4px; + border-radius: 999px; + background: color-mix(in srgb, var(--tone) 8%, var(--island-card)); + } + .open { + display: flex; + flex: 1; + align-items: center; + gap: 8px; + min-width: 0; + height: 24px; + padding: 0 6px 0 0; + border: none; + border-radius: 999px; + background: none; + color: var(--island-text); + font: inherit; + font-size: 12px; + text-align: left; + cursor: pointer; + } + .open :global(svg:last-child) { + flex: none; + color: var(--island-muted); + } + .open:hover :global(svg:last-child) { + color: var(--island-text); + } + .said-line { + flex: 1; + min-width: 0; + overflow: hidden; + font-variant-numeric: tabular-nums; + text-overflow: ellipsis; + white-space: nowrap; + } + .icon.small { + width: 22px; + height: 22px; + } + .button.slim { + flex: none; + height: 24px; + padding: 0 10px; + } .memory.quiet { --tone: var(--island-muted); align-items: center; @@ -206,6 +285,7 @@ color: var(--island-text); } .button:focus-visible, + .open:focus-visible, .close:focus-visible { outline: 2px solid var(--island-talking); outline-offset: 1px; diff --git a/src/components/island/views/memory-card.svelte.test.ts b/src/components/island/views/memory-card.svelte.test.ts new file mode 100644 index 0000000..fc9ca44 --- /dev/null +++ b/src/components/island/views/memory-card.svelte.test.ts @@ -0,0 +1,52 @@ +/* + * The memory warning over the deck. By default it is a slim strip, the full + * card a press away; Settings can ask for the full card at once, or nothing. + */ +import { afterEach, expect, test } from 'vitest'; +import { flushSync, mount, unmount } from 'svelte'; +import type { Companion } from '../../../lib/companion/companion.svelte'; +import { DEFAULT_COMPANION_PREFS, type MemoryAlert } from '../../../lib/companion/prefs'; +import { viewContext, type ViewContext } from '../../../lib/island/contract'; +import { MemoryWatch } from '../../../lib/island/pressure.svelte'; +import MemoryCard from './MemoryCard.svelte'; + +const GB = 1024 * 1024 * 1024; + +let shown: { card: Record