Gitfed
bastien-mrq/gitfed/ Commits/ b51f291

Fix repo action bar breaking on real (long) domains

HTTPS and SSH clone boxes were each their own flex:1 element competing for room in the same row as branch/Commits/Merge requests/Settings — fine with "localhost" in local testing, but git.neuromancer.ovh wrapped mid-URL. Regrouped into one compact clone box with an HTTPS/SSH toggle (reuses the existing generic [data-tab]/.gf-tabs/.gf-tabpane JS from the settings page, just restyled), separate from the actions row. Verified against the exact real-world conditions that broke it: took the rendered page and substituted the actual production domain back in, confirmed it now fits on one line instead of wrapping.

bastien-mrq 2026-07-28 23:47 commit b51f291cedbdb56b37513a83b5ed94bed74c94d1 parent 3c251ab7a0c25f3a21385c17c8eb907ff12911e1
3 files changed +41 −21
M CHANGELOG.md +4 −0
M cmd/gitfed-web/handlers_repo.go +23 −10
M cmd/gitfed-web/render.go +14 −11
CHANGELOG.md
diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c0249f..1299a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.0.1 + +- Fixed the repo page's action bar breaking on real (long) domains: the HTTPS and SSH clone boxes were each their own `flex: 1` box competing for room in the same row as the branch/Commits/Merge requests/Settings buttons, so a real hostname wrapped mid-URL instead of eliding cleanly. Regrouped into one compact clone box with an HTTPS/SSH toggle (reusing the same tab-switching JS as the settings page), separate from the row of action buttons. Found on the live instance right after making its own repo public — the first time a public, non-empty, admin-visible repo with a real long domain had ever actually rendered this bar. + ## 1.0.0 First stable release. Federated SSH-certificate identity, per-repo/per-role ACLs, a self-service web UI (repo browser, commit history and detail, merge requests with review and a real server-side merge, pinned repos, federated notifications), anonymous read-only HTTPS clone for public repos, and a documented backup/restore procedure — see `README.md` for the full picture and `ROADMAP.md` for what was deliberately left out and why.
cmd/gitfed-web/handlers_repo.go
diff --git a/cmd/gitfed-web/handlers_repo.go b/cmd/gitfed-web/handlers_repo.go index eb3a5f5..5940dcc 100644 --- a/cmd/gitfed-web/handlers_repo.go +++ b/cmd/gitfed-web/handlers_repo.go @@ -106,25 +106,38 @@ var repoTpl = newTpl("repo", ` </div> <p class="muted">{{t .Lang "repo.owner"}}: {{.Repo.Owner}}</p> -<div class="gf-action-bar"> +<div class="gf-actions-row"> {{if .Branch}}<span class="gf-btn">{{icon "branch"}} {{.Branch}}</span>{{end}} - {{if .Repo.Public}} - <div class="gf-clone-url"> - <span class="gf-clone-label">HTTPS</span> + {{if not .Empty}}<a href="/repo-commits/{{.Repo.Name}}" class="gf-btn">{{icon "history"}} {{t .Lang "repo.commits_title"}}</a>{{end}} + {{if not .Empty}}<a href="/repo-mrs/{{.Repo.Name}}" class="gf-btn">{{icon "branch"}} {{t .Lang "mr.list_title"}}</a>{{end}} + {{if .CanAdminister}}<a href="/repo-settings/{{.Repo.Name}}" class="gf-btn">{{t .Lang "nav.settings"}}</a>{{end}} +</div> + +{{if .Repo.Public}} +<div class="gf-clone-block"> + <div class="gf-tabs gf-clone-toggle"> + <button type="button" data-tab="clone-https" class="active">HTTPS</button> + <button type="button" data-tab="clone-ssh">SSH</button> + </div> + <div id="clone-https" class="gf-tabpane gf-clone-row active"> <span class="badge plain" title="{{t .Lang "repo.https_readonly_hint"}}">{{t .Lang "repo.read_only"}}</span> <code>{{.HTTPSCloneURL}}</code> <button type="button" class="linklike" data-copy="{{.HTTPSCloneURL}}" title="{{t .Lang "repo.copy_clone_url"}}" aria-label="{{t .Lang "repo.copy_clone_url"}}">{{icon "copy"}}</button> </div> - {{end}} - <div class="gf-clone-url"> - <span class="gf-clone-label">SSH</span> + <div id="clone-ssh" class="gf-tabpane gf-clone-row"> + <code>{{.CloneURL}}</code> + <button type="button" class="linklike" data-copy="{{.CloneURL}}" title="{{t .Lang "repo.copy_clone_url"}}" aria-label="{{t .Lang "repo.copy_clone_url"}}">{{icon "copy"}}</button> + </div> +</div> +{{else}} +<div class="gf-clone-block single"> + <div class="gf-clone-row"> + <span class="label">SSH</span> <code>{{.CloneURL}}</code> <button type="button" class="linklike" data-copy="{{.CloneURL}}" title="{{t .Lang "repo.copy_clone_url"}}" aria-label="{{t .Lang "repo.copy_clone_url"}}">{{icon "copy"}}</button> </div> - {{if not .Empty}}<a href="/repo-commits/{{.Repo.Name}}" class="gf-btn">{{icon "history"}} {{t .Lang "repo.commits_title"}}</a>{{end}} - {{if not .Empty}}<a href="/repo-mrs/{{.Repo.Name}}" class="gf-btn">{{icon "branch"}} {{t .Lang "mr.list_title"}}</a>{{end}} - {{if .CanAdminister}}<a href="/repo-settings/{{.Repo.Name}}" class="gf-btn">{{t .Lang "nav.settings"}}</a>{{end}} </div> +{{end}} {{if .Crumbs}} <div class="gf-crumbs">
cmd/gitfed-web/render.go
diff --git a/cmd/gitfed-web/render.go b/cmd/gitfed-web/render.go index 49efd4f..35ec9be 100644 --- a/cmd/gitfed-web/render.go +++ b/cmd/gitfed-web/render.go @@ -323,17 +323,20 @@ const shellHeadSrc = `<!doctype html> .gf-crumbs .sep { color: var(--text-faint); margin: 0 0.35em; } .gf-repo-head { display: flex; align-items: center; gap: 0.55rem; flex-wrap: wrap; margin-top: 0.6rem; } .gf-repo-head h1 { font-size: 1.3rem; margin: 0; font-weight: 700; } - .gf-action-bar { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 1rem 0; } - .gf-action-bar .gf-btn, .gf-action-bar .gf-clone-url { margin-top: 0; } - .gf-clone-url { - flex: 1; min-width: 200px; font-family: var(--mono); font-size: 0.8rem; color: var(--text-dim); - background: var(--surface-2); border: 1px solid var(--border); border-radius: 7px; padding: 0.4rem 0.7rem; - display: flex; align-items: center; gap: 0.5rem; overflow: hidden; - } - .gf-clone-label { flex-shrink: 0; font-family: var(--mono); font-size: 0.68rem; font-weight: 700; letter-spacing: 0.03em; color: var(--text-faint); } - .gf-clone-url code { background: none; padding: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - .gf-clone-url button { margin: 0 0 0 auto; padding: 0; background: none; border: none; color: var(--text-faint); cursor: pointer; flex-shrink: 0; font-size: 0.95rem; } - .gf-clone-url button:hover { color: var(--text); } + .gf-actions-row { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin: 1rem 0 0.7rem; } + .gf-actions-row .gf-btn { margin-top: 0; } + + .gf-clone-block { background: var(--surface-2); border: 1px solid var(--border); border-radius: 9px; overflow: hidden; margin-bottom: 1.25rem; max-width: 560px; } + .gf-clone-block .gf-tabs.gf-clone-toggle { display: flex; gap: 0.2rem; padding: 0.3rem; border-bottom: 1px solid var(--border); margin-bottom: 0; } + .gf-clone-block .gf-clone-toggle button { font-family: var(--mono); font-size: 0.76rem; font-weight: 700; letter-spacing: 0.03em; padding: 0.3rem 0.7rem; border-radius: 6px; border-bottom: none; margin-bottom: 0; color: var(--text-faint); } + .gf-clone-block .gf-clone-toggle button.active { background: var(--surface-3); color: var(--text); border-bottom-color: transparent; } + .gf-clone-row { display: flex; align-items: center; gap: 0.5rem; padding: 0.5rem 0.75rem; font-family: var(--mono); font-size: 0.8rem; color: var(--text-dim); } + .gf-clone-block .gf-tabpane.gf-clone-row { display: none; } + .gf-clone-block .gf-tabpane.gf-clone-row.active { display: flex; } + .gf-clone-row code { background: none; padding: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; } + .gf-clone-row .label { flex-shrink: 0; font-size: 0.68rem; font-weight: 700; letter-spacing: 0.03em; color: var(--text-faint); } + .gf-clone-row button.linklike { flex-shrink: 0; font-size: 0.95rem; } + .gf-clone-block.single .gf-clone-row { padding: 0.6rem 0.9rem; } .gf-card { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; margin-bottom: 1.25rem; } .gf-file-table { display: table; width: 100%; border-collapse: collapse; margin: 0; } .gf-file-table tr { border-bottom: 1px solid var(--border); }