From fb4dc0ca40de143ac92f73936b60d7679c8337f7 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Thu, 7 May 2026 20:28:07 +0200 Subject: Initial commit: cgit theme for danix.xyz Co-Authored-By: Claude Sonnet 4.6 --- .gitignore | 3 + CLAUDE.md | 70 +++ cgit.css | 1304 +++++++++++++++++++++++++++++++++++++++++++++++++++ cgitrc.example | 49 ++ footer.html | 4 + head.html | 4 + images/favicon.png | Bin 0 -> 45033 bytes images/lampD.png | Bin 0 -> 45033 bytes syntax-highlight.py | 67 +++ 9 files changed, 1501 insertions(+) create mode 100644 .gitignore create mode 100644 CLAUDE.md create mode 100644 cgit.css create mode 100644 cgitrc.example create mode 100644 footer.html create mode 100644 head.html create mode 100644 images/favicon.png create mode 100644 images/lampD.png create mode 100755 syntax-highlight.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b3da30f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.claude/ +.superpowers/ +docs/ diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..3f6a636 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,70 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What This Is + +A custom cgit theme for git.danix.xyz. cgit is a static-feeling git web frontend written in C that generates HTML server-side. This repo contains the theme files only — no build step, no package manager. + +## Files + +- `cgit.css` — main stylesheet; covers all cgit page types +- `head.html` — injected into cgit's ``: font imports + CSS link +- `footer.html` — injected as cgit's footer +- `syntax-highlight.py` — cgit `source-filter` script; Pygments-based, must stay executable (`chmod +x`) +- `images/lampD.png` — logo (sourced from `../danix.xyz-hacker-theme/static/images/`) +- `cgitrc.example` — deployment reference; not used at runtime + +## Design System + +Colors, fonts, and token colors are derived from `../danix2-hugo-theme/assets/css/main.css` and `../danix2-hugo-theme/assets/css/chroma-custom.css`. Do not introduce colors or fonts that aren't in those files. + +| Role | Value | +|------|-------| +| `--bg` | `#060b10` | +| `--accent` | `#a855f7` | +| `--accent2` | `#00ff88` | +| `--text` | `#c4d6e8` | +| Headings | Oxanium | +| Prose | IBM Plex Sans | +| Code/hashes/filenames | JetBrains Mono | +| Syntax tokens | Catppuccin Macchiato | + +## cgit HTML Selectors (critical) + +cgit generates fixed HTML. Key selectors used in `cgit.css`: + +| Element | Selector | +|---------|----------| +| Outer wrapper | `div#cgit` | +| Header table | `table#header` | +| Logo cell | `td.logo` | +| Site name cell | `td.main` | +| Nav tabs | `table.tabs` | +| Breadcrumb | `div.path` | +| Main content | `div.content` | +| All list tables | `table.list` | +| Section header rows | `tr.nohover-highlight td.reposection` | +| Repo name cells | `td.toplevel-repo`, `td.sublevel-repo` | +| Diff table | `table.diff` | +| Diff added rows | `tr.add` / `td.add` | +| Diff removed rows | `tr.del` / `td.del` | +| Hunk headers | `div.hunk` | +| Blob table | `table.blob` | +| Line number cell | `td.linenumbers` | +| Code cell | `td.lines` | +| Footer | `div.footer` | + +If cgit's generated markup ever differs (version-dependent), inspect the live HTML first before changing selectors. + +## Syntax Highlighting + +`syntax-highlight.py` is a cgit `source-filter`. cgit calls it as: +``` +syntax-highlight.py +``` +File content arrives on stdin; highlighted HTML goes to stdout. Requires `pygments` installed on the server (`pip install pygments`). Token CSS classes (`.highlight .k`, `.highlight .s`, etc.) are styled in `cgit.css` using Catppuccin Macchiato colors — do not switch to inline styles. + +## Deployment + +Theme files are served statically at `/cgit-theme/`. The cgit process reads them from disk (filesystem paths in `cgitrc`). See `cgitrc.example` for the full wiring. Repo categories come from `section=` directives in `cgitrc` — the CSS renders them as `# category` headings via `td.reposection::before`. diff --git a/cgit.css b/cgit.css new file mode 100644 index 0000000..de2e078 --- /dev/null +++ b/cgit.css @@ -0,0 +1,1304 @@ +/* ============================================================= + cgit-theme-danix + Design system: danix.xyz / danix2-hugo-theme + ============================================================= */ + +/* ---- Custom properties ---- */ +:root { + --bg: #060b10; + --bg2: #0c1520; + --bg2-rgb: 12, 21, 32; + --surface: #101e2d; + --border: #182840; + --accent: #a855f7; + --accent-rgb: 168, 85, 247; + --accent2: #00ff88; + --text: #c4d6e8; + --text-dim: #7a9bb8; + --muted: #304860; + --diff-add-bg: rgba(166, 218, 149, 0.08); + --diff-add-ln: rgba(166, 218, 149, 0.06); + --diff-del-bg: rgba(237, 135, 150, 0.08); + --diff-del-ln: rgba(237, 135, 150, 0.06); + --diff-hunk-bg: rgba(168, 85, 247, 0.06); + --diff-add-text: #a6da95; + --diff-del-text: #ed8796; + + /* Catppuccin Macchiato syntax token colors */ + --ctp-mauve: #c6a0f6; + --ctp-green: #a6da95; + --ctp-peach: #f5a97f; + --ctp-overlay: #6e738d; + --ctp-blue: #8aadf4; + --ctp-sky: #91d7e3; + --ctp-yellow: #eed49f; + --ctp-pink: #f5bde6; + --ctp-maroon: #ee99a0; + --ctp-red: #ed8796; + --ctp-teal: #8bd5ca; + --ctp-text: #cad3f5; +} + +/* ---- Reset & base ---- */ +*, *::before, *::after { + box-sizing: border-box; +} + +html { + overflow-x: hidden; +} + +body { + background-color: var(--bg); + color: var(--text); + font-family: 'IBM Plex Sans', sans-serif; + font-size: 16px; + line-height: 1.7; + margin: 0; + padding: 0; + overflow-x: hidden; +} + +a { + color: var(--accent); + text-decoration: none; +} + +a:hover { + opacity: 0.8; +} + +img { + max-width: 100%; +} + +/* ---- Outer wrapper ---- */ +div#cgit { + min-height: 100vh; + display: flex; + flex-direction: column; +} + +/* ============================================================= + HEADER + ============================================================= */ + +table#header { + width: 100%; + position: sticky; + top: 0; + z-index: 100; + background: rgba(var(--bg2-rgb), 0.88); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + border-bottom: 1px solid var(--border); + box-shadow: 0 0 20px rgba(var(--accent-rgb), 0.08); + border-collapse: collapse; + padding: 0 32px; +} + +table#header td { + padding: 14px 8px; + vertical-align: middle; + border: none; + background: transparent; +} + +table#header td.logo { + padding-left: 32px; + width: 1%; + white-space: nowrap; +} + +table#header td.logo a { + display: block; +} + +table#header td.logo img { + height: 40px; + width: 40px; + min-width: 40px; + display: block; +} + +table#header td.main { + padding-left: 16px; +} + +table#header td.main a { + font-family: 'Oxanium', monospace; + font-weight: 700; + font-size: 22px; + color: var(--accent); + letter-spacing: 0.03em; + text-decoration: none; +} + +table#header td.main a:hover { + opacity: 0.85; +} + +table#header td.sub { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + padding-left: 24px; +} + +table#header td.sub a { + color: var(--text-dim); +} + +table#header td.form { + text-align: right; + padding-right: 32px; + width: 1%; + white-space: nowrap; +} + +/* Search form in header */ +table#header td.form form { + display: flex; + align-items: center; + gap: 8px; +} + +table#header td.form input[type="text"], +table#header td.form input[name="q"] { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 4px; + padding: 6px 12px; + color: var(--text); + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + width: 200px; + outline: none; + transition: border-color 0.15s; +} + +table#header td.form input[type="text"]:focus, +table#header td.form input[name="q"]:focus { + border-color: rgba(var(--accent-rgb), 0.5); +} + +table#header td.form input[type="text"]::placeholder, +table#header td.form input[name="q"]::placeholder { + color: var(--text-dim); +} + +table#header td.form input[type="submit"], +table#header td.form button { + background: var(--accent); + color: #fff; + border: none; + border-radius: 4px; + padding: 6px 12px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 13px; + cursor: pointer; + transition: opacity 0.15s; +} + +table#header td.form input[type="submit"]:hover, +table#header td.form button:hover { + opacity: 0.85; +} + +table#header td.form select { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 4px; + padding: 6px 8px; + color: var(--text); + font-family: 'IBM Plex Sans', sans-serif; + font-size: 13px; + outline: none; +} + +/* ============================================================= + NAVIGATION TABS + ============================================================= */ + +table.tabs { + width: 100%; + border-collapse: collapse; + border-bottom: 1px solid var(--border); + background: var(--bg2); +} + +table.tabs td, +table.tabs th { + padding: 0; + border: none; + background: transparent; +} + +table.tabs tr > td:first-child, +table.tabs tr > th:first-child { + padding-left: 32px; +} + +table.tabs td a, +table.tabs th a { + display: inline-block; + padding: 10px 20px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 15px; + color: var(--text-dim); + text-decoration: none; + border-bottom: 2px solid transparent; + transition: color 0.15s, border-color 0.15s; +} + +table.tabs td a:hover, +table.tabs th a:hover { + color: var(--text); + opacity: 1; +} + +table.tabs td a.active, +table.tabs th a.active { + color: var(--accent); + border-bottom-color: var(--accent); + font-weight: 600; +} + +/* Right-aligned form in tabs (branch selector + index search) */ +table.tabs .right, +table.tabs td.form { + text-align: right; +} + +table.tabs .right form, +table.tabs td.form form { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 16px; + justify-content: flex-end; +} + +table.tabs .right select, +table.tabs .right input[type="text"], +table.tabs td.form select, +table.tabs td.form input[type="text"], +table.tabs td.form input[type="search"] { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 4px; + padding: 4px 8px; + color: var(--text); + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + outline: none; +} + +table.tabs .right input[type="submit"], +table.tabs td.form input[type="submit"] { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 4px; + padding: 4px 10px; + color: var(--text-dim); + font-family: 'IBM Plex Sans', sans-serif; + font-size: 12px; + cursor: pointer; + transition: border-color 0.15s, color 0.15s; +} + +table.tabs .right input[type="submit"]:hover, +table.tabs td.form input[type="submit"]:hover { + border-color: var(--accent); + color: var(--accent); +} + +/* ============================================================= + PATH BREADCRUMB + ============================================================= */ + +div.path { + padding: 10px 32px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + border-bottom: 1px solid var(--border); + background: var(--bg2); + display: flex; + align-items: center; + gap: 6px; + flex-wrap: wrap; +} + +div.path a { + color: var(--accent); + text-decoration: none; +} + +div.path a:hover { + opacity: 0.8; +} + +/* ============================================================= + MAIN CONTENT WRAPPER + ============================================================= */ + +div.content { + max-width: 980px; + margin: 0 auto; + padding: 32px 24px; + flex: 1; + width: 100%; +} + +/* ============================================================= + REPO LIST PAGE + ============================================================= */ + +table.list { + width: 100%; + border-collapse: collapse; +} + +table.list th { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 13px; + font-weight: 600; + color: var(--text-dim); + text-align: left; + padding: 8px 12px; + border-bottom: 2px solid var(--border); + background: transparent; + letter-spacing: 0.04em; + text-transform: uppercase; +} + +table.list th.left { + text-align: left; +} + +table.list th.right { + text-align: right; +} + +table.list tr { + border-bottom: 1px solid var(--border); + transition: background 0.1s; +} + +table.list tr:hover:not(.nohover):not(.nohover-highlight) { + background: rgba(var(--accent-rgb), 0.04); +} + +table.list td { + padding: 12px 12px; + vertical-align: middle; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 15px; + color: var(--text); + border: none; + background: transparent; +} + +/* Section/category header rows */ +table.list tr.nohover-highlight td, +table.list tr.nohover td.reposection { + background: transparent; + padding-top: 28px; + padding-bottom: 10px; + border-bottom: none; +} + +td.reposection { + font-family: 'JetBrains Mono', monospace !important; + font-size: 13px !important; + font-weight: 700 !important; + color: var(--accent) !important; + letter-spacing: 0.08em; + text-align: left !important; +} + +td.reposection::before { + content: '# '; + opacity: 0.6; +} + +/* Repo name cells */ +td.toplevel-repo, +td.sublevel-repo { + width: 22%; +} + +td.toplevel-repo a, +td.sublevel-repo a { + font-family: 'Oxanium', monospace; + font-weight: 600; + font-size: 17px; + color: var(--accent); + text-decoration: none; +} + +td.toplevel-repo a:hover, +td.sublevel-repo a:hover { + opacity: 0.8; +} + +/* Description column — full text color */ +table.list td:nth-child(2):not(.reposection) { + color: var(--text); + font-size: 15px; +} + +/* Age/date column */ +table.list td.age, +table.list td:last-child { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--muted); + white-space: nowrap; + text-align: right; +} + +/* Links column (summary/log/tree pills) */ +table.list td.link, +table.list td.ls-size { + text-align: right; + white-space: nowrap; +} + +table.list td.link a { + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + color: var(--text-dim); + border: 1px solid var(--border); + border-radius: 3px; + padding: 2px 7px; + margin-left: 4px; + text-decoration: none; + transition: border-color 0.15s, color 0.15s; +} + +table.list td.link a:hover { + border-color: var(--accent); + color: var(--accent); + opacity: 1; +} + +/* ============================================================= + REPO SUMMARY PAGE + ============================================================= */ + +div#summary { + margin-bottom: 24px; +} + +/* Summary info table (repo metadata card) */ +div#summary table.list { + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 6px; + overflow: hidden; + box-shadow: 0 0 20px rgba(var(--accent-rgb), 0.08); + margin-bottom: 20px; +} + +div#summary table.list th { + background: transparent; + font-size: 12px; + color: var(--text-dim); + text-transform: none; + letter-spacing: 0; + font-weight: 500; + padding: 10px 16px; + width: 140px; +} + +div#summary table.list td { + padding: 10px 16px; + font-size: 15px; +} + +/* Clone URL rows */ +div#summary table.list a[rel="vcs-git"] { + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + color: var(--accent2); + word-break: break-all; +} + +/* ============================================================= + FILE TREE PAGE + ============================================================= */ + +/* Directory links */ +a.ls-dir { + font-family: 'JetBrains Mono', monospace; + font-size: 14px; + color: var(--accent); + font-weight: 500; +} + +/* Blob/file links */ +a.ls-blob { + font-family: 'JetBrains Mono', monospace; + font-size: 14px; + color: var(--text); +} + +a.ls-blob:hover, +a.ls-dir:hover { + color: var(--accent); + opacity: 1; +} + +table.list td.ls-mode { + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + color: var(--muted); + width: 80px; +} + +table.list td.ls-size { + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + color: var(--text-dim); + text-align: right; + width: 80px; +} + +/* ============================================================= + COMMIT LOG PAGE + ============================================================= */ + +td.logsubject a, +table.list td a[href*="/commit/"] { + font-family: 'Oxanium', monospace; + font-weight: 600; + font-size: 16px; + color: var(--text); + text-decoration: none; +} + +td.logsubject a:hover, +table.list td a[href*="/commit/"]:hover { + color: var(--accent); + opacity: 1; +} + +/* Commit hash links */ +table.list td a[href*="id="], +table.list td.logsubject + td a { + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + color: var(--accent2); +} + +/* Author column */ +table.list td.author { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + white-space: nowrap; +} + +/* Insertions/deletions */ +span.insertions { + color: var(--diff-add-text); + font-family: 'JetBrains Mono', monospace; + font-size: 12px; +} + +span.deletions { + color: var(--diff-del-text); + font-family: 'JetBrains Mono', monospace; + font-size: 12px; +} + +/* Branch/tag decorations */ +span.decoration { + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + padding: 1px 5px; + border-radius: 3px; + margin-left: 6px; +} + +span.branch-deco { + background: rgba(var(--accent-rgb), 0.15); + color: var(--accent); + border: 1px solid rgba(var(--accent-rgb), 0.3); +} + +span.tag-deco, +span.tag-annotated-deco { + background: rgba(0, 255, 136, 0.12); + color: var(--accent2); + border: 1px solid rgba(0, 255, 136, 0.3); +} + +span.remote-deco { + background: rgba(56, 189, 248, 0.12); + color: #38bdf8; + border: 1px solid rgba(56, 189, 248, 0.3); +} + +/* ============================================================= + COMMIT DIFF PAGE + ============================================================= */ + +/* Commit info header */ +div.commit-info, +table.commit-info { + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 6px; + padding: 16px 20px; + margin-bottom: 16px; + box-shadow: 0 0 20px rgba(var(--accent-rgb), 0.06); +} + +div.commit-info td, +table.commit-info td { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + padding: 4px 8px; + border: none; + background: transparent; +} + +div.commit-info td.sha1, +table.commit-info td.sha1 { + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + color: var(--accent2); +} + +/* Diffstat header */ +div.diffstat-header { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + padding: 10px 16px; + border-bottom: 1px solid var(--border); + background: var(--bg2); + border-radius: 6px 6px 0 0; + border: 1px solid var(--border); + border-bottom: none; + margin-top: 16px; +} + +div.diffstat-header a { + color: var(--accent); + font-family: 'JetBrains Mono', monospace; + font-size: 13px; +} + +/* Diffstat table */ +table.diffstat { + width: 100%; + border-collapse: collapse; + border: 1px solid var(--border); + margin-bottom: 0; +} + +table.diffstat td { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 13px; + padding: 6px 12px; + border-bottom: 1px solid var(--border); + background: var(--surface); + color: var(--text-dim); +} + +table.diffstat td a { + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + color: var(--accent); +} + +table.diffstat td.add { color: var(--diff-add-text); } +table.diffstat td.del { color: var(--diff-del-text); } + +/* Diffstat graph bar */ +table.diffstat td div.bar { + display: inline-block; + height: 8px; + border-radius: 2px; +} + +div.diffstat-summary { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 13px; + color: var(--text-dim); + padding: 8px 12px; + background: var(--surface); + border: 1px solid var(--border); + border-top: none; + border-radius: 0 0 6px 6px; + margin-bottom: 20px; +} + +/* Diff header (filename bar) */ +div.head { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 6px 6px 0 0; + padding: 8px 16px; + margin-top: 20px; + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + color: var(--text-dim); + display: flex; + gap: 16px; + align-items: center; +} + +div.head a { + color: var(--accent); + font-weight: 600; +} + +/* Unified diff table */ +table.diff { + width: 100%; + border-collapse: collapse; + border: 1px solid var(--border); + border-top: none; + border-radius: 0 0 6px 6px; + overflow: hidden; + margin-bottom: 20px; + font-family: 'JetBrains Mono', monospace; + font-size: 14px; + line-height: 1.7; +} + +table.diff td { + padding: 0; + vertical-align: top; + white-space: pre; + border: none; +} + +table.diff td.linenum { + background: var(--surface); + color: var(--muted); + padding: 0 12px; + text-align: right; + user-select: none; + -webkit-user-select: none; + min-width: 50px; + border-right: 1px solid var(--border); + font-size: 12px; +} + +table.diff td.linenum a { + color: var(--muted); + text-decoration: none; +} + +table.diff td.linenum a:hover { + color: var(--accent); + opacity: 1; +} + +table.diff td.lines { + padding: 0 16px; + width: 100%; + color: var(--text); +} + +/* Added lines */ +table.diff tr.add, +table.diff td.add { + background: var(--diff-add-bg); + color: var(--diff-add-text); +} + +table.diff tr.add td.linenum, +table.diff td.add.linenum { + background: var(--diff-add-ln); + color: var(--diff-add-text); + opacity: 0.7; +} + +/* Removed lines */ +table.diff tr.del, +table.diff td.del { + background: var(--diff-del-bg); + color: var(--diff-del-text); +} + +table.diff tr.del td.linenum, +table.diff td.del.linenum { + background: var(--diff-del-ln); + color: var(--diff-del-text); + opacity: 0.7; +} + +/* Hunk headers (@@ lines) */ +div.hunk, +table.diff tr.hunk, +table.diff td.hunk { + background: var(--diff-hunk-bg); + color: var(--muted); + font-style: italic; +} + +/* Context lines */ +table.diff tr.ctx td, +table.diff td.ctx { + color: var(--text); +} + +/* ============================================================= + FILE BLOB PAGE + ============================================================= */ + +table.blob { + width: 100%; + border-collapse: collapse; + border: 1px solid var(--border); + border-radius: 6px; + overflow: hidden; + font-family: 'JetBrains Mono', monospace; + font-size: 14px; + line-height: 1.8; +} + +table.blob td { + padding: 0; + vertical-align: top; + border: none; +} + +/* Line number column */ +td.linenumbers { + background: var(--surface); + color: var(--muted); + text-align: right; + user-select: none; + -webkit-user-select: none; + border-right: 1px solid var(--border); + width: 1%; + white-space: nowrap; + vertical-align: top; +} + +td.linenumbers a { + display: block; + padding: 0 14px; + color: var(--muted); + text-decoration: none; + font-size: 13px; + line-height: 1.8; +} + +td.linenumbers a:hover { + color: var(--accent); + opacity: 1; +} + +td.linenumbers a:target { + background: rgba(var(--accent-rgb), 0.1); + color: var(--accent); +} + +/* Code column */ +td.lines { + padding: 0; + width: 100%; +} + +td.lines pre, +td.lines pre code { + margin: 0; + padding: 0 16px; + background: transparent; + border: none; + font-family: 'JetBrains Mono', monospace; + font-size: 14px; + line-height: 1.8; + color: var(--text); + white-space: pre; + overflow-x: auto; +} + +/* ============================================================= + PYGMENTS / SYNTAX HIGHLIGHTING (Catppuccin Macchiato) + ============================================================= */ + +/* Base highlight wrapper */ +.highlight, +.highlight pre { + background: transparent; + color: var(--ctp-text); +} + +/* Keywords */ +.highlight .k, +.highlight .kc, +.highlight .kd, +.highlight .kn, +.highlight .kp, +.highlight .kr, +.highlight .kt { + color: var(--ctp-mauve); + font-weight: 500; +} + +/* Strings */ +.highlight .s, +.highlight .sa, +.highlight .sb, +.highlight .sc, +.highlight .dl, +.highlight .sd, +.highlight .s1, +.highlight .s2, +.highlight .se, +.highlight .sh, +.highlight .si, +.highlight .sx, +.highlight .sr, +.highlight .ss { + color: var(--ctp-green); +} + +/* Numbers */ +.highlight .m, +.highlight .mb, +.highlight .mf, +.highlight .mh, +.highlight .mi, +.highlight .il, +.highlight .mo { + color: var(--ctp-peach); +} + +/* Comments */ +.highlight .c, +.highlight .c1, +.highlight .cm, +.highlight .cs, +.highlight .cp, +.highlight .cpf { + color: var(--ctp-overlay); + font-style: italic; +} + +/* Operators */ +.highlight .o, +.highlight .ow { + color: var(--ctp-sky); +} + +/* Names */ +.highlight .n { color: var(--ctp-text); } +.highlight .na { color: var(--ctp-yellow); } +.highlight .nb { color: var(--ctp-blue); } +.highlight .nc { color: var(--ctp-yellow); } +.highlight .nd { color: var(--ctp-pink); } +.highlight .ne { color: var(--ctp-maroon); } +.highlight .nf, +.highlight .fm { color: var(--ctp-blue); } +.highlight .ni { color: var(--ctp-text); } +.highlight .nl { color: var(--ctp-teal); } +.highlight .nn { color: var(--ctp-yellow); } +.highlight .nt { color: var(--ctp-mauve); } +.highlight .nv, +.highlight .vc, +.highlight .vg, +.highlight .vi { color: var(--ctp-text); } + +/* Punctuation */ +.highlight .p { color: var(--ctp-text); } + +/* Generic (diff tokens from Pygments) */ +.highlight .gd { + color: var(--ctp-red); + background: rgba(237, 135, 150, 0.1); +} +.highlight .gi { + color: var(--ctp-green); + background: rgba(166, 218, 149, 0.1); +} +.highlight .gh { + color: #b7bdf8; + font-weight: bold; +} +.highlight .gu { color: var(--ctp-overlay); } +.highlight .ge { font-style: italic; } +.highlight .gs { font-weight: bold; } + +/* Error */ +.highlight .err { color: var(--ctp-red); } + +/* ============================================================= + FOOTER + ============================================================= */ + +div.footer { + border-top: 1px solid var(--border); + background: rgba(var(--bg2-rgb), 0.6); + padding: 20px 32px; + margin-top: auto; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--muted); + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 8px; +} + +div.footer a { + color: var(--text-dim); + text-decoration: none; +} + +div.footer a:hover { + color: var(--accent); + opacity: 1; +} + +/* ============================================================= + PAGINATION + ============================================================= */ + +ul.pager { + list-style: none; + padding: 0; + margin: 24px 0 0; + display: flex; + gap: 8px; + align-items: center; +} + +ul.pager li a { + display: inline-block; + padding: 6px 14px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + border: 1px solid var(--border); + border-radius: 4px; + text-decoration: none; + transition: border-color 0.15s, color 0.15s; +} + +ul.pager li a:hover { + border-color: var(--accent); + color: var(--accent); + opacity: 1; +} + +/* ============================================================= + ERROR / NOTICES + ============================================================= */ + +div.error { + background: rgba(239, 68, 68, 0.08); + border: 1px solid rgba(239, 68, 68, 0.3); + border-left: 4px solid #ef4444; + border-radius: 4px; + padding: 12px 16px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 15px; + color: #ef4444; + margin: 16px 0; +} + +/* ============================================================= + CGIT PANEL (view controls) + ============================================================= */ + +div.cgit-panel { + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 4px; + padding: 8px 14px; + margin-bottom: 16px; + display: flex; + gap: 12px; + align-items: center; + flex-wrap: wrap; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 13px; + color: var(--text-dim); +} + +div.cgit-panel select, +div.cgit-panel input[type="text"] { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 3px; + padding: 4px 8px; + color: var(--text); + font-family: 'JetBrains Mono', monospace; + font-size: 12px; + outline: none; +} + +div.cgit-panel input[type="submit"] { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 3px; + padding: 4px 10px; + color: var(--text-dim); + font-family: 'IBM Plex Sans', sans-serif; + font-size: 12px; + cursor: pointer; + transition: border-color 0.15s, color 0.15s; +} + +div.cgit-panel input[type="submit"]:hover { + border-color: var(--accent); + color: var(--accent); +} + +/* ============================================================= + MISC + ============================================================= */ + +/* Binary blob */ +table.bin-blob { + border: 1px solid var(--border); + border-radius: 6px; + padding: 16px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); +} + +/* Commit log message rows */ +td.logmsg { + font-family: 'IBM Plex Sans', sans-serif; + font-size: 14px; + color: var(--text-dim); + padding: 4px 12px 12px !important; + white-space: pre-wrap; +} + +/* About page / README */ +div#readme { + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 6px; + padding: 24px 28px; + margin-top: 20px; + font-family: 'IBM Plex Sans', sans-serif; + font-size: 15px; + line-height: 1.75; + color: var(--text); +} + +div#readme h1, +div#readme h2, +div#readme h3, +div#readme h4 { + font-family: 'Oxanium', monospace; + color: var(--text); + margin-top: 1.5em; + margin-bottom: 0.5em; +} + +div#readme h1 { font-size: 26px; border-bottom: 1px solid var(--border); padding-bottom: 8px; } +div#readme h2 { font-size: 20px; } +div#readme h3 { font-size: 17px; } + +div#readme a { color: var(--accent); } + +div#readme code { + font-family: 'JetBrains Mono', monospace; + font-size: 13px; + background: var(--surface); + border: 1px solid var(--border); + border-radius: 3px; + padding: 1px 5px; + color: var(--accent2); +} + +div#readme pre { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 6px; + padding: 16px; + overflow-x: auto; +} + +div#readme pre code { + background: transparent; + border: none; + padding: 0; + color: var(--text); + font-size: 13px; +} + +div#readme blockquote { + border-left: 4px solid var(--accent); + margin: 16px 0; + padding: 8px 16px; + background: rgba(var(--accent-rgb), 0.06); + color: var(--text-dim); +} + +/* Tag list / refs */ +table.list td a[href*="/tag/"], +table.list td a[href*="/refs/"] { + font-family: 'JetBrains Mono', monospace; + font-size: 13px; +} + +/* Responsive: smaller viewports */ +@media (max-width: 768px) { + div.content { + padding: 20px 16px; + } + + table#header { + padding: 0 16px; + } + + table#header td.logo { + padding-left: 16px; + } + + table#header td.main a { + font-size: 18px; + } + + table#header td.form { + display: none; + } + + div.path { + padding: 8px 16px; + } + + div.footer { + padding: 16px; + flex-direction: column; + align-items: flex-start; + gap: 4px; + } + + table.diff, + table.blob { + font-size: 12px; + } + + td.toplevel-repo a, + td.sublevel-repo a { + font-size: 15px; + } +} + +/* Respect motion preferences */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + } +} diff --git a/cgitrc.example b/cgitrc.example new file mode 100644 index 0000000..fba2002 --- /dev/null +++ b/cgitrc.example @@ -0,0 +1,49 @@ +# cgitrc.example — cgit-theme-danix +# +# Copy relevant lines into your /etc/cgitrc or ~/.cgitrc. +# Adjust paths to match where you deployed the theme files. +# +# Assumed deployment path: /usr/share/cgit/cgit-theme-danix/ +# Assumed web-accessible path: /cgit-theme/ + +# ---- Theme ---- +css=/cgit-theme/cgit.css +favicon=/cgit-theme/images/favicon.png +logo=/cgit-theme/images/lampD.png +logo-link=https://danix.xyz +head-include=/var/www/cgit-theme-danix/head.html +footer=/usr/share/cgit/cgit-theme-danix/footer.html +source-filter=/usr/share/cgit/cgit-theme-danix/syntax-highlight.py + +# ---- Site settings ---- +root-title=git.danix.xyz +root-desc=personal git repositories +enable-index-links=1 +enable-index-owner=0 +enable-log-filecount=1 +enable-log-linecount=1 +max-stats=quarter +snapshots=tar.gz zip + +# ---- Repo grouping ---- +# Use section= before each repo to create categories. +# These map to the "# category" headings in the theme. + +section=web +repo.url=danix2-hugo-theme +repo.path=/srv/git/danix2-hugo-theme.git +repo.desc=Hugo theme for danix.xyz + +repo.url=cgit-theme-danix +repo.path=/srv/git/cgit-theme-danix.git +repo.desc=Custom cgit theme matching danix.xyz design system + +section=tools +repo.url=dotfiles +repo.path=/srv/git/dotfiles.git +repo.desc=Shell configs, neovim setup, system dotfiles + +section=configs +repo.url=nixos-config +repo.path=/srv/git/nixos-config.git +repo.desc=NixOS system configuration diff --git a/footer.html b/footer.html new file mode 100644 index 0000000..fd92532 --- /dev/null +++ b/footer.html @@ -0,0 +1,4 @@ + diff --git a/head.html b/head.html new file mode 100644 index 0000000..a6e0c46 --- /dev/null +++ b/head.html @@ -0,0 +1,4 @@ + + + + diff --git a/images/favicon.png b/images/favicon.png new file mode 100644 index 0000000..d348983 Binary files /dev/null and b/images/favicon.png differ diff --git a/images/lampD.png b/images/lampD.png new file mode 100644 index 0000000..d348983 Binary files /dev/null and b/images/lampD.png differ diff --git a/syntax-highlight.py b/syntax-highlight.py new file mode 100755 index 0000000..e7a8ad4 --- /dev/null +++ b/syntax-highlight.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +""" +cgit source-filter: syntax highlighting via Pygments (Catppuccin Macchiato). + +cgit passes the filename as argv[1] and the file content on stdin. +Output is HTML written to stdout. +""" + +import sys +import os + +try: + from pygments import highlight + from pygments.lexers import get_lexer_for_filename, TextLexer + from pygments.formatters import HtmlFormatter + from pygments.util import ClassNotFound + PYGMENTS_AVAILABLE = True +except ImportError: + PYGMENTS_AVAILABLE = False + + +def get_lexer(filename): + try: + return get_lexer_for_filename(filename, stripnl=False, ensurenl=False) + except ClassNotFound: + return TextLexer(stripnl=False, ensurenl=False) + + +def main(): + filename = sys.argv[1] if len(sys.argv) > 1 else "" + + data = sys.stdin.buffer.read() + + # Try UTF-8, fall back to latin-1 to avoid decode errors on binary-ish files + try: + text = data.decode("utf-8") + except UnicodeDecodeError: + try: + text = data.decode("latin-1") + except UnicodeDecodeError: + # Give up and emit as plain text + sys.stdout.write("
" + data.decode("ascii", errors="replace") + "
") + return + + if not PYGMENTS_AVAILABLE or not filename: + sys.stdout.write("
" + text.replace("&", "&").replace("<", "<").replace(">", ">") + "
") + return + + lexer = get_lexer(filename) + + formatter = HtmlFormatter( + style="monokai", # base style; token colors overridden by CSS + nowrap=True, # no wrapping
+ cssclass="highlight", + noclasses=False, # use CSS classes, not inline styles + ) + + highlighted = highlight(text, lexer, formatter) + + # Wrap in pre so cgit's blob table renders it correctly + sys.stdout.write('
')
+    sys.stdout.write(highlighted)
+    sys.stdout.write("
") + + +if __name__ == "__main__": + main() -- cgit v1.2.3