@otfdashkit/ui 0.1.1 → 0.1.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 (115) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +28 -41
  3. package/dist/index.js +206 -125
  4. package/dist/index.mjs +194 -124
  5. package/package.json +5 -4
  6. package/src/advanced/BulkActions/BulkActions.tsx +2 -2
  7. package/src/advanced/CommandBar/CommandBar.tsx +2 -2
  8. package/src/advanced/Filters/Filters.tsx +6 -6
  9. package/src/advanced/Kanban/Kanban.tsx +1 -1
  10. package/src/advanced/ToggleButton/ToggleButton.tsx +1 -1
  11. package/src/advanced/bulk-actions.tsx +1 -46
  12. package/src/advanced/command-bar.tsx +1 -115
  13. package/src/advanced/filters.tsx +1 -103
  14. package/src/advanced/kanban.tsx +1 -95
  15. package/src/advanced/toggle-button.tsx +1 -78
  16. package/src/blocks/ChatDetail/ChatDetail.tsx +4 -4
  17. package/src/blocks/FeedbackModal/FeedbackModal.tsx +3 -3
  18. package/src/blocks/FileCards/FileCards.tsx +2 -2
  19. package/src/blocks/FilesList/FilesList.tsx +3 -3
  20. package/src/blocks/IntegrationCard/IntegrationCard.tsx +3 -3
  21. package/src/blocks/InviteModal/InviteModal.tsx +7 -7
  22. package/src/blocks/ManageTagsModal/ManageTagsModal.tsx +4 -4
  23. package/src/blocks/MessagesCard/MessagesCard.tsx +3 -3
  24. package/src/blocks/MetricCard/MetricCard.tsx +3 -3
  25. package/src/blocks/NotificationSettings/NotificationSettings.tsx +4 -4
  26. package/src/blocks/OrganizationMenu/OrganizationMenu.tsx +30 -11
  27. package/src/blocks/RolesMenu/RolesMenu.tsx +4 -4
  28. package/src/blocks/SelectUsersModal/SelectUsersModal.tsx +5 -5
  29. package/src/blocks/SidebarLayoutDashboard/SidebarLayoutDashboard.tsx +5 -5
  30. package/src/blocks/SidebarLayoutGroups/SidebarLayoutGroups.tsx +2 -2
  31. package/src/blocks/SidebarLayoutMinimal/SidebarLayoutMinimal.tsx +3 -3
  32. package/src/blocks/SidebarLayoutSearch/SidebarLayoutSearch.tsx +3 -3
  33. package/src/blocks/SidebarLayoutUser/SidebarLayoutUser.tsx +4 -4
  34. package/src/blocks/SortableTaskList/SortableTaskList.tsx +3 -3
  35. package/src/blocks/StackedLayoutBranded/StackedLayoutBranded.tsx +4 -4
  36. package/src/blocks/StackedLayoutTabs/StackedLayoutTabs.tsx +4 -4
  37. package/src/blocks/TaskCard/TaskCard.tsx +4 -4
  38. package/src/blocks/UserMenu/UserMenu.tsx +3 -3
  39. package/src/blocks/WorkspaceMembers/WorkspaceMembers.tsx +5 -5
  40. package/src/blocks/chat-detail.tsx +1 -73
  41. package/src/blocks/feedback-modal.tsx +1 -68
  42. package/src/blocks/file-cards.tsx +1 -56
  43. package/src/blocks/files-list.tsx +1 -72
  44. package/src/blocks/integration-card.tsx +1 -50
  45. package/src/blocks/invite-modal.tsx +1 -69
  46. package/src/blocks/manage-tags-modal.tsx +1 -63
  47. package/src/blocks/messages-card.tsx +1 -59
  48. package/src/blocks/metric-card.tsx +1 -79
  49. package/src/blocks/notification-settings.tsx +1 -61
  50. package/src/blocks/organization-menu.tsx +1 -85
  51. package/src/blocks/roles-menu.tsx +1 -61
  52. package/src/blocks/select-users-modal.tsx +1 -64
  53. package/src/blocks/sidebar-layout-dashboard.tsx +1 -97
  54. package/src/blocks/sidebar-layout-groups.tsx +1 -79
  55. package/src/blocks/sidebar-layout-minimal.tsx +1 -73
  56. package/src/blocks/sidebar-layout-search.tsx +1 -79
  57. package/src/blocks/sidebar-layout-user.tsx +1 -82
  58. package/src/blocks/sortable-task-list.tsx +1 -70
  59. package/src/blocks/stacked-layout-branded.tsx +1 -64
  60. package/src/blocks/stacked-layout-tabs.tsx +1 -80
  61. package/src/blocks/task-card.tsx +1 -88
  62. package/src/blocks/user-menu.tsx +1 -62
  63. package/src/blocks/workspace-members.tsx +1 -61
  64. package/src/charts/sparkline.tsx +1 -1
  65. package/src/components/DataGrid/DataGrid.tsx +1 -1
  66. package/src/components/DataTable/DataTable.tsx +4 -4
  67. package/src/components/EmptyState/EmptyState.tsx +6 -22
  68. package/src/components/Persona/Persona.tsx +1 -1
  69. package/src/components/Stat/Stat.tsx +1 -1
  70. package/src/components/Stepper/Stepper.tsx +13 -2
  71. package/src/components/banner.tsx +1 -203
  72. package/src/components/breadcrumb.tsx +1 -58
  73. package/src/components/command-item.tsx +1 -36
  74. package/src/components/data-grid.tsx +1 -125
  75. package/src/components/data-table.tsx +1 -139
  76. package/src/components/empty-state.tsx +1 -31
  77. package/src/components/hotkeys.tsx +1 -31
  78. package/src/components/icon-badge.tsx +1 -35
  79. package/src/components/loading-overlay.tsx +1 -38
  80. package/src/components/persona.tsx +1 -38
  81. package/src/components/property-list.tsx +1 -29
  82. package/src/components/stat.tsx +1 -51
  83. package/src/components/stepper.tsx +1 -69
  84. package/src/components/structured-list.tsx +1 -51
  85. package/src/components/timeline.tsx +1 -69
  86. package/src/components/toaster.tsx +1 -42
  87. package/src/data/DataList.tsx +1 -1
  88. package/src/engagement/Tour/Tour.tsx +1 -1
  89. package/src/engagement/beacon.tsx +1 -50
  90. package/src/engagement/tour.tsx +1 -106
  91. package/src/forms/ArrayField/ArrayField.tsx +2 -2
  92. package/src/forms/AutoForm/AutoForm.tsx +9 -8
  93. package/src/forms/DatePicker/DatePicker.tsx +3 -3
  94. package/src/forms/FloatingLabelInput/FloatingLabelInput.tsx +104 -0
  95. package/src/forms/FloatingLabelInput/index.ts +1 -0
  96. package/src/forms/PasswordInput/PasswordInput.tsx +2 -2
  97. package/src/forms/SearchInput/SearchInput.tsx +2 -2
  98. package/src/forms/StepForm/StepForm.tsx +2 -2
  99. package/src/forms/array-field.tsx +1 -61
  100. package/src/forms/auto-form.tsx +1 -133
  101. package/src/forms/date-picker.tsx +1 -109
  102. package/src/forms/field.tsx +1 -62
  103. package/src/forms/file-upload.tsx +1 -101
  104. package/src/forms/floating-label-input.tsx +1 -0
  105. package/src/forms/form.tsx +1 -57
  106. package/src/forms/object-field.tsx +1 -53
  107. package/src/forms/password-input.tsx +1 -54
  108. package/src/forms/search-input.tsx +1 -64
  109. package/src/forms/step-form.tsx +1 -113
  110. package/src/index.ts +6 -3
  111. package/src/primitives/Button/Button.tsx +18 -0
  112. package/src/primitives/code-block.tsx +1 -1
  113. package/src/primitives/comparison.tsx +1 -1
  114. package/src/primitives/qr-code.tsx +5 -1
  115. package/src/themes/base.css +18 -0
@@ -1,73 +1 @@
1
- // @ts-nocheck
2
- import React from 'react'
3
- import { LayoutDashboard, FolderOpen, Users, Settings } from 'lucide-react'
4
- import { cn } from '../utils/cn'
5
- import { Avatar, AvatarFallback } from '../primitives/avatar'
6
- import { Separator } from '../primitives/separator'
7
-
8
- const NAV_ITEMS = [
9
- { icon: LayoutDashboard, label: 'Dashboard', active: true },
10
- { icon: FolderOpen, label: 'Projects' },
11
- { icon: Users, label: 'Team' },
12
- { icon: Settings, label: 'Settings' },
13
- ]
14
-
15
- interface NavItemProps { icon: React.ElementType; label: string; active?: boolean }
16
-
17
- function NavItem({ icon: Icon, label, active }: NavItemProps) {
18
- return (
19
- <button className={cn(
20
- 'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors',
21
- active
22
- ? 'bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))] font-medium'
23
- : 'text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--accent-foreground))]'
24
- )}>
25
- <Icon className="h-4 w-4 shrink-0" />
26
- {label}
27
- </button>
28
- )
29
- }
30
-
31
- export interface SidebarLayoutMinimalProps {
32
- brandName?: string
33
- pageTitle?: string
34
- children?: React.ReactNode
35
- className?: string
36
- }
37
-
38
- export function SidebarLayoutMinimal({
39
- brandName = 'Acme Inc',
40
- pageTitle = 'Dashboard',
41
- children,
42
- className,
43
- }: SidebarLayoutMinimalProps) {
44
- return (
45
- <div className={cn('flex h-[600px] overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))]', className)}>
46
- <aside className="flex w-60 flex-col border-r border-[hsl(var(--border))] bg-[hsl(var(--card))]">
47
- <div className="flex h-14 items-center px-4 font-semibold text-sm">{brandName}</div>
48
- <Separator />
49
- <nav className="flex-1 space-y-0.5 p-2">
50
- {NAV_ITEMS.map(item => <NavItem key={item.label} {...item} />)}
51
- </nav>
52
- <Separator />
53
- <div className="flex items-center gap-3 p-4">
54
- <Avatar className="h-8 w-8">
55
- <AvatarFallback className="text-xs">JD</AvatarFallback>
56
- </Avatar>
57
- <div className="min-w-0">
58
- <p className="truncate text-sm font-medium">Jane Doe</p>
59
- <p className="truncate text-xs text-[hsl(var(--muted-foreground))]">jane@acme.com</p>
60
- </div>
61
- </div>
62
- </aside>
63
- <main className="flex flex-1 flex-col overflow-auto">
64
- <header className="flex h-14 items-center border-b border-[hsl(var(--border))] px-6">
65
- <h1 className="text-sm font-semibold">{pageTitle}</h1>
66
- </header>
67
- <div className="flex-1 p-6 text-sm text-[hsl(var(--muted-foreground))]">
68
- {children ?? 'Page content goes here.'}
69
- </div>
70
- </main>
71
- </div>
72
- )
73
- }
1
+ export * from './SidebarLayoutMinimal'
@@ -1,79 +1 @@
1
- // @ts-nocheck
2
- import React, { useState } from 'react'
3
- import { LayoutDashboard, FolderOpen, Users, Settings, BarChart2, Bell } from 'lucide-react'
4
- import { cn } from '../utils/cn'
5
- import { Input } from '../primitives/input'
6
- import { Separator } from '../primitives/separator'
7
-
8
- const ALL_ITEMS = [
9
- { icon: LayoutDashboard, label: 'Dashboard', active: true },
10
- { icon: BarChart2, label: 'Analytics' },
11
- { icon: FolderOpen, label: 'Projects' },
12
- { icon: Users, label: 'Team' },
13
- { icon: Bell, label: 'Notifications' },
14
- { icon: Settings, label: 'Settings' },
15
- ]
16
-
17
- interface NavItemProps { icon: React.ElementType; label: string; active?: boolean }
18
-
19
- function NavItem({ icon: Icon, label, active }: NavItemProps) {
20
- return (
21
- <button className={cn(
22
- 'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors',
23
- active
24
- ? 'bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))] font-medium'
25
- : 'text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--accent-foreground))]'
26
- )}>
27
- <Icon className="h-4 w-4 shrink-0" />
28
- {label}
29
- </button>
30
- )
31
- }
32
-
33
- export interface SidebarLayoutSearchProps {
34
- brandName?: string
35
- pageTitle?: string
36
- children?: React.ReactNode
37
- className?: string
38
- }
39
-
40
- export function SidebarLayoutSearch({
41
- brandName = 'Acme Inc',
42
- pageTitle = 'Dashboard',
43
- children,
44
- className,
45
- }: SidebarLayoutSearchProps) {
46
- const [query, setQuery] = useState('')
47
- const filtered = ALL_ITEMS.filter(i => i.label.toLowerCase().includes(query.toLowerCase()))
48
-
49
- return (
50
- <div className={cn('flex h-[600px] overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))]', className)}>
51
- <aside className="flex w-60 flex-col border-r border-[hsl(var(--border))] bg-[hsl(var(--card))]">
52
- <div className="flex h-14 items-center px-4 font-semibold text-sm">{brandName}</div>
53
- <Separator />
54
- <div className="p-2">
55
- <Input
56
- placeholder="Search..."
57
- value={query}
58
- onChange={e => setQuery(e.target.value)}
59
- className="h-8 text-sm"
60
- />
61
- </div>
62
- <nav className="flex-1 space-y-0.5 overflow-auto p-2">
63
- {filtered.length > 0
64
- ? filtered.map(item => <NavItem key={item.label} {...item} />)
65
- : <p className="px-3 py-2 text-xs text-[hsl(var(--muted-foreground))]">No results</p>
66
- }
67
- </nav>
68
- </aside>
69
- <main className="flex flex-1 flex-col overflow-auto">
70
- <header className="flex h-14 items-center border-b border-[hsl(var(--border))] px-6">
71
- <h1 className="text-sm font-semibold">{pageTitle}</h1>
72
- </header>
73
- <div className="flex-1 p-6 text-sm text-[hsl(var(--muted-foreground))]">
74
- {children ?? 'Page content goes here.'}
75
- </div>
76
- </main>
77
- </div>
78
- )
79
- }
1
+ export * from './SidebarLayoutSearch'
@@ -1,82 +1 @@
1
- // @ts-nocheck
2
- import React from 'react'
3
- import { LayoutDashboard, FolderOpen, Users, Settings, Bell } from 'lucide-react'
4
- import { cn } from '../utils/cn'
5
- import { Avatar, AvatarFallback } from '../primitives/avatar'
6
- import { Badge } from '../primitives/badge'
7
- import { Separator } from '../primitives/separator'
8
-
9
- const NAV_ITEMS = [
10
- { icon: LayoutDashboard, label: 'Dashboard', active: true },
11
- { icon: FolderOpen, label: 'Projects' },
12
- { icon: Users, label: 'Team' },
13
- { icon: Bell, label: 'Notifications', badge: '3' },
14
- { icon: Settings, label: 'Settings' },
15
- ]
16
-
17
- interface NavItemProps { icon: React.ElementType; label: string; active?: boolean; badge?: string }
18
-
19
- function NavItem({ icon: Icon, label, active, badge }: NavItemProps) {
20
- return (
21
- <button className={cn(
22
- 'flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm transition-colors',
23
- active
24
- ? 'bg-[hsl(var(--accent))] text-[hsl(var(--accent-foreground))] font-medium'
25
- : 'text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))] hover:text-[hsl(var(--accent-foreground))]'
26
- )}>
27
- <Icon className="h-4 w-4 shrink-0" />
28
- <span className="flex-1 text-left">{label}</span>
29
- {badge && <Badge className="text-[10px] px-1.5 py-0.5 shrink-0">{badge}</Badge>}
30
- </button>
31
- )
32
- }
33
-
34
- export interface SidebarLayoutUserProps {
35
- userName?: string
36
- userEmail?: string
37
- userRole?: string
38
- pageTitle?: string
39
- children?: React.ReactNode
40
- className?: string
41
- }
42
-
43
- export function SidebarLayoutUser({
44
- userName = 'Jane Doe',
45
- userEmail = 'jane@acme.com',
46
- userRole = 'Admin',
47
- pageTitle = 'Dashboard',
48
- children,
49
- className,
50
- }: SidebarLayoutUserProps) {
51
- return (
52
- <div className={cn('flex h-[600px] overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))]', className)}>
53
- <aside className="flex w-60 flex-col border-r border-[hsl(var(--border))] bg-[hsl(var(--card))]">
54
- <div className="p-4">
55
- <div className="flex items-center gap-3 rounded-md bg-[hsl(var(--accent))] p-3">
56
- <Avatar className="h-9 w-9">
57
- <AvatarFallback className="text-xs">{userName.slice(0, 2).toUpperCase()}</AvatarFallback>
58
- </Avatar>
59
- <div className="min-w-0">
60
- <p className="truncate text-sm font-semibold">{userName}</p>
61
- <p className="truncate text-xs text-[hsl(var(--muted-foreground))]">{userRole}</p>
62
- </div>
63
- </div>
64
- </div>
65
- <Separator />
66
- <nav className="flex-1 space-y-0.5 p-2">
67
- {NAV_ITEMS.map(item => <NavItem key={item.label} {...item} />)}
68
- </nav>
69
- <Separator />
70
- <p className="p-4 text-xs text-[hsl(var(--muted-foreground))] truncate">{userEmail}</p>
71
- </aside>
72
- <main className="flex flex-1 flex-col overflow-auto">
73
- <header className="flex h-14 items-center border-b border-[hsl(var(--border))] px-6">
74
- <h1 className="text-sm font-semibold">{pageTitle}</h1>
75
- </header>
76
- <div className="flex-1 p-6 text-sm text-[hsl(var(--muted-foreground))]">
77
- {children ?? 'Page content goes here.'}
78
- </div>
79
- </main>
80
- </div>
81
- )
82
- }
1
+ export * from './SidebarLayoutUser'
@@ -1,70 +1 @@
1
- import React, { useState } from 'react'
2
- import { cn } from '../utils/cn'
3
- import { Checkbox } from '../primitives/checkbox'
4
- import { Avatar, AvatarFallback } from '../primitives/avatar'
5
-
6
- type Priority = 'High' | 'Medium' | 'Low'
7
- type Status = 'In Progress' | 'Todo' | 'Done'
8
-
9
- interface Task {
10
- id: string
11
- title: string
12
- assignee: string
13
- priority: Priority
14
- status: Status
15
- done: boolean
16
- }
17
-
18
- const TASKS: Task[] = [
19
- { id: '1', title: 'Redesign onboarding flow', assignee: 'AC', priority: 'High', status: 'In Progress', done: false },
20
- { id: '2', title: 'Fix authentication bug', assignee: 'BS', priority: 'High', status: 'In Progress', done: false },
21
- { id: '3', title: 'Write API documentation', assignee: 'JD', priority: 'Medium', status: 'Todo', done: false },
22
- { id: '4', title: 'Add dark mode support', assignee: 'TR', priority: 'Low', status: 'Todo', done: false },
23
- { id: '5', title: 'Setup CI/CD pipeline', assignee: 'SK', priority: 'Medium', status: 'Done', done: true },
24
- { id: '6', title: 'Deploy to staging', assignee: 'ML', priority: 'Low', status: 'Done', done: true },
25
- ]
26
-
27
- const PRIORITY_DOT: Record<Priority, string> = {
28
- High: 'bg-red-500',
29
- Medium: 'bg-yellow-500',
30
- Low: 'bg-green-500',
31
- }
32
-
33
- const SECTIONS: Status[] = ['In Progress', 'Todo', 'Done']
34
-
35
- function TaskRow({ task, onToggle }: { task: Task; onToggle: () => void }) {
36
- return (
37
- <div className="flex items-center gap-3 px-3 py-2.5 hover:bg-[hsl(var(--accent)/0.5)] rounded-md transition-colors">
38
- <Checkbox checked={task.done} onCheckedChange={onToggle} />
39
- <span className={cn('flex-1 text-sm', task.done && 'line-through text-[hsl(var(--muted-foreground))]')}>{task.title}</span>
40
- <span className={cn('h-2 w-2 rounded-full shrink-0', PRIORITY_DOT[task.priority])} title={task.priority} />
41
- <Avatar className="h-6 w-6 shrink-0"><AvatarFallback className="text-[10px]">{task.assignee}</AvatarFallback></Avatar>
42
- </div>
43
- )
44
- }
45
-
46
- export interface SortableTaskListProps { className?: string }
47
-
48
- export function SortableTaskList({ className }: SortableTaskListProps) {
49
- const [tasks, setTasks] = useState(TASKS)
50
- const toggle = (id: string) => setTasks(ts => ts.map(t => t.id === id ? { ...t, done: !t.done } : t))
51
-
52
- return (
53
- <div className={cn('rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--card))] p-4 space-y-4', className)}>
54
- {SECTIONS.map(section => {
55
- const items = tasks.filter(t => t.status === section)
56
- return (
57
- <div key={section}>
58
- <div className="flex items-center gap-2 mb-1.5">
59
- <p className="text-xs font-semibold text-[hsl(var(--muted-foreground))] uppercase tracking-wide">{section}</p>
60
- <span className="text-xs text-[hsl(var(--muted-foreground))]">({items.length})</span>
61
- </div>
62
- <div className="space-y-0.5">
63
- {items.map(task => <TaskRow key={task.id} task={task} onToggle={() => toggle(task.id)} />)}
64
- </div>
65
- </div>
66
- )
67
- })}
68
- </div>
69
- )
70
- }
1
+ export * from './SortableTaskList'
@@ -1,64 +1 @@
1
- import React from 'react'
2
- import { Bell, ChevronDown, ArrowRight } from 'lucide-react'
3
- import { cn } from '../utils/cn'
4
- import { Avatar, AvatarFallback } from '../primitives/avatar'
5
- import { Button } from '../primitives/button'
6
- import { Card, CardContent, CardHeader, CardTitle } from '../primitives/card'
7
-
8
- const NAV_LINKS = ['Features', 'Pricing', 'Docs', 'Blog']
9
-
10
- export interface StackedLayoutBrandedProps {
11
- brandName?: string
12
- children?: React.ReactNode
13
- className?: string
14
- }
15
-
16
- export function StackedLayoutBranded({
17
- brandName = 'Acme',
18
- children,
19
- className,
20
- }: StackedLayoutBrandedProps) {
21
- return (
22
- <div className={cn('flex h-[600px] flex-col overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))]', className)}>
23
- <nav className="flex h-14 items-center gap-6 bg-[hsl(var(--primary))] px-6">
24
- <span className="font-bold text-sm text-[hsl(var(--primary-foreground))] shrink-0">{brandName}</span>
25
- <div className="flex flex-1 items-center gap-1">
26
- {NAV_LINKS.map(link => (
27
- <button key={link} className="px-3 py-1.5 text-sm text-[hsl(var(--primary-foreground)/0.8)] hover:text-[hsl(var(--primary-foreground))] transition-colors rounded-md hover:bg-white/10">
28
- {link}
29
- </button>
30
- ))}
31
- </div>
32
- <div className="flex items-center gap-3">
33
- <Bell className="h-4 w-4 text-[hsl(var(--primary-foreground)/0.8)]" />
34
- <div className="flex items-center gap-1.5 cursor-pointer">
35
- <Avatar className="h-7 w-7 ring-2 ring-white/30">
36
- <AvatarFallback className="bg-white/20 text-[hsl(var(--primary-foreground))] text-xs">JD</AvatarFallback>
37
- </Avatar>
38
- <ChevronDown className="h-3 w-3 text-[hsl(var(--primary-foreground)/0.8)]" />
39
- </div>
40
- </div>
41
- </nav>
42
- <main className="flex-1 overflow-auto">
43
- {children ?? (
44
- <div className="p-6 space-y-6">
45
- <div>
46
- <h1 className="text-xl font-bold">Welcome back, Jane</h1>
47
- <p className="text-sm text-[hsl(var(--muted-foreground))] mt-1">Here's what's happening today.</p>
48
- </div>
49
- <div className="grid gap-4" style={{ gridTemplateColumns: 'repeat(auto-fill, minmax(min(100%,200px),1fr))' }}>
50
- {['Get Started', 'View Analytics', 'Manage Team'].map(action => (
51
- <Card key={action} className="cursor-pointer hover:shadow-md transition-shadow">
52
- <CardContent className="p-4 flex items-center justify-between">
53
- <span className="text-sm font-medium">{action}</span>
54
- <ArrowRight className="h-4 w-4 text-[hsl(var(--muted-foreground))]" />
55
- </CardContent>
56
- </Card>
57
- ))}
58
- </div>
59
- </div>
60
- )}
61
- </main>
62
- </div>
63
- )
64
- }
1
+ export * from './StackedLayoutBranded'
@@ -1,80 +1 @@
1
- import React, { useState } from 'react'
2
- import { Bell, ChevronDown } from 'lucide-react'
3
- import { cn } from '../utils/cn'
4
- import { Avatar, AvatarFallback } from '../primitives/avatar'
5
- import { Button } from '../primitives/button'
6
- import { Separator } from '../primitives/separator'
7
-
8
- const NAV_LINKS = ['Home', 'Projects', 'Analytics', 'Team']
9
- const TABS = ['Overview', 'Activity', 'Settings', 'Billing']
10
-
11
- export interface StackedLayoutTabsProps {
12
- brandName?: string
13
- children?: React.ReactNode
14
- className?: string
15
- }
16
-
17
- export function StackedLayoutTabs({
18
- brandName = 'Acme Inc',
19
- children,
20
- className,
21
- }: StackedLayoutTabsProps) {
22
- const [activeTab, setActiveTab] = useState(0)
23
- const [activeNav, setActiveNav] = useState(0)
24
-
25
- return (
26
- <div className={cn('flex h-[600px] flex-col overflow-hidden rounded-md border border-[hsl(var(--border))] bg-[hsl(var(--background))]', className)}>
27
- <nav className="flex h-14 items-center gap-6 border-b border-[hsl(var(--border))] bg-[hsl(var(--card))] px-4">
28
- <span className="font-semibold text-sm shrink-0">{brandName}</span>
29
- <div className="flex flex-1 items-center gap-1">
30
- {NAV_LINKS.map((link, i) => (
31
- <button
32
- key={link}
33
- onClick={() => setActiveNav(i)}
34
- className={cn(
35
- 'px-3 py-1.5 text-sm rounded-md transition-colors',
36
- i === activeNav
37
- ? 'bg-[hsl(var(--accent))] font-medium'
38
- : 'text-[hsl(var(--muted-foreground))] hover:bg-[hsl(var(--accent))]'
39
- )}
40
- >
41
- {link}
42
- </button>
43
- ))}
44
- </div>
45
- <div className="flex items-center gap-2">
46
- <Bell className="h-4 w-4 text-[hsl(var(--muted-foreground))]" />
47
- <div className="flex items-center gap-1.5 cursor-pointer">
48
- <Avatar className="h-7 w-7"><AvatarFallback className="text-xs">JD</AvatarFallback></Avatar>
49
- <ChevronDown className="h-3 w-3 text-[hsl(var(--muted-foreground))]" />
50
- </div>
51
- </div>
52
- </nav>
53
- <div className="border-b border-[hsl(var(--border))] bg-[hsl(var(--card))] px-4">
54
- <div className="flex gap-4">
55
- {TABS.map((tab, i) => (
56
- <button
57
- key={tab}
58
- onClick={() => setActiveTab(i)}
59
- className={cn(
60
- 'py-3 text-sm transition-colors border-b-2',
61
- i === activeTab
62
- ? 'border-[hsl(var(--primary))] font-medium'
63
- : 'border-transparent text-[hsl(var(--muted-foreground))] hover:text-[hsl(var(--foreground))]'
64
- )}
65
- >
66
- {tab}
67
- </button>
68
- ))}
69
- </div>
70
- </div>
71
- <main className="flex-1 overflow-auto p-6">
72
- {children ?? (
73
- <div className="text-sm text-[hsl(var(--muted-foreground))]">
74
- Content for <strong>{TABS[activeTab]}</strong> tab
75
- </div>
76
- )}
77
- </main>
78
- </div>
79
- )
80
- }
1
+ export * from './StackedLayoutTabs'
@@ -1,88 +1 @@
1
- import React from 'react'
2
- import { Calendar } from 'lucide-react'
3
- import { cn } from '../utils/cn'
4
- import { Card, CardContent } from '../primitives/card'
5
- import { Avatar, AvatarFallback } from '../primitives/avatar'
6
- import { Badge } from '../primitives/badge'
7
-
8
- const PRIORITY_COLOR: Record<string, string> = {
9
- High: 'bg-red-500/10 text-red-600 border-red-200',
10
- Medium: 'bg-yellow-500/10 text-yellow-600 border-yellow-200',
11
- Low: 'bg-green-500/10 text-green-600 border-green-200',
12
- }
13
-
14
- export interface TaskCardProps {
15
- title?: string
16
- description?: string
17
- assigneeInitials?: string
18
- dueDate?: string
19
- priority?: 'High' | 'Medium' | 'Low'
20
- className?: string
21
- }
22
-
23
- export function TaskCard({
24
- title = 'Redesign onboarding flow',
25
- description = 'Update the user onboarding experience with the new design language.',
26
- assigneeInitials = 'AC',
27
- dueDate = 'Mar 20',
28
- priority = 'High',
29
- className,
30
- }: TaskCardProps) {
31
- return (
32
- <Card className={cn('cursor-pointer hover:shadow-md transition-shadow', className)}>
33
- <CardContent className="p-4 space-y-3">
34
- <div className="flex items-start justify-between gap-2">
35
- <p className="text-sm font-semibold leading-tight">{title}</p>
36
- <span className={cn('text-[10px] px-1.5 py-0.5 rounded-full border font-medium shrink-0', PRIORITY_COLOR[priority])}>
37
- {priority}
38
- </span>
39
- </div>
40
- <p className="text-xs text-[hsl(var(--muted-foreground))] leading-relaxed line-clamp-2">{description}</p>
41
- <div className="flex items-center justify-between">
42
- <Avatar className="h-6 w-6"><AvatarFallback className="text-[10px]">{assigneeInitials}</AvatarFallback></Avatar>
43
- <div className="flex items-center gap-1 text-xs text-[hsl(var(--muted-foreground))]">
44
- <Calendar className="h-3 w-3" />{dueDate}
45
- </div>
46
- </div>
47
- </CardContent>
48
- </Card>
49
- )
50
- }
51
-
52
- const LABEL_COLORS = ['bg-blue-100 text-blue-700', 'bg-purple-100 text-purple-700', 'bg-green-100 text-green-700']
53
-
54
- export interface TaskCardWithLabelsProps extends TaskCardProps {
55
- labels?: string[]
56
- }
57
-
58
- export function TaskCardWithLabels({
59
- labels = ['Design', 'Frontend'],
60
- ...props
61
- }: TaskCardWithLabelsProps) {
62
- return (
63
- <Card className={cn('cursor-pointer hover:shadow-md transition-shadow', props.className)}>
64
- <CardContent className="p-4 space-y-3">
65
- <div className="flex items-start justify-between gap-2">
66
- <p className="text-sm font-semibold leading-tight">{props.title ?? 'Redesign onboarding flow'}</p>
67
- <span className={cn('text-[10px] px-1.5 py-0.5 rounded-full border font-medium shrink-0', PRIORITY_COLOR[props.priority ?? 'High'])}>
68
- {props.priority ?? 'High'}
69
- </span>
70
- </div>
71
- <p className="text-xs text-[hsl(var(--muted-foreground))] leading-relaxed line-clamp-2">
72
- {props.description ?? 'Update the user onboarding experience with the new design language.'}
73
- </p>
74
- <div className="flex flex-wrap gap-1">
75
- {labels.map((l, i) => (
76
- <span key={l} className={cn('text-[10px] px-1.5 py-0.5 rounded-full font-medium', LABEL_COLORS[i % LABEL_COLORS.length])}>{l}</span>
77
- ))}
78
- </div>
79
- <div className="flex items-center justify-between">
80
- <Avatar className="h-6 w-6"><AvatarFallback className="text-[10px]">{props.assigneeInitials ?? 'AC'}</AvatarFallback></Avatar>
81
- <div className="flex items-center gap-1 text-xs text-[hsl(var(--muted-foreground))]">
82
- <Calendar className="h-3 w-3" />{props.dueDate ?? 'Mar 20'}
83
- </div>
84
- </div>
85
- </CardContent>
86
- </Card>
87
- )
88
- }
1
+ export * from './TaskCard'
@@ -1,62 +1 @@
1
- import React from 'react'
2
- import { ChevronDown, User, Settings, CreditCard, LogOut } from 'lucide-react'
3
- import { cn } from '../utils/cn'
4
- import { Avatar, AvatarFallback } from '../primitives/avatar'
5
- import {
6
- DropdownMenu,
7
- DropdownMenuContent,
8
- DropdownMenuItem,
9
- DropdownMenuLabel,
10
- DropdownMenuSeparator,
11
- DropdownMenuTrigger,
12
- } from '../primitives/dropdown-menu'
13
-
14
- export interface UserMenuProps {
15
- name?: string
16
- email?: string
17
- initials?: string
18
- onProfile?: () => void
19
- onSettings?: () => void
20
- onBilling?: () => void
21
- onSignOut?: () => void
22
- className?: string
23
- }
24
-
25
- export function UserMenu({
26
- name = 'Jane Doe',
27
- email = 'jane@acme.com',
28
- initials = 'JD',
29
- onProfile,
30
- onSettings,
31
- onBilling,
32
- onSignOut,
33
- className,
34
- }: UserMenuProps) {
35
- return (
36
- <DropdownMenu>
37
- <DropdownMenuTrigger asChild>
38
- <button className={cn('flex items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors hover:bg-[hsl(var(--accent))] focus:outline-none', className)}>
39
- <Avatar className="h-7 w-7">
40
- <AvatarFallback className="text-xs">{initials}</AvatarFallback>
41
- </Avatar>
42
- <span className="font-medium max-w-[120px] truncate">{name}</span>
43
- <ChevronDown className="h-3.5 w-3.5 text-[hsl(var(--muted-foreground))]" />
44
- </button>
45
- </DropdownMenuTrigger>
46
- <DropdownMenuContent align="end" className="w-52">
47
- <DropdownMenuLabel className="font-normal">
48
- <p className="text-sm font-medium">{name}</p>
49
- <p className="text-xs text-[hsl(var(--muted-foreground))]">{email}</p>
50
- </DropdownMenuLabel>
51
- <DropdownMenuSeparator />
52
- <DropdownMenuItem onClick={onProfile}><User className="h-4 w-4" />Profile</DropdownMenuItem>
53
- <DropdownMenuItem onClick={onSettings}><Settings className="h-4 w-4" />Account Settings</DropdownMenuItem>
54
- <DropdownMenuItem onClick={onBilling}><CreditCard className="h-4 w-4" />Billing</DropdownMenuItem>
55
- <DropdownMenuSeparator />
56
- <DropdownMenuItem onClick={onSignOut} className="text-[hsl(var(--destructive))] focus:text-[hsl(var(--destructive))]">
57
- <LogOut className="h-4 w-4" />Sign out
58
- </DropdownMenuItem>
59
- </DropdownMenuContent>
60
- </DropdownMenu>
61
- )
62
- }
1
+ export * from './UserMenu'