@@ -4,7 +4,6 @@ import { Button } from "~/components/ui/button";
44import { Input } from "~/components/ui/input" ;
55import { Label } from "~/components/ui/label" ;
66import { Badge } from "~/components/ui/badge" ;
7- import { Card , CardContent , CardHeader , CardTitle } from "~/components/ui/card" ;
87import { Separator } from "~/components/ui/separator" ;
98import { AlignLeft , AlignCenter , AlignRight , Bold , ChevronDown , Type , Plus } from "lucide-react" ;
109import {
@@ -53,161 +52,162 @@ export default function TextEditor() {
5352 } ;
5453
5554 return (
56- < div className = "h-full flex flex-col bg-background" >
57- < div className = "flex-1 overflow-y-auto p-3" >
58- < Card className = "border-border/50" >
59- < CardHeader className = "pb-3" >
60- < div className = "flex items-center gap-2" >
61- < Type className = "h-4 w-4 text-primary" />
62- < CardTitle className = "text-sm" > Text Properties</ CardTitle >
63- </ div >
64- </ CardHeader >
65- < CardContent className = "space-y-4" >
66- { /* Text Content */ }
67- < div className = "space-y-2" >
68- < Label className = "text-xs font-medium" > Content</ Label >
69- < textarea
70- value = { textContent }
71- onChange = { ( e ) => setTextContent ( e . target . value ) }
72- className = "w-full h-20 p-3 text-sm bg-muted/50 border border-border rounded-md text-foreground placeholder-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/50 focus:border-primary resize-none"
73- placeholder = "Enter your text..."
55+ < div className = "h-full flex flex-col bg-background text-foreground" >
56+ { /* Header */ }
57+ < div className = "flex items-center gap-2 px-3 py-2 border-b border-border/50 shrink-0" >
58+ < Type className = "h-3.5 w-3.5 text-muted-foreground" />
59+ < span className = "text-xs font-semibold" > Text Properties</ span >
60+ </ div >
61+
62+ < div className = "flex-1 overflow-y-auto px-3 py-3 space-y-4 text-xs" >
63+ { /* Text Content */ }
64+ < div className = "space-y-1.5" >
65+ < div className = "text-[10px] font-medium text-muted-foreground uppercase tracking-wider" > Content</ div >
66+ < textarea
67+ value = { textContent }
68+ onChange = { ( e ) => setTextContent ( e . target . value ) }
69+ className = "w-full h-20 p-2 text-xs bg-muted/30 border border-border/50 rounded-md text-foreground placeholder-muted-foreground focus:outline-none focus:border-primary resize-none"
70+ placeholder = "Enter your text..."
71+ />
72+ </ div >
73+
74+ < Separator />
75+
76+ { /* Font Size & Family Row */ }
77+ < div className = "space-y-1.5" >
78+ < div className = "text-[10px] font-medium text-muted-foreground uppercase tracking-wider" > Typography</ div >
79+ < div className = "grid grid-cols-2 gap-2" >
80+ < div className = "space-y-1" >
81+ < Label className = "text-[10px] text-muted-foreground" > Size</ Label >
82+ < Input
83+ type = "number"
84+ min = "8"
85+ max = "200"
86+ value = { fontSize }
87+ onChange = { ( e ) => setFontSize ( parseInt ( e . target . value ) || 48 ) }
88+ className = "h-6 text-xs px-2"
7489 />
7590 </ div >
76-
77- { /* Font Size & Family Row */ }
78- < div className = "grid grid-cols-2 gap-3" >
79- < div className = "space-y-2" >
80- < Label className = "text-xs font-medium" > Size</ Label >
81- < Input
82- type = "number"
83- min = "8"
84- max = "200"
85- value = { fontSize }
86- onChange = { ( e ) => setFontSize ( parseInt ( e . target . value ) || 48 ) }
87- className = "h-8 text-sm"
88- />
89- </ div >
90- < div className = "space-y-2" >
91- < Label className = "text-xs font-medium" > Font</ Label >
92- < DropdownMenu >
93- < DropdownMenuTrigger asChild >
94- < Button
95- variant = "ghost"
96- className = "w-full h-8 px-2 text-sm bg-muted/50 border border-border rounded-md text-foreground justify-between hover:bg-muted/70"
97- style = { { fontFamily : fontFamily } }
98- aria-label = "Select font" >
99- < span className = "truncate" >
100- { availableFonts . find ( ( f ) => f . value === fontFamily ) ?. label || fontFamily }
101- </ span >
102- < ChevronDown className = "h-3.5 w-3.5 ml-2 opacity-70" />
103- </ Button >
104- </ DropdownMenuTrigger >
105- < DropdownMenuContent className = "rounded-md p-1 min-w-[12rem]" >
106- { availableFonts . map ( ( font ) => (
107- < DropdownMenuItem
108- key = { font . label }
109- onSelect = { ( ) => setFontFamily ( font . value ) }
110- className = "cursor-pointer"
111- style = { { fontFamily : font . value } } >
112- { font . label }
113- </ DropdownMenuItem >
114- ) ) }
115- </ DropdownMenuContent >
116- </ DropdownMenu >
117- </ div >
91+ < div className = "space-y-1" >
92+ < Label className = "text-[10px] text-muted-foreground" > Font</ Label >
93+ < DropdownMenu >
94+ < DropdownMenuTrigger asChild >
95+ < Button
96+ variant = "ghost"
97+ className = "w-full h-6 px-2 text-xs bg-muted/30 border border-border/50 rounded text-foreground justify-between hover:bg-muted/50"
98+ style = { { fontFamily : fontFamily } }
99+ aria-label = "Select font" >
100+ < span className = "truncate text-[10px]" >
101+ { availableFonts . find ( ( f ) => f . value === fontFamily ) ?. label || fontFamily }
102+ </ span >
103+ < ChevronDown className = "h-3 w-3 ml-1 opacity-60 shrink-0" />
104+ </ Button >
105+ </ DropdownMenuTrigger >
106+ < DropdownMenuContent className = "rounded-md p-1 min-w-[10rem]" >
107+ { availableFonts . map ( ( font ) => (
108+ < DropdownMenuItem
109+ key = { font . label }
110+ onSelect = { ( ) => setFontFamily ( font . value ) }
111+ className = "cursor-pointer text-xs"
112+ style = { { fontFamily : font . value } } >
113+ { font . label }
114+ </ DropdownMenuItem >
115+ ) ) }
116+ </ DropdownMenuContent >
117+ </ DropdownMenu >
118118 </ div >
119+ </ div >
120+ </ div >
119121
120- < Separator className = "my-4" />
121-
122- { /* Style Controls */ }
123- < div className = "space-y-3" >
124- < Label className = "text-xs font-medium" > Style</ Label >
125-
126- { /* Text Alignment */ }
127- < div className = "space-y-2" >
128- < Label className = "text-xs text-muted-foreground" > Alignment</ Label >
129- < div className = "flex rounded-md border border-border overflow-hidden" >
130- { (
131- [
132- { value : "left" , icon : AlignLeft , label : "Left" } ,
133- { value : "center" , icon : AlignCenter , label : "Center" } ,
134- { value : "right" , icon : AlignRight , label : "Right" } ,
135- ] as const
136- ) . map ( ( { value, icon : Icon , label } ) => (
137- < Button
138- key = { value }
139- variant = { textAlign === value ? "default" : "ghost" }
140- size = "sm"
141- onClick = { ( ) => setTextAlign ( value ) }
142- className = "flex-1 h-8 rounded-none border-0"
143- title = { label } >
144- < Icon className = "h-3.5 w-3.5" />
145- </ Button >
146- ) ) }
147- </ div >
148- </ div >
122+ < Separator />
123+
124+ { /* Style Controls */ }
125+ < div className = "space-y-2" >
126+ < div className = "text-[10px] font-medium text-muted-foreground uppercase tracking-wider" > Style</ div >
127+
128+ < div className = "space-y-1" >
129+ < div className = "text-[10px] text-muted-foreground" > Alignment</ div >
130+ < div className = "flex rounded border border-border/50 overflow-hidden" >
131+ { (
132+ [
133+ { value : "left" , icon : AlignLeft , label : "Left" } ,
134+ { value : "center" , icon : AlignCenter , label : "Center" } ,
135+ { value : "right" , icon : AlignRight , label : "Right" } ,
136+ ] as const
137+ ) . map ( ( { value, icon : Icon , label } ) => (
138+ < Button
139+ key = { value }
140+ variant = { textAlign === value ? "default" : "ghost" }
141+ size = "sm"
142+ onClick = { ( ) => setTextAlign ( value ) }
143+ className = "flex-1 h-7 rounded-none border-0"
144+ title = { label } >
145+ < Icon className = "h-3 w-3" />
146+ </ Button >
147+ ) ) }
148+ </ div >
149+ </ div >
149150
150- { /* Font Weight & Color */ }
151- < div className = "grid grid-cols-2 gap-3" >
152- < div className = "space-y-2" >
153- < Label className = "text-xs text-muted-foreground" > Weight</ Label >
154- < div className = "flex rounded-md border border-border overflow-hidden" >
155- { ( [ "normal" , "bold" ] as const ) . map ( ( weight ) => (
156- < Button
157- key = { weight }
158- variant = { fontWeight === weight ? "default" : "ghost" }
159- size = "sm"
160- onClick = { ( ) => setFontWeight ( weight ) }
161- className = "flex-1 h-8 rounded-none border-0 text-xs"
162- title = { weight } >
163- { weight === "normal" ? "Normal" : < Bold className = "h-3.5 w-3.5" /> }
164- </ Button >
165- ) ) }
166- </ div >
167- </ div >
168-
169- < div className = "space-y-2" >
170- < Label className = "text-xs text-muted-foreground" > Color</ Label >
171- < div className = "flex items-center gap-2" >
172- < input
173- type = "color"
174- value = { color }
175- onChange = { ( e ) => setColor ( e . target . value ) }
176- className = "w-full h-8 bg-muted/50 border border-border rounded-md cursor-pointer"
177- />
178- < Badge variant = "outline" className = "text-xs font-mono" >
179- { color . toUpperCase ( ) }
180- </ Badge >
181- </ div >
182- </ div >
151+ < div className = "grid grid-cols-2 gap-2" >
152+ < div className = "space-y-1" >
153+ < div className = "text-[10px] text-muted-foreground" > Weight</ div >
154+ < div className = "flex rounded border border-border/50 overflow-hidden" >
155+ { ( [ "normal" , "bold" ] as const ) . map ( ( weight ) => (
156+ < Button
157+ key = { weight }
158+ variant = { fontWeight === weight ? "default" : "ghost" }
159+ size = "sm"
160+ onClick = { ( ) => setFontWeight ( weight ) }
161+ className = "flex-1 h-7 rounded-none border-0 text-[10px]"
162+ title = { weight } >
163+ { weight === "normal" ? "Normal" : < Bold className = "h-3 w-3" /> }
164+ </ Button >
165+ ) ) }
183166 </ div >
184167 </ div >
185168
186- < Separator className = "my-4" />
187-
188- { /* Preview */ }
189- < div className = "space-y-2" >
190- < Label className = "text-xs font-medium" > Preview</ Label >
191- < div
192- className = "w-full h-20 bg-muted/30 border border-border rounded-md flex items-center justify-center p-3"
193- style = { {
194- textAlign : textAlign ,
195- fontSize : `${ Math . min ( fontSize * 0.3 , 18 ) } px` ,
196- fontFamily : fontFamily ,
197- fontWeight : fontWeight ,
198- color : color ,
199- } } >
200- { textContent || "Sample text" }
169+ < div className = "space-y-1" >
170+ < div className = "text-[10px] text-muted-foreground" > Color</ div >
171+ < div className = "flex items-center gap-1.5" >
172+ < input
173+ type = "color"
174+ value = { color }
175+ onChange = { ( e ) => setColor ( e . target . value ) }
176+ className = "flex-1 h-7 bg-muted/30 border border-border/50 rounded cursor-pointer"
177+ />
178+ < Badge variant = "outline" className = "text-[9px] font-mono px-1 shrink-0" >
179+ { color . toUpperCase ( ) }
180+ </ Badge >
201181 </ div >
202182 </ div >
183+ </ div >
184+ </ div >
185+
186+ < Separator />
187+
188+ { /* Preview */ }
189+ < div className = "space-y-1.5" >
190+ < div className = "text-[10px] font-medium text-muted-foreground uppercase tracking-wider" > Preview</ div >
191+ < div
192+ className = "w-full h-16 bg-muted/30 border border-border/50 rounded flex items-center justify-center p-2 overflow-hidden"
193+ style = { {
194+ textAlign : textAlign ,
195+ fontSize : `${ Math . min ( fontSize * 0.3 , 16 ) } px` ,
196+ fontFamily : fontFamily ,
197+ fontWeight : fontWeight ,
198+ color : color ,
199+ } } >
200+ { textContent || "Sample text" }
201+ </ div >
202+ </ div >
203+ </ div >
203204
204- { /* Add Button */ }
205- < Button onClick = { handleAddText } disabled = { ! textContent . trim ( ) } className = "w-full h-9" size = "sm" >
206- < Plus className = "h-3.5 w-3.5 mr-2" />
207- Add Text to Timeline
208- </ Button >
209- </ CardContent >
210- </ Card >
205+ { /* Add Button */ }
206+ < div className = "px-3 py-3 border-t border-border/50 shrink-0" >
207+ < Button onClick = { handleAddText } disabled = { ! textContent . trim ( ) } className = "w-full h-8 text-xs" size = "sm" >
208+ < Plus className = "h-3.5 w-3.5 mr-1.5" />
209+ Add Text to Timeline
210+ </ Button >
211211 </ div >
212212 </ div >
213213 ) ;
0 commit comments