diff --git a/.gitignore b/.gitignore index 505a3b1..ba221af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -# Python-generated files __pycache__/ *.py[oc] build/ @@ -6,5 +5,5 @@ dist/ wheels/ *.egg-info -# Virtual environments .venv +public/fonts diff --git a/app.py b/app.py index 2ceaef1..dcddfbd 100644 --- a/app.py +++ b/app.py @@ -5,21 +5,17 @@ import os from dataclasses import dataclass from pathlib import Path -from flask import Flask, jsonify, render_template, send_from_directory, abort, request -from pygments import highlight -from pygments.formatters import HtmlFormatter -from pygments.lexers import TextLexer, get_lexer_for_filename -from pygments.util import ClassNotFound +from flask import Flask, abort, jsonify, render_template, request, send_from_directory app = Flask(__name__, static_folder=None) -GIT_REPO_PATH = str(Path.home() / "dev") -GIST_PATH = str(Path.home() / "gists") -EXPORT_MARKER = "readme.md" +git_repo_path = str(Path.home() / "dev") +gist_path = str(Path.home() / "gists") +export_marker = "readme.md" if getpass.getuser() == "apache": - GIT_REPO_PATH = "/srv/git" - GIST_PATH = "/srv/gists" - EXPORT_MARKER = "git-daemon-export-ok" + git_repo_path = "/srv/git" + gist_path = "/srv/gists" + export_marker = "git-daemon-export-ok" @dataclass @@ -33,11 +29,11 @@ class Repository: def get_repositories(): repositories = [] - if not os.path.exists(GIT_REPO_PATH): + if not os.path.exists(git_repo_path): return repositories - for item in os.listdir(GIT_REPO_PATH): - repo_path = os.path.join(GIT_REPO_PATH, item) + for item in os.listdir(git_repo_path): + repo_path = os.path.join(git_repo_path, item) if not os.path.isdir(repo_path): continue @@ -48,7 +44,7 @@ def get_repositories(): ): continue - exported = os.path.exists(os.path.join(repo_path, EXPORT_MARKER)) + exported = os.path.exists(os.path.join(repo_path, export_marker)) description = "No description available" description_file = os.path.join(repo_path, "description") @@ -82,6 +78,24 @@ def get_repositories(): return repositories +@app.route("/gist/") +def serve_gist(filename): + base = Path(gist_path).resolve() + target = (base / filename).resolve() + if base not in target.parents and base != target: + abort(404) + if not target.exists() or not target.is_file(): + abort(404) + + try: + content = target.read_text(encoding="utf-8") + except UnicodeDecodeError: + return "Binary file cannot be displayed", 400 + + ext = target.suffix.lstrip(".") or "plaintext" + return render_template("gist.html", filename=filename, code=content, lang=ext) + + @app.route("/") def index(): repositories = [repo for repo in get_repositories() if repo.exported] @@ -98,43 +112,6 @@ def serve_scripts(filename): return send_from_directory("scripts", filename) -@app.route("/gist/") -def serve_gist(filename): - base = Path(GIST_PATH).resolve() - target = (base / filename).resolve() - if base not in target.parents and base != target: - abort(404) - - if not target.exists() or not target.is_file(): - abort(404) - - try: - content = target.read_text(encoding="utf-8") - except UnicodeDecodeError: - return "Binary file cannot be displayed", 400 - except OSError: - abort(404) - - try: - lexer = get_lexer_for_filename(target.name) - except ClassNotFound: - lexer = TextLexer() - - formatter = HtmlFormatter( - style="default", - cssclass="highlight", - linenos=False, - noclasses=True, - cssstyles="padding: 20px; font-size: 18px; background-color: #f8f8f8;", - ) - highlighted = highlight(content, lexer, formatter) - highlighted = highlighted.replace( - '', '' - ) - - return render_template("gist.html", filename=filename, highlighted_code=highlighted) - - @app.route("/") def serve_gist_root(filename): head = filename.split("/", 1)[0] @@ -166,4 +143,3 @@ def get_repo(repo_id): if __name__ == "__main__": app.run(host="0.0.0.0", port=5000, debug=True) - diff --git a/file b/file deleted file mode 100644 index e69de29..0000000 diff --git a/pyproject.toml b/pyproject.toml index c31394d..1fc734e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,5 +7,4 @@ requires-python = ">=3.11" dependencies = [ "flask>=3.1.1", "gunicorn>=23.0.0", - "pygments>=2.19.1", ] diff --git a/readme.md b/readme.md index 190159e..8ee9215 100644 --- a/readme.md +++ b/readme.md @@ -1,3 +1,7 @@ # git server ui the ui for my git server. + +## Deprecation Notice + +Go to barrettruth.com/git instead. diff --git a/scripts/index.js b/scripts/index.js index bcba2d6..ce15189 100644 --- a/scripts/index.js +++ b/scripts/index.js @@ -61,7 +61,7 @@ function renderRepoDescription(repoLink) { const cloneUrl = document.createElement("div"); cloneUrl.style.marginTop = "15px"; - cloneUrl.innerHTML = `git clone https://git.barrettruth.com/git/${repoName}.git`; + cloneUrl.innerHTML = `git clone git@git.barrettruth.com:${repoName}.git`; post.appendChild(cloneUrl); diff --git a/styles/common.css b/styles/common.css index 865d47e..02a8d3d 100644 --- a/styles/common.css +++ b/styles/common.css @@ -1,4 +1,33 @@ -/* Fonts will be loaded from system */ +@font-face { + font-family: "Apercu Mono Pro"; + src: url("/public/fonts/apercu-mono/ApercuMonoProRegular.ttf") + format("truetype"); + font-weight: 400; + font-style: normal; +} + +@font-face { + font-family: "Apercu Mono Pro"; + src: url("/public/fonts/apercu-mono/ApercuMonoProMedium.ttf") + format("truetype"); + font-weight: 500; + font-style: normal; +} + +@font-face { + font-family: "Apercu Mono Pro"; + src: url("/public/fonts/apercu-mono/ApercuMonoProLight.ttf") + format("truetype"); + font-weight: 300; + font-style: normal; +} + +@font-face { + font-family: "Apercu Mono Pro"; + src: url("/public/fonts/apercu-mono/ApercuMonoProBold.ttf") format("truetype"); + font-weight: 700; + font-style: normal; +} html, body { @@ -50,11 +79,10 @@ li { font-family: "Courier New", monospace; } -/* Code styling */ :not(pre) > code { font-family: "Courier New", Courier, monospace; margin: 0 5px; - font-size: 0.8em; /* Match the font size in barrettruth.com */ + font-size: 0.8em; white-space: nowrap; border: 1px solid #e1e1e1; background-color: #f4f4f4; @@ -64,3 +92,44 @@ li { max-width: 100%; user-select: all; } + +pre code { + font-family: "Apercu Mono Pro", "Courier New", monospace; + font-size: 0.95rem; + line-height: 1.5; + background: transparent; + white-space: pre; + overflow-x: auto; +} + +.hljs-ln-numbers { + text-align: right; + color: #999; + border-right: 1em solid #ffffff; + user-select: none; +} + +main h2 { + margin-bottom: 0; +} + +.gist-outer { + display: flex; + justify-content: center; +} + +.gist-box { + display: inline-block; + min-width: 60vw; + max-width: 80vw; + width: max-content; + border: 1px solid #000; + border-radius: 0; + background: #fff; + box-sizing: border-box; +} + +.hljs-ln-numbers { + text-align: right; + color: #999; +} diff --git a/styles/index.css b/styles/index.css index c9445c8..0743fd3 100644 --- a/styles/index.css +++ b/styles/index.css @@ -109,3 +109,4 @@ a { margin-top: 10px; font-size: 0.7em; } + diff --git a/templates/gist.html b/templates/gist.html index 06b02e6..4c730e0 100644 --- a/templates/gist.html +++ b/templates/gist.html @@ -7,17 +7,55 @@ + + + {{ filename }} -
-

{{ filename }}

-
- {{ highlighted_code|safe }} + +
+

+ {{ filename }} +

+ +
+
+
{{ code | e }}
+
+ + + + + + + diff --git a/uv.lock b/uv.lock index 6195cbc..2ed07f6 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11" [[package]] @@ -56,14 +56,12 @@ source = { virtual = "." } dependencies = [ { name = "flask" }, { name = "gunicorn" }, - { name = "pygments" }, ] [package.metadata] requires-dist = [ { name = "flask", specifier = ">=3.1.1" }, { name = "gunicorn", specifier = ">=23.0.0" }, - { name = "pygments", specifier = ">=2.19.1" }, ] [[package]] @@ -156,15 +154,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - [[package]] name = "werkzeug" version = "3.1.3"