@adea-ai/ui 0.142.4 → 0.143.0

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.
Files changed (81) hide show
  1. package/dist/components/composites/accent-picker/accent-picker.d.ts +28 -0
  2. package/dist/components/composites/accent-picker/accent-picker.d.ts.map +1 -0
  3. package/dist/components/composites/accent-picker/accent-picker.js +97 -0
  4. package/dist/components/composites/accent-picker/accent-picker.js.map +1 -0
  5. package/dist/components/composites/accent-picker/index.d.ts +2 -0
  6. package/dist/components/composites/accent-picker/index.d.ts.map +1 -0
  7. package/dist/components/composites/accent-picker/index.js +2 -0
  8. package/dist/components/composites/icon-picker/icon-picker.d.ts +37 -0
  9. package/dist/components/composites/icon-picker/icon-picker.d.ts.map +1 -0
  10. package/dist/components/composites/icon-picker/icon-picker.js +187 -0
  11. package/dist/components/composites/icon-picker/icon-picker.js.map +1 -0
  12. package/dist/components/composites/icon-picker/image-data-url.d.ts +42 -0
  13. package/dist/components/composites/icon-picker/image-data-url.d.ts.map +1 -0
  14. package/dist/components/composites/icon-picker/image-data-url.js +90 -0
  15. package/dist/components/composites/icon-picker/image-data-url.js.map +1 -0
  16. package/dist/components/composites/icon-picker/index.d.ts +4 -0
  17. package/dist/components/composites/icon-picker/index.d.ts.map +1 -0
  18. package/dist/components/composites/icon-picker/index.js +4 -0
  19. package/dist/components/composites/icon-picker/shell-icons.d.ts +264 -0
  20. package/dist/components/composites/icon-picker/shell-icons.d.ts.map +1 -0
  21. package/dist/components/composites/icon-picker/shell-icons.js +334 -0
  22. package/dist/components/composites/icon-picker/shell-icons.js.map +1 -0
  23. package/dist/components/composites/terminal/terminal.js +2 -2
  24. package/dist/components/composites/terminal/terminal.js.map +1 -1
  25. package/dist/components/composites/workspace-switcher/index.d.ts +2 -0
  26. package/dist/components/composites/workspace-switcher/index.d.ts.map +1 -0
  27. package/dist/components/composites/workspace-switcher/index.js +2 -0
  28. package/dist/components/composites/workspace-switcher/workspace-switcher.d.ts +44 -0
  29. package/dist/components/composites/workspace-switcher/workspace-switcher.d.ts.map +1 -0
  30. package/dist/components/composites/workspace-switcher/workspace-switcher.js +157 -0
  31. package/dist/components/composites/workspace-switcher/workspace-switcher.js.map +1 -0
  32. package/dist/components/layout/shell-rail/index.d.ts +2 -0
  33. package/dist/components/layout/shell-rail/index.d.ts.map +1 -0
  34. package/dist/components/layout/shell-rail/index.js +2 -0
  35. package/dist/components/layout/shell-rail/shell-rail.d.ts +36 -0
  36. package/dist/components/layout/shell-rail/shell-rail.d.ts.map +1 -0
  37. package/dist/components/layout/shell-rail/shell-rail.js +124 -0
  38. package/dist/components/layout/shell-rail/shell-rail.js.map +1 -0
  39. package/dist/components/layout/shell-top-bar/index.d.ts +2 -0
  40. package/dist/components/layout/shell-top-bar/index.d.ts.map +1 -0
  41. package/dist/components/layout/shell-top-bar/index.js +2 -0
  42. package/dist/components/layout/shell-top-bar/shell-top-bar.d.ts +68 -0
  43. package/dist/components/layout/shell-top-bar/shell-top-bar.d.ts.map +1 -0
  44. package/dist/components/layout/shell-top-bar/shell-top-bar.js +135 -0
  45. package/dist/components/layout/shell-top-bar/shell-top-bar.js.map +1 -0
  46. package/dist/index.d.ts +5 -0
  47. package/dist/index.d.ts.map +1 -1
  48. package/dist/index.js +8 -1
  49. package/dist/r/accent-picker.json +25 -0
  50. package/dist/r/icon-picker.json +36 -0
  51. package/dist/r/registry.json +137 -0
  52. package/dist/r/shell-rail.json +27 -0
  53. package/dist/r/shell-top-bar.json +23 -0
  54. package/dist/r/src/components/composites/accent-picker/accent-picker.tsx +85 -0
  55. package/dist/r/src/components/composites/accent-picker/index.ts +1 -0
  56. package/dist/r/src/components/composites/icon-picker/icon-picker.tsx +184 -0
  57. package/dist/r/src/components/composites/icon-picker/image-data-url.ts +107 -0
  58. package/dist/r/src/components/composites/icon-picker/index.ts +20 -0
  59. package/dist/r/src/components/composites/icon-picker/shell-icons.ts +166 -0
  60. package/dist/r/src/components/composites/workspace-switcher/index.ts +5 -0
  61. package/dist/r/src/components/composites/workspace-switcher/workspace-switcher.tsx +128 -0
  62. package/dist/r/src/components/layout/shell-rail/index.ts +1 -0
  63. package/dist/r/src/components/layout/shell-rail/shell-rail.tsx +120 -0
  64. package/dist/r/src/components/layout/shell-top-bar/index.ts +1 -0
  65. package/dist/r/src/components/layout/shell-top-bar/shell-top-bar.tsx +185 -0
  66. package/dist/r/workspace-switcher.json +26 -0
  67. package/package.json +1 -1
  68. package/registry.json +137 -0
  69. package/src/components/composites/accent-picker/accent-picker.tsx +85 -0
  70. package/src/components/composites/accent-picker/index.ts +1 -0
  71. package/src/components/composites/icon-picker/icon-picker.tsx +184 -0
  72. package/src/components/composites/icon-picker/image-data-url.ts +107 -0
  73. package/src/components/composites/icon-picker/index.ts +20 -0
  74. package/src/components/composites/icon-picker/shell-icons.ts +166 -0
  75. package/src/components/composites/workspace-switcher/index.ts +5 -0
  76. package/src/components/composites/workspace-switcher/workspace-switcher.tsx +128 -0
  77. package/src/components/layout/shell-rail/index.ts +1 -0
  78. package/src/components/layout/shell-rail/shell-rail.tsx +120 -0
  79. package/src/components/layout/shell-top-bar/index.ts +1 -0
  80. package/src/components/layout/shell-top-bar/shell-top-bar.tsx +185 -0
  81. package/src/index.ts +5 -0
@@ -0,0 +1,128 @@
1
+ import { ChevronDown, Plus, Settings } from 'lucide-solid'
2
+ import type { JSX } from 'solid-js'
3
+ import { For, Show, createSignal } from 'solid-js'
4
+ import { cn } from '#lib/utils'
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuGroup,
9
+ DropdownMenuItem,
10
+ DropdownMenuLabel,
11
+ DropdownMenuRadioGroup,
12
+ DropdownMenuRadioItem,
13
+ DropdownMenuSeparator,
14
+ DropdownMenuTrigger,
15
+ } from '../../ui/dropdown-menu'
16
+ import { ActionButton } from '../action-button'
17
+
18
+ /**
19
+ * WorkspaceSwitcher.
20
+ *
21
+ * The workspace picker that sits in the top bar beside the sidebar toggle. One
22
+ * ghost button shows the current workspace's mark and name; pressing it opens a
23
+ * radio list of the others. Choosing one only changes what the window is
24
+ * looking at: the switcher reports the id and the host decides what that means,
25
+ * which is why it carries no status of its own and never closes, restarts or
26
+ * moves anything.
27
+ *
28
+ * It is deliberately the simple interaction (a single menu, not a nested
29
+ * accordion): the sidebar below it already shows what is inside the chosen
30
+ * workspace, so the switcher's only job is to name the workspace and let the
31
+ * user change it.
32
+ */
33
+ export type WorkspaceSwitcherItem = {
34
+ id: string
35
+ name: string
36
+ /** The workspace's mark, drawn in the trigger and its row. Decorative. */
37
+ mark: JSX.Element
38
+ /** A quiet trailing readout in the row, e.g. an unread count. Optional. */
39
+ detail?: JSX.Element
40
+ }
41
+
42
+ export type WorkspaceSwitcherProps = {
43
+ workspaces: readonly WorkspaceSwitcherItem[]
44
+ /** The current workspace's id. */
45
+ value: string | undefined
46
+ onValueChange(id: string): void
47
+ /** Offered at the foot of the menu when present. */
48
+ onCreate?(): void
49
+ createLabel?: string
50
+ /** Offered beside the create action when present: open the current workspace's settings. */
51
+ onManage?(): void
52
+ manageLabel?: string
53
+ /** The menu's heading; also the trigger's accessible-name prefix. */
54
+ label?: string
55
+ /** Shown while no workspace is current. */
56
+ placeholder?: string
57
+ disabled?: boolean
58
+ class?: string
59
+ }
60
+
61
+ export function WorkspaceSwitcher(props: WorkspaceSwitcherProps) {
62
+ const [open, setOpen] = createSignal(false)
63
+ const current = () => props.workspaces.find((item) => item.id === props.value)
64
+ const label = () => props.label ?? 'Workspaces'
65
+
66
+ return (
67
+ <DropdownMenu modal={false} open={open()} onOpenChange={setOpen}>
68
+ <DropdownMenuTrigger
69
+ as={ActionButton}
70
+ variant="ghost"
71
+ size="sm"
72
+ disabled={props.disabled}
73
+ data-slot="workspace-switcher"
74
+ tooltip={`Workspace: ${current()?.name ?? props.placeholder ?? 'Choose workspace'}`}
75
+ aria-label={`Switch workspace, current: ${current()?.name ?? 'none'}`}
76
+ class={cn('max-w-full min-w-0 shrink', props.class)}
77
+ >
78
+ <span aria-hidden="true" class="flex shrink-0">
79
+ {current()?.mark}
80
+ </span>
81
+ <span class="min-w-0 max-w-40 truncate">
82
+ {current()?.name ?? props.placeholder ?? 'Choose workspace'}
83
+ </span>
84
+ <ChevronDown aria-hidden="true" class="size-3.5 shrink-0 text-muted-foreground" />
85
+ </DropdownMenuTrigger>
86
+ <DropdownMenuContent align="start" sideOffset={6} class="min-w-56">
87
+ <DropdownMenuGroup>
88
+ <DropdownMenuLabel>{label()}</DropdownMenuLabel>
89
+ <DropdownMenuRadioGroup
90
+ value={props.value}
91
+ onChange={(value) => {
92
+ setOpen(false)
93
+ const id = String(value)
94
+ if (id !== props.value) props.onValueChange(id)
95
+ }}
96
+ >
97
+ <For each={props.workspaces}>
98
+ {(item) => (
99
+ <DropdownMenuRadioItem value={item.id} closeOnSelect data-workspace-id={item.id}>
100
+ <span aria-hidden="true" class="flex shrink-0">
101
+ {item.mark}
102
+ </span>
103
+ <span class="min-w-0 flex-1 truncate">{item.name}</span>
104
+ <Show when={item.detail}>{item.detail}</Show>
105
+ </DropdownMenuRadioItem>
106
+ )}
107
+ </For>
108
+ </DropdownMenuRadioGroup>
109
+ </DropdownMenuGroup>
110
+ <Show when={props.onCreate || props.onManage}>
111
+ <DropdownMenuSeparator />
112
+ <Show when={props.onCreate}>
113
+ <DropdownMenuItem onSelect={() => props.onCreate?.()}>
114
+ <Plus aria-hidden="true" />
115
+ {props.createLabel ?? 'New workspace'}
116
+ </DropdownMenuItem>
117
+ </Show>
118
+ <Show when={props.onManage}>
119
+ <DropdownMenuItem onSelect={() => props.onManage?.()}>
120
+ <Settings aria-hidden="true" />
121
+ {props.manageLabel ?? 'Workspace settings…'}
122
+ </DropdownMenuItem>
123
+ </Show>
124
+ </Show>
125
+ </DropdownMenuContent>
126
+ </DropdownMenu>
127
+ )
128
+ }
@@ -0,0 +1 @@
1
+ export { ShellRail, type ShellRailProps } from './shell-rail'
@@ -0,0 +1,120 @@
1
+ import { Search } from 'lucide-solid'
2
+ import type { ComponentProps, JSX } from 'solid-js'
3
+ import { children, For, Show, splitProps } from 'solid-js'
4
+ import { cn } from '#lib/utils'
5
+ import { Kbd, KbdGroup } from '../../ui/kbd'
6
+ import { Separator } from '../../ui/separator'
7
+ import {
8
+ SideRail,
9
+ SideRailContent,
10
+ SideRailFooter,
11
+ SideRailHeader,
12
+ SideRailItem,
13
+ } from '../side-rail'
14
+
15
+ /**
16
+ * ShellRail.
17
+ *
18
+ * The side rail both applications put at the window's leading edge: always the
19
+ * collapsed icon column, with the app's mark at the top, a search entry point
20
+ * under it, the app's destinations in the middle and a footer for account and
21
+ * settings.
22
+ *
23
+ * The rail is never the thing the sidebar toggle collapses. The toggle belongs
24
+ * to the sidebar beside the rail, which is why this component takes no
25
+ * `collapsed` prop: a rail that could be expanded would be a second sidebar,
26
+ * and the two apps would drift on which of them the toggle meant.
27
+ *
28
+ * Destinations are the caller's: pass `SideRailItem`s (or a `SideRailSection`)
29
+ * as children. The mark, the search row and the footer are slots with the
30
+ * geometry decided here, so the rail's rhythm cannot differ between apps.
31
+ */
32
+ export type ShellRailProps = Omit<ComponentProps<'nav'>, 'children'> & {
33
+ /** The app's mark. Decorative: the rail names itself through `aria-label`. */
34
+ mark: JSX.Element
35
+ /** Opens search. Omit to leave the search row out. */
36
+ onSearch?: () => void
37
+ /** The search row's accessible name. */
38
+ searchLabel?: string
39
+ /** The chord as it is announced, e.g. `Meta+K Control+K`. */
40
+ searchKeyshortcuts?: string
41
+ /** The cap labels drawn under the icon, in press order, e.g. `['⌘', 'K']`. */
42
+ searchKeys?: readonly string[]
43
+ /** Destinations between the search row and the footer. */
44
+ children?: JSX.Element
45
+ /** Account, plugins, settings. Pinned to the rail's foot. */
46
+ footer?: JSX.Element
47
+ }
48
+
49
+ export function ShellRail(props: ShellRailProps) {
50
+ const [local, rest] = splitProps(props, [
51
+ 'class',
52
+ 'mark',
53
+ 'onSearch',
54
+ 'searchLabel',
55
+ 'searchKeyshortcuts',
56
+ 'searchKeys',
57
+ 'children',
58
+ 'footer',
59
+ 'aria-label',
60
+ ])
61
+
62
+ // Resolve the footer once: reading a JSX prop twice builds two copies.
63
+ const footer = children(() => local.footer)
64
+ const content = children(() => local.children)
65
+
66
+ return (
67
+ <SideRail
68
+ collapsed
69
+ data-slot="shell-rail"
70
+ aria-label={local['aria-label'] ?? 'Global navigation'}
71
+ class={cn('relative z-(--z-sticky) min-w-0', local.class)}
72
+ {...rest}
73
+ >
74
+ <SideRailHeader data-slot="shell-rail-header" class="h-auto justify-center px-0 pt-1">
75
+ <span
76
+ data-slot="shell-rail-mark"
77
+ aria-hidden="true"
78
+ class="flex h-rail-item items-center justify-center"
79
+ >
80
+ {local.mark}
81
+ </span>
82
+ </SideRailHeader>
83
+
84
+ <SideRailContent data-slot="shell-rail-content" class="pt-0.5">
85
+ <Show when={local.onSearch}>
86
+ <div data-slot="shell-rail-search" class="flex min-w-0 flex-col gap-0.5">
87
+ <SideRailItem
88
+ as="button"
89
+ type="button"
90
+ label={local.searchLabel ?? 'Search'}
91
+ aria-label={local.searchLabel ?? 'Search'}
92
+ keyshortcuts={local.searchKeyshortcuts}
93
+ shortcut={local.searchKeys?.join('')}
94
+ onClick={() => local.onSearch?.()}
95
+ >
96
+ <Search aria-hidden="true" />
97
+ </SideRailItem>
98
+ {/* The chord is drawn as key caps under the icon: the one row that
99
+ advertises a shortcut. The accessible chord stays on the row. */}
100
+ <Show when={local.searchKeys?.length}>
101
+ <KbdGroup
102
+ size="compact"
103
+ class="justify-center pb-1"
104
+ data-slot="shell-rail-search-keys"
105
+ >
106
+ <For each={local.searchKeys}>{(key) => <Kbd size="compact">{key}</Kbd>}</For>
107
+ </KbdGroup>
108
+ </Show>
109
+ </div>
110
+ <Separator class="my-1" />
111
+ </Show>
112
+ {content()}
113
+ </SideRailContent>
114
+
115
+ <Show when={footer()}>
116
+ <SideRailFooter data-slot="shell-rail-footer">{footer()}</SideRailFooter>
117
+ </Show>
118
+ </SideRail>
119
+ )
120
+ }
@@ -0,0 +1 @@
1
+ export { ShellTopBar, type ShellTopBarProps } from './shell-top-bar'
@@ -0,0 +1,185 @@
1
+ import type { ComponentProps, JSX } from 'solid-js'
2
+ import { children, Show, splitProps } from 'solid-js'
3
+ import { cn } from '#lib/utils'
4
+ import { Separator } from '../../ui/separator'
5
+
6
+ /**
7
+ * ShellTopBar.
8
+ *
9
+ * The window's top bar as both applications draw it. It has two halves with a
10
+ * vertical divider between them:
11
+ *
12
+ * - **Leading**: history arrows, the sidebar toggle and the workspace
13
+ * switcher, in that order. This is the part that belongs to the window.
14
+ * - **Content**: breadcrumbs, search and the view's actions. This is the part
15
+ * that belongs to the view, and it always sits to the right of the divider.
16
+ *
17
+ * ## Why the divider tracks the sidebar
18
+ *
19
+ * With the sidebar open the divider lands on the sidebar's trailing edge, so the
20
+ * bar reads as the rail and sidebar's header on one side and the content's
21
+ * header on the other. The bar spans the rail and the sidebar (they sit under
22
+ * it), so the leading half is as wide as `--rail-width` plus the sidebar's width
23
+ * less the bar's own start padding. The host publishes the width as
24
+ * `--shell-sidebar-width` on an ancestor; the fallback of 17rem matches the
25
+ * default sidebar. Below the 48rem breakpoint the sidebar is a drawer and the
26
+ * leading half is only as wide as its controls.
27
+ *
28
+ * ## Narrow windows
29
+ *
30
+ * The bar is its own container. Below 34rem the search drops to a row of its
31
+ * own so the leading controls, the breadcrumb and the actions keep their room;
32
+ * the breadcrumb is the first thing to truncate.
33
+ *
34
+ * On a frameless desktop window the bar is the drag region (`draggable`) and
35
+ * every control opts back out; `macosInset` and `windowsInset` reserve the
36
+ * native window controls.
37
+ */
38
+ export type ShellTopBarProps = Omit<ComponentProps<'header'>, 'children'> & {
39
+ /** History arrows. Rendered first, left of the sidebar toggle. */
40
+ navigation?: JSX.Element
41
+ /** The sidebar toggle button. */
42
+ sidebarToggle?: JSX.Element
43
+ /** The workspace switcher. */
44
+ workspace?: JSX.Element
45
+ /**
46
+ * Whether the sidebar is open at wide widths. Open, the divider aligns with
47
+ * the sidebar's edge; closed, the leading half hugs its controls.
48
+ */
49
+ sidebarOpen?: boolean
50
+ /**
51
+ * The open sidebar's width in pixels. Published as `--shell-sidebar-width` on
52
+ * the bar so the divider tracks a resizable sidebar; leave it unset to use an
53
+ * ancestor's variable or the 17rem default.
54
+ */
55
+ sidebarWidth?: number
56
+ /** Breadcrumbs or the view's title. Takes the free space and truncates first. */
57
+ breadcrumb?: JSX.Element
58
+ /** The view's search. */
59
+ search?: JSX.Element
60
+ /** The view's actions, at the trailing edge. */
61
+ actions?: JSX.Element
62
+ /** Make the bar a drag region, for a frameless window. */
63
+ draggable?: boolean
64
+ /** Reserve space for the macOS traffic lights. */
65
+ macosInset?: boolean
66
+ /** Reserve space for the Windows caption buttons. */
67
+ windowsInset?: boolean
68
+ /** Blur the content scrolling under the bar. */
69
+ glass?: boolean
70
+ }
71
+
72
+ export function ShellTopBar(props: ShellTopBarProps) {
73
+ const [local, rest] = splitProps(props, [
74
+ 'class',
75
+ 'navigation',
76
+ 'sidebarToggle',
77
+ 'workspace',
78
+ 'sidebarOpen',
79
+ 'sidebarWidth',
80
+ 'breadcrumb',
81
+ 'search',
82
+ 'actions',
83
+ 'draggable',
84
+ 'macosInset',
85
+ 'windowsInset',
86
+ 'glass',
87
+ ])
88
+
89
+ // Resolve each slot once: a JSX prop is a getter that builds its elements on
90
+ // every read, so testing it with `Show` and then rendering it would build
91
+ // (and run the refs of) two copies.
92
+ const navigation = children(() => local.navigation)
93
+ const sidebarToggle = children(() => local.sidebarToggle)
94
+ const workspace = children(() => local.workspace)
95
+ const breadcrumb = children(() => local.breadcrumb)
96
+ const search = children(() => local.search)
97
+ const actions = children(() => local.actions)
98
+
99
+ return (
100
+ <header
101
+ data-slot="shell-top-bar"
102
+ class={cn(
103
+ '@container/shell-top-bar relative z-(--z-sticky) flex min-h-topbar shrink-0 flex-wrap items-center border-b border-border bg-card text-card-foreground',
104
+ local.glass && 'glass-panel',
105
+ local.draggable && 'window-drag',
106
+ /* Each edge gets exactly one inline-padding utility, for the reason the
107
+ shared TopBar documents: two would tie-break by build order. The inset
108
+ is also published as a variable so the leading half can subtract it. */
109
+ local.macosInset
110
+ ? 'window-inset-macos [--shell-top-bar-inset:84px]'
111
+ : 'ps-3 [--shell-top-bar-inset:0.75rem]',
112
+ local.windowsInset ? 'window-inset-windows' : 'pe-3',
113
+ local.class
114
+ )}
115
+ style={
116
+ local.sidebarWidth === undefined
117
+ ? undefined
118
+ : { '--shell-sidebar-width': `${local.sidebarWidth}px` }
119
+ }
120
+ {...rest}
121
+ >
122
+ <div
123
+ data-slot="shell-top-bar-leading"
124
+ data-sidebar-open={local.sidebarOpen ? 'true' : 'false'}
125
+ class={cn(
126
+ 'window-no-drag flex h-topbar min-w-0 shrink-0 items-center gap-2 overflow-x-auto overflow-y-hidden pe-3',
127
+ /* Wide and open: span the rail and the sidebar so the divider lands on
128
+ the sidebar's edge. The sidebar's own border is the 1px the divider
129
+ overlaps, so no extra allowance is needed. */
130
+ local.sidebarOpen &&
131
+ 'md:w-[calc(var(--rail-width)+var(--shell-sidebar-width,17rem)-var(--shell-top-bar-inset))]'
132
+ )}
133
+ >
134
+ <Show when={navigation()}>
135
+ <div data-slot="shell-top-bar-navigation" class="flex shrink-0 items-center gap-2">
136
+ {navigation()}
137
+ </div>
138
+ </Show>
139
+ <Show when={sidebarToggle()}>
140
+ <div data-slot="shell-top-bar-toggle" class="flex shrink-0 items-center">
141
+ {sidebarToggle()}
142
+ </div>
143
+ </Show>
144
+ <Show when={workspace()}>
145
+ <div data-slot="shell-top-bar-workspace" class="flex min-w-0 items-center">
146
+ {workspace()}
147
+ </div>
148
+ </Show>
149
+ </div>
150
+ <Separator
151
+ orientation="vertical"
152
+ data-slot="shell-top-bar-divider"
153
+ aria-hidden="true"
154
+ class="h-5"
155
+ />
156
+ <Show when={breadcrumb()}>
157
+ <div
158
+ data-slot="shell-top-bar-breadcrumb"
159
+ class="window-no-drag flex h-topbar min-w-0 flex-1 items-center truncate ps-3 text-sm [&_:is(a,button)]:window-no-drag"
160
+ >
161
+ {breadcrumb()}
162
+ </div>
163
+ </Show>
164
+ <Show when={!breadcrumb()}>
165
+ <div class="min-w-0 flex-1" aria-hidden="true" />
166
+ </Show>
167
+ <Show when={search()}>
168
+ <div
169
+ data-slot="shell-top-bar-search"
170
+ class="window-no-drag min-w-0 max-w-md shrink basis-72 px-3 @max-[34rem]/shell-top-bar:order-last @max-[34rem]/shell-top-bar:max-w-none @max-[34rem]/shell-top-bar:basis-full @max-[34rem]/shell-top-bar:pb-2"
171
+ >
172
+ {search()}
173
+ </div>
174
+ </Show>
175
+ <Show when={actions()}>
176
+ <div
177
+ data-slot="shell-top-bar-actions"
178
+ class="window-no-drag flex h-topbar min-w-0 shrink-0 items-center gap-2 overflow-x-auto overflow-y-hidden ps-1"
179
+ >
180
+ {actions()}
181
+ </div>
182
+ </Show>
183
+ </header>
184
+ )
185
+ }
package/src/index.ts CHANGED
@@ -100,6 +100,8 @@ export * from './components/layout/sidebar-nav'
100
100
  export * from './components/layout/contextual-sidebar'
101
101
  export * from './components/layout/status-bar'
102
102
  export * from './components/layout/top-bar'
103
+ export * from './components/layout/shell-top-bar'
104
+ export * from './components/layout/shell-rail'
103
105
 
104
106
  /* --- Conversation -------------------------------------------------------- */
105
107
  export * from './components/conversation'
@@ -141,6 +143,9 @@ export * from './components/composites/update-dialog'
141
143
  export * from './components/composites/about-dialog'
142
144
  export * from './components/composites/help-center'
143
145
  export * from './components/composites/workspace-mark'
146
+ export * from './components/composites/workspace-switcher'
147
+ export * from './components/composites/icon-picker'
148
+ export * from './components/composites/accent-picker'
144
149
 
145
150
  /* --- Library ------------------------------------------------------------- */
146
151
  export { cn } from './lib/utils'