- Add matrix-js-sdk, marked, highlight.js, twemoji, @tanstack/svelte-virtual deps - Copy Matrix core layer: /matrix/, /stores/matrix.ts, /cache/, /services/ - Copy Matrix components: matrix/, message/, chat-layout/, chat-settings/ - Copy UI components: EmojiPicker, Twemoji, ImagePreviewModal, VirtualList - Copy utils: emojiData, twemoji, twemojiGlobal - Replace lucide-svelte with Material Symbols in SyncRecoveryBanner - Extend Avatar with xs size and status indicator prop - Fix ui.ts store conflict: re-export toasts from toast.svelte.ts - Add migration 020_matrix_credentials for storing Matrix tokens per user/org - Add /api/matrix-credentials endpoint (GET/POST/DELETE) - Create [orgSlug]/chat page with Matrix login form + full chat UI - Add Chat to sidebar navigation
64 lines
1.7 KiB
Svelte
64 lines
1.7 KiB
Svelte
<script lang="ts">
|
|
interface Props {
|
|
src: string;
|
|
alt?: string;
|
|
onClose: () => void;
|
|
}
|
|
|
|
let { src, alt = "", onClose }: Props = $props();
|
|
|
|
function handleKeyDown(e: KeyboardEvent) {
|
|
if (e.key === "Escape") {
|
|
onClose();
|
|
}
|
|
}
|
|
|
|
function handleBackdropClick(e: MouseEvent) {
|
|
if (e.target === e.currentTarget) {
|
|
onClose();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:window onkeydown={handleKeyDown} />
|
|
|
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
<div
|
|
class="fixed inset-0 z-[200] flex items-center justify-center bg-black/90 backdrop-blur-sm"
|
|
onclick={handleBackdropClick}
|
|
>
|
|
<!-- Close button -->
|
|
<button
|
|
class="absolute top-4 right-4 w-10 h-10 flex items-center justify-center rounded-full bg-light/10 hover:bg-light/20 transition-colors text-light"
|
|
onclick={onClose}
|
|
>
|
|
<svg class="w-6 h-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M18 6L6 18M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
|
|
<!-- Image container -->
|
|
<div class="max-w-[90vw] max-h-[90vh] flex items-center justify-center">
|
|
<img
|
|
{src}
|
|
{alt}
|
|
class="max-w-full max-h-[90vh] object-contain rounded-lg shadow-2xl"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Open in new tab button -->
|
|
<a
|
|
href={src}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
class="absolute bottom-4 right-4 px-4 py-2 rounded-lg bg-light/10 hover:bg-light/20 transition-colors text-light text-sm flex items-center gap-2"
|
|
>
|
|
<svg class="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
|
|
<polyline points="15 3 21 3 21 9" />
|
|
<line x1="10" y1="14" x2="21" y2="3" />
|
|
</svg>
|
|
Open Original
|
|
</a>
|
|
</div>
|