Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions src/components/island/IslandBar.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@

<div class="pill" class:asking in:bloom={{ reduced }} out:blurAway={{ reduced }}>
<span class="measure" aria-hidden="true" bind:offsetWidth={statusWidth}>{line.text}</span>
{#if live}<span class="measure live-measure" aria-hidden="true" data-kind={live.kind} bind:offsetWidth={liveWidth}>{#if live.kind !== 'live'}<i class="kind"></i>{/if}<b>{live.name}</b> <span class="doing">{live.doing}</span></span>{/if}
{#if live}<span class="measure live-measure" aria-hidden="true" data-kind={live.kind} bind:offsetWidth={liveWidth}>{#if live.kind !== 'live'}<i class="kind"></i>{/if}<b>{live.name}</b> {#if live.progress !== null}<span class="goal"></span>{/if}<span class="doing">{live.doing}</span></span>{/if}
<button
class="bar"
data-testid="island-bar"
Expand Down Expand Up @@ -325,16 +325,13 @@
{:else if live}
<!-- The timer's clock ticks in place: only its name rolls the line. -->
<span class="live roll" in:bloom={{ reduced }} data-kind={live.kind} data-tone={live.tone} data-paused={live.paused || undefined} data-testid="island-live">
{#key live.kind === 'timer' ? `timer\n${live.name}` : `${live.name}\n${live.doing}`}<span class="line" in:rollIn={{ reduced, back }} out:rollOut={{ reduced, back }}>{#if live.kind === 'quota'}<Gauge class="kind" size={12} strokeWidth={2} aria-hidden="true" />{:else if live.kind === 'music'}<Music class="kind" size={12} strokeWidth={2} aria-hidden="true" />{:else if live.kind === 'timer'}<Timer class="kind" size={12} strokeWidth={2} aria-hidden="true" />{/if}<b>{live.name}</b> <span class="doing">{live.doing}</span></span>{/key}
{#key live.kind === 'timer' ? `timer\n${live.name}` : `${live.name}\n${live.doing}`}<span class="line" in:rollIn={{ reduced, back }} out:rollOut={{ reduced, back }}>{#if live.kind === 'quota'}<Gauge class="kind" size={12} strokeWidth={2} aria-hidden="true" />{:else if live.kind === 'music'}<Music class="kind" size={12} strokeWidth={2} aria-hidden="true" />{:else if live.kind === 'timer'}<Timer class="kind" size={12} strokeWidth={2} aria-hidden="true" />{/if}<b>{live.name}</b> {#if live.progress !== null}<span class="goal" aria-hidden="true"><i style:width="{(live.progress * 100).toFixed(1)}%"></i></span>{/if}<span class="doing">{live.doing}</span></span>{/key}
</span>
{/if}
<span class="dots" aria-hidden="true">
{#if trace}<span class="dot rule" data-testid="island-rule-trace" title={traceLine?.text} in:bloom={{ reduced }}><ShieldCheck size={11} strokeWidth={2.4} /></span>{/if}
{#each dots as dot (dot.key)}<span class="dot" class:on={dot.key === hoveredKey} data-dot={dot.key}><i data-tone={dot.tone}></i></span>{/each}
</span>
{#if !peeking && live?.progress}
<span class="progress" aria-hidden="true"><i style:transform="scaleX({live.progress.toFixed(3)})"></i></span>
{/if}
</button>
{#if ask && said}
{@const request = ask.request}
Expand Down Expand Up @@ -468,23 +465,26 @@
.live[data-paused] .doing {
opacity: 0.55;
}
.progress {
position: absolute;
right: 16px;
bottom: 3px;
left: 16px;
height: 2px;
/* The goal: how far the task list is, a short rounded meter before its count ("2/5"), in the line. */
.goal {
display: inline-block;
width: 28px;
height: 5px;
margin: 0 7px 0 3px;
overflow: hidden;
border-radius: 1px;
background: rgb(255 255 255 / 0.1);
border-radius: 999px;
background: var(--island-line-strong);
vertical-align: 1px;
}
.progress i {
.goal i {
display: block;
width: 100%;
height: 100%;
border-radius: inherit;
background: var(--island-working);
transform-origin: left;
transition: transform 400ms ease;
transition: width 400ms ease;
}
.live[data-tone='waiting'] .goal i {
background: var(--island-attention);
}
.dots {
display: flex;
Expand Down
4 changes: 3 additions & 1 deletion src/components/island/deck/DeckTile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,12 @@
scrollbar-width: thin;
scrollbar-color: var(--island-line-strong) transparent;
}
/* The island's cards, drawn inside a tile: the tile is their box. */
/* The island's cards, drawn inside a tile: the tile is their box, and the surface what fades over them. */
.content :global(.island-card) {
--island-card: var(--deck-tile);
padding: 0;
border: none;
background: none;
box-shadow: none;
}
</style>
13 changes: 7 additions & 6 deletions src/components/island/music/MusicBubble.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!--
The music bubble: a small black drop beside the island's pill, the music's
own (`lib/companion/music.svelte.ts`). Folded, the cover and a meter that
moves with the sound, the track's progress along its bottom edge. Under the
moves with the sound, the track's progress under the meter. Under the
pointer or the keyboard it unfolds into the player: the cover (which opens
Spotify), the title and the artist, the meter, previous, play or pause, and
next, and the timeline, where a click or a drag moves the track
Expand Down Expand Up @@ -372,15 +372,16 @@
.paused .thumb {
filter: saturate(0.4) brightness(0.8);
}
/* The track's progress, under the meter beside the cover, clear of the bubble's edge. */
.line {
position: absolute;
right: 12px;
bottom: 3px;
left: 12px;
right: 10px;
bottom: 4px;
left: 36px;
height: 2px;
overflow: hidden;
border-radius: 1px;
background: rgb(255 255 255 / 0.1);
border-radius: 999px;
background: var(--island-line-strong);
pointer-events: none;
}
.line i {
Expand Down
6 changes: 6 additions & 0 deletions src/components/island/sessions/SubAgentList.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@
font-size: 11px;
line-height: 20px;
}
/* The count heads the list: apart from the row's line above, close to the list it counts. */
.progress {
margin: 4px 0 2px;
font-weight: 500;
letter-spacing: 0.01em;
}
.lines {
display: flex;
flex-direction: column;
Expand Down
11 changes: 11 additions & 0 deletions src/lib/island/pose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@
* asks to push two seconds in); read by the companion, the fake side in
* `fake-client/machines-demo.ts`.
* - `todo=1`: a to-do list in the today tab, one item ticked;
* - `tasks=1`: the tests thread keeps a task list, two of five done, so the
* collapsed pill's live line shows its goal bar (wait for the ended
* threads' line to pass);
* - `mission=ask|list`: a mission waiting for the user's word, or three set
* (one paused, one whose project is gone) for Settings;
* - `bar=custom`: the bar arranged by hand: two tabs left out, one renamed,
Expand Down Expand Up @@ -151,6 +154,13 @@ function poseTodo(companion: Companion): void {
companion.todos.apply([{ kind: 'done', index: 2 }]);
}

/** The tests thread's task list, two of five done, the third at work. */
async function poseTasks(companion: Companion): Promise<void> {
const texts = ['Pull the merge', 'Install the packages', 'Run the unit tests', 'Run the end-to-end tests', 'Sum up the failures'];
const status = (index: number) => (index < 2 ? 'completed' : index === 2 ? 'in_progress' : 'pending') as 'completed' | 'in_progress' | 'pending';
await companion.client?.call('threads.tasks.set', { threadId: DEMO_THREAD, tasks: texts.map((text, index) => ({ id: `task-pose-${index}`, text, status: status(index) })) }).catch(() => {});
}

/** A mission waiting for the user's word (`ask`), or three set, one paused and one whose project is gone (`list`, for Settings). */
function poseMissions(companion: Companion, kind: 'ask' | 'list'): void {
const found = [...companion.projects].find(([, name]) => companion.projectNames?.includes(name));
Expand Down Expand Up @@ -242,6 +252,7 @@ export async function strikePose(companion: Companion, frame: IslandFrame, param
}
if (params.get('sessions') === 'none') posed.idle = true;
if (params.get('todo') === '1') poseTodo(companion);
if (params.get('tasks') === '1') await poseTasks(companion);
const mission = params.get('mission');
if (mission === 'ask' || mission === 'list') poseMissions(companion, mission);
const rest = params.get('rest') as PillRest | null;
Expand Down
Loading