replies timeline only, appview-less bluesky client
at main 2.6 kB view raw
1<script lang="ts"> 2 import type { Snippet } from 'svelte'; 3 import { portal } from 'svelte-portal'; 4 5 interface Props { 6 isOpen: boolean; 7 onClose?: () => void; 8 title: string; 9 width?: string; 10 height?: string; 11 padding?: string; 12 showHeaderDivider?: boolean; 13 headerActions?: Snippet; 14 children: Snippet; 15 footer?: Snippet; 16 } 17 18 let { 19 isOpen = $bindable(false), 20 onClose = () => (isOpen = false), 21 title, 22 width = 'w-full max-w-md', 23 height = 'auto', 24 padding = 'p-4', 25 showHeaderDivider = false, 26 headerActions, 27 children, 28 footer 29 }: Props = $props(); 30 31 const handleKeydown = (event: KeyboardEvent) => { 32 if (event.key === 'Escape') onClose(); 33 }; 34 35 $effect(() => { 36 document.body.style.overflow = isOpen ? 'hidden' : 'auto'; 37 }); 38</script> 39 40{#if isOpen} 41 <div 42 use:portal={'#app-root'} 43 class="fixed inset-0 z-50 flex items-center justify-center bg-(--nucleus-bg)/80 backdrop-blur-sm" 44 onclick={onClose} 45 onkeydown={handleKeydown} 46 role="button" 47 tabindex="-1" 48 > 49 <!-- svelte-ignore a11y_interactive_supports_focus --> 50 <!-- svelte-ignore a11y_click_events_have_key_events --> 51 <div 52 class=" 53 flex {height === 'auto' ? '' : `h-[${height}]`} {width} shrink animate-fade-in-scale flex-col 54 rounded-sm border-2 border-(--nucleus-accent) bg-(--nucleus-bg) shadow-2xl transition-all 55 " 56 style={height !== 'auto' ? `height: ${height}` : ''} 57 onclick={(e) => e.stopPropagation()} 58 role="dialog" 59 > 60 <!-- Header --> 61 <div 62 class="flex items-center gap-4 {showHeaderDivider 63 ? 'border-b-2 border-(--nucleus-accent)/20' 64 : ''} {padding}" 65 > 66 <div> 67 <h2 class="text-2xl font-bold">{title}</h2> 68 <div class="mt-2 flex gap-2"> 69 <div class="h-1 w-8 rounded-full bg-(--nucleus-accent)"></div> 70 <div class="h-1 w-9.5 rounded-full bg-(--nucleus-accent2)"></div> 71 </div> 72 </div> 73 74 {#if headerActions} 75 {@render headerActions()} 76 {/if} 77 78 <div class="grow"></div> 79 80 <!-- svelte-ignore a11y_consider_explicit_label --> 81 <button 82 onclick={onClose} 83 class="rounded-xl p-2 text-(--nucleus-fg)/40 transition-all hover:scale-110 hover:text-(--nucleus-fg)" 84 > 85 <svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"> 86 <path 87 stroke-linecap="round" 88 stroke-linejoin="round" 89 stroke-width="2.5" 90 d="M6 18L18 6M6 6l12 12" 91 /> 92 </svg> 93 </button> 94 </div> 95 96 <!-- Content --> 97 <div class="{height === 'auto' ? '' : 'flex-1 overflow-y-auto'} {padding}"> 98 {@render children()} 99 </div> 100 101 <!-- Footer --> 102 {#if footer} 103 {@render footer()} 104 {/if} 105 </div> 106 </div> 107{/if}