@stacksjs/components 0.2.119 → 0.2.120
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Sidebar-hjazqxv8.stx → Sidebar-vgckg8f7.stx} +185 -33
- package/dist/{SidebarFooter-0aegr99p.stx → SidebarFooter-s7skj92y.stx} +46 -0
- package/dist/{SidebarHeader-ed5wb13t.stx → SidebarHeader-sa9mtdst.stx} +94 -1
- package/dist/SidebarPinned-tvj28bm0.stx +88 -0
- package/dist/SidebarSpace-61b662jx.stx +134 -0
- package/dist/SidebarSpaceSwitcher-882njcxq.stx +98 -0
- package/dist/SidebarSpaces-gq3mx984.stx +560 -0
- package/dist/index.js +164 -7
- package/dist/ui/sidebar/index.d.ts +17 -30
- package/dist/ui/sidebar/rows.d.ts +43 -0
- package/dist/ui/sidebar/spaces.d.ts +105 -0
- package/dist/ui/sidebar/themes.d.ts +5 -0
- package/package.json +3 -3
- package/src/ui/sidebar/Sidebar.stx +185 -33
- package/src/ui/sidebar/SidebarFooter.stx +46 -0
- package/src/ui/sidebar/SidebarHeader.stx +94 -1
- package/src/ui/sidebar/SidebarPinned.stx +88 -0
- package/src/ui/sidebar/SidebarSpace.stx +134 -0
- package/src/ui/sidebar/SidebarSpaceSwitcher.stx +98 -0
- package/src/ui/sidebar/SidebarSpaces.stx +560 -0
- package/src/ui/sidebar/index.ts +38 -42
- package/src/ui/sidebar/rows.ts +55 -0
- package/src/ui/sidebar/spaces.ts +260 -0
- package/src/ui/sidebar/themes.ts +108 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes a sidebar's rows are described with.
|
|
3
|
+
*
|
|
4
|
+
* These live apart from `index.ts` because both the barrel and `spaces.ts`
|
|
5
|
+
* need them: a space carries sections exactly like a plain sidebar does. With
|
|
6
|
+
* the definitions in the barrel, the leaf had to import from it and the two
|
|
7
|
+
* modules formed a cycle — legal for types, but it drags the whole public
|
|
8
|
+
* surface into any program that touches one small module.
|
|
9
|
+
*
|
|
10
|
+
* `index.ts` re-exports everything here, so this split is invisible to callers.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* One navigation row.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* { id: 'icloud', label: 'iCloud', icon: 'i-f7-tray', iconColor: 'blue', count: 248, active: true }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export interface SidebarItemData {
|
|
23
|
+
id: string
|
|
24
|
+
label: string
|
|
25
|
+
/** Iconify utility class, e.g. `i-f7-tray`. F7 icons mirror SF Symbols. */
|
|
26
|
+
icon?: string
|
|
27
|
+
/** macOS system color name (`"blue"`, `"red"`, `"yellow"`, …) or any CSS color. */
|
|
28
|
+
iconColor?: string
|
|
29
|
+
/** Image URL rendered instead of an icon (album art, avatars). */
|
|
30
|
+
image?: string
|
|
31
|
+
href?: string
|
|
32
|
+
/** Right-aligned count — rendered as plain gray text like native macOS. */
|
|
33
|
+
count?: string | number
|
|
34
|
+
/** @deprecated Use `count`. */
|
|
35
|
+
badge?: string | number
|
|
36
|
+
active?: boolean
|
|
37
|
+
disabled?: boolean
|
|
38
|
+
/** Nested rows, indented and collapsible under this one. */
|
|
39
|
+
children?: SidebarItemData[]
|
|
40
|
+
/** Show a disclosure chevron even without children. */
|
|
41
|
+
expandable?: boolean
|
|
42
|
+
/** Initial disclosure state when the item has children. Defaults to true. */
|
|
43
|
+
expanded?: boolean
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** A titled group of rows (e.g. "Favorites"). Untitled when `label` is empty. */
|
|
47
|
+
export interface SidebarSectionData {
|
|
48
|
+
id: string
|
|
49
|
+
label?: string
|
|
50
|
+
items: SidebarItemData[]
|
|
51
|
+
/** Section headers collapse their group on click. Defaults to true. */
|
|
52
|
+
collapsible?: boolean
|
|
53
|
+
/** Initial collapse state. Defaults to false (expanded). */
|
|
54
|
+
collapsed?: boolean
|
|
55
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar spaces — the data side of Arc's swipeable scenes.
|
|
3
|
+
*
|
|
4
|
+
* A *space* is a whole sidebar at once: its own pinned tiles, its own folders
|
|
5
|
+
* and rows, its own bottom action, and — the part that carries the identity —
|
|
6
|
+
* its own color. Arc stacks them side by side and you swipe horizontally to
|
|
7
|
+
* move between them. `<SidebarSpaces>` renders that; this module owns
|
|
8
|
+
* everything about a space that is data rather than markup.
|
|
9
|
+
*
|
|
10
|
+
* ## Color is derived, never enumerated
|
|
11
|
+
*
|
|
12
|
+
* A space carries one seed color and every surface is mixed from it:
|
|
13
|
+
*
|
|
14
|
+
* from / to the panel's gradient stops
|
|
15
|
+
* ink the text color the whole space inherits
|
|
16
|
+
* accent the saturated color for the selected switcher icon
|
|
17
|
+
*
|
|
18
|
+
* The mixing happens in CSS via `color-mix(in oklab, …)` rather than in
|
|
19
|
+
* TypeScript, for three reasons. The browser interpolates in a perceptually
|
|
20
|
+
* even space, so a yellow space and a blue space land at the same apparent
|
|
21
|
+
* lightness instead of yellow washing out. `tint: 'blue'` (a macOS system
|
|
22
|
+
* color) and `tint: '#ff6b6b'` (a brand color) go through the identical path,
|
|
23
|
+
* so there is no second-class citizen. And because the output is a real
|
|
24
|
+
* `<color>`, the registered custom properties in `Sidebar.stx` can *animate*
|
|
25
|
+
* it — switching spaces crossfades the panel instead of cutting.
|
|
26
|
+
*
|
|
27
|
+
* ## Two palettes, one source
|
|
28
|
+
*
|
|
29
|
+
* Every tint resolves to a light and a dark set, and both are written to the
|
|
30
|
+
* pane as inline custom properties (`--stx-space-light-*`, `--stx-space-dark-*`).
|
|
31
|
+
* The scoped CSS picks between them under `prefers-color-scheme`. That split
|
|
32
|
+
* matters: it keeps the appearance switch in CSS, so a space renders correctly
|
|
33
|
+
* in dark mode on the *server*, before any client script runs.
|
|
34
|
+
*
|
|
35
|
+
* @module
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
import type { SidebarSectionData } from './rows'
|
|
39
|
+
import { macosColors, type MacosColor } from './themes'
|
|
40
|
+
|
|
41
|
+
/** The four surfaces a space paints, in one appearance. */
|
|
42
|
+
export interface SidebarSpaceTintColors {
|
|
43
|
+
/** Top stop of the panel gradient. */
|
|
44
|
+
from: string
|
|
45
|
+
/** Bottom stop of the panel gradient. */
|
|
46
|
+
to: string
|
|
47
|
+
/** Text color inherited by everything inside the space. */
|
|
48
|
+
ink: string
|
|
49
|
+
/** Saturated color for the active switcher icon and focus rings. */
|
|
50
|
+
accent: string
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** A space's palette in both appearances. */
|
|
54
|
+
export interface SidebarSpaceTint {
|
|
55
|
+
light: SidebarSpaceTintColors
|
|
56
|
+
dark: SidebarSpaceTintColors
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** A tile in a space's pinned grid — Arc's favorites row. */
|
|
60
|
+
export interface SidebarPinnedItemData {
|
|
61
|
+
id: string
|
|
62
|
+
/** Accessible name. Shown as a tooltip, never as visible text. */
|
|
63
|
+
label: string
|
|
64
|
+
/** Iconify utility class, e.g. `i-f7-house-fill`. */
|
|
65
|
+
icon?: string
|
|
66
|
+
/** Favicon or artwork URL, rendered instead of an icon. */
|
|
67
|
+
image?: string
|
|
68
|
+
/** macOS system color name or any CSS color, applied to `icon`. */
|
|
69
|
+
iconColor?: string
|
|
70
|
+
href?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A single labelled action row (Arc's "+ New Tab", Notes' "+ New Note"). */
|
|
74
|
+
export interface SidebarSpaceActionData {
|
|
75
|
+
/** Emitted back to the app. Defaults to the space id suffixed with the role. */
|
|
76
|
+
id?: string
|
|
77
|
+
label: string
|
|
78
|
+
/** Iconify utility class. Defaults to a plus for the primary action. */
|
|
79
|
+
icon?: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** One scene in a swipeable sidebar. */
|
|
83
|
+
export interface SidebarSpaceData {
|
|
84
|
+
id: string
|
|
85
|
+
/** Title shown above the rows, e.g. "Personal". */
|
|
86
|
+
label?: string
|
|
87
|
+
/** Iconify utility class — used for both the title and the switcher rail. */
|
|
88
|
+
icon?: string
|
|
89
|
+
/**
|
|
90
|
+
* Seed color. A macOS system color name (`'blue'`, `'green'`, …), any CSS
|
|
91
|
+
* color (`'#ff6b6b'`, `'oklch(70% 0.15 20)'`), or a fully specified
|
|
92
|
+
* {@link SidebarSpaceTint} when you want exact control.
|
|
93
|
+
*/
|
|
94
|
+
tint?: string | SidebarSpaceTint
|
|
95
|
+
/** Favorites grid pinned above the rows. */
|
|
96
|
+
pinned?: SidebarPinnedItemData[]
|
|
97
|
+
/** Row groups, identical in shape to a plain `<Sidebar>`'s sections. */
|
|
98
|
+
sections?: SidebarSectionData[]
|
|
99
|
+
/** Primary action row at the foot of the list. */
|
|
100
|
+
action?: SidebarSpaceActionData
|
|
101
|
+
/** Small trailing action on the rule above `action` — Arc's "Clear". */
|
|
102
|
+
clear?: SidebarSpaceActionData
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Payload of the `spaceChange` event. */
|
|
106
|
+
export interface SidebarSpaceChangeEvent {
|
|
107
|
+
id: string
|
|
108
|
+
index: number
|
|
109
|
+
/** What moved the sidebar — useful for telling a user gesture from a restore. */
|
|
110
|
+
source: 'swipe' | 'switcher' | 'keyboard' | 'native' | 'restore' | 'api'
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** A space with its palette resolved and its inline custom properties built. */
|
|
114
|
+
export interface NormalizedSidebarSpace {
|
|
115
|
+
id: string
|
|
116
|
+
label: string
|
|
117
|
+
icon: string
|
|
118
|
+
pinned: SidebarPinnedItemData[]
|
|
119
|
+
sections: SidebarSectionData[]
|
|
120
|
+
action: SidebarSpaceActionData | null
|
|
121
|
+
clear: SidebarSpaceActionData | null
|
|
122
|
+
tint: SidebarSpaceTint
|
|
123
|
+
/** `style` attribute value that publishes this space's palette. */
|
|
124
|
+
style: string
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Neutral seed for spaces that declare no tint. Deliberately the macOS system
|
|
129
|
+
* gray rather than a literal gray, so an untinted space sits in the same
|
|
130
|
+
* perceptual family as the tinted ones instead of reading as "broken".
|
|
131
|
+
*/
|
|
132
|
+
const NEUTRAL_SEED = macosColors.gray
|
|
133
|
+
|
|
134
|
+
function mix(color: string, percent: number, into: string): string {
|
|
135
|
+
return `color-mix(in oklab, ${color} ${percent}%, ${into})`
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Build a full light/dark palette from one seed color.
|
|
140
|
+
*
|
|
141
|
+
* The percentages are the tuning surface of the whole feature, so they are
|
|
142
|
+
* worth stating plainly. In light appearance the panel stays *pale* — 16% and
|
|
143
|
+
* 34% of the seed — because Arc's spaces are washes, not fills; anything
|
|
144
|
+
* stronger and the white selection cards stop reading as raised. The ink is
|
|
145
|
+
* the seed pulled almost to black (22% seed) so text keeps a hint of the
|
|
146
|
+
* space's hue without losing contrast. In dark appearance the relationship
|
|
147
|
+
* inverts: the seed is mixed *into* near-black for the panel and *into* white
|
|
148
|
+
* for the ink and accent, which keeps a dark space recognizably the same color
|
|
149
|
+
* as its light counterpart rather than a different one.
|
|
150
|
+
*/
|
|
151
|
+
export function deriveSpaceTint(seed: string): SidebarSpaceTint {
|
|
152
|
+
return {
|
|
153
|
+
light: {
|
|
154
|
+
from: mix(seed, 16, '#ffffff'),
|
|
155
|
+
to: mix(seed, 34, '#ffffff'),
|
|
156
|
+
ink: mix(seed, 22, '#17171b'),
|
|
157
|
+
accent: mix(seed, 88, '#2a2a30'),
|
|
158
|
+
},
|
|
159
|
+
dark: {
|
|
160
|
+
from: mix(seed, 26, '#101014'),
|
|
161
|
+
to: mix(seed, 14, '#08080b'),
|
|
162
|
+
ink: mix(seed, 12, '#f4f4f7'),
|
|
163
|
+
accent: mix(seed, 74, '#ffffff'),
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Resolve a space's `tint` prop to a palette.
|
|
170
|
+
*
|
|
171
|
+
* Accepts a macOS system color name, any CSS color, or a pre-built palette.
|
|
172
|
+
* Unset falls back to the neutral seed.
|
|
173
|
+
*/
|
|
174
|
+
export function resolveSpaceTint(tint?: string | SidebarSpaceTint): SidebarSpaceTint {
|
|
175
|
+
if (!tint)
|
|
176
|
+
return deriveSpaceTint(NEUTRAL_SEED)
|
|
177
|
+
if (typeof tint !== 'string')
|
|
178
|
+
return tint
|
|
179
|
+
return deriveSpaceTint(macosColors[tint as MacosColor] || tint)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Render a palette as inline custom properties.
|
|
184
|
+
*
|
|
185
|
+
* Both appearances are published at once. `Sidebar.stx` maps them onto the
|
|
186
|
+
* four registered properties it actually paints with, choosing per
|
|
187
|
+
* `prefers-color-scheme`, so the correct appearance is already right in the
|
|
188
|
+
* server-rendered HTML.
|
|
189
|
+
*/
|
|
190
|
+
export function spaceTintVars(tint: SidebarSpaceTint): string {
|
|
191
|
+
return [
|
|
192
|
+
`--stx-space-light-from: ${tint.light.from}`,
|
|
193
|
+
`--stx-space-light-to: ${tint.light.to}`,
|
|
194
|
+
`--stx-space-light-ink: ${tint.light.ink}`,
|
|
195
|
+
`--stx-space-light-accent: ${tint.light.accent}`,
|
|
196
|
+
`--stx-space-dark-from: ${tint.dark.from}`,
|
|
197
|
+
`--stx-space-dark-to: ${tint.dark.to}`,
|
|
198
|
+
`--stx-space-dark-ink: ${tint.dark.ink}`,
|
|
199
|
+
`--stx-space-dark-accent: ${tint.dark.accent}`,
|
|
200
|
+
].join('; ')
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function normalizeAction(
|
|
204
|
+
action: SidebarSpaceActionData | undefined,
|
|
205
|
+
spaceId: string,
|
|
206
|
+
role: string,
|
|
207
|
+
fallbackIcon: string,
|
|
208
|
+
): SidebarSpaceActionData | null {
|
|
209
|
+
if (!action || !action.label)
|
|
210
|
+
return null
|
|
211
|
+
return {
|
|
212
|
+
id: action.id || `${spaceId}-${role}`,
|
|
213
|
+
label: action.label,
|
|
214
|
+
icon: action.icon || fallbackIcon,
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Normalize one space so template bindings stay plain property reads. */
|
|
219
|
+
export function normalizeSpace(space: SidebarSpaceData): NormalizedSidebarSpace {
|
|
220
|
+
const tint = resolveSpaceTint(space.tint)
|
|
221
|
+
return {
|
|
222
|
+
id: space.id,
|
|
223
|
+
label: space.label || '',
|
|
224
|
+
icon: space.icon || '',
|
|
225
|
+
pinned: space.pinned || [],
|
|
226
|
+
sections: space.sections || [],
|
|
227
|
+
action: normalizeAction(space.action, space.id, 'action', 'i-f7-plus'),
|
|
228
|
+
clear: normalizeAction(space.clear, space.id, 'clear', 'i-f7-arrow-down'),
|
|
229
|
+
tint,
|
|
230
|
+
style: spaceTintVars(tint),
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function normalizeSpaces(spaces: SidebarSpaceData[]): NormalizedSidebarSpace[] {
|
|
235
|
+
return (spaces || []).map(normalizeSpace)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Index of `id` within `spaces`, or 0 when it is missing.
|
|
240
|
+
*
|
|
241
|
+
* Falling back to the first space rather than to -1 is deliberate: a stale
|
|
242
|
+
* persisted id or a typo should open the sidebar on *something*, never on a
|
|
243
|
+
* blank track scrolled past its own content.
|
|
244
|
+
*/
|
|
245
|
+
export function spaceIndexOf(spaces: NormalizedSidebarSpace[], id?: string): number {
|
|
246
|
+
if (!id)
|
|
247
|
+
return 0
|
|
248
|
+
const index = spaces.findIndex(space => space.id === id)
|
|
249
|
+
return index === -1 ? 0 : index
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The per-space palettes the client controller needs to repaint the pane.
|
|
254
|
+
*
|
|
255
|
+
* Only the colors travel — markup, sections and actions are already in the
|
|
256
|
+
* DOM, so re-serializing them would just bloat the attribute.
|
|
257
|
+
*/
|
|
258
|
+
export function spaceTintPayload(spaces: NormalizedSidebarSpace[]): SidebarSpaceTint[] {
|
|
259
|
+
return spaces.map(space => space.tint)
|
|
260
|
+
}
|
package/src/ui/sidebar/themes.ts
CHANGED
|
@@ -23,6 +23,11 @@
|
|
|
23
23
|
* when the window resigns key it falls back to a neutral fill with the label
|
|
24
24
|
* left dark. Icons desaturate to gray in the same non-key state.
|
|
25
25
|
*
|
|
26
|
+
* The other first-class theme is `arc`, a recreation of the Arc browser's
|
|
27
|
+
* sidebar. It inverts the macOS selection model — a raised white card on a
|
|
28
|
+
* warm tinted panel instead of an accent fill on gray — so it uses the
|
|
29
|
+
* `classes` selection model rather than `accent`. See its own block below.
|
|
30
|
+
*
|
|
26
31
|
* Legacy themes (`workspace`, `desktop`, `solid`, `transparent`, `vibrancy`)
|
|
27
32
|
* are preserved verbatim from the previous variant maps. `tahoe` now aliases
|
|
28
33
|
* `macos` — it always meant "look like macOS", and now it actually does.
|
|
@@ -228,6 +233,108 @@ const desktop: SidebarTheme = {
|
|
|
228
233
|
},
|
|
229
234
|
}
|
|
230
235
|
|
|
236
|
+
/**
|
|
237
|
+
* `arc` — the Arc browser sidebar.
|
|
238
|
+
*
|
|
239
|
+
* Where macOS paints the selected row with the system accent, Arc raises it:
|
|
240
|
+
* the active row becomes a white card floating on a warm tinted panel, with a
|
|
241
|
+
* hairline border and a single-pixel drop shadow. That inversion — light card
|
|
242
|
+
* on tinted ground, rather than saturated fill on gray — is the whole look, so
|
|
243
|
+
* this theme uses the `classes` selection model and puts the card in
|
|
244
|
+
* `item.active` instead of the accent rules the `accent` model applies.
|
|
245
|
+
*
|
|
246
|
+
* Metrics taken from Arc 1.5x at @2x:
|
|
247
|
+
*
|
|
248
|
+
* row pitch 30px with 2px between rows — rows are separate cards, not the
|
|
249
|
+
* contiguous run AppKit uses, so consecutive selections read as distinct
|
|
250
|
+
* selection radius 8px · white fill · 1px hairline · shadow 0 1px 2px/8%
|
|
251
|
+
* label 13px, and the selected row goes to 500 (not 600 — Arc keeps the
|
|
252
|
+
* weight shift subtle because the card already carries the emphasis)
|
|
253
|
+
* section header 11px medium, sentence case, 55% muted
|
|
254
|
+
* icon 16px in an 18px slot · child indent 14px
|
|
255
|
+
* panel warm off-white (#f7f5f1), noticeably warmer than macOS's neutral
|
|
256
|
+
* #f2f2f4 — the warmth is what makes it read as Arc at a glance
|
|
257
|
+
*
|
|
258
|
+
* The panel tint is a soft top-down gradient rather than a flat fill, which is
|
|
259
|
+
* how Arc suggests the current space's color. Apps that want a per-space tint
|
|
260
|
+
* can override `--stx-sidebar-tint` on the pane; the gradient falls back to the
|
|
261
|
+
* warm default when it is unset.
|
|
262
|
+
*/
|
|
263
|
+
const arc: SidebarTheme = {
|
|
264
|
+
selection: 'classes',
|
|
265
|
+
pane: [
|
|
266
|
+
'bg-[#f7f5f1]/92 dark:bg-[#1a1a1c]/92',
|
|
267
|
+
'backdrop-blur-[40px] backdrop-saturate-[160%]',
|
|
268
|
+
'text-[#2c2a28] dark:text-[#ededf0]',
|
|
269
|
+
'select-none',
|
|
270
|
+
].join(' '),
|
|
271
|
+
layers: {
|
|
272
|
+
// Space tint. `--stx-sidebar-tint` lets an app color the panel per space
|
|
273
|
+
// the way Arc does; unset, it resolves to a warm neutral wash.
|
|
274
|
+
tint: [
|
|
275
|
+
'bg-[linear-gradient(180deg,var(--stx-sidebar-tint,rgba(255,251,242,0.55))_0%,rgba(255,255,255,0)_38%)]',
|
|
276
|
+
'dark:bg-[linear-gradient(180deg,var(--stx-sidebar-tint,rgba(255,255,255,0.05))_0%,rgba(255,255,255,0)_42%)]',
|
|
277
|
+
].join(' '),
|
|
278
|
+
},
|
|
279
|
+
scrollArea: 'flex-1 overflow-y-auto overflow-x-hidden px-[8px] pb-[8px]',
|
|
280
|
+
// Text takes its color from the panel rather than declaring its own, and is
|
|
281
|
+
// muted with opacity instead. On the plain warm panel `currentColor` is the
|
|
282
|
+
// pane's own `#2c2a28`, so this renders identically to a hardcoded value —
|
|
283
|
+
// but inside a space it becomes `--stx-space-ink` and the whole list shifts
|
|
284
|
+
// hue with the panel on every swipe. Opacity is safe on these because each
|
|
285
|
+
// is a standalone span; the row itself keeps a solid color, since fading a
|
|
286
|
+
// row would take its white selection card down with it.
|
|
287
|
+
sectionHeader: [
|
|
288
|
+
'group/section flex w-full items-center',
|
|
289
|
+
'px-[8px] pt-[14px] pb-[4px]',
|
|
290
|
+
'text-[11px] font-medium leading-[13px]',
|
|
291
|
+
'opacity-55',
|
|
292
|
+
].join(' '),
|
|
293
|
+
sectionChevron: [
|
|
294
|
+
'i-f7-chevron-down h-[10px] w-[10px] ml-auto',
|
|
295
|
+
'opacity-0 group-hover/section:opacity-100 transition-opacity duration-150',
|
|
296
|
+
'transition-transform duration-200',
|
|
297
|
+
].join(' '),
|
|
298
|
+
// 2px gutter: Arc rows are discrete cards, unlike AppKit's contiguous run.
|
|
299
|
+
sectionGroup: 'flex flex-col space-y-[2px]',
|
|
300
|
+
item: {
|
|
301
|
+
base: [
|
|
302
|
+
'flex w-full items-center',
|
|
303
|
+
'h-[30px] rounded-[8px] pl-[6px] pr-[8px]',
|
|
304
|
+
'text-[13px] leading-[16px] font-normal',
|
|
305
|
+
'text-current',
|
|
306
|
+
'transition-[background-color,box-shadow,color] duration-150 ease-out',
|
|
307
|
+
'cursor-default',
|
|
308
|
+
].join(' '),
|
|
309
|
+
hover: 'hover:bg-white/55 dark:hover:bg-white/8',
|
|
310
|
+
// The signature: a raised white card rather than an accent fill. The label
|
|
311
|
+
// stays on the panel ink — Arc does not recolor a selected row, the card
|
|
312
|
+
// under it carries the emphasis.
|
|
313
|
+
active: [
|
|
314
|
+
'bg-white dark:bg-white/14',
|
|
315
|
+
'font-medium',
|
|
316
|
+
'shadow-[0_1px_2px_rgba(0,0,0,0.08)] dark:shadow-[0_1px_2px_rgba(0,0,0,0.35)]',
|
|
317
|
+
'ring-1 ring-black/5 dark:ring-white/8',
|
|
318
|
+
].join(' '),
|
|
319
|
+
pressed: 'active:bg-white/80 dark:active:bg-white/18',
|
|
320
|
+
disabled: 'opacity-40 pointer-events-none',
|
|
321
|
+
disclosure: 'flex h-[16px] w-[16px] shrink-0 items-center justify-center',
|
|
322
|
+
chevron: [
|
|
323
|
+
'i-f7-chevron-right h-[10px] w-[10px] opacity-45',
|
|
324
|
+
'transition-transform duration-200 ease-out',
|
|
325
|
+
].join(' '),
|
|
326
|
+
iconSlot: 'flex h-[18px] w-[18px] shrink-0 items-center justify-center mr-[8px]',
|
|
327
|
+
icon: 'h-[16px] w-[16px]',
|
|
328
|
+
image: 'h-[18px] w-[18px] rounded-[5px] object-cover shadow-sm',
|
|
329
|
+
label: 'flex-1 truncate text-left',
|
|
330
|
+
count: [
|
|
331
|
+
'ml-[8px] shrink-0 tabular-nums',
|
|
332
|
+
'text-[12px] leading-[16px] opacity-45',
|
|
333
|
+
].join(' '),
|
|
334
|
+
indentPerLevel: 14,
|
|
335
|
+
},
|
|
336
|
+
}
|
|
337
|
+
|
|
231
338
|
const solid: SidebarTheme = {
|
|
232
339
|
...macos,
|
|
233
340
|
pane: 'bg-stone-100 dark:bg-neutral-900 text-black dark:text-white select-none',
|
|
@@ -252,6 +359,7 @@ export const sidebarThemes: Record<string, SidebarTheme> = {
|
|
|
252
359
|
'tahoe': macos,
|
|
253
360
|
'macos-tahoe': macos,
|
|
254
361
|
'macos-latest': macos,
|
|
362
|
+
arc,
|
|
255
363
|
workspace,
|
|
256
364
|
desktop,
|
|
257
365
|
solid,
|