Skip to content

feat(app): redesign the goal pill - #60001

Open
arvsrn wants to merge 1 commit into
pill-icon-renderfrom
goal-pill-plugin
Open

arvsrn wants to merge 1 commit into
pill-icon-renderfrom
goal-pill-plugin

Conversation

@arvsrn

@arvsrn arvsrn commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Issue for this PR

None. Stacked on #60000, which adds ComposerPill.icon.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Redesigns the goal plugin's composer pill and popover.

Pill

  • Labels read Following goal, Goal paused and Goal reached.
  • The goal draws its own glyph through ComposerPill.icon:
    • active: an accent ring whose center dot sends out a ripple that fades as it spreads, then grows back (a 2.4s loop)
    • paused: a ring with a faded dot, in --v2-state-fg-warning
    • reached: a ring with a check, in --v2-state-fg-success
  • Under reduced motion, the active glyph holds still on its ring and dot.

Popover

  • It leads with the objective. Long objectives scroll.
  • Once the goal has a reason, a full-width divider follows, then the colored status (Active, Paused or Finished) with the reason under it. Before the first review there's no reason, so the popover is just the objective and the actions.
  • Left-aligned buttons: Pause or Resume beside a red Clear. A reached goal offers only Dismiss, which clears it.
  • The content adds 4px at the top and 8px elsewhere to the host's 4px inset, so it sits 8/12/12 from the edges.

The glyph colors, popover layout and keyframes ship as plugin CSS through ctx.add(Style, …). The plugin's strings title and met are replaced.

How did you verify your code works?

  • bun typecheck in packages/gui-plugins and packages/app
  • oxlint, prettier and the gui-plugins ast-grep rules
  • In the app against this branch's server, with real /goal runs in a scratch session: active before the first review, paused with "Paused by the user", and reached with the reviewer's evidence and only Dismiss

Visual

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="72" viewBox="0 0 240 72" fill="none">
<style>
.r{animation:r 2.4s infinite;transform-box:fill-box;transform-origin:center}
.c{animation:c 2.4s infinite;transform-box:fill-box;transform-origin:center}
.p{animation:p 4.8s ease-out infinite;transform-origin:60px 34px}
@keyframes r{0%,16.7%{transform:scale(1);opacity:1;animation-timing-function:cubic-bezier(.2,.6,.35,1)}91.7%,100%{transform:scale(2.8);opacity:0}}
@keyframes c{0%,16.6%{transform:scale(1);opacity:1}16.7%,33.3%{transform:scale(0);opacity:0;animation-timing-function:cubic-bezier(.33,0,.2,1)}75%,100%{transform:scale(1);opacity:1}}
@keyframes p{0%,10%{opacity:0;transform:translateY(4px) scale(.97)}22%,84%{opacity:1;transform:none}96%,100%{opacity:0;transform:translateY(4px) scale(.97)}}
@media (prefers-reduced-motion:reduce){.r,.c,.p{animation:none}}
</style>
<rect x="6" y="44" width="92" height="24" rx="6" stroke="currentColor" stroke-opacity=".35" stroke-width=".75"/>
<circle cx="19" cy="56" r="5" stroke="currentColor"/>
<circle class="r" cx="19" cy="56" r="1.6" fill="currentColor"/>
<circle class="c" cx="19" cy="56" r="1.6" fill="currentColor"/>
<rect x="30" y="54" width="58" height="4" rx="2" fill="currentColor" opacity=".7"/>
<g class="p">
<rect x="6" y="2" width="160" height="38" rx="6" fill="currentColor" fill-opacity=".05" stroke="currentColor" stroke-opacity=".3" stroke-width=".75"/>
<rect x="14" y="8" width="128" height="3" rx="1.5" fill="currentColor" opacity=".7"/>
<rect x="14" y="14" width="96" height="3" rx="1.5" fill="currentColor" opacity=".7"/>
<line x1="6" y1="21" x2="166" y2="21" stroke="currentColor" stroke-opacity=".2" stroke-width=".5"/>
<rect x="14" y="25" width="26" height="9" rx="2" stroke="currentColor" stroke-opacity=".4" stroke-width=".75"/>
<rect x="44" y="25" width="24" height="9" rx="2" stroke="currentColor" stroke-opacity=".4" stroke-width=".75"/>
<rect x="18" y="28.5" width="18" height="2" rx="1" fill="currentColor" opacity=".7"/>
<rect x="48" y="28.5" width="16" height="2" rx="1" fill="currentColor" opacity=".45"/>
</g>
</svg>

Screenshots / recordings

Captured in the app against this branch's server: reached (objective, Finished, the reviewer's evidence, Dismiss), active before the first review (objective, Pause, Clear) and paused (objective, Paused, "Paused by the user", Resume, Clear). The pill keeps today's plugin capsule style; #59979 moves it to the shared 32px pill.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

The goal plugin's pill gets its own glyph through the composer pill icon: a ripple
for an active goal, a faded dot when paused and a check once reached. The labels
now read Following goal, Goal paused and Goal reached.

The popover leads with the objective. Once the goal has a reason, a divider and
the colored status follow with the reason under it. Pause or Resume sit beside a
red Clear, and a reached goal offers only Dismiss.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant