From 109e52f3630fbd58004227887e89eb7f68286e5c Mon Sep 17 00:00:00 2001 From: whereareiam Date: Thu, 22 Oct 2026 18:42:51 +0200 Subject: [PATCH] feat(repo): GitHub's header, tab counters and repository buttons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Measured against github.com (signed in) at 1280, 1011, 900, 768, 600 and 400px. These parts are shared by every repository page, and the changes go through the theme's shared components instead of page-specific copies: - Global header: one transparent, outlined menu button before the logo opens the existing navigation drawer on every width; the logo is a bare 32px mark and is dropped below 600px; the repository breadcrumb shows a repository icon instead of the owner avatar and folds the owner into a "…" menu on narrow screens. A transparent 197px search field (the shared search component, with a new monospace shortcut hint) searches repositories from 1012px, "/" focuses it, and a search button from the shared header icons replaces it below 1012px. On mobile the header keeps only search and the inbox; the drawer holds the dashboard links. - Tabs: repository, organisation and profile tabs use the counter's tab variant (18px, semibold), 8px after the label; tab icons drop on mobile and the tabs keep a 16px gutter. - Watch, Fork and Star are single small controls with the count inside; Fork gets a split menu with forks and "Fork repository" through the shared dropdown, which gains a small size and a square icon-only trigger. The feed button is gone, as on GitHub. - Buttons: the shared control gets GitHub's 4px gap and muted icons at the small size, and sizes the branch selector and Add file buttons (14px, weight 500, 16px carets). - The Code page uses GitHub's gutter: 16px, and 32px from 1012px. Co-Authored-By: Claude Opus 5.5 --- components/common/button/button.css | 57 ++++++++++++++++- components/common/dropdown/dropdown.tmpl | 4 +- components/common/search/search.css | 22 +++++++ components/common/search/search.js | 10 +++ components/common/search/search.tmpl | 5 +- public/assets/js/navbar-drawer.js | 16 ++--- public/navbar-drawer.css | 7 +++ src/build-output.test.ts | 16 +++-- src/navbar-drawer.test.ts | 15 +++-- styles/components/navbar.ts | 50 ++++++++++++++- styles/pages/user-profile.css | 2 + styles/templates/repo/header.ts | 68 +++++++++------------ styles/templates/repo/home.ts | 13 ++-- templates/base/head_navbar.tmpl | 15 ++++- templates/base/head_navbar_icons.tmpl | 12 +++- templates/base/navbar_breadcrumb_items.tmpl | 1 + templates/org/menu.tmpl | 10 +-- templates/repo/global_header.tmpl | 12 ++-- templates/repo/header.tmpl | 6 +- templates/repo/header_fork.tmpl | 49 +++++++++++++++ templates/repo/header_fork_menu.tmpl | 4 ++ templates/repo/star_unstar.tmpl | 11 ++++ templates/repo/view_content.tmpl | 2 +- templates/repo/watch_unwatch.tmpl | 47 ++++++++++++++ templates/user/overview/header.tmpl | 8 +-- 25 files changed, 365 insertions(+), 97 deletions(-) create mode 100644 templates/base/navbar_breadcrumb_items.tmpl create mode 100644 templates/repo/header_fork.tmpl create mode 100644 templates/repo/header_fork_menu.tmpl create mode 100644 templates/repo/star_unstar.tmpl create mode 100644 templates/repo/watch_unwatch.tmpl diff --git a/components/common/button/button.css b/components/common/button/button.css index 14383318..9acbc975 100644 --- a/components/common/button/button.css +++ b/components/common/button/button.css @@ -22,6 +22,7 @@ } .button.theme-control-small { + gap: 4px; height: 28px; min-height: 28px; padding: 0 8px; @@ -29,10 +30,43 @@ line-height: 18px; } +/* A main action and its menu joined into one shape, like GitHub's Fork button. */ +.theme-control-split { + display: inline-flex; + align-items: stretch; +} +.theme-control-split > .theme-control { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.theme-control-split > .theme-dropdown > summary.theme-control { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +/* An icon-only small menu trigger is a 28px square, like GitHub's "…" and split carets. */ +.theme-dropdown > summary.theme-control-small:not(:has(> span)) { + width: 28px; + padding: 0; +} + .theme-control:hover { background: var(--color-hover); } +/* GitHub draws a default button's icons muted; a filled star keeps its own colour. */ +.theme-control:not(.primary) > svg:not(.octicon-star-fill) { + color: var(--color-text-light-1); +} + +/* Forgejo sizes buttons in dropdown summaries through --button-min-height on more specific rules. */ +details > summary.button.theme-control { + min-height: 32px; +} +details > summary.button.theme-control-small { + min-height: 28px; +} + .theme-control:focus-visible { outline: 2px solid var(--github-fgColor-accent); outline-offset: 2px; @@ -87,7 +121,9 @@ .comment-code-cloud .field.footer .ui.ui.ui.button, .comment-code-cloud :is(.button-row, .button-sequence):has(.comment-form-reply) .ui.ui.ui.button, .page-content.repository.new.issue.github-issue-new .issue-content-left .text.right .ui.ui.ui.button, - .page-content.repository.new.release .ui.form .ui.ui.ui.button:not(.mini) + .page-content.repository.new.release .ui.form .ui.ui.ui.button:not(.mini), + .repo-button-row .ui.ui.ui.button.repo-add-file, + .js-branch-tag-selector .ui.ui.ui.button.branch-dropdown-button ) { height: 32px; min-height: 32px; @@ -96,3 +132,22 @@ font-weight: 500; line-height: 20px; } + +/* The branch selector is a Forgejo Vue component: GitHub sets its branch name in the button's weight and uses a + 16px caret. */ +/* Its spacing comes from Forgejo's Tailwind utilities, which are !important. */ +.js-branch-tag-selector .ui.ui.ui.ui.button.branch-dropdown-button { + padding: 5px 12px !important; +} +.js-branch-tag-selector .branch-dropdown-button > .text { + gap: 8px; + margin-right: 0 !important; +} +.js-branch-tag-selector .branch-dropdown-button strong { + margin-left: 0 !important; + font-weight: inherit; +} +.js-branch-tag-selector .branch-dropdown-button > svg:last-child { + width: 16px; + height: 16px; +} diff --git a/components/common/dropdown/dropdown.tmpl b/components/common/dropdown/dropdown.tmpl index 3663931f..502c92af 100644 --- a/components/common/dropdown/dropdown.tmpl +++ b/components/common/dropdown/dropdown.tmpl @@ -1,6 +1,6 @@ -{{/* Kind: single (radio), multiple (checkbox), or actions (links/buttons). Items owns page-specific content. */}} +{{/* Kind: single (radio), multiple (checkbox), or actions (links/buttons). Items owns page-specific content. Small uses the 28px control. */}}
- + {{if .Icon}}{{svg .Icon 16}}{{end}} {{if not .IconOnly}}{{.Label}}{{svg "octicon-triangle-down" 12}}{{end}} diff --git a/components/common/search/search.css b/components/common/search/search.css index 0f317dd3..4d87e693 100644 --- a/components/common/search/search.css +++ b/components/common/search/search.css @@ -98,6 +98,28 @@ display: none; } +/* A shortcut hint, like the "/" in GitHub's header search; it gives way to the clear button once there is text. */ +.theme-search-field > .theme-search-shortcut { + flex: none; + display: inline-grid; + place-items: center; + box-sizing: border-box; + min-width: 16px; + height: 16px; + margin-right: 8px; + padding: 0 3px; + border: 1px solid var(--color-text-light-1); + border-radius: 3px; + box-shadow: none; + background: transparent; + color: var(--color-text-light-1); + font: 12px/1 var(--fonts-monospace); +} + +.theme-search-field:not(:has(> input:placeholder-shown)) > .theme-search-shortcut { + display: none; +} + /* Syntax fields: a mirror behind the transparent input text colours qualifier values (author:). */ .theme-search-syntax-control { position: relative; diff --git a/components/common/search/search.js b/components/common/search/search.js index a8eee458..eb5fb60b 100644 --- a/components/common/search/search.js +++ b/components/common/search/search.js @@ -13,6 +13,16 @@ if (applied && input.form) input.form.requestSubmit(); }); + // A field with a shortcut takes focus when its key is pressed outside another text field. + document.addEventListener("keydown", event => { + if (event.ctrlKey || event.metaKey || event.altKey || event.isComposing) return; + if (event.target.closest("input, textarea, select, [contenteditable]")) return; + const input = document.querySelector(`input[data-search-shortcut="${CSS.escape(event.key)}"]`); + if (!input || !input.checkVisibility()) return; + event.preventDefault(); + input.focus(); + }); + // Qualifiers Forgejo's issue search understands; their values are highlighted like GitHub's. const qualifiers = new Set(["is", "author", "assignee", "review", "mentions", "sort", "modified"]); diff --git a/components/common/search/search.tmpl b/components/common/search/search.tmpl index 34f5aa81..f26a9a1c 100644 --- a/components/common/search/search.tmpl +++ b/components/common/search/search.tmpl @@ -1,10 +1,11 @@ -{{/* Kind: submit (default, trailing search button), icon (leading search icon), or plain. Local marks a client-side filter that is never submitted. Class adds page layout hooks. Syntax adds GitHub's qualifier popup and value highlighting (issue and pull request searches). */}} +{{/* Kind: submit (default, trailing search button), icon (leading search icon), or plain. Local marks a client-side filter that is never submitted. Class adds page layout hooks. Syntax adds GitHub's qualifier popup and value highlighting (issue and pull request searches). Shortcut shows a key that focuses the field from anywhere on the page. */}} {{$icon := eq .Kind "icon"}} {{if .Syntax}}
{{end}} {{if $icon}}
+{{else}} + {{/* not logged-in user */}} + + {{svg "octicon-eye" 16}}{{ctx.Locale.Tr "repo.watch"}} + {{CountFmt .Repository.NumWatches}} + +{{end}} diff --git a/templates/user/overview/header.tmpl b/templates/user/overview/header.tmpl index 14353694..c6b755b0 100644 --- a/templates/user/overview/header.tmpl +++ b/templates/user/overview/header.tmpl @@ -10,7 +10,7 @@ {{svg "octicon-repo"}} {{ctx.Locale.Tr "user.repositories"}} {{if .RepoCount}} - {{.RepoCount}} + {{.RepoCount}} {{end}} @@ -18,7 +18,7 @@ {{svg "octicon-project-symlink"}} {{ctx.Locale.Tr "user.projects"}} {{if .ProjectCount}} - {{.ProjectCount}} + {{.ProjectCount}} {{end}} @@ -27,7 +27,7 @@ {{svg "octicon-package"}} {{ctx.Locale.Tr "packages.title"}} {{if .PackageCount}} - {{.PackageCount}} + {{.PackageCount}} {{end}} @@ -52,7 +52,7 @@ {{svg "octicon-star"}} {{ctx.Locale.Tr "user.starred"}} {{if .ContextUser.NumStars}} - {{.ContextUser.NumStars}} + {{.ContextUser.NumStars}} {{end}} {{else}}