Something went wrong. Try again.
Monorepo for Tangled
Something went wrong. Try again.
Svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222<script lang="ts"> import CodeXml from "$icon/code-xml"; import Download from "$icon/download"; import ExternalLink from "$icon/external-link"; import Eye from "$icon/eye"; import History from "$icon/history"; import type { ResolvedPathname } from "$app/types"; import { hasRenderedView, hasTextView, type BlobKind, type BlobViewMode } from "$lib/api/blob"; import Button from "$lib/components/ui/Button.svelte"; import ButtonGroup, { segmentProps } from "$lib/components/ui/ButtonGroup.svelte"; import Checkbox from "$lib/components/ui/Checkbox.svelte"; import ColorBall from "$lib/components/ui/ColorBall.svelte"; import CopyButton from "$lib/components/ui/CopyButton.svelte"; import Separator from "$lib/components/ui/Separator.svelte"; import { LANGUAGE_COLORS, LANGUAGE_COLOR_FALLBACK } from "$lib/components/repo/languageColors"; import FilePathChip from "$lib/components/repo/FilePathChip.svelte"; import RefChip from "$lib/components/repo/RefChip.svelte"; import RepoCrumbs from "$lib/components/repo/RepoCrumbs.svelte"; import { baseName } from "$lib/components/repo/urls";
interface Props { path: string; repo?: { ownerHandle: string; repoName: string; ref: string } | null; rawHref: ResolvedPathname; historyHref?: ResolvedPathname | null; kind: BlobKind; // enry language name. the blob xrpc does not expose one yet language?: string | null; sizeLabel?: string | null; lines?: number | null; timeLabel?: string | null; view?: BlobViewMode; wrap?: boolean; showWrap?: boolean; showBlame?: boolean; blame?: boolean; blameLoading?: boolean; blameError?: string | null; copyText?: string | null; }
let { path, repo = null, rawHref, historyHref = null, kind, language = null, sizeLabel = null, lines = null, timeLabel = null, view = $bindable("code"), wrap = $bindable(false), showWrap = false, showBlame = false, blame = $bindable(false), blameLoading = false, blameError = null, copyText = null }: Props = $props();
const fileName = $derived(baseName(path));
const showLines = $derived(lines !== null && view === "code"); const showWrapToggle = $derived(showWrap && hasTextView(kind) && view === "code"); const showBlameToggle = $derived(showBlame && hasTextView(kind) && view === "code"); const languageColor = $derived( language ? (LANGUAGE_COLORS[language] ?? LANGUAGE_COLOR_FALLBACK) : null );</script>
<div class="mb-xs flex flex-col gap-sm typography-paragraph-regular md:mb-md md:grid md:grid-cols-[minmax(0,1fr)_auto] md:items-center md:gap-md"> <div class="flex min-w-0 items-center justify-between gap-sm md:justify-start"> <div class="flex min-w-0 items-center gap-xs"> {#if repo} <RepoCrumbs ownerHandle={repo.ownerHandle} repoName={repo.repoName} ref={repo.ref} {path} /> {:else} <FilePathChip> <span class="truncate">{path}</span> </FilePathChip> {/if} {#if timeLabel} <span class="flex shrink-0 items-center gap-xs typography-paragraph-small text-foreground-muted" > <Separator variant="dot" /> <span class="whitespace-nowrap">{timeLabel}</span> {#if sizeLabel || showLines} <Separator variant="dot" /> {/if} </span> {/if} </div>
<div class="flex shrink-0 items-center gap-xs typography-paragraph-small text-foreground-muted" > {#if sizeLabel} <span>{sizeLabel}</span> {/if} {#if sizeLabel && showLines} <Separator variant="dot" /> {/if} {#if showLines} <span>{lines} {lines === 1 ? "line" : "lines"}</span> {/if} </div> </div>
<div class="flex flex-col gap-md whitespace-nowrap md:flex-row md:items-center md:gap-xs"> {#if repo || (language && languageColor)} <div class="flex items-center gap-md max-md:justify-between md:flex-row-reverse md:px-xs" > {#if language && languageColor} <div class="flex w-fit items-center gap-xs px-2xs typography-paragraph-small md:px-none" > <ColorBall color={languageColor} /> {language} </div> {/if} {#if repo} <RefChip ownerHandle={repo.ownerHandle} repoName={repo.repoName} ref={repo.ref} class="typography-paragraph-small max-md:ms-auto" /> {/if} </div> {/if}
{#if kind !== "submodule"} <div class="flex items-center gap-xs max-md:justify-between"> {#if showWrapToggle || showBlameToggle || hasRenderedView(kind)} <div class="flex items-center gap-xs"> {#if showBlameToggle} <Checkbox bind:checked={blame} aria-busy={blameLoading} title={blameError ?? undefined} class="px-xs text-foreground-muted" > {blameLoading ? "Blame…" : "Blame"} </Checkbox> {/if} {#if showWrapToggle} <Checkbox bind:checked={wrap} class="px-xs text-foreground-muted"> Wrap </Checkbox> {/if} {#if hasRenderedView(kind)} <ButtonGroup> <Button size="small" icon={CodeXml} aria-pressed={view === "code"} {...segmentProps(view === "code")} onclick={() => (view = "code")} title="View source" /> <Button size="small" icon={Eye} aria-pressed={view === "rendered"} {...segmentProps(view === "rendered")} onclick={() => (view = "rendered")} title="View rendered" /> </ButtonGroup> {/if} </div> {/if} <ButtonGroup class="max-md:ms-auto"> {#if copyText !== null} <CopyButton value={copyText} variant="default" label="Copy contents" title="Copy contents" /> {/if} <Button size="small" href={rawHref} download={fileName} title="Download" aria-label="Download" icon={Download} /> <Button size="small" href={rawHref} target="_blank" title="Open raw file" aria-label="Open raw file" icon={ExternalLink} iconSide="right" /> {#if historyHref} <Button size="small" href={historyHref} title="File history" aria-label="File history" icon={History} /> {/if} </ButtonGroup> </div> {/if} </div></div>