Skip to content

Commit 157a978

Browse files
committed
feat(devtools): rainbow trigger, persist strip fold, and pane gutters
Use the rainbow palm as the default trigger mark and default triggerMode to floating. Keep the folded plugin strip across reloads. Lay plugin panes in rounded cards with even gutters, theme panel scrollbars, and keep resize handles on the live layout so they stay in the gap after a pane opens or a drag.
1 parent 2df2e04 commit 157a978

24 files changed

Lines changed: 564 additions & 170 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/devtools': patch
3+
---
4+
5+
Persist the folded plugin strip across reloads so it does not steal height back on refresh.

.changeset/rainbow-trigger-mark.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tanstack/devtools': patch
3+
---
4+
5+
Use the rainbow palm favicon as the default trigger mark, default the trigger to floating, and make pane gutters follow the pointer instead of compounding each drag move.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@tanstack/devtools': patch
3+
'@tanstack/devtools-ui': patch
4+
---
5+
6+
Give plugin tabs a small inset in a rounded card, keep pane gutters visible at rest, and theme the panel scrollbars.

docs/architecture.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,26 +146,26 @@ The devtools shell is a Solid.js application that renders the entire devtools UI
146146
- **`setConfig(config)`** -- Updates configuration and plugins at runtime. Plugins are reactive: adding or removing them updates the tab bar immediately.
147147

148148
The shell renders:
149-
- A **trigger button** (the floating devtools toggle, customizable or replaceable)
149+
- A **trigger button** (the floating rainbow palm mark, customizable or replaceable)
150150
- A **resizable Workbench panel** (docked to the top or bottom of the viewport, resizable via pointer or keyboard)
151151
- A compact **36px TanStack Devtools header** with Plugins, Marketplace, SEO, and Settings destinations. The palm emblem is inline SVG, so it stays sharp and takes its colour from the theme.
152152
- A fixed-height **44px secondary strip** for plugin and SEO navigation. It scrolls horizontally when space is limited, and a pull tab on its bottom edge folds it away behind the header. Folding changes nothing else — the panel keeps its height and the destination content keeps running — so the tab is rendered only on the destinations that have a strip.
153153
- A separate **Marketplace** header tab that does not disturb mounted plugin panes
154154
- A **settings panel** for theme, hotkeys, position, and other preferences
155155
- Up to three simultaneous **plugin mount frames**, divided into equal widths by static separators
156156

157-
Settings and UI state (panel size, position, active tab, theme) are persisted in `localStorage` so they survive page reloads.
157+
Settings and UI state (panel size, position, active tab, theme, and whether the secondary strip is folded) are persisted in `localStorage` so they survive page reloads.
158158

159159
The core shell owns the Workbench header, navigation, mount-frame geometry, separators, and surrounding light/dark surfaces. Each external plugin owns everything inside its mount target; core styling deliberately does not reach into plugin descendants. Detaching the Workbench uses a fixed `100vh` Picture-in-Picture layout and restores the stored docked height when reattached.
160160

161161
#### Workbench surfaces and gutters
162162

163163
Two rules keep the shell reading as one surface:
164164

165-
- **Chrome versus canvas.** The header and every secondary strip paint the brand surface (cream in light mode, near-black in dark mode) and close with a translucent ink hairline. Destination content and plugin mount frames paint the workspace surface. A plugin pane can paint any colour it likes, so the separator between panes uses a mid-tone border that stays visible against both.
165+
- **Chrome versus canvas.** The header and every secondary strip paint the brand surface (cream in light mode, near-black in dark mode) and close with a translucent ink hairline. Destination content and plugin mount frames paint the workspace surface. A plugin pane can paint any colour it likes. The resize gutter between panes is invisible at rest and paints a line on hover or keyboard focus.
166166
- **One gutter.** `WORKBENCH_GUTTER` (16px, or `WORKBENCH_GUTTER_NARROW` at 12px below 430px) is the single inline gutter. The header, the strips, and each destination's content all start there, so the left edge is one column instead of three. `MainPanel withPadding` uses the same value.
167167

168-
Colour comes from the semantic theme only. Raw hex values in core-owned source are rejected by `tests/semantic-color-usage.test.ts` unless they carry a narrow, path-scoped `semantic-color-exempt` marker — currently only third-party network marks and the source-inspector highlight alpha. Status colours (success, warning, error, info) mark real state; identity accents do not compete with them, so a card that is both featured and active keeps the neutral outline and lets its badge say which it is.
168+
Colour comes from the semantic theme only. Raw hex values in core-owned source are rejected by `tests/semantic-color-usage.test.ts` unless they carry a narrow, path-scoped `semantic-color-exempt` marker. The current exemptions are third-party network marks, the source-inspector highlight alpha, and the trigger rainbow mark. Status colours (success, warning, error, info) mark real state; identity accents do not compete with them, so a card that is both featured and active keeps the neutral outline and lets its badge say which it is.
169169

170170
### @tanstack/devtools-ui -- Component Library
171171

docs/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ The `config` object is mainly focused around user interaction with the devtools
3535
{ position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'middle-left' | 'middle-right' }
3636
```
3737

38-
- `triggerMode` - How the trigger is placed. `'fixed'` anchors it to `position`; `'floating'` lets you drag the trigger anywhere on screen (and throw itit glides with momentum and springs back off the edges). The floating spot is persisted in local storage.
38+
- `triggerMode` - How the trigger is placed. `'floating'` (the default) lets you drag the trigger anywhere on screen, and throw it: it glides with momentum and springs back off the edges. `'fixed'` anchors it to `position`. The floating spot is persisted in local storage.
3939

4040
```ts
4141
{ triggerMode: 'fixed' | 'floating' }

docs/plugin-workspace.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ close it, so there is only ever one control for it.
1818
same zones as below. Dropping onto an empty workspace gives it the whole area.
1919

2020
The strip folds itself away when everything is open, and comes back on its own the
21-
moment a plugin closes and returns to it.
21+
moment a plugin closes and returns to it. A fold you make with the pull tab is
22+
kept across reloads.
2223

2324
## Arranging panes
2425

@@ -50,8 +51,9 @@ or bottom edge stack instead. Drag the panel taller first if you want rows.
5051

5152
## Resizing
5253

53-
Drag the gutter between two panes. One pane grows by exactly what the other loses,
54-
and neither can shrink past a readable minimum.
54+
Each pane sits in a rounded card with a small gutter from the workspace edge.
55+
Drag between cards to resize: the resize line appears on hover. One pane grows
56+
by exactly what the other loses, and neither can shrink past a readable minimum.
5557

5658
## Keyboard
5759

e2e/apps/react-vite/tests/plugin-workspace.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,13 @@ test('dragging the gutter moves width from one pane to the other', async ({
8080

8181
const afterDemo = (await dt.pane(DEMO).boundingBox())!.width
8282
const afterProbe = (await dt.pane(PROBE).boundingBox())!.width
83-
expect(afterDemo).toBeGreaterThan(beforeDemo + 50)
83+
const moved = afterDemo - beforeDemo
84+
// The gutter must follow the pointer (~120px), not compound each move into
85+
// a spring that flings the pane across the workspace.
86+
expect(moved).toBeGreaterThan(80)
87+
expect(moved).toBeLessThan(160)
8488
// One grows by exactly what the other loses.
85-
expect(afterDemo - beforeDemo).toBeCloseTo(beforeProbe - afterProbe, 0)
89+
expect(moved).toBeCloseTo(beforeProbe - afterProbe, 0)
8690
expect(afterDemo + afterProbe).toBeCloseTo(beforeDemo + beforeProbe, 0)
8791
})
8892

packages/devtools-ui/src/styles/use-styles.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,27 @@ const stylesFactory = (theme: TanStackDevtoolsTheme) => {
683683
/* Keep a scroll gesture inside the devtools instead of chaining it on
684684
to the host page once this panel hits its end. */
685685
overscroll-behavior: contain;
686+
scrollbar-width: thin;
687+
scrollbar-color: ${semantic.color.border.control} transparent;
688+
&::-webkit-scrollbar {
689+
width: 8px;
690+
height: 8px;
691+
}
692+
&::-webkit-scrollbar-track {
693+
background: transparent;
694+
}
695+
&::-webkit-scrollbar-thumb {
696+
background-color: ${semantic.color.border.control};
697+
border-radius: 999px;
698+
border: 2px solid transparent;
699+
background-clip: padding-box;
700+
}
701+
&::-webkit-scrollbar-thumb:hover {
702+
background-color: ${semantic.color.text.muted};
703+
}
704+
&::-webkit-scrollbar-corner {
705+
background: transparent;
706+
}
686707
height: 100%;
687708
&::selection,
688709
& *::selection {

packages/devtools/skills/devtools-app-setup/SKILL.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ Pass a `config` prop to `TanStackDevtools` to set initial shell behavior. These
159159
Storage keys used internally:
160160

161161
- `tanstack_devtools_settings` -- persisted settings
162-
- `tanstack_devtools_state` -- persisted UI state (active tab, panel height, active plugins, persistOpen)
162+
- `tanstack_devtools_state` -- persisted UI state (active tab, panel height, layout, persistOpen, subheaderCollapsed)
163163

164164
All config properties are optional. Defaults shown below:
165165

@@ -168,7 +168,8 @@ All config properties are optional. Defaults shown below:
168168
config={{
169169
defaultOpen: false, // open panel on mount
170170
hideUntilHover: false, // hide trigger until mouse hover
171-
position: 'bottom-right', // trigger position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'middle-left' | 'middle-right'
171+
position: 'bottom-right', // used when triggerMode is 'fixed': 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'middle-left' | 'middle-right'
172+
triggerMode: 'floating', // 'floating' (default, draggable) | 'fixed'
172173
panelLocation: 'bottom', // panel position: 'top' | 'bottom'
173174
openHotkey: ['Control', '~'],
174175
inspectHotkey: ['Shift', 'Alt', 'CtrlOrMeta'],

0 commit comments

Comments
 (0)