Images in chat and descriptions open large on click
The channel description preview stays open underneath while an image from it is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -49,8 +49,20 @@
|
||||
// Short grace period, so the pointer can move from the row into the preview
|
||||
function leaveRow() {
|
||||
clearTimeout(hoverTimer);
|
||||
hoverTimer = setTimeout(() => (preview = null), 250);
|
||||
// An image opened from the preview covers it; the preview stays underneath
|
||||
hoverTimer = setTimeout(() => { if (!ui.image) preview = null; }, 250);
|
||||
}
|
||||
// Back from the image: the preview stays while the pointer is on it, and goes when it is not
|
||||
let popEl = $state<HTMLElement>();
|
||||
let hadImage = false;
|
||||
$effect(() => {
|
||||
const open = !!ui.image;
|
||||
if (hadImage && !open && preview && !popEl?.matches(':hover')) {
|
||||
clearTimeout(hoverTimer);
|
||||
hoverTimer = setTimeout(() => { if (!popEl?.matches(':hover')) preview = null; }, 1500);
|
||||
}
|
||||
hadImage = open;
|
||||
});
|
||||
function showDescription() {
|
||||
clearTimeout(hoverTimer);
|
||||
preview = null;
|
||||
@@ -131,7 +143,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
{#if preview}
|
||||
<div class="desc-pop" role="tooltip" style:left="{preview.x}px" style:top="{preview.y}px"
|
||||
<div class="desc-pop" role="tooltip" bind:this={popEl} style:left="{preview.x}px" style:top="{preview.y}px"
|
||||
onmouseenter={() => clearTimeout(hoverTimer)} onmouseleave={leaveRow}>
|
||||
<strong>{channel.name || 'Root'}</strong>
|
||||
{#if descriptionHtml}<div class="html">{@html descriptionHtml}</div>{:else}<p>Loading description...</p>{/if}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<script lang="ts">
|
||||
import { ui } from '../lib/ui.svelte.ts';
|
||||
|
||||
// An image from the chat or a description, as large as the window allows. A click anywhere
|
||||
// or Escape closes it.
|
||||
const src = $derived(ui.image);
|
||||
const remote = $derived(!!src && /^https?:/i.test(src));
|
||||
</script>
|
||||
|
||||
<svelte:window onkeydown={e => { if (src && e.key === 'Escape') { e.stopPropagation(); ui.image = null; } }} />
|
||||
|
||||
{#if src}
|
||||
<div class="viewer" role="dialog" aria-modal="true" aria-label="Image">
|
||||
<button class="shade" aria-label="Close image" onclick={() => (ui.image = null)}></button>
|
||||
<img {src} alt="" />
|
||||
{#if remote}<a class="open" href={src} target="_blank" rel="noopener noreferrer">Open original</a>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.viewer { position: fixed; inset: 0; z-index: 300; display: flex; align-items: center; justify-content: center; padding: 16px; }
|
||||
.shade { position: absolute; inset: 0; background: rgb(0 0 0 / 0.85); cursor: zoom-out; }
|
||||
img { position: relative; max-width: 100%; max-height: 100%; object-fit: contain; pointer-events: none; box-shadow: 0 16px 48px rgb(0 0 0 / 0.6); }
|
||||
.open { position: absolute; bottom: 14px; left: 50%; transform: translateX(-50%); padding: 4px 10px; font-size: 13px; color: #fff; background: rgb(0 0 0 / 0.7); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user