Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204<script lang="ts"> import FileDiff from "$icon/file-diff"; import FileCode from "$icon/file-code"; import FileDown from "$icon/file-down"; import PanelLeftClose from "$icon/panel-left-close"; import ListTree from "$icon/list-tree"; import LoaderCircle from "$icon/loader-circle"; import SquareSplitHorizontal from "$icon/square-split-horizontal"; import SquareSplitVertical from "$icon/square-split-vertical"; import FoldVertical from "$icon/fold-vertical"; import UnfoldVertical from "$icon/unfold-vertical"; import Button from "$lib/components/ui/Button.svelte"; import ButtonGroup, { segmentProps } from "$lib/components/ui/ButtonGroup.svelte"; import Card from "$lib/components/ui/Card.svelte"; import DiffFileTree from "$lib/components/repo/DiffFileTree.svelte"; import DiffStatPill from "$lib/components/repo/DiffStatPill.svelte"; import Separator from "$lib/components/ui/Separator.svelte"; import PullDiffFiles from "$lib/components/repo/pulls/PullDiffFiles.svelte"; import type { DiffStyle } from "$lib/components/repo/pierre"; import type { PullDiff, PullDiffDeps } from "$lib/api/pullDiff"; import Dropdown from "$lib/components/ui/Dropdown.svelte"; import DropdownItem from "$lib/components/ui/DropdownItem.svelte"; import repoPullsPulldiffSkeletonFixture from "$lib/bones/repo-pulls-pulldiff--skeleton-fixture.bones.json"; import Bones from "$lib/components/ui/Bones.svelte";
interface Props { deps: PullDiffDeps; // absent while loading and on an error diff?: PullDiff; error?: string; loading?: boolean; initialDiffStyle?: DiffStyle; downloadUrls?: { patch: string; diff: string }; stickyTop?: "page" | "viewport"; }
let { deps, diff, error, loading = false, initialDiffStyle = "unified", downloadUrls, stickyTop = "page" }: Props = $props();
let treeOpen = $state(true); let allOpen = $state(true); let diffStyle = $derived<DiffStyle>(initialDiffStyle);</script>
{#if loading && !diff} <Bones capture={repoPullsPulldiffSkeletonFixture} />{:else} <Card padding="none" class="flex gap-2 px-2"> <!-- file tree --> {#if treeOpen} <aside class={[ "sticky flex w-80 shrink-0 flex-col self-start", stickyTop === "viewport" ? "top-0 max-h-svh" : "top-11 max-h-[calc(100vh-3.75rem)]" ]} > <div class={[ "sticky flex min-h-14 items-center bg-background-default py-2", stickyTop === "viewport" ? "top-0" : "top-11" ]} > <Button icon={PanelLeftClose} title="Collapse file tree" onclick={() => (treeOpen = false)} variant="ghost" /> </div> <div class="min-h-0 flex-1 scrollbar-gutter-stable overflow-y-auto"> {#if diff} <DiffFileTree files={diff.files} /> {/if} </div> </aside> <Separator orientation="vertical" /> {/if} <!-- diffs --> <div class="min-w-0 flex-1"> <div class={[ "sticky z-20 flex min-h-14 items-center justify-between bg-background-default py-2", stickyTop === "viewport" ? "top-0" : "top-11" ]} > <div class="{treeOpen ? 'pl-1' : ''} flex items-center gap-3"> {#if !treeOpen} <Button title="Expand file tree" icon={ListTree} onclick={() => (treeOpen = true)} variant="ghost" /> {/if} {#if diff} <DiffStatPill stat={diff.stat} /> <span class="text-foreground-muted"> {diff.files.length} changed {diff.files.length === 1 ? "file" : "files"} {#if diff.truncated > 0} <Separator variant="dot" class="px-1" />{diff.truncated} not rendered {/if} </span> {/if} </div> <div class="flex gap-2"> <Button icon={allOpen ? FoldVertical : UnfoldVertical} title={allOpen ? "Collapse lines" : "Expand lines"} onclick={() => (allOpen = !allOpen)} variant="ghost">{allOpen ? "Collapse" : "Expand"}</Button > {#if downloadUrls} <Dropdown variant="button" buttonVariant="ghost" align="right" label="Download commit" > {#snippet trigger()} <FileDown /> Download commit {/snippet} <DropdownItem href={downloadUrls.patch as "/"} data-sveltekit-reload icon={FileCode} aria-label="As a patch file" ><span class="hidden sm:inline" aria-hidden="true" >As a patch file</span > </DropdownItem> <DropdownItem href={downloadUrls.diff as "/"} data-sveltekit-reload icon={FileDiff} aria-label="As a diff file" ><span class="hidden sm:inline" aria-hidden="true" >As a diff file</span > </DropdownItem> </Dropdown> {/if} <ButtonGroup> <Button icon={SquareSplitVertical} title="Unified diff" onclick={() => (diffStyle = "unified")} {...segmentProps(diffStyle !== "split")} > Unified </Button> <Button icon={SquareSplitHorizontal} title="Split diff" onclick={() => (diffStyle = "split")} {...segmentProps(diffStyle === "split")} > Split </Button> </ButtonGroup> </div> </div> <!-- plugs rounding gaps between the sticky toolbar and file headers --> <div class={["sticky -mb-6 h-6", stickyTop === "viewport" ? "top-7.5" : "top-18.5"]} aria-hidden="true" ></div>
{#if error} <div class="flex min-h-32 items-center justify-center rounded-sm border border-border-danger bg-background-danger-subtle p-4 typography-paragraph-regular text-foreground-danger" > <span>{error}</span> </div> {:else if diff && diff.files.length > 0} <!-- a new diff gets a fresh fill pool by teardown, so a version switch cannot show the previous version's text under a repeated file path --> {#key diff} <PullDiffFiles {deps} {diff} {diffStyle} {allOpen} {stickyTop} /> {/key} {:else if diff} <div class="flex min-h-32 items-center justify-center rounded-sm border border-border-default bg-background-info-subtle p-4 typography-paragraph-regular text-foreground-info" > <span>No change between two revisions.</span> </div> {:else} <div class="flex min-h-32 items-center justify-center text-foreground-subtle"> <LoaderCircle class="inline-flex size-4 animate-spin" aria-hidden="true" /> </div> {/if} </div> </Card>{/if}