@khal-os/ui 1.0.1 → 1.0.2

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 (59) hide show
  1. package/LICENSE +94 -0
  2. package/README.md +25 -0
  3. package/dist/index.cjs +2661 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +926 -0
  6. package/dist/index.d.ts +926 -0
  7. package/dist/index.js +2510 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +59 -40
  10. package/tokens.css +260 -238
  11. package/src/components/ContextMenu.tsx +0 -130
  12. package/src/components/avatar.tsx +0 -71
  13. package/src/components/badge.tsx +0 -39
  14. package/src/components/button.tsx +0 -102
  15. package/src/components/command.tsx +0 -165
  16. package/src/components/cost-counter.tsx +0 -75
  17. package/src/components/data-row.tsx +0 -97
  18. package/src/components/dropdown-menu.tsx +0 -233
  19. package/src/components/glass-card.tsx +0 -74
  20. package/src/components/input.tsx +0 -48
  21. package/src/components/khal-logo.tsx +0 -73
  22. package/src/components/live-feed.tsx +0 -109
  23. package/src/components/mesh-gradient.tsx +0 -57
  24. package/src/components/metric-display.tsx +0 -93
  25. package/src/components/note.tsx +0 -55
  26. package/src/components/number-flow.tsx +0 -25
  27. package/src/components/pill-badge.tsx +0 -65
  28. package/src/components/progress-bar.tsx +0 -70
  29. package/src/components/section-card.tsx +0 -76
  30. package/src/components/separator.tsx +0 -25
  31. package/src/components/spinner.tsx +0 -42
  32. package/src/components/status-dot.tsx +0 -90
  33. package/src/components/switch.tsx +0 -36
  34. package/src/components/theme-provider.tsx +0 -58
  35. package/src/components/theme-switcher.tsx +0 -59
  36. package/src/components/ticker-bar.tsx +0 -41
  37. package/src/components/tooltip.tsx +0 -62
  38. package/src/components/window-minimized-context.tsx +0 -29
  39. package/src/hooks/useReducedMotion.ts +0 -21
  40. package/src/index.ts +0 -58
  41. package/src/lib/animations.ts +0 -50
  42. package/src/primitives/collapsible-sidebar.tsx +0 -226
  43. package/src/primitives/dialog.tsx +0 -76
  44. package/src/primitives/empty-state.tsx +0 -43
  45. package/src/primitives/index.ts +0 -22
  46. package/src/primitives/list-view.tsx +0 -155
  47. package/src/primitives/property-panel.tsx +0 -108
  48. package/src/primitives/section-header.tsx +0 -19
  49. package/src/primitives/sidebar-nav.tsx +0 -110
  50. package/src/primitives/split-pane.tsx +0 -146
  51. package/src/primitives/status-badge.tsx +0 -10
  52. package/src/primitives/status-bar.tsx +0 -100
  53. package/src/primitives/toolbar.tsx +0 -152
  54. package/src/server.ts +0 -4
  55. package/src/stores/notification-store.ts +0 -271
  56. package/src/stores/theme-store.ts +0 -33
  57. package/src/tokens/lp-tokens.ts +0 -36
  58. package/src/utils.ts +0 -6
  59. package/tsconfig.json +0 -17
@@ -1,62 +0,0 @@
1
- 'use client';
2
-
3
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
4
- import * as React from 'react';
5
- import { cn } from '../utils';
6
-
7
- const TooltipProvider = TooltipPrimitive.Provider;
8
- const TooltipRoot = TooltipPrimitive.Root;
9
- const TooltipTrigger = TooltipPrimitive.Trigger;
10
-
11
- const TooltipContent = React.forwardRef<
12
- React.ComponentRef<typeof TooltipPrimitive.Content>,
13
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
14
- >(({ className, sideOffset = 4, style, ...props }, ref) => (
15
- <TooltipPrimitive.Portal>
16
- <TooltipPrimitive.Content
17
- ref={ref}
18
- sideOffset={sideOffset}
19
- className={cn(
20
- 'z-[9999] overflow-hidden rounded-md px-2.5 py-1 text-label-12',
21
- 'animate-in fade-in-0 zoom-in-95',
22
- 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
23
- 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
24
- className
25
- )}
26
- style={{
27
- background: 'var(--khal-text-primary, var(--ds-gray-1000))',
28
- color: 'var(--khal-text-inverse, var(--ds-background-100))',
29
- ...style,
30
- }}
31
- {...props}
32
- />
33
- </TooltipPrimitive.Portal>
34
- ));
35
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
36
-
37
- interface SimpleTooltipProps {
38
- text: React.ReactNode;
39
- children: React.ReactNode;
40
- position?: 'top' | 'bottom' | 'left' | 'right';
41
- delay?: boolean;
42
- delayTime?: number;
43
- desktopOnly?: boolean;
44
- className?: string;
45
- }
46
-
47
- function Tooltip({ text, children, position = 'top', delay, delayTime, desktopOnly, className }: SimpleTooltipProps) {
48
- const delayDuration = delayTime ?? (delay ? 400 : 200);
49
-
50
- return (
51
- <TooltipProvider delayDuration={delayDuration}>
52
- <TooltipRoot>
53
- <TooltipTrigger asChild>{children}</TooltipTrigger>
54
- <TooltipContent side={position} className={cn(desktopOnly && 'max-md:hidden', className)}>
55
- {text}
56
- </TooltipContent>
57
- </TooltipRoot>
58
- </TooltipProvider>
59
- );
60
- }
61
-
62
- export { Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger };
@@ -1,29 +0,0 @@
1
- 'use client';
2
-
3
- import { createContext, useContext } from 'react';
4
-
5
- /**
6
- * Exposes the parent window's minimized state to deeply nested child components.
7
- * Terminal panes use this to dispose WebGL contexts when minimized (GPU savings)
8
- * and re-attach them on restore.
9
- */
10
- const WindowMinimizedContext = createContext(false);
11
-
12
- export const WindowMinimizedProvider = WindowMinimizedContext.Provider;
13
-
14
- export function useWindowMinimized(): boolean {
15
- return useContext(WindowMinimizedContext);
16
- }
17
-
18
- /**
19
- * Exposes the parent window's focused/active state to child components.
20
- * Apps use this to pause polling, animations, and heavy rendering when
21
- * their window is behind another (app-nap behavior).
22
- */
23
- const WindowActiveContext = createContext(true);
24
-
25
- export const WindowActiveProvider = WindowActiveContext.Provider;
26
-
27
- export function useWindowActive(): boolean {
28
- return useContext(WindowActiveContext);
29
- }
@@ -1,21 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect, useState } from 'react';
4
-
5
- /**
6
- * Returns true when the user prefers reduced motion (OS setting or app toggle).
7
- */
8
- export function useReducedMotion(): boolean {
9
- const [reduced, setReduced] = useState(false);
10
-
11
- useEffect(() => {
12
- const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
13
- setReduced(mq.matches || document.documentElement.dataset.reduceMotion === 'true');
14
-
15
- const handler = (e: MediaQueryListEvent) => setReduced(e.matches);
16
- mq.addEventListener('change', handler);
17
- return () => mq.removeEventListener('change', handler);
18
- }, []);
19
-
20
- return reduced;
21
- }
package/src/index.ts DELETED
@@ -1,58 +0,0 @@
1
- // App component props type
2
- export interface AppComponentProps {
3
- windowId: string;
4
- meta?: Record<string, unknown>;
5
- }
6
-
7
- // Auth — re-export from SDK
8
- export { SUBJECTS, useKhalAuth, useKhalAuth as useOSAuth, useNats, useNatsSubscription } from '@khal-os/sdk/app';
9
- // shadcn/ui components — local implementations
10
- export * from './components/avatar';
11
- export * from './components/badge';
12
- export * from './components/button';
13
- export * from './components/ContextMenu';
14
- export * from './components/command';
15
- // Design system components — local implementations
16
- export * from './components/cost-counter';
17
- // Design system components — LP section patterns
18
- export * from './components/data-row';
19
- export * from './components/dropdown-menu';
20
- export * from './components/glass-card';
21
- export * from './components/input';
22
- export * from './components/khal-logo';
23
- export * from './components/live-feed';
24
- export * from './components/mesh-gradient';
25
- export * from './components/metric-display';
26
- export * from './components/note';
27
- export * from './components/number-flow';
28
- export * from './components/pill-badge';
29
- export * from './components/progress-bar';
30
- export * from './components/section-card';
31
- export * from './components/separator';
32
- export * from './components/spinner';
33
- export * from './components/status-dot';
34
- export * from './components/switch';
35
- export * from './components/theme-provider';
36
- export * from './components/theme-switcher';
37
- export * from './components/ticker-bar';
38
- export * from './components/tooltip';
39
- export {
40
- useWindowActive,
41
- useWindowMinimized,
42
- WindowActiveProvider,
43
- WindowMinimizedProvider,
44
- } from './components/window-minimized-context';
45
- // Hooks
46
- export { useReducedMotion } from './hooks/useReducedMotion';
47
- // Animations
48
- export { fadeIn, fadeUp, khalEasing, scaleUp, springConfig, staggerChild, staggerContainer } from './lib/animations';
49
- // OS Primitives — local implementations
50
- export * from './primitives';
51
- export type { DesktopNotification, DesktopNotifMode, NotificationUrgency, TrayIcon } from './stores/notification-store';
52
- // Stores (OS-level state)
53
- export { useNotificationStore } from './stores/notification-store';
54
- export { useThemeStore } from './stores/theme-store';
55
- // LP Design Tokens
56
- export * from './tokens/lp-tokens';
57
- // Utilities
58
- export { cn } from './utils';
@@ -1,50 +0,0 @@
1
- /**
2
- * KhalOS animation presets — motion.js configurations for OS-wide use.
3
- * Import these in components for consistent, branded animations.
4
- */
5
-
6
- /** Custom easing curve — KhalOS primary */
7
- export const khalEasing = [0.22, 1, 0.36, 1] as const;
8
-
9
- /** Spring config for interactive elements */
10
- export const springConfig = {
11
- stiffness: 300,
12
- damping: 22,
13
- } as const;
14
-
15
- /** Window open animation — fade up with blur */
16
- export const fadeUp = {
17
- initial: { opacity: 0, y: 12, filter: 'blur(4px)' },
18
- animate: { opacity: 1, y: 0, filter: 'blur(0px)' },
19
- transition: { duration: 0.7, ease: khalEasing },
20
- } as const;
21
-
22
- /** App launch animation — scale up with blur */
23
- export const scaleUp = {
24
- initial: { opacity: 0, scale: 0.96, filter: 'blur(6px)' },
25
- animate: { opacity: 1, scale: 1, filter: 'blur(0px)' },
26
- transition: { duration: 0.9, ease: khalEasing },
27
- } as const;
28
-
29
- /** Stagger container — children appear with 0.12s delay */
30
- export const staggerContainer = {
31
- animate: {
32
- transition: {
33
- staggerChildren: 0.12,
34
- },
35
- },
36
- } as const;
37
-
38
- /** Stagger child — each item fades up */
39
- export const staggerChild = {
40
- initial: { opacity: 0, y: 8 },
41
- animate: { opacity: 1, y: 0 },
42
- transition: { duration: 0.4, ease: khalEasing },
43
- } as const;
44
-
45
- /** Fade in — simple opacity animation */
46
- export const fadeIn = {
47
- initial: { opacity: 0 },
48
- animate: { opacity: 1 },
49
- transition: { duration: 0.5, ease: khalEasing },
50
- } as const;
@@ -1,226 +0,0 @@
1
- 'use client';
2
-
3
- import { createContext, type ReactNode, useCallback, useContext, useRef, useState } from 'react';
4
-
5
- // ---------------------------------------------------------------------------
6
- // CollapsibleSidebar — resizable sidebar with collapse/expand toggle.
7
- //
8
- // Usage:
9
- // <CollapsibleSidebar defaultSize={220} min={160} max={360}>
10
- // <CollapsibleSidebar.Header>
11
- // <span>Explorer</span>
12
- // <CollapsibleSidebar.CollapseButton />
13
- // </CollapsibleSidebar.Header>
14
- // <CollapsibleSidebar.Content>
15
- // <FileTree />
16
- // </CollapsibleSidebar.Content>
17
- // </CollapsibleSidebar>
18
- // ---------------------------------------------------------------------------
19
-
20
- interface SidebarContextValue {
21
- collapsed: boolean;
22
- toggle: () => void;
23
- size: number;
24
- }
25
-
26
- const SidebarContext = createContext<SidebarContextValue>({
27
- collapsed: false,
28
- toggle: () => {},
29
- size: 220,
30
- });
31
-
32
- export function useSidebar() {
33
- return useContext(SidebarContext);
34
- }
35
-
36
- interface CollapsibleSidebarProps {
37
- children: ReactNode;
38
- defaultSize?: number;
39
- min?: number;
40
- max?: number;
41
- defaultCollapsed?: boolean;
42
- side?: 'left' | 'right';
43
- className?: string;
44
- }
45
-
46
- function CollapsibleSidebarRoot({
47
- children,
48
- defaultSize = 220,
49
- min = 140,
50
- max = 400,
51
- defaultCollapsed = false,
52
- side = 'left',
53
- className = '',
54
- }: CollapsibleSidebarProps) {
55
- const [collapsed, setCollapsed] = useState(defaultCollapsed);
56
- const [size, setSize] = useState(defaultSize);
57
- const dragging = useRef(false);
58
- const startX = useRef(0);
59
- const startSize = useRef(0);
60
-
61
- const toggle = useCallback(() => setCollapsed((v) => !v), []);
62
-
63
- const onPointerDown = useCallback(
64
- (e: React.PointerEvent) => {
65
- if (collapsed) return;
66
- e.preventDefault();
67
- dragging.current = true;
68
- startX.current = e.clientX;
69
- startSize.current = size;
70
- (e.target as HTMLElement).setPointerCapture(e.pointerId);
71
- },
72
- [collapsed, size]
73
- );
74
-
75
- const onPointerMove = useCallback(
76
- (e: React.PointerEvent) => {
77
- if (!dragging.current) return;
78
- const delta = side === 'left' ? e.clientX - startX.current : startX.current - e.clientX;
79
- setSize(Math.min(max, Math.max(min, startSize.current + delta)));
80
- },
81
- [side, min, max]
82
- );
83
-
84
- const onPointerUp = useCallback(() => {
85
- dragging.current = false;
86
- }, []);
87
-
88
- const resizeHandle = (
89
- <div
90
- className={`w-px shrink-0 cursor-col-resize bg-gray-alpha-200 transition-colors hover:w-0.5 hover:bg-blue-700/50 active:w-0.5 active:bg-blue-700 ${
91
- collapsed ? 'pointer-events-none' : ''
92
- }`}
93
- onPointerDown={onPointerDown}
94
- onPointerMove={onPointerMove}
95
- onPointerUp={onPointerUp}
96
- role="separator"
97
- aria-orientation="vertical"
98
- />
99
- );
100
-
101
- return (
102
- <SidebarContext.Provider value={{ collapsed, toggle, size }}>
103
- <div className={`flex shrink-0 ${className}`} style={{ width: collapsed ? 0 : size }}>
104
- {side === 'right' && resizeHandle}
105
- <div
106
- className={`flex h-full flex-col overflow-hidden transition-[width] duration-150 ${
107
- collapsed ? 'w-0' : 'w-full'
108
- }`}
109
- >
110
- {children}
111
- </div>
112
- {side === 'left' && resizeHandle}
113
- </div>
114
- </SidebarContext.Provider>
115
- );
116
- }
117
-
118
- // ---------------------------------------------------------------------------
119
- // CollapsibleSidebar.Header
120
- // ---------------------------------------------------------------------------
121
-
122
- function SidebarHeader({ children, className = '' }: { children: ReactNode; className?: string }) {
123
- return (
124
- <div className={`flex h-9 shrink-0 items-center justify-between border-b border-gray-alpha-200 px-3 ${className}`}>
125
- {children}
126
- </div>
127
- );
128
- }
129
-
130
- // ---------------------------------------------------------------------------
131
- // CollapsibleSidebar.CollapseButton
132
- // ---------------------------------------------------------------------------
133
-
134
- function CollapseButton({ className = '' }: { className?: string }) {
135
- const { collapsed, toggle } = useSidebar();
136
- return (
137
- <button
138
- onClick={toggle}
139
- className={`inline-flex h-5 w-5 items-center justify-center rounded text-gray-800 hover:bg-gray-alpha-200 hover:text-gray-1000 transition-colors ${className}`}
140
- aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
141
- >
142
- <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
143
- <path
144
- d={collapsed ? 'M4.5 2L8.5 6L4.5 10' : 'M8.5 2L4.5 6L8.5 10'}
145
- stroke="currentColor"
146
- strokeWidth="1.5"
147
- strokeLinecap="round"
148
- strokeLinejoin="round"
149
- />
150
- </svg>
151
- </button>
152
- );
153
- }
154
-
155
- // ---------------------------------------------------------------------------
156
- // CollapsibleSidebar.Content
157
- // ---------------------------------------------------------------------------
158
-
159
- function SidebarContent({ children, className = '' }: { children: ReactNode; className?: string }) {
160
- return <div className={`flex-1 overflow-y-auto ${className}`}>{children}</div>;
161
- }
162
-
163
- // ---------------------------------------------------------------------------
164
- // CollapsibleSidebar.Section
165
- // ---------------------------------------------------------------------------
166
-
167
- function SidebarSection({
168
- title,
169
- children,
170
- className = '',
171
- }: {
172
- title?: string;
173
- children: ReactNode;
174
- className?: string;
175
- }) {
176
- return (
177
- <div className={`${className}`}>
178
- {title && (
179
- <div className="px-3 pt-2 pb-1">
180
- <span className="text-label-13 font-medium text-gray-800">{title}</span>
181
- </div>
182
- )}
183
- {children}
184
- </div>
185
- );
186
- }
187
-
188
- // ---------------------------------------------------------------------------
189
- // CollapsibleSidebar.Item
190
- // ---------------------------------------------------------------------------
191
-
192
- interface SidebarItemProps {
193
- children: ReactNode;
194
- icon?: ReactNode;
195
- active?: boolean;
196
- indent?: number;
197
- onClick?: () => void;
198
- className?: string;
199
- }
200
-
201
- function SidebarItem({ children, icon, active, indent = 0, onClick, className = '' }: SidebarItemProps) {
202
- return (
203
- <button
204
- onClick={onClick}
205
- className={`flex w-full items-center gap-2 rounded-md px-2 py-1 text-left text-label-13 transition-colors
206
- ${active ? 'bg-gray-alpha-200 text-gray-1000' : 'text-gray-900 hover:bg-gray-alpha-100 hover:text-gray-1000'}
207
- ${className}`}
208
- style={{ paddingLeft: 8 + indent * 12 }}
209
- >
210
- {icon && <span className="shrink-0 text-gray-800 [&>svg]:h-3.5 [&>svg]:w-3.5">{icon}</span>}
211
- <span className="min-w-0 truncate">{children}</span>
212
- </button>
213
- );
214
- }
215
-
216
- // ---------------------------------------------------------------------------
217
- // Export
218
- // ---------------------------------------------------------------------------
219
-
220
- export const CollapsibleSidebar = Object.assign(CollapsibleSidebarRoot, {
221
- Header: SidebarHeader,
222
- CollapseButton,
223
- Content: SidebarContent,
224
- Section: SidebarSection,
225
- Item: SidebarItem,
226
- });
@@ -1,76 +0,0 @@
1
- 'use client';
2
-
3
- import type { ButtonHTMLAttributes, ReactNode } from 'react';
4
-
5
- /* ------------------------------------------------------------------ */
6
- /* Minimal compound Dialog primitive for OS chrome. */
7
- /* Enough to satisfy DeleteConfirmDialog; expand as needed. */
8
- /* ------------------------------------------------------------------ */
9
-
10
- interface DialogRootProps {
11
- open: boolean;
12
- onClose: () => void;
13
- children: ReactNode;
14
- }
15
-
16
- function DialogRoot({ open, onClose, children }: DialogRootProps) {
17
- if (!open) return null;
18
- return (
19
- <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/40" onClick={onClose}>
20
- <div
21
- className="bg-popover text-popover-foreground rounded-lg border p-6 shadow-lg"
22
- onClick={(e) => e.stopPropagation()}
23
- >
24
- {children}
25
- </div>
26
- </div>
27
- );
28
- }
29
-
30
- function Body({ children }: { children: ReactNode }) {
31
- return <div className="flex items-start gap-4">{children}</div>;
32
- }
33
-
34
- function Icon({ children, variant: _variant }: { children: ReactNode; variant?: string }) {
35
- return <div className="shrink-0">{children}</div>;
36
- }
37
-
38
- function Title({ children }: { children: ReactNode }) {
39
- return <h2 className="text-lg font-semibold">{children}</h2>;
40
- }
41
-
42
- function Description({ children }: { children: ReactNode }) {
43
- return <p className="text-muted-foreground text-sm">{children}</p>;
44
- }
45
-
46
- function Actions({ children }: { children: ReactNode }) {
47
- return <div className="mt-4 flex justify-end gap-2">{children}</div>;
48
- }
49
-
50
- type BtnProps = ButtonHTMLAttributes<HTMLButtonElement> & { variant?: string };
51
-
52
- function Cancel({ children, ...props }: BtnProps) {
53
- return (
54
- <button type="button" className="rounded px-3 py-1.5 text-sm hover:bg-muted" {...props}>
55
- {children}
56
- </button>
57
- );
58
- }
59
-
60
- function Confirm({ children, variant: _variant, ...props }: BtnProps) {
61
- return (
62
- <button type="button" className="rounded bg-destructive px-3 py-1.5 text-sm text-destructive-foreground" {...props}>
63
- {children}
64
- </button>
65
- );
66
- }
67
-
68
- export const Dialog = Object.assign(DialogRoot, {
69
- Body,
70
- Icon,
71
- Title,
72
- Description,
73
- Actions,
74
- Cancel,
75
- Confirm,
76
- });
@@ -1,43 +0,0 @@
1
- 'use client';
2
-
3
- import { type ReactNode } from 'react';
4
-
5
- // ---------------------------------------------------------------------------
6
- // EmptyState — placeholder for empty views (no files, no results, etc.).
7
- //
8
- // Usage:
9
- // <EmptyState
10
- // icon={<FolderOpen />}
11
- // title="No files"
12
- // description="This folder is empty."
13
- // action={<Button onClick={upload}>Upload File</Button>}
14
- // />
15
- // ---------------------------------------------------------------------------
16
-
17
- interface EmptyStateProps {
18
- icon?: ReactNode;
19
- title: string;
20
- description?: string;
21
- action?: ReactNode;
22
- compact?: boolean;
23
- className?: string;
24
- }
25
-
26
- export function EmptyState({ icon, title, description, action, compact, className = '' }: EmptyStateProps) {
27
- return (
28
- <div
29
- className={`flex flex-col items-center justify-center text-center ${
30
- compact ? 'gap-2 py-6' : 'gap-3 py-12'
31
- } ${className}`}
32
- >
33
- {icon && (
34
- <div className={`text-gray-700 ${compact ? '[&>svg]:h-5 [&>svg]:w-5' : '[&>svg]:h-8 [&>svg]:w-8'}`}>{icon}</div>
35
- )}
36
- <div className="space-y-0.5">
37
- <p className="text-label-13 font-medium text-gray-1000">{title}</p>
38
- {description && <p className={`text-gray-800 ${compact ? 'text-label-13' : 'text-label-13'}`}>{description}</p>}
39
- </div>
40
- {action && <div className="mt-2 shrink-0">{action}</div>}
41
- </div>
42
- );
43
- }
@@ -1,22 +0,0 @@
1
- // OS Primitives — UI building blocks for desktop app chrome.
2
- // Built on top of shadcn/ui components and Geist design tokens.
3
- //
4
- // These fill the gap between shadcn's web-focused components and the
5
- // needs of a desktop-style app (toolbars, split panes, status bars, etc.).
6
- //
7
- // shadcn/ui components to use directly (from @/components/ui/*):
8
- // Button, Input, Badge, Spinner, Separator, Tooltip, Toggle (Switch),
9
- // ContextMenu, Command (CommandDialog), DropdownMenu, Note, LoadingDots,
10
- // ThemeSwitcher
11
-
12
- export { CollapsibleSidebar, useSidebar } from './collapsible-sidebar';
13
- export { Dialog } from './dialog';
14
- export { EmptyState } from './empty-state';
15
- export { ListView } from './list-view';
16
- export { PropertyPanel } from './property-panel';
17
- export { SectionHeader } from './section-header';
18
- export { SidebarNav } from './sidebar-nav';
19
- export { SplitPane } from './split-pane';
20
- export { StatusBadge } from './status-badge';
21
- export { StatusBar } from './status-bar';
22
- export { Toolbar } from './toolbar';