1- import React , { useState , useEffect } from "react" ;
1+ import React from "react" ;
22import { HTMLPreview } from "types" ;
33import {
44 Maximize2 ,
@@ -7,57 +7,49 @@ import {
77 Smartphone ,
88 Circle ,
99 Ruler ,
10- MonitorIcon ,
10+ Monitor ,
1111} from "lucide-react" ;
12+ import { cn } from "../lib/utils" ;
1213
14+ // Update the component props to receive state from parent
1315const Preview : React . FC < {
1416 htmlPreview : HTMLPreview ;
17+ expanded : boolean ;
18+ setExpanded : React . Dispatch < React . SetStateAction < boolean > > ;
19+ viewMode : "desktop" | "mobile" | "precision" ;
20+ setViewMode : React . Dispatch <
21+ React . SetStateAction < "desktop" | "mobile" | "precision" >
22+ > ;
23+ bgColor : "white" | "black" ;
24+ setBgColor : React . Dispatch < React . SetStateAction < "white" | "black" > > ;
1525} > = ( props ) => {
16- const [ expanded , setExpanded ] = useState ( false ) ;
17- const [ viewMode , setViewMode ] = useState < "desktop" | "mobile" | "precision" > (
18- "desktop" ,
19- ) ;
20- const [ animationClass , setAnimationClass ] = useState < string > ( "" ) ;
21- const [ bgColor , setBgColor ] = useState < "white" | "black" > ( "white" ) ;
26+ const {
27+ htmlPreview,
28+ expanded,
29+ setExpanded,
30+ viewMode,
31+ setViewMode,
32+ bgColor,
33+ setBgColor,
34+ } = props ;
2235
2336 // Define consistent dimensions regardless of mode
2437 const containerWidth = expanded ? 320 : 240 ;
2538 const containerHeight = expanded ? 180 : 120 ;
2639
40+ // Calculate scale factor first to use in content width calculation
41+ const scaleFactor = Math . min (
42+ containerWidth / htmlPreview . size . width ,
43+ containerHeight / htmlPreview . size . height ,
44+ ) ;
45+
2746 // Calculate content dimensions based on view mode
2847 const contentWidth =
2948 viewMode === "desktop"
3049 ? containerWidth
3150 : viewMode === "mobile"
3251 ? Math . floor ( containerWidth * 0.4 ) // Narrower for mobile
33- : containerWidth ; // For precision, use container width for the outer frame
34-
35- const scaleFactor = Math . min (
36- containerWidth / props . htmlPreview . size . width ,
37- containerHeight / props . htmlPreview . size . height ,
38- ) ;
39-
40- // Add animation when changing view mode
41- useEffect ( ( ) => {
42- if ( viewMode === "desktop" ) {
43- setAnimationClass ( "animate-slide-in-left" ) ;
44- } else if ( viewMode === "mobile" ) {
45- setAnimationClass ( "animate-slide-in-right" ) ;
46- } else {
47- setAnimationClass ( "animate-fade-in" ) ;
48- }
49- const timer = setTimeout ( ( ) => setAnimationClass ( "" ) , 300 ) ; // Remove animation class after it completes
50- return ( ) => clearTimeout ( timer ) ;
51- } , [ viewMode ] ) ;
52-
53- // Add animation when changing size
54- useEffect ( ( ) => {
55- const timer = setTimeout ( ( ) => setAnimationClass ( "animate-scale-in" ) , 50 ) ;
56- return ( ) => {
57- clearTimeout ( timer ) ;
58- setAnimationClass ( "" ) ;
59- } ;
60- } , [ expanded ] ) ;
52+ : htmlPreview . size . width * scaleFactor ; // For precision, use scaled original width
6153
6254 return (
6355 < div className = "flex flex-col w-full bg-white dark:bg-neutral-800 rounded-lg shadow-sm border border-neutral-200 dark:border-neutral-700" >
@@ -69,21 +61,18 @@ const Preview: React.FC<{
6961 </ h3 >
7062 < div className = "flex items-center gap-1" >
7163 { /* Background Color Toggle - Only show in desktop and mobile modes */ }
72- { viewMode !== "precision" && (
73- < button
74- onClick = { ( ) =>
75- setBgColor ( bgColor === "white" ? "black" : "white" )
76- }
77- className = "p-1.5 mr-1 rounded hover:bg-neutral-100 dark:hover:bg-neutral-700 text-neutral-500 dark:text-neutral-400 transition-colors"
78- aria-label = { `Switch the preview to ${ bgColor === "white" ? "black" : "white" } background.\nUseful to avoid black text on black background.` }
79- title = { `Switch the preview to ${ bgColor === "white" ? "black" : "white" } background.\nUseful to avoid black text on black background.` }
80- >
81- < Circle size = { 14 } fill = { bgColor } className = "stroke-current" />
82- </ button >
83- ) }
64+
65+ < button
66+ onClick = { ( ) => setBgColor ( bgColor === "white" ? "black" : "white" ) }
67+ className = "p-1.5 mr-1 rounded hover:bg-neutral-100 dark:hover:bg-neutral-700 text-neutral-500 dark:text-neutral-400 transition-colors"
68+ aria-label = { `Switch the preview to ${ bgColor === "white" ? "black" : "white" } background.\nUseful to avoid black text on black background.` }
69+ title = { `Switch the preview to ${ bgColor === "white" ? "black" : "white" } background.\nUseful to avoid black text on black background.` }
70+ >
71+ < Circle size = { 14 } fill = { bgColor } className = "stroke-current" />
72+ </ button >
8473
8574 { /* View Mode Toggle */ }
86- < div className = "mr-1 flex bg-neutral-100 dark:bg-neutral-700 rounded-md p-0.5" >
75+ { /* <div className="mr-1 flex bg-neutral-100 dark:bg-neutral-700 rounded-md p-0.5">
8776 <button
8877 onClick={() => setViewMode("desktop")}
8978 className={`p-1 rounded text-xs ${
@@ -94,7 +83,7 @@ const Preview: React.FC<{
9483 aria-label="Desktop view"
9584 title="Desktop view"
9685 >
97- < MonitorSmartphone size = { 14 } />
86+ <Monitor size={14} />
9887 </button>
9988 <button
10089 onClick={() => setViewMode("mobile")}
@@ -120,7 +109,7 @@ const Preview: React.FC<{
120109 >
121110 <Ruler size={14} />
122111 </button>
123- </ div >
112+ </div> */ }
124113
125114 { /* Expand/Collapse Button */ }
126115 < button
@@ -147,31 +136,30 @@ const Preview: React.FC<{
147136 >
148137 { /* Inner content positioned based on view mode */ }
149138 < div
150- className = { `absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 ${ animationClass } ` }
139+ className = { `absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2` }
151140 style = { {
152141 width : contentWidth ,
153142 height :
154143 viewMode === "mobile"
155144 ? Math . min ( containerHeight * 0.9 , containerHeight )
156- : containerHeight , // Use full container height for both desktop and precision
145+ : viewMode === "precision"
146+ ? htmlPreview . size . height * scaleFactor // Use scaled height for precision
147+ : containerHeight ,
157148 transition : "width 0.3s ease, height 0.3s ease" ,
158149 } }
159150 >
160151 { /* Device frame - no background for precision mode */ }
161152 < div
162- className = { `w-full h-full flex justify-center items-center overflow-hidden ${
163- viewMode === "precision"
164- ? "" // No background in precision mode
165- : bgColor === "white"
166- ? "bg-white"
167- : "bg-black"
168- } ${
153+ className = { cn (
154+ "w-full h-full flex justify-center items-center overflow-hidden" ,
155+ bgColor === "white" ? "bg-white" : "bg-black" ,
169156 viewMode === "desktop"
170157 ? "border border-neutral-300 dark:border-neutral-600 rounded shadow-sm"
171158 : viewMode === "mobile"
172159 ? "border-2 border-neutral-400 dark:border-neutral-500 rounded-xl shadow-sm"
173- : "border border-indigo-400 dark:border-indigo-500 rounded shadow-sm" // Precision mode uses indigo border with rounded corners
174- } transition-all duration-300 ease-in-out`}
160+ : "border border-indigo-400 dark:border-indigo-500 rounded shadow-sm" ,
161+ `transition-all duration-300 ease-in-out` ,
162+ ) }
175163 >
176164 { /* Content */ }
177165 < div className = "w-full h-full flex justify-center items-center" >
@@ -180,23 +168,23 @@ const Preview: React.FC<{
180168 zoom : scaleFactor ,
181169 width :
182170 viewMode === "precision"
183- ? props . htmlPreview . size . width
171+ ? htmlPreview . size . width
184172 : "100%" ,
185173 height :
186174 viewMode === "precision"
187- ? props . htmlPreview . size . height
175+ ? htmlPreview . size . height
188176 : "100%" ,
189177 transformOrigin : "center" ,
190178 maxWidth : "100%" ,
191179 maxHeight : "100%" ,
192180 aspectRatio :
193181 viewMode === "precision"
194- ? `${ props . htmlPreview . size . width } / ${ props . htmlPreview . size . height } `
182+ ? `${ htmlPreview . size . width } / ${ htmlPreview . size . height } `
195183 : undefined ,
196184 transition : "all 0.3s ease" ,
197185 } }
198186 dangerouslySetInnerHTML = { {
199- __html : props . htmlPreview . content ,
187+ __html : htmlPreview . content ,
200188 } }
201189 />
202190 </ div >
@@ -208,10 +196,10 @@ const Preview: React.FC<{
208196 { /* Footer with size info */ }
209197 < div className = "px-3 py-1.5 text-xs text-neutral-500 dark:text-neutral-400 flex items-center justify-between border-t border-neutral-200 dark:border-neutral-700" >
210198 < span >
211- { props . htmlPreview . size . width . toFixed ( 0 ) } ×
212- { props . htmlPreview . size . height . toFixed ( 0 ) } px
199+ { htmlPreview . size . width . toFixed ( 0 ) } ×
200+ { htmlPreview . size . height . toFixed ( 0 ) } px
213201 </ span >
214- < div className = "flex items-center gap-1.5" >
202+ { /* <div className="flex items-center gap-1.5">
215203 {viewMode === "mobile" ? (
216204 <span className="flex items-center gap-1">
217205 <Smartphone size={10} />
@@ -224,11 +212,11 @@ const Preview: React.FC<{
224212 </span>
225213 ) : (
226214 <span className="flex items-center gap-1">
227- < MonitorIcon size = { 10 } />
215+ <Monitor size={10} />
228216 <span>Desktop view</span>
229217 </span>
230218 )}
231- </ div >
219+ </div> */ }
232220 </ div >
233221 </ div >
234222 ) ;
0 commit comments