darkmode is now available

This commit is contained in:
2026-05-07 13:42:46 +02:00
parent ec309eb626
commit 8cb918b064
36 changed files with 588 additions and 489 deletions
+30 -30
View File
@@ -50,7 +50,7 @@ export default function BlobPage() {
}
if (isLoading) return <div className="p-6"><RepoListSkeleton /></div>
if (isError || !blob) return <div className="p-6 text-sm text-[#DE350B]">File not found.</div>
if (isError || !blob) return <div className="p-6 text-sm text-[var(--c-danger)]">File not found.</div>
const lines = blob.content.split('\n')
const pathParts = filePath.split('/')
@@ -60,18 +60,18 @@ export default function BlobPage() {
{/* Breadcrumb */}
<div className="flex items-center gap-1 text-sm flex-wrap">
<Link to="/repos" className="text-[#0052CC] hover:underline">Repositories</Link>
<span className="text-[#5E6C84]">/</span>
<Link to={`/repos/${owner}/${repoName}`} className="text-[#0052CC] hover:underline">{repoName}</Link>
<Link to="/repos" className="text-[var(--c-brand)] hover:underline">Repositories</Link>
<span className="text-[var(--c-muted)]">/</span>
<Link to={`/repos/${owner}/${repoName}`} className="text-[var(--c-brand)] hover:underline">{repoName}</Link>
{pathParts.map((seg, i) => {
const partial = pathParts.slice(0, i + 1).join('/')
const isLast = i === pathParts.length - 1
return (
<span key={partial} className="flex items-center gap-1">
<span className="text-[#5E6C84]">/</span>
<span className="text-[var(--c-muted)]">/</span>
{isLast
? <span className="font-semibold text-[#172B4D]">{seg}</span>
: <Link to={`/repos/${owner}/${repoName}?path=${encodeURIComponent(partial)}&ref=${encodeURIComponent(branch)}`} className="text-[#0052CC] hover:underline">{seg}</Link>
? <span className="font-semibold text-[var(--c-text)]">{seg}</span>
: <Link to={`/repos/${owner}/${repoName}?path=${encodeURIComponent(partial)}&ref=${encodeURIComponent(branch)}`} className="text-[var(--c-brand)] hover:underline">{seg}</Link>
}
</span>
)
@@ -79,24 +79,24 @@ export default function BlobPage() {
</div>
{/* File card */}
<div className="border border-[#DFE1E6] rounded bg-white overflow-hidden">
<div className="border border-[var(--c-border)] rounded bg-[var(--c-surface)] overflow-hidden">
{/* Toolbar */}
<div className="flex items-center justify-between px-4 py-2.5 border-b border-[#DFE1E6] bg-[#FAFBFC] gap-3 flex-wrap">
<div className="flex items-center justify-between px-4 py-2.5 border-b border-[var(--c-border)] bg-[var(--c-surface-raised)] gap-3 flex-wrap">
<div className="flex items-center gap-2 text-sm">
{/* Branch pill */}
<span className="flex items-center gap-1 px-2 py-0.5 border border-[#DFE1E6] rounded text-xs text-[#5E6C84] bg-white">
<span className="flex items-center gap-1 px-2 py-0.5 border border-[var(--c-border)] rounded text-xs text-[var(--c-muted)] bg-[var(--c-surface)]">
<svg width="12" height="12" fill="none" stroke="currentColor" strokeWidth="1.5" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 0 0 5.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 0 0 9.568 3Z" />
</svg>
{branch}
</span>
<span className="text-[#5E6C84]">{repoName}</span>
<span className="text-[#5E6C84]">/</span>
<span className="font-medium text-[#172B4D]">{fileName}</span>
<span className="text-[var(--c-muted)]">{repoName}</span>
<span className="text-[var(--c-muted)]">/</span>
<span className="font-medium text-[var(--c-text)]">{fileName}</span>
<button
onClick={() => navigator.clipboard.writeText(filePath)}
className="text-[#5E6C84] hover:text-[#172B4D]"
className="text-[var(--c-muted)] hover:text-[var(--c-text)]"
title="Copy path"
>
<svg width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.5" viewBox="0 0 24 24">
@@ -110,14 +110,14 @@ export default function BlobPage() {
{isMarkdown && (
<button
onClick={() => setPreview(p => !p)}
className={`px-3 py-1.5 text-xs font-medium rounded border ${preview ? 'border-[#0052CC] text-[#0052CC] bg-[#DEEBFF]' : 'border-[#DFE1E6] text-[#5E6C84] hover:bg-[#F4F5F7]'}`}
className={`px-3 py-1.5 text-xs font-medium rounded border ${preview ? 'border-[var(--c-brand)] text-[var(--c-brand)] bg-[var(--c-brand-tint)]' : 'border-[var(--c-border)] text-[var(--c-muted)] hover:bg-[var(--c-surface-muted)]'}`}
>
{preview ? 'Source' : 'Preview'}
</button>
)}
<button
onClick={startEdit}
className="px-3 py-1.5 text-xs font-medium border border-[#DFE1E6] rounded text-[#172B4D] hover:bg-[#F4F5F7] flex items-center gap-1.5"
className="px-3 py-1.5 text-xs font-medium border border-[var(--c-border)] rounded text-[var(--c-text)] hover:bg-[var(--c-surface-muted)] flex items-center gap-1.5"
>
<svg width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125" />
@@ -126,7 +126,7 @@ export default function BlobPage() {
</button>
<button
onClick={() => navigator.clipboard.writeText(blob.content)}
className="px-3 py-1.5 text-xs font-medium border border-[#DFE1E6] rounded text-[#5E6C84] hover:bg-[#F4F5F7]"
className="px-3 py-1.5 text-xs font-medium border border-[var(--c-border)] rounded text-[var(--c-muted)] hover:bg-[var(--c-surface-muted)]"
>
Copy
</button>
@@ -140,17 +140,17 @@ export default function BlobPage() {
<textarea
value={editContent}
onChange={e => setEditContent(e.target.value)}
className="w-full font-mono text-xs text-[#172B4D] bg-white p-4 resize-none focus:outline-none border-b border-[#DFE1E6]"
className="w-full font-mono text-xs text-[var(--c-text)] bg-[var(--c-surface)] p-4 resize-none focus:outline-none border-b border-[var(--c-border)]"
style={{ minHeight: Math.max(300, lines.length * 20) }}
spellCheck={false}
/>
<div className="p-4 bg-[#FAFBFC] border-t border-[#DFE1E6] space-y-3">
<div className="p-4 bg-[var(--c-surface-raised)] border-t border-[var(--c-border)] space-y-3">
<div>
<label className="block text-xs font-semibold text-[#172B4D] mb-1">Commit message</label>
<label className="block text-xs font-semibold text-[var(--c-text)] mb-1">Commit message</label>
<input
value={commitMsg}
onChange={e => setCommitMsg(e.target.value)}
className="w-full border border-[#DFE1E6] rounded px-3 py-2 text-sm focus:outline-none focus:border-[#4C9AFF]"
className="w-full border border-[var(--c-border)] rounded px-3 py-2 text-sm focus:outline-none focus:border-[var(--c-brand-focus)]"
placeholder="Describe your changes…"
/>
</div>
@@ -158,24 +158,24 @@ export default function BlobPage() {
<button
onClick={handleCommit}
disabled={updateBlob.isPending || !commitMsg.trim()}
className="px-4 py-2 rounded bg-[#0052CC] text-white text-sm font-medium hover:bg-[#0065FF] disabled:opacity-50"
className="px-4 py-2 rounded bg-[var(--c-brand)] text-white text-sm font-medium hover:bg-[var(--c-brand-hover)] disabled:opacity-50"
>
{updateBlob.isPending ? 'Committing…' : 'Commit changes'}
</button>
<button onClick={cancelEdit} className="px-4 py-2 rounded border border-[#DFE1E6] text-sm text-[#172B4D] hover:bg-[#F4F5F7]">
<button onClick={cancelEdit} className="px-4 py-2 rounded border border-[var(--c-border)] text-sm text-[var(--c-text)] hover:bg-[var(--c-surface-muted)]">
Cancel
</button>
{updateBlob.isError && (
<span className="text-xs text-[#DE350B]">{(updateBlob.error as Error)?.message}</span>
<span className="text-xs text-[var(--c-danger)]">{(updateBlob.error as Error)?.message}</span>
)}
</div>
</div>
</div>
) : isMarkdown && preview ? (
<div className="px-6 py-5 prose prose-sm max-w-none text-[#172B4D]
prose-headings:text-[#172B4D] prose-headings:font-semibold prose-headings:border-b prose-headings:border-[#DFE1E6] prose-headings:pb-1
prose-a:text-[#0052CC] prose-code:bg-[#F4F5F7] prose-code:px-1 prose-code:rounded
prose-pre:bg-[#F4F5F7] prose-pre:border prose-pre:border-[#DFE1E6] prose-pre:rounded">
<div className="px-6 py-5 prose prose-sm max-w-none text-[var(--c-text)]
prose-headings:text-[var(--c-text)] prose-headings:font-semibold prose-headings:border-b prose-headings:border-[var(--c-border)] prose-headings:pb-1
prose-a:text-[var(--c-brand)] prose-code:bg-[var(--c-surface-muted)] prose-code:px-1 prose-code:rounded
prose-pre:bg-[var(--c-surface-muted)] prose-pre:border prose-pre:border-[var(--c-border)] prose-pre:rounded">
<ReactMarkdown remarkPlugins={[remarkGfm]}>{blob.content}</ReactMarkdown>
</div>
) : (
@@ -184,10 +184,10 @@ export default function BlobPage() {
<tbody>
{lines.map((line, i) => (
<tr key={i} className="hover:bg-[#FFFBDD]">
<td className="select-none text-right text-[#5E6C84] px-4 py-0.5 w-12 border-r border-[#DFE1E6] bg-[#FAFBFC] sticky left-0">
<td className="select-none text-right text-[var(--c-muted)] px-4 py-0.5 w-12 border-r border-[var(--c-border)] bg-[var(--c-surface-raised)] sticky left-0">
{i + 1}
</td>
<td className="px-4 py-0.5 text-[#172B4D] whitespace-pre">{line || ' '}</td>
<td className="px-4 py-0.5 text-[var(--c-text)] whitespace-pre">{line || ' '}</td>
</tr>
))}
</tbody>