Files
egorin/src/modules/repos/ReposModule.tsx
T
GermanandClaude Opus 4.8 b1c52ab748 Железный Егорин — форк Орбиты: тёплый стиль (amber), логин с odyssey WebGL-молнией справа, энергомониторинг+панель
Ребренд Мониторинг Орбита -> Железный Егорин; accent green->amber #F59E0B; LoginScreen правая половина = Lightning (WebGL, hue 35 тёплый) под стеклянной формой; левая панель — тёплый градиент.
Доступ агентам: репо публичный, push german-токеном.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 23:57:16 +03:00

114 lines
4.4 KiB
TypeScript

import { useMemo } from 'react';
import { FolderGit2, GitBranch, Lock, Globe, ExternalLink, Sparkles, CircleSlash } from 'lucide-react';
import { PageHeader } from '@/components/PageHeader';
import { Card, CardHeader, Badge } from '@/components/ui/primitives';
import { KpiCard } from '@/components/ui/KpiCard';
import { cn } from '@/lib/utils';
import {
repos,
repoUrl,
CATEGORY_LABEL,
CATEGORY_ORDER,
GITEA_BASE,
type GiteaRepo,
} from '@/data/repos';
function RepoRow({ r }: { r: GiteaRepo }) {
return (
<a
href={repoUrl(r)}
target="_blank"
rel="noreferrer"
className="group flex items-center gap-3 py-2.5 transition-colors hover:bg-muted/40"
>
<FolderGit2 className={cn('h-4 w-4 shrink-0', r.empty ? 'text-fg-muted' : 'text-accent')} />
<div className="min-w-0 flex-1">
<div className="flex items-center gap-1.5">
<span className="truncate text-sm font-medium text-fg">{r.name}</span>
{r.isNew && (
<Badge severity="ok">
<Sparkles className="h-3 w-3" /> новый
</Badge>
)}
{r.empty && (
<Badge severity="warning">
<CircleSlash className="h-3 w-3" /> пусто
</Badge>
)}
</div>
<div className="truncate text-[11px] text-fg-muted">{r.note}</div>
</div>
<span className="hidden items-center gap-1 text-[11px] text-fg-muted sm:inline-flex">
<GitBranch className="h-3.5 w-3.5" />
<span className={cn('font-mono', r.branch === 'master' && 'text-warn')}>{r.branch}</span>
</span>
{r.private ? (
<Lock className="h-3.5 w-3.5 shrink-0 text-fg-muted" aria-label="приватный" />
) : (
<Globe className="h-3.5 w-3.5 shrink-0 text-ok" aria-label="публичный" />
)}
<ExternalLink className="h-3.5 w-3.5 shrink-0 text-transparent group-hover:text-fg-muted" />
</a>
);
}
export function ReposModule() {
const stats = useMemo(() => {
const total = repos.length;
const pub = repos.filter((r) => !r.private).length;
const master = repos.filter((r) => r.branch === 'master').length;
const empty = repos.filter((r) => r.empty).length;
return { total, priv: total - pub, pub, master, empty };
}, []);
const byCat = useMemo(
() => CATEGORY_ORDER.map((cat) => ({ cat, items: repos.filter((r) => r.category === cat) })),
[],
);
return (
<div>
<PageHeader
icon={FolderGit2}
title="Карта репозиториев"
desc="Gitea git1.servaki.online · owner german · канон = git"
actions={
<a
href={GITEA_BASE}
target="_blank"
rel="noreferrer"
className="inline-flex items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-1.5 text-xs font-medium text-fg-muted transition-colors hover:text-fg"
>
<ExternalLink className="h-3.5 w-3.5" /> Открыть Gitea
</a>
}
/>
<div className="mb-4 grid grid-cols-2 gap-3 sm:grid-cols-4">
<KpiCard label="Всего репо" value={stats.total} digits={0} icon={FolderGit2} tone="accent" />
<KpiCard label="Приватных" value={stats.priv} digits={0} icon={Lock} tone="muted" />
<KpiCard label="Публичных" value={stats.pub} digits={0} icon={Globe} tone="ok" sub="только Heritage" />
<KpiCard label="Ветка master" value={stats.master} digits={0} icon={GitBranch} tone="warn" sub="cascade · vpn-clients" />
</div>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
{byCat.map(({ cat, items }) => (
<Card key={cat}>
<CardHeader title={CATEGORY_LABEL[cat]} right={<Badge severity="info">{items.length}</Badge>} />
<div className="divide-y divide-border px-4 pb-2">
{items.map((r) => (
<RepoRow key={r.name} r={r} />
))}
</div>
</Card>
))}
</div>
<p className="mt-4 text-center text-xs text-fg-muted">
Источник истины — git1. Карта сверена вручную 2026-06-30 ({stats.total} репо, {stats.empty} пустой). Пуш — через
<span className="font-mono"> http.extraHeader</span>, токен в URL не сохраняется.
</p>
</div>
);
}