This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / web / src / lib / components / repo / BlobHeader.svelte
3.6 kB 120 lines
1<script lang="ts"> 2 import Check from "$icon/check"; 3 import Copy from "$icon/copy"; 4 import Download from "$icon/download"; 5 import { hasRenderedView, hasTextView, type BlobKind, type BlobViewMode } from "$lib/api/blob"; 6 import { createCopyFeedback } from "$lib/copy.svelte"; 7 import Button from "$lib/components/ui/Button.svelte"; 8 import ButtonGroup from "$lib/components/ui/ButtonGroup.svelte"; 9 import Checkbox from "$lib/components/ui/Checkbox.svelte"; 10 import ColorBall from "$lib/components/ui/ColorBall.svelte"; 11 import { LANGUAGE_COLORS, LANGUAGE_COLOR_FALLBACK } from "./language-colors"; 12 import RefChip from "./RefChip.svelte"; 13 import RepoCrumbs from "./RepoCrumbs.svelte"; 14 import { baseName, rawBlobHref } from "./urls"; 15 16 interface Props { 17 ownerHandle: string; 18 repoName: string; 19 ref: string; 20 path: string; 21 kind: BlobKind; 22 // enry language name. the blob xrpc does not expose one yet 23 language?: string | null; 24 sizeLabel?: string | null; 25 lines?: number | null; 26 view?: BlobViewMode; 27 wrap?: boolean; 28 showWrap?: boolean; 29 copyText?: string | null; 30 } 31 32 let { 33 ownerHandle, 34 repoName, 35 ref, 36 path, 37 kind, 38 language = null, 39 sizeLabel = null, 40 lines = null, 41 view = $bindable("code"), 42 wrap = $bindable(false), 43 showWrap = false, 44 copyText = null 45 }: Props = $props(); 46 47 const rawHref = $derived(rawBlobHref(ownerHandle, repoName, ref, path)); 48 const fileName = $derived(baseName(path)); 49 50 const showLines = $derived(lines !== null && view === "code"); 51 const showWrapToggle = $derived(showWrap && hasTextView(kind) && view === "code"); 52 const languageColor = $derived( 53 language ? (LANGUAGE_COLORS[language] ?? LANGUAGE_COLOR_FALLBACK) : null 54 ); 55 56 const copyFeedback = createCopyFeedback(); 57 const copyContents = () => { 58 if (copyText !== null) void copyFeedback.copy(copyText); 59 }; 60</script> 61 62<div class="mb-2 flex flex-wrap items-center justify-between gap-2 typography-paragraph-regular"> 63 <div class="flex min-w-0 items-center gap-3"> 64 <RepoCrumbs {ownerHandle} {repoName} {ref} {path} /> 65 66 <div class="flex items-center gap-2 text-foreground-muted"> 67 {#if sizeLabel} 68 <span>{sizeLabel}</span> 69 {/if} 70 {#if sizeLabel && showLines} 71 <span class="select-none" aria-hidden="true">&middot;</span> 72 {/if} 73 {#if showLines} 74 <span>{lines} {lines === 1 ? "line" : "lines"}</span> 75 {/if} 76 </div> 77 </div> 78 79 <div class="flex flex-wrap items-center gap-2 whitespace-nowrap max-md:order-3 max-md:w-full"> 80 {#if showWrapToggle} 81 <Checkbox bind:checked={wrap} class="px-2 text-foreground-muted">Wrap</Checkbox> 82 {/if} 83 <RefChip {ownerHandle} {repoName} {ref} /> 84 {#if language && languageColor} 85 <div 86 class="flex w-fit items-center gap-2 rounded border border-border-default bg-background-canvas px-2 py-1 whitespace-nowrap" 87 > 88 <ColorBall color={languageColor} /> 89 {language} 90 </div> 91 {/if} 92 {#if kind !== "submodule"} 93 <ButtonGroup> 94 {#if hasRenderedView(kind)} 95 <Button size="sm" onclick={() => (view = view === "code" ? "rendered" : "code")}> 96 View {view === "rendered" ? "code" : "rendered"} 97 </Button> 98 {/if} 99 <Button size="sm" href={rawHref}>View raw</Button> 100 {#if copyText !== null} 101 <Button 102 size="sm" 103 onclick={copyContents} 104 title="Copy contents" 105 aria-label="Copy contents" 106 icon={copyFeedback.copied !== null ? Check : Copy} 107 /> 108 {/if} 109 <Button 110 size="sm" 111 href={rawHref} 112 download={fileName} 113 title="Download" 114 aria-label="Download" 115 icon={Download} 116 /> 117 </ButtonGroup> 118 {/if} 119 </div> 120</div>