fix: separate preview tile component

This commit is contained in:
2026-09-12 17:17:25 +05:00
parent 05165031c3
commit 35df076732
3 changed files with 124 additions and 95 deletions
+14 -42
View File
@@ -1,12 +1,13 @@
<script lang="ts">
import { toDataUrl } from "$lib/core/io";
import type { PixelImage } from "$lib/core/types";
import type { FileResult } from "$lib/registry";
import { Check, RefreshCw } from "@lucide/svelte";
import type { FileResult, ResultKind } from "$lib/registry";
import { Check } from "@lucide/svelte";
import SchemaTextResult from "./SchemaTextResult.svelte";
import PreviewTile from "./layout/PreviewTile.svelte";
interface Props {
resultKind?: "image" | "text" | "verdict" | "files";
resultKind?: ResultKind;
result: PixelImage | null;
fileResult?: FileResult | null;
textResult?: string | null;
@@ -33,20 +34,13 @@
}))
: [],
);
let parts = $derived(
resultKind === "files" && fileResult ? fileResult.files.length : undefined,
);
</script>
<figure class="tile">
<figcaption>
<span>
RESULT
{#if resultKind === "files" && fileResult}
<span class="count">{fileResult.files.length} parts</span>
{/if}
{#if running}
<RefreshCw class="rotating" size="16" />
{/if}
</span>
</figcaption>
<PreviewTile label="RESULT" viewMode={resultKind} loading={running} {parts}>
<div class="canvas" class:checker={resultKind === "image"}>
{#if resultKind === "text" && textResult}
<div class="text-result-wrap">
@@ -83,20 +77,9 @@
<span class="empty">no result yet</span>
{/if}
</div>
</figure>
</PreviewTile>
<style>
.tile figcaption {
display: flex;
align-items: center;
gap: var(--space-m);
margin-bottom: var(--space-m);
font: var(--font-size-s) var(--font-mono);
color: var(--color-text-muted);
& :global(.rotating) {
animation: rotate var(--duration-l) linear infinite;
}
}
.canvas {
display: flex;
align-items: center;
@@ -109,8 +92,10 @@
color: var(--color-text-muted);
}
.canvas img {
width: 100%;
height: 100%;
width: auto;
max-width: 100%;
height: auto;
max-height: 100vh;
object-fit: contain;
display: block;
}
@@ -124,10 +109,6 @@
.empty {
font: var(--font-size-s) var(--font-mono);
}
.count {
margin-left: var(--space-m);
color: var(--color-main);
}
.parts-grid {
display: grid;
grid-template-columns: repeat(
@@ -170,13 +151,4 @@
padding: var(--space-l);
box-sizing: border-box;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
+19 -53
View File
@@ -2,6 +2,7 @@
import { toDataUrl } from "$lib/core/io";
import type { PixelImage } from "$lib/core/types";
import type { InputMode } from "$lib/registry";
import PreviewTile from "./layout/PreviewTile.svelte";
import SchemaTextSource from "./SchemaTextSource.svelte";
interface Props {
@@ -24,61 +25,26 @@
const sourceUrl = $derived(source ? toDataUrl(source) : null);
</script>
<figure class="tile">
<figcaption><span>SOURCE</span></figcaption>
<div class="canvas" class:checker={mode === "image"}>
{#if mode === "text"}
<div class="text-source-wrap">
<SchemaTextSource
value={textSource}
disabled={running}
oninput={ontextinput ?? (() => {})}
onrender={onrendertext ?? (() => {})}
/>
</div>
{:else if mode === "image" && sourceUrl}
<img src={sourceUrl} alt="source" />
{:else if mode === "image"}
<span class="empty">choose an image</span>
{:else}
<span class="empty">no source — configure the parameters</span>
{/if}
</div>
</figure>
<PreviewTile label="SOURCE" viewMode={mode}>
{#if mode === "text"}
<div class="text-source-wrap">
<SchemaTextSource
value={textSource}
disabled={running}
oninput={ontextinput ?? (() => {})}
onrender={onrendertext ?? (() => {})}
/>
</div>
{:else if mode === "image" && sourceUrl}
<img src={sourceUrl} alt="source" />
{:else if mode === "image"}
<span class="empty">choose an image</span>
{:else}
<span class="empty">no source — configure the parameters</span>
{/if}
</PreviewTile>
<style>
.tile figcaption {
display: flex;
align-items: center;
gap: var(--space-m);
margin-bottom: var(--space-m);
font: var(--font-size-s) var(--font-mono);
color: var(--color-text-muted);
}
.canvas {
display: flex;
align-items: center;
justify-content: center;
min-height: clamp(var(--space-brand), 30vh, 60vh);
border: var(--size-border) solid var(--color-border);
border-radius: var(--radius-s);
overflow: hidden;
background: var(--color-background-muted);
color: var(--color-text-muted);
}
.canvas img {
width: 100%;
height: 100%;
object-fit: contain;
display: block;
}
.canvas.checker {
background: repeating-conic-gradient(
var(--color-checker-main) 0 25%,
var(--color-checker-alt) 0 50%
)
50% / 28px 28px;
}
.empty {
font: var(--font-size-s) var(--font-mono);
}
@@ -0,0 +1,91 @@
<script lang="ts">
import type { InputMode, ResultKind } from "$lib/registry";
import { RefreshCw } from "@lucide/svelte";
import type { Snippet } from "svelte";
interface Props {
label: string;
viewMode: InputMode | ResultKind;
children: Snippet;
loading?: boolean;
parts?: number;
}
let {
label,
viewMode: mode,
children,
loading = false,
parts = undefined,
}: Props = $props();
// TODO: make canvas aspect ratio auto, from 16:9 to 9:16 max
</script>
<figure class="tile">
<figcaption>
<span>
{label}
{#if parts !== undefined}
<span class="count">{parts} parts</span>
{/if}
{#if loading}
<RefreshCw class="rotating" size="12" />
{/if}
</span>
</figcaption>
<div class="canvas" class:checker={mode === "image"}>
{@render children()}
</div>
</figure>
<style>
.tile figcaption {
display: flex;
align-items: center;
gap: var(--space-m);
margin-bottom: var(--space-m);
font: var(--font-size-s) var(--font-mono);
color: var(--color-text-muted);
& :global(.rotating) {
animation: rotate var(--duration-l) linear infinite;
}
}
.count {
margin-left: var(--space-m);
color: var(--color-main);
}
.canvas {
display: flex;
align-items: center;
justify-content: center;
min-height: clamp(var(--space-brand), 30vh, 60vh);
border: var(--size-border) solid var(--color-border);
border-radius: var(--radius-s);
overflow: hidden;
background: var(--color-background-muted);
color: var(--color-text-muted);
}
.canvas :global(img) {
width: auto;
max-width: 100%;
height: auto;
max-height: 100vh;
object-fit: contain;
display: block;
}
.canvas.checker {
background: repeating-conic-gradient(
var(--color-checker-main) 0 25%,
var(--color-checker-alt) 0 50%
)
50% / 28px 28px;
}
@keyframes rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>