@stacksjs/components 0.2.53 → 0.2.63
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-73vc78as.stx → Sidebar-0jzasrmt.stx} +116 -22
- package/dist/{SidebarHeader-7v174a9c.stx → SidebarHeader-ywpmx14d.stx} +80 -3
- package/dist/{SidebarItem-3y3e8g2t.stx → SidebarItem-h53sgqzz.stx} +8 -8
- package/dist/{SidebarSection-z5ey6awe.stx → SidebarSection-npt9h265.stx} +2 -2
- package/dist/index.js +6 -6
- package/dist/ui/sidebar/Sidebar.stx +9 -0
- package/dist/ui/sidebar/SidebarHeader.stx +7 -0
- package/dist/ui/sidebar/SidebarItem.stx +1 -1
- package/dist/ui/sidebar/index.d.ts +14 -0
- package/package.json +5 -5
- package/src/ui/sidebar/Sidebar.stx +116 -22
- package/src/ui/sidebar/SidebarHeader.stx +80 -3
- package/src/ui/sidebar/SidebarItem.stx +8 -8
- package/src/ui/sidebar/SidebarSection.stx +2 -2
- package/src/ui/sidebar/index.ts +30 -0
- package/src/utils/accessibility.ts +1 -1
|
@@ -4,10 +4,19 @@ export const collapsed = $props.collapsed ?? false
|
|
|
4
4
|
export const collapsible = $props.collapsible ?? true
|
|
5
5
|
export const width = $props.width || 240
|
|
6
6
|
export const minWidth = $props.minWidth || 64
|
|
7
|
+
export const collapseMode = $props.collapseMode || 'rail'
|
|
7
8
|
export const variant = $props.variant || 'tahoe'
|
|
8
9
|
export const position = $props.position || 'left'
|
|
9
10
|
export const placement = $props.placement || 'fixed'
|
|
10
11
|
export const bordered = $props.bordered ?? true
|
|
12
|
+
export const materialOpacity = $props.materialOpacity ?? (variant === 'desktop' ? 0.78 : 0.7)
|
|
13
|
+
export const materialDarkOpacity = $props.materialDarkOpacity ?? (variant === 'desktop' ? 0.8 : materialOpacity)
|
|
14
|
+
export const materialScheme = $props.materialScheme || 'system'
|
|
15
|
+
export const persistKey = $props.persistKey || ''
|
|
16
|
+
export const shellSelector = $props.shellSelector || ''
|
|
17
|
+
export const widthVar = $props.widthVar || '--stx-sidebar-width'
|
|
18
|
+
export const collapsedClass = $props.collapsedClass || ''
|
|
19
|
+
export const nativeMaterialCollapse = $props.nativeMaterialCollapse ?? (variant === 'desktop' && collapseMode === 'hidden')
|
|
11
20
|
export const className = $props.className || ''
|
|
12
21
|
|
|
13
22
|
const variantStyles = {
|
|
@@ -44,13 +53,13 @@ const variantStyles = {
|
|
|
44
53
|
slot: 'px-5 py-5',
|
|
45
54
|
},
|
|
46
55
|
desktop: {
|
|
47
|
-
bg: 'bg-
|
|
48
|
-
border: 'border-white/
|
|
49
|
-
backdrop: 'backdrop-blur-3xl backdrop-saturate-
|
|
56
|
+
bg: 'bg-[#f3f3f1]/48 dark:bg-neutral-950/32',
|
|
57
|
+
border: 'border-white/15 dark:border-white/10',
|
|
58
|
+
backdrop: 'backdrop-blur-3xl backdrop-saturate-150',
|
|
50
59
|
tint: false,
|
|
51
60
|
shimmer: true,
|
|
52
|
-
nav: 'px-
|
|
53
|
-
slot: 'px-
|
|
61
|
+
nav: 'px-5 py-2 space-y-1',
|
|
62
|
+
slot: 'px-5 py-2',
|
|
54
63
|
},
|
|
55
64
|
}
|
|
56
65
|
|
|
@@ -77,7 +86,9 @@ export const containerClasses = [
|
|
|
77
86
|
className,
|
|
78
87
|
].filter(Boolean).join(' ')
|
|
79
88
|
|
|
80
|
-
export const collapseBtnPosition =
|
|
89
|
+
export const collapseBtnPosition = variant === 'desktop'
|
|
90
|
+
? (position === 'left' ? 'left-[166px]' : 'right-[166px]')
|
|
91
|
+
: (position === 'left' ? 'right-2' : 'left-2')
|
|
81
92
|
export const navClasses = style.nav || 'px-3 py-2 space-y-1'
|
|
82
93
|
export const slotClasses = style.slot || 'px-3 py-2'
|
|
83
94
|
</script>
|
|
@@ -88,9 +99,18 @@ const collapsedProp = {{ collapsed }}
|
|
|
88
99
|
const collapsibleProp = {{ collapsible }}
|
|
89
100
|
const widthProp = {{ width }}
|
|
90
101
|
const minWidthProp = {{ minWidth }}
|
|
102
|
+
const collapseModeProp = {{ collapseMode }}
|
|
91
103
|
const sectionsProp = {{ sections }}
|
|
92
104
|
const positionProp = {{ position }}
|
|
93
105
|
const variantProp = {{ variant }}
|
|
106
|
+
const materialOpacityProp = {{ materialOpacity }}
|
|
107
|
+
const materialDarkOpacityProp = {{ materialDarkOpacity }}
|
|
108
|
+
const materialSchemeProp = {{ materialScheme }}
|
|
109
|
+
const persistKeyProp = {{ persistKey }}
|
|
110
|
+
const shellSelectorProp = {{ shellSelector }}
|
|
111
|
+
const widthVarProp = {{ widthVar }}
|
|
112
|
+
const collapsedClassProp = {{ collapsedClass }}
|
|
113
|
+
const nativeMaterialCollapseProp = {{ nativeMaterialCollapse }}
|
|
94
114
|
|
|
95
115
|
const collapsed = state(collapsedProp)
|
|
96
116
|
const isHovered = state(false)
|
|
@@ -98,14 +118,45 @@ const hasNativeSidebar = state(false)
|
|
|
98
118
|
|
|
99
119
|
const showExpanded = derived(() => !collapsed() || isHovered())
|
|
100
120
|
const sidebarWidth = derived(() => {
|
|
121
|
+
if (collapsed() && collapseModeProp === 'hidden') return '0px'
|
|
101
122
|
if (collapsed() && !isHovered()) return `${minWidthProp}px`
|
|
102
123
|
return `${widthProp}px`
|
|
103
124
|
})
|
|
104
125
|
const collapseAriaLabel = derived(() => collapsed() ? 'Expand sidebar' : 'Collapse sidebar')
|
|
105
|
-
|
|
126
|
+
|
|
127
|
+
function applyCollapseEffects(nextCollapsed) {
|
|
128
|
+
if (persistKeyProp) {
|
|
129
|
+
try {
|
|
130
|
+
window.localStorage?.setItem(persistKeyProp, nextCollapsed ? 'true' : 'false')
|
|
131
|
+
}
|
|
132
|
+
catch {}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (shellSelectorProp) {
|
|
136
|
+
document.querySelectorAll(shellSelectorProp).forEach((shell) => {
|
|
137
|
+
shell.style?.setProperty?.(widthVarProp, nextCollapsed && collapseModeProp === 'hidden' ? '0px' : `${widthProp}px`)
|
|
138
|
+
if (shell.dataset) shell.dataset.sidebarCollapsed = nextCollapsed ? 'true' : 'false'
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
document.documentElement.dataset.stxSidebarCollapsed = nextCollapsed ? 'true' : 'false'
|
|
143
|
+
if (collapsedClassProp) {
|
|
144
|
+
document.documentElement.classList.toggle(collapsedClassProp, nextCollapsed)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (nativeMaterialCollapseProp) {
|
|
148
|
+
window.craft?.window?.setWebSidebarCollapsed?.(nextCollapsed).catch?.(() => {})
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function setCollapsed(nextCollapsed, shouldEmit = true) {
|
|
153
|
+
collapsed.set(nextCollapsed)
|
|
154
|
+
applyCollapseEffects(nextCollapsed)
|
|
155
|
+
if (shouldEmit) emit('collapse', nextCollapsed)
|
|
156
|
+
}
|
|
106
157
|
|
|
107
158
|
function onMouseEnter() {
|
|
108
|
-
if (collapsed() && collapsibleProp) isHovered.set(true)
|
|
159
|
+
if (collapsed() && collapsibleProp && collapseModeProp !== 'hidden') isHovered.set(true)
|
|
109
160
|
}
|
|
110
161
|
|
|
111
162
|
function onMouseLeave() {
|
|
@@ -113,8 +164,7 @@ function onMouseLeave() {
|
|
|
113
164
|
}
|
|
114
165
|
|
|
115
166
|
function toggleCollapse() {
|
|
116
|
-
|
|
117
|
-
emit('collapse', collapsed())
|
|
167
|
+
setCollapsed(!collapsed())
|
|
118
168
|
}
|
|
119
169
|
|
|
120
170
|
function onSectionToggle(sectionId) {
|
|
@@ -125,22 +175,46 @@ function onItemClick(event) {
|
|
|
125
175
|
emit('itemClick', event.detail)
|
|
126
176
|
}
|
|
127
177
|
|
|
178
|
+
function isCraftRuntime() {
|
|
179
|
+
return window.__craftNativeSidebar === true
|
|
180
|
+
|| window.craft?.__craft_bridge_loaded === true
|
|
181
|
+
|| !!window.craft?.window
|
|
182
|
+
|| !!window.webkit?.messageHandlers?.craft
|
|
183
|
+
}
|
|
184
|
+
|
|
128
185
|
onMount(async () => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
186
|
+
if (persistKeyProp) {
|
|
187
|
+
try {
|
|
188
|
+
const saved = window.localStorage?.getItem(persistKeyProp)
|
|
189
|
+
if (saved === 'true' || saved === 'false') collapsed.set(saved === 'true')
|
|
190
|
+
}
|
|
191
|
+
catch {}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
applyCollapseEffects(collapsed())
|
|
195
|
+
|
|
196
|
+
if (variantProp === 'desktop' && isCraftRuntime()) {
|
|
197
|
+
document.documentElement.classList.add('has-stx-sidebar-material')
|
|
198
|
+
if (document.body?.dataset) document.body.dataset.sidebarMaterial = 'desktop'
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
hasNativeSidebar.set(isCraftRuntime() && window.craft?.hasNativeSidebar?.() === true)
|
|
202
|
+
|
|
203
|
+
const nativeSidebarApi = window.craft?.nativeUI || window.craft?.components
|
|
204
|
+
if (isCraftRuntime() && nativeSidebarApi?.createSidebar) {
|
|
135
205
|
try {
|
|
136
|
-
await
|
|
206
|
+
const sidebar = await nativeSidebarApi.createSidebar({
|
|
137
207
|
position: positionProp,
|
|
138
208
|
width: widthProp,
|
|
139
209
|
minWidth: minWidthProp,
|
|
210
|
+
collapseMode: collapseModeProp,
|
|
140
211
|
collapsible: collapsibleProp,
|
|
141
212
|
variant: variantProp,
|
|
142
213
|
material: variantProp === 'desktop' ? 'sidebar' : undefined,
|
|
143
|
-
backgroundEffect: variantProp === 'desktop' ? '
|
|
214
|
+
backgroundEffect: variantProp === 'desktop' ? 'vibrancy' : undefined,
|
|
215
|
+
materialOpacity: materialOpacityProp,
|
|
216
|
+
materialDarkOpacity: materialDarkOpacityProp,
|
|
217
|
+
materialScheme: materialSchemeProp,
|
|
144
218
|
allowsVibrancy: variantProp === 'desktop' || variantProp === 'vibrancy' || variantProp === 'tahoe',
|
|
145
219
|
sections: sectionsProp.map(s => ({
|
|
146
220
|
id: s.id,
|
|
@@ -148,6 +222,7 @@ onMount(async () => {
|
|
|
148
222
|
items: s.items?.map(i => ({ id: i.id, label: i.label, icon: i.icon, href: i.href, badge: i.badge })),
|
|
149
223
|
})),
|
|
150
224
|
})
|
|
225
|
+
if (sidebar) hasNativeSidebar.set(true)
|
|
151
226
|
}
|
|
152
227
|
catch (err) {
|
|
153
228
|
console.warn('[Sidebar] Failed to create native sidebar, using web fallback:', err)
|
|
@@ -161,7 +236,10 @@ defineExpose({ collapsed, toggle: toggleCollapse })
|
|
|
161
236
|
<aside
|
|
162
237
|
:show="!hasNativeSidebar()"
|
|
163
238
|
class="{{ containerClasses }} sidebar-container"
|
|
164
|
-
|
|
239
|
+
data-sidebar-variant="{{ variant }}"
|
|
240
|
+
data-sidebar-material-scheme="{{ materialScheme }}"
|
|
241
|
+
:aria-hidden="String(collapsed() && collapseModeProp === 'hidden')"
|
|
242
|
+
:style="`width: ${sidebarWidth()}; --stx-sidebar-material-opacity: ${materialOpacityProp}; --stx-sidebar-material-dark-opacity: ${materialDarkOpacityProp}`"
|
|
165
243
|
@mouseenter="onMouseEnter()"
|
|
166
244
|
@mouseleave="onMouseLeave()"
|
|
167
245
|
role="navigation"
|
|
@@ -171,7 +249,7 @@ defineExpose({ collapsed, toggle: toggleCollapse })
|
|
|
171
249
|
<div class="absolute inset-0 pointer-events-none bg-gradient-to-b from-amber-50/30 via-orange-50/20 to-stone-100/30 dark:from-neutral-800/20 dark:via-neutral-900/10 dark:to-neutral-800/20 mix-blend-overlay"></div>
|
|
172
250
|
@endif
|
|
173
251
|
@if(variantShimmer)
|
|
174
|
-
<div class="absolute inset-0 pointer-events-none bg-[
|
|
252
|
+
<div class="absolute inset-0 pointer-events-none bg-[linear-gradient(112deg,rgba(255,255,255,0.20)_0%,rgba(255,255,255,0.04)_45%,rgba(226,226,222,0.16)_100%)] dark:bg-[linear-gradient(112deg,rgba(255,255,255,0.08)_0%,rgba(255,255,255,0.02)_46%,rgba(255,255,255,0.06)_100%)]"></div>
|
|
175
253
|
@endif
|
|
176
254
|
|
|
177
255
|
@if($slots.header)
|
|
@@ -213,13 +291,15 @@ defineExpose({ collapsed, toggle: toggleCollapse })
|
|
|
213
291
|
|
|
214
292
|
@if(collapsible)
|
|
215
293
|
<button
|
|
216
|
-
:show="showExpanded()"
|
|
217
294
|
type="button"
|
|
218
295
|
class="absolute top-4 {{ collapseBtnPosition }} p-1.5 rounded-lg text-stone-400 hover:text-stone-600 hover:bg-black/5 dark:hover:text-neutral-300 dark:hover:bg-white/10 transition-colors z-20"
|
|
219
296
|
@click="toggleCollapse()"
|
|
220
297
|
:aria-label="collapseAriaLabel()"
|
|
298
|
+
data-sidebar-collapse
|
|
299
|
+
data-stx-sidebar-collapse-button
|
|
221
300
|
>
|
|
222
|
-
<div :
|
|
301
|
+
<div :show="!collapsed()" class="i-hugeicons-sidebar-left w-5 h-5"></div>
|
|
302
|
+
<div :show="collapsed()" class="i-hugeicons-sidebar-right w-5 h-5"></div>
|
|
223
303
|
</button>
|
|
224
304
|
@endif
|
|
225
305
|
</aside>
|
|
@@ -229,7 +309,21 @@ defineExpose({ collapsed, toggle: toggleCollapse })
|
|
|
229
309
|
.overflow-y-auto::-webkit-scrollbar-track { background: transparent; }
|
|
230
310
|
.overflow-y-auto::-webkit-scrollbar-thumb { background-color: rgba(0, 0, 0, 0.15); border-radius: 3px; }
|
|
231
311
|
.overflow-y-auto::-webkit-scrollbar-thumb:hover { background-color: rgba(0, 0, 0, 0.25); }
|
|
312
|
+
.sidebar-container[data-sidebar-variant="desktop"] {
|
|
313
|
+
background-color: rgba(246, 246, 244, var(--stx-sidebar-material-opacity, 0.78));
|
|
314
|
+
backdrop-filter: blur(24px) saturate(1.08);
|
|
315
|
+
-webkit-backdrop-filter: blur(24px) saturate(1.08);
|
|
316
|
+
}
|
|
317
|
+
html.has-native-sidebar [data-stx-native-window-controls] {
|
|
318
|
+
display: none;
|
|
319
|
+
}
|
|
320
|
+
html.has-native-sidebar [data-stx-sidebar-web-chrome] {
|
|
321
|
+
margin-left: 202px;
|
|
322
|
+
}
|
|
232
323
|
@media (prefers-color-scheme: dark) {
|
|
324
|
+
.sidebar-container[data-sidebar-variant="desktop"]:not([data-sidebar-material-scheme="light"]) {
|
|
325
|
+
background-color: rgba(24, 24, 23, var(--stx-sidebar-material-dark-opacity, 0.8));
|
|
326
|
+
}
|
|
233
327
|
.overflow-y-auto::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, 0.15); }
|
|
234
328
|
.overflow-y-auto::-webkit-scrollbar-thumb:hover { background-color: rgba(255, 255, 255, 0.25); }
|
|
235
329
|
}
|
|
@@ -8,6 +8,8 @@ export const searchPlaceholder = $props.searchPlaceholder || 'Search...'
|
|
|
8
8
|
export const searchValue = $props.searchValue || ''
|
|
9
9
|
export const collapsed = $props.collapsed ?? false
|
|
10
10
|
export const variant = $props.variant || 'tahoe'
|
|
11
|
+
export const showWindowControls = $props.showWindowControls ?? (variant === 'desktop' ? 'auto' : false)
|
|
12
|
+
export const showNavigationControls = $props.showNavigationControls ?? variant === 'desktop'
|
|
11
13
|
|
|
12
14
|
const headerVariants = {
|
|
13
15
|
workspace: {
|
|
@@ -19,10 +21,13 @@ const headerVariants = {
|
|
|
19
21
|
searchInput: 'w-full rounded-[16px] border border-zinc-200/70 bg-white/70 px-10 py-2.5 text-[15px] text-zinc-900 placeholder:text-zinc-400 focus:outline-none focus:ring-2 focus:ring-zinc-300/80 dark:border-white/10 dark:bg-white/10 dark:text-white',
|
|
20
22
|
},
|
|
21
23
|
desktop: {
|
|
22
|
-
titlebar: 'h-
|
|
24
|
+
titlebar: 'h-14 flex items-center gap-5 px-5 border-b border-black/5 dark:border-white/10',
|
|
25
|
+
chrome: 'flex shrink-0 items-center justify-start gap-5 min-h-7',
|
|
26
|
+
trafficLight: 'h-3.5 w-3.5 rounded-full shadow-[inset_0_0_0_1px_rgba(0,0,0,0.08)]',
|
|
27
|
+
navButton: 'inline-flex h-7 w-7 items-center justify-center rounded-full text-zinc-500/80 transition-colors hover:bg-white/35 hover:text-zinc-900 disabled:opacity-35 disabled:hover:bg-transparent disabled:hover:text-zinc-500/80 dark:text-zinc-400 dark:hover:bg-white/10 dark:hover:text-white',
|
|
23
28
|
logo: 'w-9 h-9 rounded-[12px] bg-black/80 text-white flex items-center justify-center font-semibold text-sm shadow-sm dark:bg-white/14',
|
|
24
|
-
title: 'text-[
|
|
25
|
-
subtitle: 'text-
|
|
29
|
+
title: 'text-[15px] leading-[22px] font-medium text-zinc-950 dark:text-white truncate',
|
|
30
|
+
subtitle: 'text-xs text-zinc-500 dark:text-zinc-400 truncate',
|
|
26
31
|
searchWrap: 'px-4 pb-4',
|
|
27
32
|
searchInput: 'w-full rounded-[16px] border border-white/40 bg-white/45 px-10 py-2.5 text-[15px] text-zinc-900 placeholder:text-zinc-500 shadow-sm focus:outline-none focus:ring-2 focus:ring-white/70 dark:border-white/10 dark:bg-white/10 dark:text-white',
|
|
28
33
|
},
|
|
@@ -38,24 +43,96 @@ const headerVariants = {
|
|
|
38
43
|
|
|
39
44
|
const headerStyle = headerVariants[variant] || headerVariants.default
|
|
40
45
|
export const titlebarClasses = headerStyle.titlebar
|
|
46
|
+
export const chromeClasses = headerStyle.chrome || ''
|
|
47
|
+
export const trafficLightClasses = headerStyle.trafficLight || ''
|
|
48
|
+
export const navButtonClasses = headerStyle.navButton || ''
|
|
41
49
|
export const logoClasses = headerStyle.logo
|
|
42
50
|
export const titleClasses = headerStyle.title
|
|
43
51
|
export const subtitleClasses = headerStyle.subtitle
|
|
44
52
|
export const searchWrapClasses = headerStyle.searchWrap
|
|
45
53
|
export const searchInputClasses = headerStyle.searchInput
|
|
54
|
+
export const hasDesktopChrome = variant === 'desktop' && (showWindowControls || showNavigationControls)
|
|
55
|
+
export const windowControlsClasses = showWindowControls === 'auto' ? 'hidden items-center gap-2' : 'flex items-center gap-2'
|
|
46
56
|
</script>
|
|
47
57
|
|
|
48
58
|
<script client>
|
|
49
59
|
const emit = defineEmits()
|
|
50
60
|
|
|
61
|
+
function isCraftRuntime() {
|
|
62
|
+
return window.__craftNativeSidebar === true
|
|
63
|
+
|| window.craft?.__craft_bridge_loaded === true
|
|
64
|
+
|| !!window.craft?.window
|
|
65
|
+
|| !!window.webkit?.messageHandlers?.craft
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function usesCustomWindowControls() {
|
|
69
|
+
return window.__craftCustomWindowControls === true
|
|
70
|
+
|| document.documentElement.classList.contains('has-custom-window-controls')
|
|
71
|
+
|| document.body?.dataset?.customWindowControls === 'true'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function syncWindowControls() {
|
|
75
|
+
document.querySelectorAll('[data-stx-native-window-controls]').forEach((element) => {
|
|
76
|
+
const show = element.dataset.stxNativeWindowControls === 'auto'
|
|
77
|
+
? isCraftRuntime() && usesCustomWindowControls()
|
|
78
|
+
: true
|
|
79
|
+
element.classList.toggle('hidden', !show)
|
|
80
|
+
element.classList.toggle('flex', show)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
51
84
|
function onSearchInput(event) {
|
|
52
85
|
emit('search', event.target.value)
|
|
53
86
|
}
|
|
87
|
+
|
|
88
|
+
function goBack() {
|
|
89
|
+
window.history.back()
|
|
90
|
+
emit('back')
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function goForward() {
|
|
94
|
+
window.history.forward()
|
|
95
|
+
emit('forward')
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
onMount(() => {
|
|
99
|
+
syncWindowControls()
|
|
100
|
+
window.addEventListener('craft:ready', syncWindowControls)
|
|
101
|
+
window.addEventListener('stx:load', syncWindowControls)
|
|
102
|
+
|
|
103
|
+
return () => {
|
|
104
|
+
window.removeEventListener('craft:ready', syncWindowControls)
|
|
105
|
+
window.removeEventListener('stx:load', syncWindowControls)
|
|
106
|
+
}
|
|
107
|
+
})
|
|
54
108
|
</script>
|
|
55
109
|
|
|
56
110
|
<div class="flex-shrink-0">
|
|
57
111
|
<!-- Title bar area -->
|
|
58
112
|
<div class="{{ titlebarClasses }}">
|
|
113
|
+
@if(hasDesktopChrome)
|
|
114
|
+
<div class="{{ chromeClasses }}" data-stx-sidebar-web-chrome>
|
|
115
|
+
@if(showWindowControls)
|
|
116
|
+
<div class="{{ windowControlsClasses }}" aria-hidden="true" data-stx-native-window-controls="{{ showWindowControls === 'auto' ? 'auto' : 'always' }}">
|
|
117
|
+
<span class="{{ trafficLightClasses }} bg-[#ff5f57]"></span>
|
|
118
|
+
<span class="{{ trafficLightClasses }} bg-[#ffbd2e]"></span>
|
|
119
|
+
<span class="{{ trafficLightClasses }} bg-[#28c840]"></span>
|
|
120
|
+
</div>
|
|
121
|
+
@endif
|
|
122
|
+
|
|
123
|
+
@if(showNavigationControls)
|
|
124
|
+
<div class="flex items-center gap-2">
|
|
125
|
+
<button type="button" class="{{ navButtonClasses }}" @click="goBack()" aria-label="Go back">
|
|
126
|
+
<span class="h-5 w-5 i-hugeicons-arrow-left-02" aria-hidden="true"></span>
|
|
127
|
+
</button>
|
|
128
|
+
<button type="button" class="{{ navButtonClasses }}" @click="goForward()" aria-label="Go forward">
|
|
129
|
+
<span class="h-5 w-5 i-hugeicons-arrow-right-02" aria-hidden="true"></span>
|
|
130
|
+
</button>
|
|
131
|
+
</div>
|
|
132
|
+
@endif
|
|
133
|
+
</div>
|
|
134
|
+
@endif
|
|
135
|
+
|
|
59
136
|
@if(!collapsed)
|
|
60
137
|
<div class="flex items-center gap-3 min-w-0">
|
|
61
138
|
<!-- Logo -->
|
|
@@ -11,20 +11,20 @@ export const variant = $props.variant || 'tahoe'
|
|
|
11
11
|
|
|
12
12
|
const itemVariants = {
|
|
13
13
|
workspace: {
|
|
14
|
-
base: 'flex w-full items-center gap-3 rounded-[
|
|
14
|
+
base: 'flex w-full items-center gap-3 rounded-[16px] px-3.5 py-2 text-[14px] leading-tight transition-colors duration-150',
|
|
15
15
|
indent: '',
|
|
16
16
|
active: 'bg-[#e7e7e5] text-zinc-950',
|
|
17
17
|
inactive: 'text-zinc-700 hover:bg-[#ececea] hover:text-zinc-950 dark:text-zinc-300 dark:hover:bg-white/10',
|
|
18
18
|
icon: active ? 'text-zinc-900 dark:text-zinc-100' : 'text-zinc-500 dark:text-zinc-500',
|
|
19
|
-
badge: 'ml-auto rounded-full bg-white/70 px-
|
|
19
|
+
badge: 'ml-auto grid h-5 min-w-5 place-items-center rounded-full bg-white/70 px-1.5 text-[11px] font-medium text-zinc-500 shadow-sm dark:bg-white/10 dark:text-zinc-400',
|
|
20
20
|
},
|
|
21
21
|
desktop: {
|
|
22
|
-
base: 'flex w-full items-center gap-3 rounded-[
|
|
22
|
+
base: 'flex w-full items-center gap-3 rounded-[14px] px-3 py-1.5 text-[13.5px] leading-tight transition-colors duration-150',
|
|
23
23
|
indent: '',
|
|
24
|
-
active: 'bg-
|
|
25
|
-
inactive: 'text-zinc-700 hover:bg-white/
|
|
26
|
-
icon: active ? 'text-zinc-900 dark:text-white' : 'text-zinc-
|
|
27
|
-
badge: 'ml-auto rounded-full bg-white/
|
|
24
|
+
active: 'bg-[#e8e8e6]/90 text-zinc-950 dark:bg-white/12 dark:text-white',
|
|
25
|
+
inactive: 'text-zinc-700 hover:bg-white/38 hover:text-zinc-950 dark:text-zinc-300 dark:hover:bg-white/10',
|
|
26
|
+
icon: active ? 'text-zinc-900 dark:text-white' : 'text-zinc-600 dark:text-zinc-400',
|
|
27
|
+
badge: 'ml-auto grid h-5 min-w-5 place-items-center rounded-full bg-white/72 px-1.5 text-[11px] font-medium text-zinc-500 shadow-sm dark:bg-white/10 dark:text-zinc-400',
|
|
28
28
|
},
|
|
29
29
|
default: {
|
|
30
30
|
base: 'flex items-center gap-2.5 px-2.5 py-1.5 rounded-md text-[13px] transition-all duration-150',
|
|
@@ -41,7 +41,7 @@ const baseItemList = [itemStyle.base, itemStyle.indent]
|
|
|
41
41
|
const stateClasses = disabled ? 'opacity-50 cursor-not-allowed' : active ? itemStyle.active : itemStyle.inactive
|
|
42
42
|
|
|
43
43
|
export const itemClasses = [...baseItemList, stateClasses].filter(Boolean).join(' ')
|
|
44
|
-
export const iconClasses = `${icon}
|
|
44
|
+
export const iconClasses = `${icon} h-[18px] w-[18px] flex-shrink-0 ${itemStyle.icon}`
|
|
45
45
|
export const badgeClasses = itemStyle.badge
|
|
46
46
|
</script>
|
|
47
47
|
|
|
@@ -14,7 +14,7 @@ const headerVariants = {
|
|
|
14
14
|
hover: 'hover:text-zinc-600 dark:hover:text-zinc-300 cursor-pointer',
|
|
15
15
|
},
|
|
16
16
|
desktop: {
|
|
17
|
-
base: 'w-full flex items-center gap-2.5 px-3
|
|
17
|
+
base: 'w-full flex items-center gap-2.5 px-3 pb-1.5 pt-3 rounded-[14px] text-left transition-colors duration-150 text-[12px] font-semibold uppercase tracking-[0.10em] text-zinc-500/80 dark:text-zinc-400/80',
|
|
18
18
|
hover: 'hover:bg-white/25 dark:hover:bg-white/10 cursor-pointer',
|
|
19
19
|
},
|
|
20
20
|
default: {
|
|
@@ -26,7 +26,7 @@ const headerVariants = {
|
|
|
26
26
|
const headerStyle = headerVariants[variant] || headerVariants.default
|
|
27
27
|
const headerClasses = [headerStyle.base, collapsible ? headerStyle.hover : ''].filter(Boolean).join(' ')
|
|
28
28
|
export const headerClassesValue = headerClasses
|
|
29
|
-
export const sectionClasses = variant === 'workspace'
|
|
29
|
+
export const sectionClasses = variant === 'workspace' ? 'py-1.5' : variant === 'desktop' ? 'py-1' : 'py-1'
|
|
30
30
|
export const groupClasses = variant === 'workspace' || variant === 'desktop' ? 'space-y-1 overflow-hidden' : 'mt-1 space-y-0.5 overflow-hidden'
|
|
31
31
|
export const labelClasses = variant === 'workspace' || variant === 'desktop'
|
|
32
32
|
? 'flex-1 truncate'
|