mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 11:20:36 +08:00
228 lines
5.2 KiB
Svelte
228 lines
5.2 KiB
Svelte
<script lang="ts">
|
|
import type { RepoInfo } from "./RepoCard";
|
|
import type { BaseUrl } from "@http-client";
|
|
|
|
import { HttpdClient } from "@http-client";
|
|
|
|
import {
|
|
absoluteTimestamp,
|
|
formatTimestamp,
|
|
formatRepositoryId,
|
|
twemoji,
|
|
} from "@app/lib/utils";
|
|
|
|
import ActivityDiagram from "@app/components/ActivityDiagram.svelte";
|
|
import Icon from "@app/components/Icon.svelte";
|
|
import Id from "@app/components/Id.svelte";
|
|
import Link from "@app/components/Link.svelte";
|
|
import RepoAvatar from "@app/components/RepoAvatar.svelte";
|
|
|
|
export let compact = false;
|
|
export let repoInfo: RepoInfo;
|
|
export let baseUrl: BaseUrl;
|
|
|
|
const api = new HttpdClient(baseUrl);
|
|
|
|
$: repo = repoInfo.repo;
|
|
$: project = repoInfo.repo.payloads["xyz.radicle.project"];
|
|
$: baseUrl = repoInfo.baseUrl;
|
|
$: isPrivate = repo.visibility.type === "private";
|
|
</script>
|
|
|
|
<style>
|
|
.repo-card {
|
|
container-type: inline-size;
|
|
height: 10rem;
|
|
background-color: var(--color-surface-canvas);
|
|
padding: 1rem;
|
|
position: relative;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
border: 1px solid var(--color-border-subtle);
|
|
margin-top: -1px;
|
|
margin-left: -1px;
|
|
}
|
|
|
|
.repo-card.compact {
|
|
height: 8rem;
|
|
}
|
|
|
|
.repo-card:hover {
|
|
background-color: var(--color-surface-subtle);
|
|
}
|
|
|
|
.content-and-activity {
|
|
display: flex;
|
|
gap: 1rem;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.content {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
|
|
.activity {
|
|
flex: 1;
|
|
max-width: 12rem;
|
|
align-self: flex-end;
|
|
}
|
|
|
|
.activity-shimmer {
|
|
width: 100%;
|
|
min-width: 185px;
|
|
aspect-ratio: 493 / 116;
|
|
background: linear-gradient(
|
|
90deg,
|
|
var(--color-surface-base) 0%,
|
|
var(--color-surface-subtle) 50%,
|
|
var(--color-surface-base) 100%
|
|
);
|
|
background-size: 200% 100%;
|
|
animation:
|
|
shimmer 1.8s ease-in-out infinite,
|
|
shimmer-fade-in 200ms ease-out 500ms both;
|
|
}
|
|
|
|
@keyframes shimmer {
|
|
0% {
|
|
background-position: 100% 0;
|
|
}
|
|
100% {
|
|
background-position: -100% 0;
|
|
}
|
|
}
|
|
|
|
@keyframes shimmer-fade-in {
|
|
from {
|
|
opacity: 0;
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.headline-and-badges {
|
|
display: flex;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.badges {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.badge {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
border-radius: 50%;
|
|
overflow: hidden;
|
|
position: relative;
|
|
padding: 0.25rem;
|
|
}
|
|
|
|
.stats-row {
|
|
position: relative;
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
height: 1.5rem;
|
|
align-items: center;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.icon {
|
|
width: 1.5rem;
|
|
height: 1.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: var(--color-brand-bg);
|
|
color: var(--color-text-on-brand);
|
|
}
|
|
|
|
@container (max-width: 30rem) {
|
|
.activity {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<Link
|
|
route={{
|
|
resource: "repo.source",
|
|
repo: repo.rid,
|
|
node: baseUrl,
|
|
}}>
|
|
<div class="repo-card" class:compact>
|
|
<div class="headline-and-badges txt-overflow">
|
|
<div class="icon">
|
|
<RepoAvatar
|
|
rid={repoInfo.repo.rid}
|
|
name={project.data.name}
|
|
styleWidth="1.5rem" />
|
|
</div>
|
|
<div class="txt-body-l-semibold" use:twemoji>{project.data.name}</div>
|
|
<div class="badges" style:margin-left="auto">
|
|
{#if isPrivate}
|
|
<div
|
|
title="Private"
|
|
class="badge"
|
|
style="background-color: var(--color-feedback-warning-bg); color: var(--color-feedback-warning-text)">
|
|
<Icon name="lock" />
|
|
</div>
|
|
{/if}
|
|
<slot name="delegate" />
|
|
</div>
|
|
</div>
|
|
<div class="content-and-activity">
|
|
<div class="content">
|
|
<div class="txt-body-m-regular txt-overflow" use:twemoji>
|
|
{project.data.description}
|
|
</div>
|
|
<span style:text-overflow="ellipsis">
|
|
<Id id={repo.rid} title={repo.rid}>
|
|
{formatRepositoryId(repo.rid)}
|
|
</Id>
|
|
</span>
|
|
</div>
|
|
<div class="activity">
|
|
{#await repoInfo.activity}
|
|
<div class="activity-shimmer"></div>
|
|
{:then activity}
|
|
<ActivityDiagram
|
|
id={repo.rid}
|
|
viewBoxHeight={100}
|
|
styleColor="var(--color-text-brand)"
|
|
{activity} />
|
|
{/await}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div
|
|
class="stats-row txt-code-regular"
|
|
style:color="var(--color-text-tertiary)">
|
|
<Icon name="seed" />
|
|
{repoInfo.repo.seeding} ·
|
|
<Icon name="issue" />
|
|
{project.meta.issues.open} ·
|
|
<Icon name="patch" />
|
|
{project.meta.patches.open}
|
|
{#await api.repo.getCommitBySha(repo.rid, project.meta.head) then { commit }}
|
|
<span
|
|
class="txt-body-m-regular"
|
|
style:margin-left="auto"
|
|
style:overflow="hidden"
|
|
style:text-overflow="ellipsis"
|
|
title={absoluteTimestamp(commit.committer.time)}>
|
|
Updated {formatTimestamp(commit.committer.time)}
|
|
</span>
|
|
{/await}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Link>
|