Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
Svelte
at icy/tmrrpn
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120<script lang="ts"> import { diffFileName, type DiffFile, type DiffStat } from "$lib/api/diff"; import { fileStats } from "$lib/api/rawdiff"; import type { Snippet } from "svelte"; import DiffFileCard from "./DiffFileCard.svelte"; import DiffFileList from "./DiffFileList.svelte"; import DiffTopbar from "./DiffTopbar.svelte"; import { diffRowKey, toFileDiffMetadata } from "./fileDiff"; import type { DiffStyle } from "./pierre"; import { encodePathSegments } from "./urls";
interface Props { files: DiffFile[]; stat?: DiffStat; // side-by-side or stacked, persisted by the route in ?diff= diffStyle?: DiffStyle; // raw .patch/.diff targets, only present for full-hash refs downloadUrls?: { patch: string; diff: string }; // blob route prefix for the per-file "view file" links, hidden when absent blobBase?: string; // server-prerendered shadow dom per row key, only for the initial ssr prerendered?: Record<string, string>; // round/interdiff indicator slot in the topbar (pull pages) topbarCenter?: Snippet; // subscription-toggle slot at the topbar's far end (pull review panel) topbarActions?: Snippet; // review-button slot on each file header (pull pages) fileHeaderActions?: Snippet<[DiffFile]>; }
let { files, stat, diffStyle = "unified", downloadUrls, blobBase, prerendered, topbarCenter, topbarActions, fileHeaderActions }: Props = $props();
// one structured diff per text file, binary notes stay // interleaved in the original diff order const rows = $derived( files.map((file) => ({ file, name: diffFileName(file), key: diffRowKey(file), stat: { ...fileStats(file), files_changed: 1 }, fileDiff: file.is_binary ? undefined : toFileDiffMetadata(file), prerenderedHTML: file.is_binary ? undefined : prerendered?.[diffRowKey(file)], blobUrl: blobBase && file.name.new ? `${blobBase}/${encodePathSegments(file.name.new)}` : undefined })) );
// cards default to open let openStates = $state<Record<string, boolean>>({}); const isOpen = (key: string) => openStates[key] ?? true; const allOpen = $derived(rows.every((row) => isOpen(row.key))); const setAll = (open: boolean) => { openStates = Object.fromEntries(rows.map((row) => [row.key, open])); };
let filesOpen = $state(true);</script>
<div class="flex flex-col"> <DiffTopbar {stat} fileCount={files.length} {diffStyle} {downloadUrls} {filesOpen} onToggleFiles={rows.length > 0 ? () => (filesOpen = !filesOpen) : undefined} {allOpen} onSetAllOpen={setAll} center={topbarCenter} actions={topbarActions} />
<div class="flex grow gap-4"> {#if rows.length > 0 && filesOpen} <aside class="sticky top-[calc(3rem+env(safe-area-inset-top))] hidden max-h-[calc(100vh-3rem-env(safe-area-inset-top))] w-fit max-w-60 shrink-0 overflow-y-auto md:block" > <section class="mx-auto min-h-full w-full overflow-x-auto rounded-sm border border-border-default bg-background-default px-6 py-2 typography-paragraph-regular" > <DiffFileList files={rows.map((row) => ({ name: row.name }))} /> </section> </aside> {/if}
<div class="flex min-w-0 flex-1 flex-col gap-4"> {#if rows.length === 0} <div class="py-8 text-center text-foreground-muted"> <p>No differences found between the selected revisions.</p> </div> {/if} {#each rows as row (row.key)} <DiffFileCard file={row.file} name={row.name} stat={row.stat} fileDiff={row.fileDiff} prerenderedHTML={row.prerenderedHTML} {diffStyle} blobUrl={row.blobUrl} bind:open={() => isOpen(row.key), (open) => (openStates[row.key] = open)} headerActions={fileHeaderActions} /> {/each} </div> </div></div>