Skip to content

Commit dffcf49

Browse files
webui: fullscreen HTML preview dialog using bits-ui
1 parent a6c2c52 commit dffcf49

File tree

1 file changed

+62
-23
lines changed

1 file changed

+62
-23
lines changed
Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script lang="ts">
2-
import * as Dialog from '$lib/components/ui/dialog';
2+
import { Dialog as DialogPrimitive } from 'bits-ui';
3+
import XIcon from '@lucide/svelte/icons/x';
34
45
interface Props {
56
open: boolean;
@@ -13,12 +14,12 @@
1314
let iframeRef = $state<HTMLIFrameElement | null>(null);
1415
1516
$effect(() => {
16-
if (iframeRef) {
17-
if (open) {
18-
iframeRef.srcdoc = code;
19-
} else {
20-
iframeRef.srcdoc = '';
21-
}
17+
if (!iframeRef) return;
18+
19+
if (open) {
20+
iframeRef.srcdoc = code;
21+
} else {
22+
iframeRef.srcdoc = '';
2223
}
2324
});
2425
@@ -28,27 +29,65 @@
2829
}
2930
</script>
3031

31-
<Dialog.Root {open} onOpenChange={handleOpenChange}>
32-
<Dialog.Content class="max-w-[calc(100%-1rem)] sm:max-w-4xl md:max-w-5xl">
33-
<Dialog.Header>
34-
<Dialog.Title>HTML Preview</Dialog.Title>
35-
</Dialog.Header>
32+
<DialogPrimitive.Root {open} onOpenChange={handleOpenChange}>
33+
<DialogPrimitive.Portal>
34+
<DialogPrimitive.Overlay class="code-preview-overlay" />
3635

37-
<div class="preview-container mt-2">
36+
<DialogPrimitive.Content class="code-preview-content">
3837
<iframe
3938
bind:this={iframeRef}
4039
title={`Preview ${language}`}
4140
sandbox="allow-scripts"
42-
class="h-[70vh] w-full rounded-md border border-border/40 bg-background"
41+
class="code-preview-iframe"
4342
></iframe>
44-
</div>
45-
</Dialog.Content>
46-
</Dialog.Root>
47-
48-
<style>
49-
.preview-container {
50-
display: flex;
51-
flex-direction: column;
52-
gap: 0.75rem;
43+
44+
<DialogPrimitive.Close
45+
class="code-preview-close absolute top-4 right-6 rounded-xs text-white opacity-70 mix-blend-difference ring-offset-background transition-opacity hover:opacity-100 focus:ring-2 focus:ring-ring focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-8"
46+
aria-label="Close preview"
47+
>
48+
<XIcon />
49+
<span class="sr-only">Close preview</span>
50+
</DialogPrimitive.Close>
51+
</DialogPrimitive.Content>
52+
</DialogPrimitive.Portal>
53+
</DialogPrimitive.Root>
54+
55+
<style lang="postcss">
56+
:global(.code-preview-overlay) {
57+
position: fixed;
58+
inset: 0;
59+
background-color: transparent;
60+
z-index: 100000;
61+
}
62+
63+
:global(.code-preview-content) {
64+
position: fixed;
65+
inset: 0;
66+
top: 0 !important;
67+
left: 0 !important;
68+
width: 100dvw;
69+
height: 100dvh;
70+
margin: 0;
71+
padding: 0;
72+
border: none;
73+
border-radius: 0;
74+
background-color: transparent;
75+
box-shadow: none;
76+
display: block;
77+
overflow: hidden;
78+
transform: none !important;
79+
z-index: 100001;
80+
}
81+
82+
:global(.code-preview-iframe) {
83+
display: block;
84+
width: 100dvw;
85+
height: 100dvh;
86+
border: 0;
87+
}
88+
89+
:global(.code-preview-close) {
90+
position: absolute;
91+
z-index: 100002;
5392
}
5493
</style>

0 commit comments

Comments
 (0)