Skip to content

Commit 08e22db

Browse files
leopu00claude
andcommitted
feat(git): pagina /git — branch attivi con ahead/behind, diff stat, autore, ultimo commit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 91837f0 commit 08e22db

1 file changed

Lines changed: 97 additions & 0 deletions

File tree

web/app/git/page.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'use client'
2+
3+
import Link from 'next/link'
4+
import { useEffect, useState, useCallback } from 'react'
5+
6+
type DiffStat = { files: number; insertions: number; deletions: number }
7+
type Branch = { name: string; lastCommit: string; lastCommitDate: string; author: string; ahead: number; behind: number; diffStat: DiffStat; isCurrent: boolean }
8+
9+
function AheadBehind({ ahead, behind }: { ahead: number; behind: number }) {
10+
if (ahead === 0 && behind === 0) return <span className="text-[10px] text-[var(--color-dim)]">in sync</span>
11+
return (
12+
<div className="flex gap-1.5">
13+
{ahead > 0 && <span className="text-[10px] font-mono font-bold" style={{ color: 'var(--color-green)' }}>+{ahead}</span>}
14+
{behind > 0 && <span className="text-[10px] font-mono font-bold" style={{ color: 'var(--color-red)' }}>-{behind}</span>}
15+
</div>
16+
)
17+
}
18+
19+
function DiffBar({ stat }: { stat: DiffStat }) {
20+
if (stat.files === 0) return <span className="text-[9px] text-[var(--color-dim)]">-</span>
21+
return (
22+
<span className="text-[9px] font-mono">
23+
<span className="text-[var(--color-muted)]">{stat.files}f</span>
24+
{stat.insertions > 0 && <span className="text-[var(--color-green)] ml-1">+{stat.insertions}</span>}
25+
{stat.deletions > 0 && <span className="text-[var(--color-red)] ml-1">-{stat.deletions}</span>}
26+
</span>
27+
)
28+
}
29+
30+
function BranchRow({ b }: { b: Branch }) {
31+
const isMain = b.name === 'main' || b.name === 'master'
32+
return (
33+
<div className="flex items-center gap-4 px-5 py-3 border-b border-[var(--color-border)] hover:bg-[var(--color-row)] transition-colors">
34+
<div className="w-36 flex-shrink-0 flex items-center gap-2">
35+
<span className="text-[11px] font-mono font-semibold" style={{ color: isMain ? 'var(--color-yellow)' : b.isCurrent ? 'var(--color-green)' : 'var(--color-bright)' }}>{b.name}</span>
36+
{b.isCurrent && <span className="w-1.5 h-1.5 rounded-full flex-shrink-0" style={{ background: 'var(--color-green)' }} />}
37+
</div>
38+
<div className="flex-1 min-w-0 truncate">
39+
<span className="text-[10px] text-[var(--color-muted)]">{b.lastCommit}</span>
40+
</div>
41+
<span className="w-16 text-[9px] text-[var(--color-dim)] flex-shrink-0 text-right">{b.lastCommitDate}</span>
42+
<span className="w-16 text-[10px] text-[var(--color-dim)] flex-shrink-0 font-mono">{b.author}</span>
43+
<div className="w-16 flex-shrink-0 text-right"><AheadBehind ahead={b.ahead} behind={b.behind} /></div>
44+
<div className="w-28 flex-shrink-0 text-right"><DiffBar stat={b.diffStat} /></div>
45+
</div>
46+
)
47+
}
48+
49+
export default function GitPage() {
50+
const [branches, setBranches] = useState<Branch[]>([])
51+
const [currentBranch, setCurrentBranch] = useState('')
52+
const [totalAhead, setTotalAhead] = useState(0)
53+
54+
const fetchGit = useCallback(async () => {
55+
const res = await fetch('/api/git').catch(() => null)
56+
if (!res?.ok) return
57+
const data = await res.json()
58+
setBranches(data.branches ?? [])
59+
setCurrentBranch(data.currentBranch ?? '')
60+
setTotalAhead(data.totalCommitsAhead ?? 0)
61+
}, [])
62+
63+
useEffect(() => { fetchGit() }, [fetchGit])
64+
65+
const activeBranches = branches.filter(b => b.ahead > 0 || b.name === 'main' || b.name === 'master')
66+
67+
return (
68+
<div style={{ animation: 'fade-in 0.35s ease both' }}>
69+
<div className="mb-8 pb-6 border-b border-[var(--color-border)]">
70+
<div className="flex items-center gap-2 mb-1">
71+
<Link href="/dashboard" className="text-[10px] text-[var(--color-dim)] hover:text-[var(--color-muted)] no-underline transition-colors">Dashboard</Link>
72+
<span className="text-[var(--color-border)]">/</span>
73+
<span className="text-[10px] text-[var(--color-muted)]">Git</span>
74+
</div>
75+
<h1 className="text-2xl font-bold tracking-tight text-[var(--color-white)] mt-3">Git</h1>
76+
<p className="text-[var(--color-muted)] text-[11px] mt-1">
77+
{branches.length} branch · {activeBranches.length} attivi · {totalAhead} commit ahead totali · branch corrente: <span className="font-mono text-[var(--color-green)]">{currentBranch}</span>
78+
</p>
79+
</div>
80+
81+
<div className="border border-[var(--color-border)] rounded-lg overflow-hidden bg-[var(--color-panel)]">
82+
<div className="flex items-center gap-4 px-5 py-2 border-b border-[var(--color-border)]" style={{ background: 'var(--color-deep)' }}>
83+
<span className="w-36 text-[8px] font-bold tracking-widest text-[var(--color-dim)]">BRANCH</span>
84+
<span className="flex-1 text-[8px] font-bold tracking-widest text-[var(--color-dim)]">ULTIMO COMMIT</span>
85+
<span className="w-16 text-[8px] font-bold tracking-widest text-[var(--color-dim)] text-right">QUANDO</span>
86+
<span className="w-16 text-[8px] font-bold tracking-widest text-[var(--color-dim)]">AUTORE</span>
87+
<span className="w-16 text-[8px] font-bold tracking-widest text-[var(--color-dim)] text-right">+/-</span>
88+
<span className="w-28 text-[8px] font-bold tracking-widest text-[var(--color-dim)] text-right">DIFF</span>
89+
</div>
90+
{branches.length === 0
91+
? <div className="py-16 text-center"><p className="text-[var(--color-dim)] text-[12px]">Nessun branch trovato.</p></div>
92+
: branches.map(b => <BranchRow key={b.name} b={b} />)
93+
}
94+
</div>
95+
</div>
96+
)
97+
}

0 commit comments

Comments
 (0)