Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142<script lang="ts"> import { resolve } from "$app/paths"; import { getAuth } from "#lib/auth.svelte.ts"; import BookMarked from "$icon/book-marked"; import Star from "$icon/star"; import GitFork from "$icon/git-fork"; import CircleDot from "$icon/circle-dot"; import GitPullRequest from "$icon/git-pull-request"; import ColorBall from "#lib/components/ui/ColorBall.svelte"; import StarButton from "#lib/components/repo/StarButton.svelte"; import { LANGUAGE_COLORS, LANGUAGE_COLOR_FALLBACK } from "#lib/components/repo/languageColors.ts"; import type { RepoCardData, StarChange } from "#lib/components/profile/types.ts"; import { formatCount } from "#lib/format.ts"; import { createOptimisticCount } from "#lib/optimistic.svelte.ts"; let { repo, starButton = true, showOwner = true, uniformHeight = false, layout = "card", onStar }: { repo: RepoCardData; starButton?: boolean; showOwner?: boolean; uniformHeight?: boolean; layout?: "card" | "row"; onStar?: (change: StarChange) => void; } = $props();
const auth = getAuth(); const showStar = $derived(starButton && Boolean(auth.currentDid));
const starCount = createOptimisticCount({ key: () => repo.repoDid, loaded: () => repo.stars });
const stats = $derived( [ { value: repo.stars === undefined ? undefined : starCount.value, Icon: Star }, { value: repo.forks, Icon: GitFork }, { value: repo.issues, Icon: CircleDot }, { value: repo.pulls, Icon: GitPullRequest } ].filter((s) => s.value !== undefined && s.value > 0) );</script>
<div class={layout === "row" ? "flex flex-col gap-2xs sm:flex-row sm:items-center sm:gap-md" : "flex h-full flex-1 flex-col gap-2xs"}> <div class={[ "flex items-start justify-between font-medium text-foreground-default", layout === "row" && "sm:contents" ]} > <div class={[ "mr-xs flex min-w-0 flex-1 items-center", layout === "card" && "mt-2xs", layout === "row" && "self-center" ]} data-vt="move" > <BookMarked class="mr-1.5 size-3.5 shrink-0 text-foreground-subtle" aria-hidden="true" /> <a href={resolve(`/${repo.ownerHandle}/${repo.name}` as "/")} class="min-w-0 truncate text-foreground-default no-underline hover:underline" > {showOwner ? `${repo.ownerHandle}/${repo.name}` : repo.name} </a> </div> {#if showStar} <div class={["ml-md shrink-0", layout === "row" && "sm:order-last"]} data-vt="move"> <StarButton subject={{ kind: "repo", did: repo.repoDid, ownerHandle: repo.ownerHandle, name: repo.name }} initialCount={repo.stars} initialRkey={repo.viewerStarRkey} count="never" onAdjust={(delta) => starCount.adjust(delta)} onCommit={onStar} /> </div> {/if} </div>
<!-- in a grid the description and footer keep their space even when empty, so a card with nothing to show doesn't sit shorter than the ones around it --> {#if layout === "card" && (repo.description || uniformHeight)} <p data-vt="fade" class={[ "line-clamp-2 pr-24 typography-paragraph-small text-pretty text-foreground-muted", uniformHeight && "min-h-[2lh]" ]} > {repo.description} </p> {/if}
{#if repo.language || stats.length > 0 || (layout === "card" && uniformHeight)} <div class={[ "flex flex-wrap items-center gap-md typography-monospace-small text-foreground-muted", layout === "card" && "mt-auto pt-xs", layout === "card" && uniformHeight && "box-content min-h-lh" ]} data-vt="move" > {#if repo.language} <span class="flex items-center gap-xs"> <ColorBall color={LANGUAGE_COLORS[repo.language] ?? LANGUAGE_COLOR_FALLBACK} class="size-2.5" /> <span>{repo.language}</span> </span> {/if} {#each stats as stat (stat.Icon)} <span class="flex items-center gap-2xs"> <stat.Icon class="size-3.5 shrink-0" aria-hidden="true" /> <span>{formatCount(stat.value)}</span> </span> {/each} </div> {/if}</div>