Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
853 changes: 853 additions & 0 deletions bun.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@
<!-- gitlawb:social-meta:end -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700;800&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700;800&family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
<!-- Anti-FOUC: set theme class before first paint. Dark is the default theme. -->
<script>
(function () {
var t = localStorage.getItem('theme');
var dark = t ? t === 'dark' : true;
document.documentElement.classList.toggle('dark', dark);
var root = document.documentElement;
root.classList.toggle('dark', dark);
root.setAttribute('data-theme', dark ? 'dark' : 'light');
})();
</script>
</head>
Expand Down
1,427 changes: 1,058 additions & 369 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,28 @@
},
"dependencies": {
"@expo-google-fonts/jetbrains-mono": "^0.4.1",
"@radix-ui/react-separator": "^1.1.9",
"@radix-ui/react-slot": "^1.2.5",
"@radix-ui/react-tabs": "^1.1.14",
"@heroui/react": "^3.2.2",
"@heroui/styles": "^3.2.2",
"@shuding/opentype.js": "^1.4.0-beta.0",
"@tailwindcss/postcss": "^4.3.3",
"@vercel/og": "^0.11.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"dompurify": "^3.4.11",
"gemoji": "^8.1.0",
"lucide-react": "^1.17.0",
"lucide-react": "^1.27.0",
"marked": "^18.0.5",
"marked-alert": "^2.1.2",
"marked-emoji": "^2.0.3",
"marked-footnote": "^1.4.0",
"marked-gfm-heading-id": "^4.1.4",
"marked-highlight": "^2.2.4",
"postcss": "^8.5.23",
"react": "^19.2.6",
"react-dom": "^19.2.6",
"react-router-dom": "^7.17.0",
"shiki": "^4.3.0",
"tailwind-merge": "^3.6.0"
"tailwind-merge": "^3.6.0",
"tailwind-variants": "^3.3.0"
},
"devDependencies": {
"@eslint/js": "^10.0.1",
Expand Down
5 changes: 5 additions & 0 deletions postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
4 changes: 2 additions & 2 deletions src/components/agents/AgentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AgentRow } from './AgentRow';
function AgentRowSkeleton() {
return (
<li className="grid grid-cols-[16px_minmax(0,1fr)] md:grid-cols-[24px_minmax(0,4fr)_minmax(0,3fr)_140px_110px]
items-start gap-x-3 md:gap-x-4 px-4 sm:px-6 py-4 border-b border-border-inner last:border-b-0">
items-start gap-x-3 md:gap-x-4 px-4 sm:px-6 py-4 border-b border-separator last:border-b-0">
<span />
<div>
<Skeleton className="h-4 w-40 max-w-full" />
Expand Down Expand Up @@ -49,7 +49,7 @@ export function AgentList({ agents, loading = false, skeletonCount = 10 }: Agent
{Array.from({ length: skeletonCount }, (_, i) => <AgentRowSkeleton key={i} />)}
</ul>
) : agents.length === 0 ? (
<p className="m-0 py-20 text-center text-[13px] text-muted-foreground">no agents match</p>
<p className="m-0 py-20 text-center text-[13px] text-muted">no agents match</p>
) : (
<ul className="m-0 p-0 list-none">
{agents.map((agent, i) => <AgentRow key={agent.did} agent={agent} index={i} />)}
Expand Down
19 changes: 10 additions & 9 deletions src/components/agents/AgentRow.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Circle } from 'lucide-react';
import type { ApiAgent } from '../../lib/api';
import { shortDid, didKeySegment, trustTier, timeAgo, formatDate } from '../../lib/api';
import { cn } from '../../lib/utils';
Expand All @@ -16,24 +17,24 @@ export function AgentRow({ agent, index }: AgentRowProps) {
<li
className="grid grid-cols-[16px_minmax(0,1fr)] md:grid-cols-[24px_minmax(0,4fr)_minmax(0,3fr)_140px_110px]
items-start gap-x-3 md:gap-x-4 px-4 sm:px-6 py-3
border-b border-border-inner last:border-b-0 hover:bg-hover transition-colors
animate-fade-up motion-reduce:animate-none"
border-b border-separator last:border-b-0 hover:bg-surface-secondary transition-colors
"
style={{ animationDelay: `${index * 16}ms` }}
>
{/* Status dot */}
<span
aria-hidden="true"
className={cn('pt-[3px] text-[8px] leading-none select-none', active ? 'text-ok' : 'text-status-dot')}
className={cn('pt-[3px] text-[8px] leading-none select-none', active ? 'text-success' : 'text-muted')}
title={agent.status}
>
<Circle size={7} fill="currentColor" />
</span>

{/* Identity + capabilities */}
<div className="min-w-0">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-[14px] font-bold text-foreground">{shortDid(agent.did)}</span>
<span className="text-[11px] text-dim">{agent.status}</span>
<span className="text-[11px] text-muted">{agent.status}</span>
<CopyButton value={agent.did} label="did" />
<Pill to={`/repos?owner=${encodeURIComponent(didKeySegment(agent.did))}`} data-row-link="">
repos →
Expand All @@ -42,7 +43,7 @@ export function AgentRow({ agent, index }: AgentRowProps) {
{agent.capabilities.length > 0 && (
<div className="flex items-center gap-1.5 mt-2.5 flex-wrap">
{agent.capabilities.map(cap => (
<span key={cap} className="text-[10px] uppercase tracking-[0.12em] text-muted-foreground border border-border-inner rounded-[2px] px-1.5 py-0.5">
<span key={cap} className="text-[10px] uppercase tracking-[0.12em] text-muted border border-separator rounded-[--radius] px-1.5 py-0.5">
{cap}
</span>
))}
Expand All @@ -51,17 +52,17 @@ export function AgentRow({ agent, index }: AgentRowProps) {
</div>

{/* Trust */}
<span className="hidden md:block pt-[2px] text-[12px] text-muted-foreground tabular-nums">
<span className="hidden md:block pt-[2px] text-[12px] text-muted tabular-nums">
{agent.trust_score.toFixed(2)} · {trustTier(agent.trust_score)}
</span>

{/* Last seen */}
<span className="hidden md:block pt-[2px] text-[12px] text-dim tabular-nums">
<span className="hidden md:block pt-[2px] text-[12px] text-muted tabular-nums">
{agent.last_seen ? `seen ${timeAgo(agent.last_seen)}` : 'never seen'}
</span>

{/* Registered */}
<span className="hidden md:block pt-[2px] text-[11px] text-dim tabular-nums text-right whitespace-nowrap">
<span className="hidden md:block pt-[2px] text-[11px] text-muted tabular-nums text-right whitespace-nowrap">
{formatDate(agent.registered_at)}
</span>
</li>
Expand Down
23 changes: 12 additions & 11 deletions src/components/events/RefUpdateList.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Circle } from 'lucide-react';
import { Link } from 'react-router-dom';
import { cn } from '../../lib/utils';
import type { ApiRefUpdate } from '../../lib/api';
Expand All @@ -14,35 +15,35 @@ function RefUpdateRow({ event, index }: { event: ApiRefUpdate; index: number })
<li
className="grid grid-cols-[16px_minmax(0,1fr)_80px] md:grid-cols-[24px_minmax(0,1fr)_150px_120px_90px]
items-baseline gap-x-3 md:gap-x-4 px-4 sm:px-6 py-3
border-b border-border-inner last:border-b-0 hover:bg-hover transition-colors
animate-fade-up motion-reduce:animate-none"
border-b border-separator last:border-b-0 hover:bg-surface-secondary transition-colors
"
style={{ animationDelay: `${index * 16}ms` }}
>
<span
aria-hidden="true"
className={cn('text-[8px] leading-none select-none self-start pt-[5px]', gossip ? 'text-warm' : 'text-status-dot')}
className={cn('text-[8px] leading-none select-none self-start pt-[5px]', gossip ? 'text-accent' : 'text-muted')}
title={gossip ? 'received via gossip' : 'local push'}
>
<Circle size={7} fill="currentColor" />
</span>

{/* repo / ref */}
<span className="min-w-0 truncate text-[13px]">
{repoRef ? (
<Link
to={`/repos/${encodeURIComponent(repoRef.ownerDid)}/${encodeURIComponent(repoRef.name)}`}
className="font-bold text-foreground hover:text-warm-text transition-colors"
className="font-bold text-foreground hover:text-accent transition-colors"
>
{repoRef.label}
</Link>
) : (
<span className="font-bold text-foreground">{event.repo}</span>
)}
<span className="text-dim"> · {shortRefName(event.ref_name)}</span>
<span className="text-muted"> · {shortRefName(event.ref_name)}</span>
</span>

{/* sha transition */}
<span className="hidden md:block text-[12px] text-muted-foreground tabular-nums whitespace-nowrap">
<span className="hidden md:block text-[12px] text-muted tabular-nums whitespace-nowrap">
{created ? (
<>new · {shortSha(event.new_sha)}</>
) : (
Expand All @@ -51,12 +52,12 @@ function RefUpdateRow({ event, index }: { event: ApiRefUpdate; index: number })
</span>

{/* pusher */}
<span className="hidden md:block text-[12px] text-dim truncate" title={event.pusher_did}>
<span className="hidden md:block text-[12px] text-muted truncate" title={event.pusher_did}>
{shortDid(event.pusher_did)}
</span>

{/* time */}
<span className="text-[11px] text-dim tabular-nums text-right whitespace-nowrap">
<span className="text-[11px] text-muted tabular-nums text-right whitespace-nowrap">
{timeAgo(event.timestamp)}
</span>
</li>
Expand All @@ -66,7 +67,7 @@ function RefUpdateRow({ event, index }: { event: ApiRefUpdate; index: number })
function RefUpdateRowSkeleton() {
return (
<li className="grid grid-cols-[16px_minmax(0,1fr)_80px] md:grid-cols-[24px_minmax(0,1fr)_150px_120px_90px]
items-center gap-x-3 md:gap-x-4 px-4 sm:px-6 py-3 border-b border-border-inner last:border-b-0">
items-center gap-x-3 md:gap-x-4 px-4 sm:px-6 py-3 border-b border-separator last:border-b-0">
<span />
<Skeleton className="h-4 w-52 max-w-full" />
<Skeleton className="hidden md:block h-4 w-28" />
Expand Down Expand Up @@ -112,7 +113,7 @@ export function RefUpdateList({
{Array.from({ length: skeletonCount }, (_, i) => <RefUpdateRowSkeleton key={i} />)}
</ul>
) : events.length === 0 ? (
<p className="m-0 py-16 text-center text-[13px] text-muted-foreground">{emptyMessage}</p>
<p className="m-0 py-16 text-center text-[13px] text-muted">{emptyMessage}</p>
) : (
<ul className="m-0 p-0 list-none">
{events.map((event, i) => <RefUpdateRow key={event.id} event={event} index={i} />)}
Expand Down
Loading
Loading