@gunjo/ui 0.0.1-alpha.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 (88) hide show
  1. package/README.md +129 -0
  2. package/design/atoms-metadata.json +82 -0
  3. package/design/molecules-metadata.json +130 -0
  4. package/design/organisms-metadata.json +38 -0
  5. package/design/templates-metadata.json +38 -0
  6. package/package.json +158 -0
  7. package/src/components/atoms/Alert.tsx +63 -0
  8. package/src/components/atoms/Avatar.tsx +57 -0
  9. package/src/components/atoms/Badge.tsx +30 -0
  10. package/src/components/atoms/Button.tsx +29 -0
  11. package/src/components/atoms/ButtonVariants.ts +37 -0
  12. package/src/components/atoms/Checkbox.tsx +52 -0
  13. package/src/components/atoms/Img.tsx +102 -0
  14. package/src/components/atoms/Input.tsx +37 -0
  15. package/src/components/atoms/Kbd.tsx +22 -0
  16. package/src/components/atoms/Label.tsx +22 -0
  17. package/src/components/atoms/Progress.tsx +38 -0
  18. package/src/components/atoms/RadioGroup.tsx +86 -0
  19. package/src/components/atoms/Select.tsx +28 -0
  20. package/src/components/atoms/Separator.tsx +33 -0
  21. package/src/components/atoms/Skeleton.tsx +36 -0
  22. package/src/components/atoms/Slider.tsx +26 -0
  23. package/src/components/atoms/Spinner.tsx +34 -0
  24. package/src/components/atoms/Switch.tsx +47 -0
  25. package/src/components/atoms/Textarea.tsx +34 -0
  26. package/src/components/atoms/ToggleGroup.tsx +60 -0
  27. package/src/components/atoms/ToolPill.tsx +77 -0
  28. package/src/components/atoms/generated/default-variant-keys.ts +36 -0
  29. package/src/components/atoms/generated/variant-keys.ts +61 -0
  30. package/src/components/generated/component-manifest.ts +741 -0
  31. package/src/components/generated/component-style-hints.ts +1262 -0
  32. package/src/components/molecules/AIChatInput.tsx +140 -0
  33. package/src/components/molecules/AIChatMessage.tsx +109 -0
  34. package/src/components/molecules/Accordion.tsx +99 -0
  35. package/src/components/molecules/Breadcrumb.tsx +115 -0
  36. package/src/components/molecules/Calendar.tsx +60 -0
  37. package/src/components/molecules/Card.tsx +78 -0
  38. package/src/components/molecules/Carousel.tsx +261 -0
  39. package/src/components/molecules/Command.tsx +152 -0
  40. package/src/components/molecules/ContextMenu.tsx +200 -0
  41. package/src/components/molecules/Dialog.tsx +122 -0
  42. package/src/components/molecules/DropdownMenu.tsx +200 -0
  43. package/src/components/molecules/FilterButton.tsx +133 -0
  44. package/src/components/molecules/Form.tsx +90 -0
  45. package/src/components/molecules/HoverCard.tsx +29 -0
  46. package/src/components/molecules/List.tsx +120 -0
  47. package/src/components/molecules/Menubar.tsx +231 -0
  48. package/src/components/molecules/Modal.tsx +66 -0
  49. package/src/components/molecules/NotificationCenter.tsx +118 -0
  50. package/src/components/molecules/Pagination.tsx +118 -0
  51. package/src/components/molecules/Popover.tsx +31 -0
  52. package/src/components/molecules/ProgressWidget.tsx +40 -0
  53. package/src/components/molecules/Resizable.tsx +47 -0
  54. package/src/components/molecules/ScrollArea.tsx +48 -0
  55. package/src/components/molecules/Sheet.tsx +140 -0
  56. package/src/components/molecules/SidebarItem.tsx +134 -0
  57. package/src/components/molecules/SortButton.tsx +56 -0
  58. package/src/components/molecules/StatusBar.tsx +41 -0
  59. package/src/components/molecules/Stepper.tsx +108 -0
  60. package/src/components/molecules/Table.tsx +117 -0
  61. package/src/components/molecules/Tabs.tsx +64 -0
  62. package/src/components/molecules/Toast.tsx +57 -0
  63. package/src/components/molecules/Tooltip.tsx +30 -0
  64. package/src/components/molecules/generated/default-variant-keys.ts +22 -0
  65. package/src/components/molecules/generated/variant-keys.ts +33 -0
  66. package/src/components/organisms/AppRail.tsx +28 -0
  67. package/src/components/organisms/CommandPalette.tsx +58 -0
  68. package/src/components/organisms/FileUploader.tsx +151 -0
  69. package/src/components/organisms/FloatingPanel.tsx +46 -0
  70. package/src/components/organisms/InspectorPanel.tsx +65 -0
  71. package/src/components/organisms/RightRail.tsx +29 -0
  72. package/src/components/organisms/ShareModal.tsx +182 -0
  73. package/src/components/organisms/SpatialCanvas.tsx +36 -0
  74. package/src/components/organisms/ToastProvider.tsx +49 -0
  75. package/src/components/templates/AuthTemplate.tsx +58 -0
  76. package/src/components/templates/BannalyzeTemplate.tsx +55 -0
  77. package/src/components/templates/ChatTemplate.tsx +55 -0
  78. package/src/components/templates/DashboardTemplate.tsx +34 -0
  79. package/src/components/templates/EditorTemplate.tsx +46 -0
  80. package/src/components/templates/KanbanTemplate.tsx +38 -0
  81. package/src/components/templates/LandingTemplate.tsx +53 -0
  82. package/src/components/templates/MediaLibraryTemplate.tsx +55 -0
  83. package/src/components/templates/SettingsTemplate.tsx +48 -0
  84. package/src/globals.css +108 -0
  85. package/src/index.ts +89 -0
  86. package/src/lib/utils.ts +6 -0
  87. package/tailwind-preset.js +11 -0
  88. package/tailwind-theme-extend.cjs +86 -0
@@ -0,0 +1,29 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { cn } from "../../lib/utils"
5
+
6
+ export interface RightRailProps extends React.HTMLAttributes<HTMLDivElement> {
7
+ width?: string
8
+ }
9
+
10
+ const RightRail = React.forwardRef<HTMLDivElement, RightRailProps>(
11
+ ({ className, width = "w-64", children, ...props }, ref) => {
12
+ return (
13
+ <div
14
+ ref={ref}
15
+ className={cn(
16
+ "flex flex-col w-[256px] h-[360px] h-full border border-l border-border bg-background z-30 flex-shrink-0",
17
+ width,
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ {children}
23
+ </div>
24
+ )
25
+ }
26
+ )
27
+ RightRail.displayName = "RightRail"
28
+
29
+ export { RightRail }
@@ -0,0 +1,182 @@
1
+ "use client"
2
+ import React, { useState, useEffect } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import { X, Copy, Globe, Lock, Check, ExternalLink } from 'lucide-react';
5
+ import { cn } from '../../lib/utils';
6
+
7
+ export interface ShareData {
8
+ isPublic: boolean;
9
+ token?: string;
10
+ accessCount?: number;
11
+ createdAt?: string;
12
+ }
13
+
14
+ export interface ShareableItem {
15
+ id: string;
16
+ share?: ShareData;
17
+ [key: string]: any;
18
+ }
19
+
20
+ interface ShareModalProps {
21
+ isOpen: boolean;
22
+ onClose: () => void;
23
+ item: ShareableItem;
24
+ onUpdate: (id: string, updates: Partial<ShareableItem>) => void;
25
+ apiEndpoint?: string; // Allow customizing API endpoint
26
+ }
27
+
28
+ export const ShareModal = ({ isOpen, onClose, item, onUpdate, apiEndpoint = '/api/share' }: ShareModalProps) => {
29
+ const [isPublic, setIsPublic] = useState(item.share?.isPublic || false);
30
+ const [isLoading, setIsLoading] = useState(false);
31
+ const [copied, setCopied] = useState(false);
32
+ const [shareData, setShareData] = useState<ShareData | undefined>(item.share);
33
+ const [mounted, setMounted] = useState(false);
34
+
35
+ useEffect(() => {
36
+ setMounted(true);
37
+ }, []);
38
+
39
+ useEffect(() => {
40
+ setIsPublic(item.share?.isPublic || false);
41
+ setShareData(item.share);
42
+ }, [item.id, item.share]);
43
+
44
+ if (!isOpen || !mounted) return null;
45
+
46
+ const handleToggleShare = async () => {
47
+ setIsLoading(true);
48
+ try {
49
+ const res = await fetch(apiEndpoint, {
50
+ method: 'POST',
51
+ headers: { 'Content-Type': 'application/json' },
52
+ body: JSON.stringify({
53
+ id: item.id,
54
+ enable: !isPublic
55
+ })
56
+ });
57
+
58
+ if (res.ok) {
59
+ const json = await res.json();
60
+ setIsPublic(!isPublic);
61
+ setShareData(json.share);
62
+ // Optimistic update for parent
63
+ onUpdate(item.id, { share: json.share });
64
+ }
65
+ } catch (error) {
66
+ console.error('Failed to toggle share', error);
67
+ } finally {
68
+ setIsLoading(false);
69
+ }
70
+ };
71
+
72
+ const shareUrl = shareData?.token
73
+ ? `${window.location.origin}/share/${shareData.token}`
74
+ : '';
75
+
76
+ const handleCopy = () => {
77
+ if (shareUrl) {
78
+ navigator.clipboard.writeText(shareUrl);
79
+ setCopied(true);
80
+ setTimeout(() => setCopied(false), 2000);
81
+ }
82
+ };
83
+
84
+ return createPortal(
85
+ <div className="fixed inset-0 z-50 flex items-center justify-center bg-overlay/50 backdrop-blur-sm animate-in fade-in duration-200" onClick={(e) => { e.stopPropagation(); onClose(); }}>
86
+ <div className="bg-background border border-border rounded-xl shadow-2xl w-[448px] w-full max-w-md overflow-hidden animate-in zoom-in-95 duration-200" onClick={e => e.stopPropagation()}>
87
+ {/* Header */}
88
+ <div className="flex items-center justify-between px-4 py-3 border-b border-border bg-muted/50">
89
+ <h3 className="text-sm font-semibold text-foreground flex items-center gap-2">
90
+ <Globe size={16} className="text-primary" />
91
+ Share Image
92
+ </h3>
93
+ <button onClick={onClose} className="text-muted-foreground hover:text-foreground transition-colors">
94
+ <X size={18} />
95
+ </button>
96
+ </div>
97
+
98
+ {/* Content */}
99
+ <div className="p-6 space-y-6">
100
+
101
+ {/* Toggle Switch */}
102
+ <div className="flex items-center justify-between">
103
+ <div className="space-y-1">
104
+ <div className="text-sm font-medium text-foreground">Public Link</div>
105
+ <div className="text-xs text-muted-foreground">
106
+ {isPublic
107
+ ? "Anyone with the link can view this image."
108
+ : "Only you can view this image."}
109
+ </div>
110
+ </div>
111
+
112
+ <button
113
+ onClick={handleToggleShare}
114
+ disabled={isLoading}
115
+ className={cn(
116
+ "relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:ring-offset-background",
117
+ isPublic ? "bg-primary" : "bg-muted",
118
+ isLoading && "opacity-50 cursor-not-allowed"
119
+ )}
120
+ >
121
+ <span
122
+ className={cn(
123
+ "inline-block h-4 w-4 transform rounded-full bg-background transition-transform",
124
+ isPublic ? "translate-x-6" : "translate-x-1"
125
+ )}
126
+ />
127
+ </button>
128
+ </div>
129
+
130
+ {/* URL Display */}
131
+ {isPublic && shareData && (
132
+ <div className="space-y-2 animate-in slide-in-from-top-2 duration-200">
133
+ <label className="text-xs font-medium text-muted-foreground">Public URL</label>
134
+ <div className="flex items-center gap-2">
135
+ <div className="flex-1 bg-muted border border-border rounded-md px-3 py-2 text-xs text-muted-foreground font-mono truncate select-all">
136
+ {shareUrl}
137
+ </div>
138
+ <button
139
+ onClick={handleCopy}
140
+ className="p-2 bg-background hover:bg-muted text-muted-foreground rounded-md transition-colors border border-border"
141
+ title="Copy to clipboard"
142
+ >
143
+ {copied ? <Check size={16} className="text-primary" /> : <Copy size={16} />}
144
+ </button>
145
+ <a
146
+ href={shareUrl}
147
+ target="_blank"
148
+ rel="noopener noreferrer"
149
+ className="p-2 bg-background hover:bg-muted text-muted-foreground rounded-md transition-colors border border-border"
150
+ title="Open in new tab"
151
+ >
152
+ <ExternalLink size={16} />
153
+ </a>
154
+ </div>
155
+
156
+ {/* Stats */}
157
+ <div className="flex items-center gap-4 pt-2">
158
+ <div className="flex items-center gap-1.5 text-xs text-muted-foreground">
159
+ <Globe size={12} />
160
+ <span>Access Count: <span className="text-foreground font-mono">{shareData.accessCount || 0}</span></span>
161
+ </div>
162
+ <div className="flex items-center gap-1.5 text-xs text-muted-foreground">
163
+ <Lock size={12} />
164
+ <span>Token: <span className="text-foreground font-mono">{shareData.token?.slice(0, 8)}...</span></span>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ )}
169
+
170
+ {!isPublic && (
171
+ <div className="flex flex-col items-center justify-center py-4 text-muted-foreground space-y-2 border-2 border-dashed border-border rounded-lg bg-muted/50">
172
+ <Lock size={24} />
173
+ <span className="text-xs">Sharing is disabled</span>
174
+ </div>
175
+ )}
176
+
177
+ </div>
178
+ </div>
179
+ </div>,
180
+ document.body
181
+ );
182
+ };
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import { cn } from '../../lib/utils';
3
+
4
+ interface SpatialCanvasProps {
5
+ children: React.ReactNode;
6
+ className?: string;
7
+ gridSize?: number;
8
+ }
9
+
10
+ export const SpatialCanvas: React.FC<SpatialCanvasProps> = ({
11
+ children,
12
+ className,
13
+ gridSize = 20
14
+ }) => {
15
+ return (
16
+ <div
17
+ className={cn(
18
+ "relative flex flex-col w-[640px] h-[360px] w-full h-full overflow-hidden bg-muted/50 select-none",
19
+ className
20
+ )}
21
+ style={{
22
+ backgroundImage: `radial-gradient(circle, hsl(var(--foreground) / 0.08) 1px, transparent 1px)`,
23
+ backgroundSize: `${gridSize}px ${gridSize}px`
24
+ }}
25
+ >
26
+ <div className="absolute inset-0 pointer-events-none dark:opacity-20 opacity-5"
27
+ style={{
28
+ backgroundImage: `linear-gradient(to right, hsl(var(--foreground) / 0.07) 1px, transparent 1px),
29
+ linear-gradient(to bottom, hsl(var(--foreground) / 0.07) 1px, transparent 1px)`,
30
+ backgroundSize: `${gridSize * 5}px ${gridSize * 5}px`
31
+ }}
32
+ />
33
+ {children}
34
+ </div>
35
+ );
36
+ };
@@ -0,0 +1,49 @@
1
+ "use client"
2
+ import React, { createContext, useContext, useState, useCallback } from 'react';
3
+ import { Toast, ToastType } from '../molecules/Toast';
4
+
5
+ interface ToastContextType {
6
+ showToast: (message: string, type: ToastType, duration?: number) => void;
7
+ }
8
+
9
+ const ToastContext = createContext<ToastContextType | undefined>(undefined);
10
+
11
+ export const ToastProvider = ({ children }: { children: React.ReactNode }) => {
12
+ const [toasts, setToasts] = useState<{ id: number, message: string, type: ToastType, duration: number, isVisible: boolean }[]>([]);
13
+
14
+ const showToast = useCallback((message: string, type: ToastType, duration = 3000) => {
15
+ const id = Date.now();
16
+ setToasts(prev => [...prev, { id, message, type, duration, isVisible: true }]);
17
+ }, []);
18
+
19
+ const closeToast = useCallback((id: number) => {
20
+ setToasts(prev => prev.map(t => t.id === id ? { ...t, isVisible: false } : t));
21
+ setTimeout(() => {
22
+ setToasts(prev => prev.filter(t => t.id !== id));
23
+ }, 300);
24
+ }, []);
25
+
26
+ return (
27
+ <ToastContext.Provider value={{ showToast }}>
28
+ {children}
29
+ <div className="fixed top-6 right-6 z-[100] flex flex-col items-center w-[320px] gap-2 pointer-events-none">
30
+ {toasts.map(toast => (
31
+ <Toast
32
+ key={toast.id}
33
+ message={toast.message}
34
+ type={toast.type}
35
+ isVisible={toast.isVisible}
36
+ onClose={() => closeToast(toast.id)}
37
+ duration={toast.duration}
38
+ />
39
+ ))}
40
+ </div>
41
+ </ToastContext.Provider>
42
+ );
43
+ };
44
+
45
+ export const useToast = () => {
46
+ const context = useContext(ToastContext);
47
+ if (!context) throw new Error('useToast must be used within a ToastProvider');
48
+ return context;
49
+ };
@@ -0,0 +1,58 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface AuthTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ logo?: React.ReactNode
6
+ quote?: string
7
+ quoteAuthor?: string
8
+ children: React.ReactNode // The form
9
+ }
10
+
11
+ export function AuthTemplate({
12
+ children,
13
+ logo,
14
+ quote,
15
+ quoteAuthor,
16
+ className,
17
+ ...props
18
+ }: AuthTemplateProps) {
19
+ return (
20
+ <div className={cn("container relative w-[1280px] h-[720px] h-screen flex-col items-center justify-center md:grid lg:max-w-none lg:grid-cols-2 lg:px-0", className)} {...props}>
21
+ <div className="relative hidden h-full flex-col bg-muted p-10 text-background dark:border-r lg:flex">
22
+ <div className="absolute inset-0 bg-foreground" />
23
+ <div className="relative z-20 flex items-center text-lg font-medium">
24
+ {logo || (
25
+ <>
26
+ <svg
27
+ xmlns="http://www.w3.org/2000/svg"
28
+ viewBox="0 0 24 24"
29
+ fill="none"
30
+ stroke="currentColor"
31
+ strokeWidth="2"
32
+ strokeLinecap="round"
33
+ strokeLinejoin="round"
34
+ className="mr-2 h-6 w-6"
35
+ >
36
+ <path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3" />
37
+ </svg>
38
+ Acme Inc
39
+ </>
40
+ )}
41
+ </div>
42
+ <div className="relative z-20 mt-auto">
43
+ <blockquote className="space-y-2">
44
+ <p className="text-lg">
45
+ &ldquo;{quote || "This library has saved me infinite hours. I can build rich apps faster than ever before."}&rdquo;
46
+ </p>
47
+ <footer className="text-sm">{quoteAuthor || "Sofia Davis"}</footer>
48
+ </blockquote>
49
+ </div>
50
+ </div>
51
+ <div className="lg:p-8 flex items-center justify-center h-full">
52
+ <div className="mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px]">
53
+ {children}
54
+ </div>
55
+ </div>
56
+ </div>
57
+ )
58
+ }
@@ -0,0 +1,55 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface BannalyzeTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ header?: React.ReactNode
6
+ sidebar?: React.ReactNode
7
+ inspector?: React.ReactNode
8
+ children: React.ReactNode
9
+ }
10
+
11
+ export function BannalyzeTemplate({
12
+ children,
13
+ header,
14
+ sidebar,
15
+ inspector,
16
+ className,
17
+ ...props
18
+ }: BannalyzeTemplateProps) {
19
+ return (
20
+ <div className={cn("flex flex-col w-[1280px] h-[720px] h-screen w-full overflow-hidden bg-background", className)} {...props}>
21
+ {/* Header */}
22
+ {header && (
23
+ <div className="flex-shrink-0 z-20 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
24
+ <div className="flex h-14 items-center px-4">
25
+ {header}
26
+ </div>
27
+ </div>
28
+ )}
29
+
30
+ {/* Main Content Area */}
31
+ <div className="flex flex-1 overflow-hidden relative">
32
+ {/* Left Sidebar */}
33
+ {sidebar && (
34
+ <aside className="group flex-shrink-0 w-64 border-r bg-muted/10 hidden md:block overflow-y-auto">
35
+ {sidebar}
36
+ </aside>
37
+ )}
38
+
39
+ {/* Canvas / Center Area */}
40
+ <main className="flex-1 relative overflow-hidden flex flex-col items-center justify-center bg-muted/20">
41
+ <div className="w-full h-full p-4 overflow-auto flex items-center justify-center">
42
+ {children}
43
+ </div>
44
+ </main>
45
+
46
+ {/* Right Inspector Panel */}
47
+ {inspector && (
48
+ <aside className="flex-shrink-0 w-80 border-l bg-background hidden lg:block overflow-y-auto">
49
+ {inspector}
50
+ </aside>
51
+ )}
52
+ </div>
53
+ </div>
54
+ )
55
+ }
@@ -0,0 +1,55 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface ChatTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ sidebarList?: React.ReactNode // Channel/User list
6
+ sidebarDetail?: React.ReactNode // User profile / Thread details
7
+ header?: React.ReactNode
8
+ children: React.ReactNode // Message stream
9
+ composer?: React.ReactNode // Input area
10
+ }
11
+
12
+ export function ChatTemplate({
13
+ sidebarList,
14
+ sidebarDetail,
15
+ header,
16
+ children,
17
+ composer,
18
+ className,
19
+ ...props
20
+ }: ChatTemplateProps) {
21
+ return (
22
+ <div className={cn("flex w-[1280px] h-[720px] h-screen w-full overflow-hidden bg-background", className)} {...props}>
23
+ {/* Left Sidebar (Channels) */}
24
+ {sidebarList && (
25
+ <aside className="hidden w-[280px] flex-col border-r bg-muted/30 md:flex flex-shrink-0">
26
+ {sidebarList}
27
+ </aside>
28
+ )}
29
+
30
+ {/* Main Chat Area */}
31
+ <div className="flex flex-col flex-1 min-w-0">
32
+ {header && (
33
+ <header className="flex h-14 items-center border-b px-4 lg:h-[60px]">
34
+ {header}
35
+ </header>
36
+ )}
37
+ <main className="flex-1 overflow-y-auto p-4 flex flex-col">
38
+ {children}
39
+ </main>
40
+ {composer && (
41
+ <div className="p-4 border-t bg-background">
42
+ {composer}
43
+ </div>
44
+ )}
45
+ </div>
46
+
47
+ {/* Right Sidebar (Details) - Optional */}
48
+ {sidebarDetail && (
49
+ <aside className="hidden w-[300px] border-l bg-muted/30 xl:block flex-shrink-0">
50
+ {sidebarDetail}
51
+ </aside>
52
+ )}
53
+ </div>
54
+ )
55
+ }
@@ -0,0 +1,34 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface DashboardTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ header?: React.ReactNode
6
+ sidebar?: React.ReactNode
7
+ children: React.ReactNode
8
+ }
9
+
10
+ export function DashboardTemplate({
11
+ children,
12
+ header,
13
+ sidebar,
14
+ className,
15
+ ...props
16
+ }: DashboardTemplateProps) {
17
+ return (
18
+ <div className={cn("flex flex-col w-[1280px] h-[720px] min-h-screen w-full", className)} {...props}>
19
+ {header && <div className="border-b">{header}</div>}
20
+ <div className="flex flex-1">
21
+ {sidebar && (
22
+ <aside className="hidden border-r w-64 md:block flex-shrink-0">
23
+ {sidebar}
24
+ </aside>
25
+ )}
26
+ <main className="flex-1 overflow-auto bg-muted/50">
27
+ <div className="container mx-auto py-6 space-y-8 px-4 md:px-6">
28
+ {children}
29
+ </div>
30
+ </main>
31
+ </div>
32
+ </div>
33
+ )
34
+ }
@@ -0,0 +1,46 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface EditorTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ topBar?: React.ReactNode
6
+ leftPanel?: React.ReactNode
7
+ rightPanel?: React.ReactNode
8
+ children: React.ReactNode // The canvas area
9
+ }
10
+
11
+ export function EditorTemplate({
12
+ children,
13
+ topBar,
14
+ leftPanel,
15
+ rightPanel,
16
+ className,
17
+ ...props
18
+ }: EditorTemplateProps) {
19
+ return (
20
+ <div className={cn("flex flex-col w-[1280px] h-[720px] h-screen w-full overflow-hidden", className)} {...props}>
21
+ {topBar && (
22
+ <div className="flex-shrink-0 border-b h-14 flex items-center bg-background z-10">
23
+ {topBar}
24
+ </div>
25
+ )}
26
+ <div className="flex flex-1 overflow-hidden relative">
27
+ {leftPanel && (
28
+ <aside className="flex-shrink-0 border-r w-64 bg-background z-10 hidden md:block">
29
+ {leftPanel}
30
+ </aside>
31
+ )}
32
+
33
+ <main className="flex-1 relative bg-muted/50 overflow-hidden">
34
+ {/* Canvas Area */}
35
+ {children}
36
+ </main>
37
+
38
+ {rightPanel && (
39
+ <aside className="flex-shrink-0 border-l w-72 bg-background z-10 hidden lg:block">
40
+ {rightPanel}
41
+ </aside>
42
+ )}
43
+ </div>
44
+ </div>
45
+ )
46
+ }
@@ -0,0 +1,38 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface KanbanTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ sidebar?: React.ReactNode
6
+ header?: React.ReactNode
7
+ children: React.ReactNode // The columns
8
+ }
9
+
10
+ export function KanbanTemplate({
11
+ sidebar,
12
+ header,
13
+ children,
14
+ className,
15
+ ...props
16
+ }: KanbanTemplateProps) {
17
+ return (
18
+ <div className={cn("flex w-[1280px] h-[720px] h-screen w-full overflow-hidden", className)} {...props}>
19
+ {sidebar && (
20
+ <aside className="hidden w-64 border-r bg-muted/40 md:block flex-shrink-0">
21
+ {sidebar}
22
+ </aside>
23
+ )}
24
+ <div className="flex flex-col flex-1 h-full min-w-0">
25
+ {header && (
26
+ <header className="flex h-14 items-center gap-4 border-b bg-muted/40 px-6 lg:h-[60px]">
27
+ {header}
28
+ </header>
29
+ )}
30
+ <main className="flex-1 overflow-x-auto overflow-y-hidden p-6">
31
+ <div className="flex h-full gap-6">
32
+ {children}
33
+ </div>
34
+ </main>
35
+ </div>
36
+ </div>
37
+ )
38
+ }
@@ -0,0 +1,53 @@
1
+ import * as React from "react"
2
+ import { cn } from "../../lib/utils"
3
+
4
+ interface LandingTemplateProps extends React.HTMLAttributes<HTMLDivElement> {
5
+ header?: React.ReactNode
6
+ hero: React.ReactNode
7
+ features?: React.ReactNode
8
+ testimonials?: React.ReactNode
9
+ pricing?: React.ReactNode
10
+ cta?: React.ReactNode
11
+ footer?: React.ReactNode
12
+ }
13
+
14
+ export function LandingTemplate({
15
+ header,
16
+ hero,
17
+ features,
18
+ testimonials,
19
+ pricing,
20
+ cta,
21
+ footer,
22
+ className,
23
+ ...props
24
+ }: LandingTemplateProps) {
25
+ return (
26
+ <div className={cn("flex flex-col w-[1280px] h-[720px] min-h-screen w-full", className)} {...props}>
27
+ {/* Sticky Header */}
28
+ {header && (
29
+ <div className="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
30
+ <div className="container flex h-14 items-center">
31
+ {header}
32
+ </div>
33
+ </div>
34
+ )}
35
+
36
+ <main className="flex-1">
37
+ {hero}
38
+ {features && <section className="container py-12 md:py-24 lg:py-32">{features}</section>}
39
+ {testimonials && <section className="bg-muted/50 py-12 md:py-24 lg:py-32">{testimonials}</section>}
40
+ {pricing && <section className="container py-12 md:py-24 lg:py-32">{pricing}</section>}
41
+ {cta}
42
+ </main>
43
+
44
+ {footer && (
45
+ <footer className="border-t py-6 md:py-0">
46
+ <div className="container flex flex-col items-center justify-between gap-4 md:h-24 md:flex-row">
47
+ {footer}
48
+ </div>
49
+ </footer>
50
+ )}
51
+ </div>
52
+ )
53
+ }