11import { Button } from "@/components/Button" ;
22import { ResizablePanel } from "@/components/Resizable" ;
3+ import { useTheme } from "@/contexts/theme" ;
34import {
45 type Diagnostic ,
56 type InternalDiagnostic ,
@@ -10,7 +11,8 @@ import { useDebouncedValue } from "@/hooks/debounce";
1011import { useStore } from "@/store" ;
1112import { cn } from "@/utils/cn" ;
1213import { ActivityIcon , ExternalLinkIcon , LoaderIcon } from "lucide-react" ;
13- import { type FC , useEffect , useState } from "react" ;
14+ import { AnimatePresence , motion } from "motion/react" ;
15+ import { type FC , useEffect , useMemo , useState } from "react" ;
1416
1517export const Preview : FC = ( ) => {
1618 const $wasmState = useStore ( ( state ) => state . wasmState ) ;
@@ -87,9 +89,23 @@ export const Preview: FC = () => {
8789 ) }
8890 >
8991 < div className = "flex w-full items-center justify-between" >
90- < p className = "font-semibold text-3xl text-content-primary" >
91- Parameters
92- </ p >
92+ < div className = "flex items-center justify-center gap-4" >
93+ < p className = "font-semibold text-3xl text-content-primary" >
94+ Parameters
95+ </ p >
96+
97+ < AnimatePresence >
98+ { isDebouncing && $wasmState === "loaded" ? (
99+ < motion . div
100+ initial = { { opacity : 0 , scale : 0.75 } }
101+ animate = { { opacity : 1 , scale : 1 } }
102+ exit = { { opacity : 0 , scale : 0.75 } }
103+ >
104+ < LoaderIcon className = "animate-spin text-content-primary" />
105+ </ motion . div >
106+ ) : null }
107+ </ AnimatePresence >
108+ </ div >
93109 < Button variant = "destructive" > Reset form</ Button >
94110 </ div >
95111
@@ -98,9 +114,6 @@ export const Preview: FC = () => {
98114 "flex h-full w-full items-center justify-center overflow-x-clip rounded-xl border p-4" ,
99115 output && "block overflow-y-scroll" ,
100116 ) }
101- style = { {
102- opacity : isDebouncing && $wasmState === "loaded" ? 0.5 : 1 ,
103- } }
104117 >
105118 { output ? (
106119 < div className = "flex flex-col gap-4" >
@@ -183,60 +196,75 @@ const ErrorPane = () => {
183196 const $errors = useStore ( ( state ) => state . errors ) ;
184197 const $toggleShowError = useStore ( ( state ) => state . toggleShowError ) ;
185198
186- if ( $errors . diagnostics . length === 0 ) {
187- return null ;
188- }
199+ const hasErrors = useMemo ( ( ) => $errors . diagnostics . length > 0 , [ $errors ] ) ;
189200
190201 return (
191202 < >
192- { /*
193- * biome-ignore lint/a11y/useKeyWithClickEvents: key events don't seem to
194- * work for divs, and I'm otherwise not sure how to make this element
195- * more accesible. But I think it's fine since the functionality is able to
196- * be used with the button.
197- */ }
198- < div
199- aria-hidden = { true }
200- className = { cn (
201- "absolute top-0 left-0 hidden h-full w-full transition-all" ,
202- $errors . show && "block cursor-pointer bg-black/20 dark:bg-black/50" ,
203- ) }
204- onClick = { ( ) => {
205- $toggleShowError ( false ) ;
206- } }
207- >
208- { /* OVERLAY */ }
209- </ div >
203+ < AnimatePresence propagate = { true } >
204+ { $errors . show && hasErrors ? (
205+ // lint/a11y/useKeyWithClickEvents: key events don't seem to
206+ // work for divs, and I'm otherwise not sure how to make this element
207+ // more accesible. But I think it's fine since the functionality is able to
208+ // be used with the button below.
209+ < motion . div
210+ initial = { { opacity : 0 } }
211+ animate = { { opacity : 1 } }
212+ exit = { { opacity : 0 } }
213+ aria-hidden = { true }
214+ className = "absolute top-0 left-0 h-full w-full cursor-pointer bg-black/10 dark:bg-black/50"
215+ onClick = { ( ) => {
216+ $toggleShowError ( false ) ;
217+ } }
218+ >
219+ { /* OVERLAY */ }
220+ </ motion . div >
221+ ) : null }
222+ </ AnimatePresence >
210223
211- < div
212- role = "alertdialog"
213- className = { cn (
214- "absolute bottom-0 left-0 flex max-h-[60%] w-full flex-col justify-start" ,
215- $errors . show && "h-auto" ,
216- ) }
217- >
218- < button
219- className = "flex h-4 min-h-4 w-full items-center justify-center rounded-t-xl bg-border-destructive"
220- onClick = { ( ) => $toggleShowError ( ) }
221- aria-label = { $errors . show ? "Hide error dialog" : "Show error dialog" }
222- >
223- < div className = "h-0.5 w-2/3 max-w-32 rounded-full bg-white/40" > </ div >
224- </ button >
224+ < AnimatePresence propagate = { true } >
225+ { hasErrors ? (
226+ < motion . div
227+ role = "alertdialog"
228+ transition = { {
229+ when : "afterChildren" ,
230+ } }
231+ exit = { { opacity : 0 } }
232+ className = { cn (
233+ "absolute bottom-0 left-0 flex max-h-[60%] w-full flex-col justify-start" ,
234+ $errors . show && "h-auto" ,
235+ ) }
236+ >
237+ < motion . button
238+ className = "flex h-4 min-h-4 w-full items-center justify-center rounded-t-xl bg-border-destructive"
239+ onClick = { ( ) => $toggleShowError ( ) }
240+ aria-label = {
241+ $errors . show ? "Hide error dialog" : "Show error dialog"
242+ }
243+ >
244+ < div className = "h-0.5 w-2/3 max-w-32 rounded-full bg-white/40" > </ div >
245+ </ motion . button >
225246
226- < div
227- aria-hidden = { ! $errors . show }
228- className = { cn (
229- "flex flex-col gap-6 overflow-y-scroll bg-surface-secondary p-6" ,
230- ! $errors . show && "pointer-events-none h-0 p-0" ,
231- ) }
232- >
233- < div className = "flex w-full flex-col gap-3" >
234- { $errors . diagnostics . map ( ( diagnostic , index ) => (
235- < ErrorBlock diagnostic = { diagnostic } key = { index } />
236- ) ) }
237- </ div >
238- </ div >
239- </ div >
247+ < AnimatePresence propagate = { true } >
248+ { $errors . show ? (
249+ < motion . div
250+ initial = { { height : 0 } }
251+ animate = { {
252+ height : "auto" ,
253+ } }
254+ exit = { { height : 0 } }
255+ className = "flex flex-col gap-6 overflow-y-scroll bg-surface-secondary"
256+ >
257+ < div className = "flex w-full flex-col gap-3 p-6" >
258+ { $errors . diagnostics . map ( ( diagnostic , index ) => (
259+ < ErrorBlock diagnostic = { diagnostic } key = { index } />
260+ ) ) }
261+ </ div >
262+ </ motion . div >
263+ ) : null }
264+ </ AnimatePresence >
265+ </ motion . div >
266+ ) : null }
267+ </ AnimatePresence >
240268 </ >
241269 ) ;
242270} ;
0 commit comments