Skip to content

Commit d75ad6c

Browse files
Maxaubertclaude
andcommitted
feat(console): minimise instead of close, and a Clear button that resets the console
Refs #39 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 843963b commit d75ad6c

8 files changed

Lines changed: 39 additions & 14 deletions

File tree

-765 Bytes
Loading
514 Bytes
Loading

‎docs/superpowers/specs/2026-10-06-console-design.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ toggle in the heads of Completed, Settings, Tools and Generate (Ctrl+` works the
5454
`.chead`, `.hib`, `.stopbtn`, `.cbody`, `.ln`, `.blk`, `.cmd`, `.pline`, `.comp`) into a new
5555
`theme/console.css`.
5656
- **Head (owner feedback 2026-10-06, "just an open and close, keep it simple"):** a slim 28px row, right-aligned:
57-
the red **Stop** (only while a command runs) and an icon-only close X (`aria-label="Close console"`).
58-
Nothing else: no label, folder button, note, Open in terminal or Clear. The folder shows in the prompt and
57+
the red **Stop** (only while a command runs), an icon-only Clear (circle with a slash, `aria-label="Clear console"`, disabled while running; clears the output and the input) and an icon-only Minimise (a bar, `aria-label="Minimise console"`) that hides the panel (owner, 2026-10-06).
58+
Nothing else: no label, folder button, note or Open in terminal. The folder shows in the prompt and
5959
changes with `cd`; `clear`/`cls` and Ctrl+L clear.
6060
- **Body:** scrollback then the prompt line. The body scrolls (`.scroll-thin`), the output is selectable
6161
(`.select-text`; `body` is `user-select:none`).

‎e2e/console.spec.ts‎

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ async function type(line: string): Promise<void> {
8989
await prompt().press('Enter')
9090
}
9191

92-
const closeBtn = () => panel().getByRole('button', { name: 'Close console' })
92+
const closeBtn = () => panel().getByRole('button', { name: 'Minimise console' })
9393
const headNames = () =>
9494
panel()
9595
.locator('.chead')
@@ -145,14 +145,13 @@ test('closed, the strip holds only the Console button; open, the panel replaces
145145
await expect(panel()).toBeVisible()
146146
})
147147

148-
test('the panel head holds only the close X, slim and on the right', async () => {
149-
expect(await headNames()).toEqual(['Close console'])
148+
test('the panel head holds Clear and Minimise, slim and on the right', async () => {
149+
expect(await headNames()).toEqual(['Clear console', 'Minimise console'])
150150
const head = (await panel().locator('.chead').boundingBox())!
151151
expect(Math.round(head.height)).toBeLessThanOrEqual(28)
152152
const x = (await closeBtn().boundingBox())!
153153
expect(Math.round(x.x + x.width)).toBe(Math.round(head.x + head.width))
154154
await expect(panel().getByRole('button', { name: 'Open in terminal' })).toHaveCount(0)
155-
await expect(panel().getByRole('button', { name: 'Clear console' })).toHaveCount(0)
156155
})
157156

158157
test('typing in the console never changes the view size or zooms the page', async () => {
@@ -232,7 +231,7 @@ test('console completion follows typing while the list is open', async () => {
232231
await prompt().fill('')
233232
})
234233

235-
test('clear and Ctrl+L empty the scrollback', async () => {
234+
test('clear, Ctrl+L and the Clear button empty the scrollback', async () => {
236235
await type('help')
237236
await expect(panel().locator('.blk')).not.toHaveCount(0)
238237
await prompt().press('Control+l')
@@ -241,6 +240,10 @@ test('clear and Ctrl+L empty the scrollback', async () => {
241240
await expect(panel().locator('.blk')).not.toHaveCount(0)
242241
await type('clear')
243242
await expect(panel().locator('.blk')).toHaveCount(0)
243+
await type('help')
244+
await expect(panel().locator('.blk')).not.toHaveCount(0)
245+
await panel().getByRole('button', { name: 'Clear console' }).click()
246+
await expect(panel().locator('.blk')).toHaveCount(0)
244247
})
245248

246249
test('Stop cancels a running convert with exit 130', async () => {
@@ -249,7 +252,7 @@ test('Stop cancels a running convert with exit 130', async () => {
249252
await expect(stop).toBeVisible()
250253
// The running footer keeps its key hints; the head is Stop and the close X only.
251254
await expect(panel().locator('.pline .keys')).toBeVisible()
252-
expect(await headNames()).toEqual(['StopCtrl+C', 'Close console'])
255+
expect(await headNames()).toEqual(['StopCtrl+C', 'Clear console', 'Minimise console'])
253256
await stop.click()
254257
await expect(panel().getByText('exit 130', { exact: false })).toBeVisible({ timeout: 15_000 })
255258
await expect(stop).toBeHidden()

‎e2e/ui.spec.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ test('an empty workspace offers Add files and a disabled Run', async () => {
9191
await strip.getByRole('button', { name: /^Console/ }).click()
9292
await expect(panel).toBeVisible()
9393
await expect(strip).toBeHidden()
94-
await expect(panel.locator('.chead').getByRole('button')).toHaveCount(1)
95-
await panel.getByRole('button', { name: 'Close console' }).click()
94+
await expect(panel.locator('.chead').getByRole('button')).toHaveCount(2)
95+
await panel.getByRole('button', { name: 'Minimise console' }).click()
9696
await expect(panel).toBeHidden()
9797
await expect(strip).toBeVisible()
9898
})

‎src/renderer/src/components/console/ConsolePanel.tsx‎

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ export function ConsolePanel(p: {
354354
onPointerUp={onSashUp}
355355
onKeyDown={onSashKey}
356356
/>
357-
{/* Only close, and Stop while a command runs (owner feedback, 2026-10-06). */}
357+
{/* Stop while a command runs, then Clear and Minimise (owner feedback, 2026-10-06). */}
358358
<div className="chead">
359359
{runId && (
360360
<button type="button" className="stopbtn" onClick={stop}>
@@ -365,11 +365,24 @@ export function ConsolePanel(p: {
365365
<button
366366
type="button"
367367
className="hib"
368-
title="Close console"
369-
aria-label="Close console"
368+
title="Clear console"
369+
aria-label="Clear console"
370+
disabled={!!runId}
371+
onClick={() => {
372+
dispatch({ type: 'clear' })
373+
setInput('')
374+
}}
375+
>
376+
<Icon name="reset" />
377+
</button>
378+
<button
379+
type="button"
380+
className="hib"
381+
title="Minimise console"
382+
aria-label="Minimise console"
370383
onClick={p.onClose}
371384
>
372-
<Icon name="close" />
385+
<Icon name="minimize" />
373386
</button>
374387
</div>
375388
<div

‎src/renderer/src/components/icons/shapes.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ export const ICON_SHAPES: Record<IconName, Prim[]> = {
4949
'chev-r': [['path', 'M6 4l4 4-4 4']],
5050
'chev-d': [['path', 'M4 6l4 4 4-4']],
5151
cleardone: [['path', 'M2 4.5l1.25 1.25L5.5 3.5M2 10.5l1.25 1.25L5.5 9.5M7.5 4.5H14M7.5 10.5H14']],
52+
// A bar at the bottom: hide the panel, like a window's minimise.
53+
minimize: [['path', 'M3.5 11.5h9']],
54+
// Circle with a slash: clear the console back to an empty prompt.
55+
reset: [
56+
['circle', 8, 8, 5.5],
57+
['path', 'M4.1 11.9l7.8-7.8']
58+
],
5259
trash: [['path', 'M3 4.5h10M6 4.5V2.5h4v2M4.5 4.5l.5 9h6l.5-9']],
5360
eye: [
5461
['path', 'M1.5 8s2.5-4.5 6.5-4.5S14.5 8 14.5 8s-2.5 4.5-6.5 4.5S1.5 8 1.5 8z'],

‎src/shared/icons.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export const ICON_NAMES = [
2323
'chev-r',
2424
'chev-d',
2525
'trash',
26+
'minimize',
27+
'reset',
2628
'cleardone',
2729
'eye',
2830
'info',

0 commit comments

Comments
 (0)