diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index bded3bc..f89b045 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,4 +1,4 @@ -# GitHub theme for Gitea 1.27.3 — Architecture +# GitHub theme for Gitea 1.27.x and 28.x — Architecture Goal: a self-hosted Gitea 1.27.3 that a daily github.com user needs a second look to tell apart from github.com, in light and dark. Every color, size, radius, shadow, type and motion value comes from **Primer Primitives**, every @@ -30,7 +30,7 @@ Environment facts: `docs/CONTEXT.md`. Gitea source research (with file:line cita | `@primer/primitives` | **11.10.0** | all tokens (`build/gen-tokens.mjs` → `src/tokens/generated/`) | | `@primer/octicons` | **19.38.0** | icon source (Gitea 1.27.3 bundles 19.28.1) | | `@primer/css` | **22.3.2** | reference only for component specs (not shipped) | -| Gitea | **1.27.3** | source at `../gitea-src-1.27.3` (tag v1.27.3) | +| Gitea | **1.27.3** and **28.1.0** | sources at `../gitea-src-1.27.3`, `../gitea-src-28.1.0`; one package for both (§7 "Two Gitea versions") | Recorded again in `docs/STATUS.json → pinned`. @@ -182,12 +182,36 @@ keep the non-GitHub output byte-identical. | `templates/base/head_style.tmpl` | Cascade layering (§3) + cache-busting `?github_revision=`. Shared with the Modern theme's existing override: our branch is additive, the else-branch is untouched. | `github-*` themes only | integrator, wave 0 | | `templates/custom/footer.tmpl` | Primer Dialog close button (request OV-4): Gitea's modals mostly have no `×`; a 12-line inline script (CSP nonce) prepends `button.close.inside` to every `.ui.modal` (Fomantic closes on `> .close`). `custom/footer` is Gitea's empty extension hook, so no upstream markup is replaced. Install is done by the orchestrator (docs/requests/ORCHESTRATOR.md ORC-1). | `github-*` themes only (renders nothing otherwise) | integrator, wave 2 | | `templates/user/settings/layout_head.tmpl` | github.com settings page header (48px avatar, name, subtitle, profile button; request SA-4): needs the signed-in user's data, CSS cannot create it. Upstream 1.27.3 file + one trimmed `{{- if … }}` block; copy text is Gitea's `your_settings` / `your_profile` locale keys (Gitea has no "Your personal account" string). Styled by `src/pages/settings-admin/header.css`. Install: docs/requests/ORCHESTRATOR.md ORC-3. | `github-*` themes only, pages whose pageClass contains `settings` (other themes: upstream bytes) | integrator, wave 3 | -| `templates/base/head_navbar.tmpl` + `templates/custom/gh_head_navbar.tmpl` | github.com AppHeader (FG-007, judges' #1 tell, impact 130) and the slim auth header (FG-063): hamburger drawer with Gitea's links, context crumbs, search form, Issues/PRs icon buttons — the crumbs, search and cross-container moves are not CSS-reachable (docs/final-gate/issues.md "Header decision"). The override is `{{if github-*}}{{template "custom/gh_head_navbar" .}}{{else}}` + upstream 1.27.3 verbatim + `{{end}}` (no trailing newline). All JS hooks kept, no JavaScript added (native `
`). Install: ORCHESTRATOR.md ORC-5. Styled by navigation (`.gh-app-header*`) and pages/auth (`.gh-app-header--auth`). | `github-*` themes only (else-branch = upstream bytes) | integrator, final-gate #1 (pending install) | +| `templates/base/head_navbar.tmpl` + `templates/custom/gh_head_navbar.tmpl` | github.com AppHeader (FG-007, judges' #1 tell, impact 130) and the slim auth header (FG-063): hamburger drawer with Gitea's links, context crumbs, search form, Issues/PRs icon buttons — the crumbs, search and cross-container moves are not CSS-reachable (docs/final-gate/issues.md "Header decision"). The override is `{{if github-*}}{{template "custom/gh_head_navbar" .}}{{else if AppVer 1.*}}` + upstream 1.27.3 verbatim + `{{else}}` + upstream 28.1.0 verbatim + `{{end}}` (no trailing newline). All JS hooks kept, no JavaScript added (native `
`). Install: ORCHESTRATOR.md ORC-5. Styled by navigation (`.gh-app-header*`) and pages/auth (`.gh-app-header--auth`). | `github-*` themes only (else-branch = upstream bytes) | integrator, final-gate #1 (pending install) | | `templates/repo/commits_list.tmpl` | "Commits on " day groups (FG-019, impact 35): per-row date state, CSS cannot insert rows. One `tr.gh-commit-day` per committer day (template funcs only: `When.Format`, `DateUtils.ParseLegacy/AbsoluteShort`); date-only label (no "Commits on" locale key). ORC-6. Styled by pages/repo. | `github-*` themes, not the wiki revision list | integrator, final-gate #1 (pending install) | | `templates/repo/view_file.tmpl` + `templates/repo/blame.tmpl` | Preview \| Code \| Blame SegmentedControl (FG-021, impact 29): the "Code" segment and moving Blame out of the button group need markup; existing links only, keys `preview` / `repo.code` / `repo.blame`. README box untouched. ORC-7. Styled by code. | `github-*` themes only | integrator, final-gate #1 (pending install) | | `templates/repo/wiki/view.tmpl` | wiki "Pages (N)" Box + clone input (FG-022, impact 27): `.Pages` and the clone link are in ctx on every wiki view (routers/web/repo/wiki.go renderViewPage); the Fomantic dropdown and tippy-only clone popup cannot be turned into a static sidebar with CSS. No filter input (would need JS) and no "Clone this wiki locally" heading (no locale key). ORC-8. Styled by pages/repo. | `github-*` themes only | integrator, final-gate #1 (pending install) | | `templates/repo/issue/list.tmpl` | issues / PRs left NavList + title (FG-017, impact 45): links to Gitea's existing `?type=` filters, Milestones, Labels (keys `repo.issues.filter_type.*`); CSS cannot create a sidebar column. Issue/PR list only — the Labels and Milestones pages were not given it (cap). ORC-9. Loop 2 (FG2-027): the NavList is rendered on the issue list only, not the PR list (github.com) — project copy edited, install ORC-13. Styled by pages/issues-prs. | `github-*` themes only | integrator, final-gate #1; FG2-027 edit loop 2 (install pending) | +**Two Gitea versions (1.27.x and 28.x, one package).** Each template that differs between 1.27.3 and 28.1.0 starts with +`{{$gitea1 := StringUtils.HasPrefix AppVer "1."}}` (no output) and branches only where upstream differs, so a non-github +theme gets each version's upstream bytes (checked: anonymous HTML of all routes with vs. without the templates, both +versions, differs only by the documented `hidden` "N Commits" link). Two rules learned the hard way: +- Fields and methods are resolved at execution, so an untaken branch may name `.Repository.CanEnableEditor` (1.27) or + `CanContentChange` (28); use `and`/`or` (lazy since Go 1.18) or `{{if $gitea1}}` around them. +- `{{template "x"}}` is checked by html/template's escaper even in a branch that never runs: an undefined name breaks the + whole page. Hence `templates/base/head_impersonate_banner.tmpl` (28.1.0 verbatim) ships so the name exists on 1.27. +CSS: where 28 renamed or restructured markup, the 28 selectors are added next to the 1.27 ones and commented "28.x" +(profile sidebar `#profile-avatar-card.segment`, commit header and its "N files changed" footer row, `.site-banner-*`, +diff kebab, feed excerpt, `.dropzone` without `.ui`, release header `.flex-left-right`, notifications toolbar +`.flex-text-block`, Actions sidebar with a second "Management" menu, deploy key / token panels). The wiki view template +keeps the `view` class (dropped in 28) for github-* themes. Features only 28 has are styled to the matching Primer +component, not left on Gitea's defaults: toasts per level (Primer Toast), site + impersonation banners (flash-full), +repo switcher (SelectPanel on the AppHeader repo crumb, as on github.com; the repo-header copy is hidden), Actions job queue (PageLayout pane + DataTable), artifact preview (NavList file tree), +diff file filter + extension menu (TextInput + IconButton + ActionMenu), audit log (filter row + Box table), deploy +tokens (Box rows, Blankslate), "Mark this page as read". Verified 2026-10-12 on 1.27.3 and 28.1.0: light, dark, 390px; +1.27 pixel-diffed against a pre-change capture of every route (only live data differs). Not seen with real data: the +`diff-line-truncated` label (lines over 5000 characters) and a bot account's label (both plain Primer Labels). +When 1.27 support ends, delete the `$gitea1` branches and the 1.27 selectors. + +Pitfall: `X > :is(A > B)` does not mean "B under A under X" — the `:is()` element must match X's child AND have an +A parent, so it silently matches nothing. List whole paths instead (`:has(> … > A > B, > … > C)`). + Final gate #1 template requests REJECTED (§7 criteria: a impact, b data in ctx, c existing locale keys, d byte-identical branch, e ≤ 8 new overrides; the seven files above are 7 of 8): FG-024 branches table (c: no keys for Updated / Check status / Behind|Ahead column headers; kebab needs a full row rewrite; e), FG-025 tree-pane branch picker and FG-044 @@ -246,7 +270,8 @@ column colors, repo units, federation, wiki clone box, etc.) get the **closest P ## 10. Budget -- ≤ 300 KB per theme file minified (build fails otherwise); gate for every loop: ≤ 295 KB. Current sizes in `docs/STATUS.json`. +- ≤ 340 KB per theme file minified (build fails otherwise); gate for every loop: ≤ 335 KB. Raised from 300 / 295 KB on + 2026-10-12 (user decision) to style Gitea 28's new UI in the same single file for 1.27 and 28 (gzip at 300 KB: ~57 KB). Current sizes in `docs/STATUS.json`. Loop 1 (after wave L1, 2026-09-30): the wave added 63.6 KB of flat CSS (auto 283,706 → 347,273 B; per-layer growth in STATUS.json → budget.loop1); the lossless prefix nesting (§9) brings the files to auto 295,880 B (288.9 KB), light 290,683 B, dark 291,734 B — no rules were deleted. diff --git a/README.md b/README.md index 6f2b1de..8be6a1e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Build & release](https://github.com/mechiland/gitea-theme-github/actions/workflows/release.yml/badge.svg)](https://github.com/mechiland/gitea-theme-github/actions/workflows/release.yml) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -A GitHub look-and-feel theme for **Gitea 1.27.3**, in light, dark and auto (follows the OS color scheme). +A GitHub look-and-feel theme for **Gitea 1.27.x and 28.x** (tested on 1.27.3 and 28.1.0; one package for both), in light, dark and auto (follows the OS color scheme). It is built from GitHub's own open-source design system, not by recolouring Gitea: - every color, size, radius, shadow, type and motion value comes from [Primer Primitives](https://primer.style/product/primitives/) (`@primer/primitives` 11.10.0); @@ -48,7 +48,7 @@ The theme is a set of files for Gitea's custom directory (`CUSTOM_PATH`, `$GITEA ### 1. Download the release package -Take `gitea-theme-github--gitea1.27.3.tar.gz` (or `.zip`) from [Releases](https://github.com/mechiland/gitea-theme-github/releases), or the `gitea-theme-github` artifact of the latest [CI run](https://github.com/mechiland/gitea-theme-github/actions). +Take `gitea-theme-github--gitea1.27-28.tar.gz` (or `.zip`) from [Releases](https://github.com/mechiland/gitea-theme-github/releases), or the `gitea-theme-github` artifact of the latest [CI run](https://github.com/mechiland/gitea-theme-github/actions). It contains: @@ -65,13 +65,13 @@ INSTALL.md, LICENSE, NOTICE **Docker (docker compose, volume `./gitea:/data`):** ```bash -tar -xzf gitea-theme-github-*-gitea1.27.3.tar.gz -C ./gitea/gitea +tar -xzf gitea-theme-github-*-gitea1.27-28.tar.gz -C ./gitea/gitea ``` **Binary / systemd:** ```bash -sudo tar -xzf gitea-theme-github-*-gitea1.27.3.tar.gz -C /var/lib/gitea/custom +sudo tar -xzf gitea-theme-github-*-gitea1.27-28.tar.gz -C /var/lib/gitea/custom sudo chown -R git:git /var/lib/gitea/custom ``` @@ -90,7 +90,7 @@ With the Docker image, you can set the same values with environment variables in ```yaml services: server: - image: docker.gitea.com/gitea:1.27.3 + image: docker.gitea.com/gitea:28.1.0 # or 1.27.x environment: - GITEA__ui__THEMES=gitea-auto,gitea-light,gitea-dark,github-auto,github-light,github-dark - GITEA__ui__DEFAULT_THEME=github-auto @@ -123,8 +123,9 @@ Extracting never deletes files. If the release notes say a template was removed, ### Notes -- **Gitea version:** the templates are copies of Gitea **1.27.3** templates with added GitHub-only blocks. Re-check them when you upgrade Gitea. The CSS alone still works without the templates, but you lose the cascade layering (see [ARCHITECTURE.md §3](ARCHITECTURE.md)), the GitHub-style header and a few page structures. -- **If you already override templates:** the package ships these templates (all under `templates/`): `base/head_style.tmpl`, `base/head_navbar.tmpl`, `custom/footer.tmpl`, `custom/gh_head_navbar.tmpl`, `repo/blame.tmpl`, `repo/commits_list.tmpl`, `repo/issue/list.tmpl`, `repo/view_file.tmpl`, `repo/view_list.tmpl`, `repo/wiki/view.tmpl`, `user/settings/layout_head.tmpl`. If you override one of them yourself, extracting the package replaces your copy. Back it up first and merge the GitHub additions by hand: the `{{if StringUtils.HasPrefix … "github-"}}` blocks, and in `repo/view_list.tmpl` the `hidden` "N Commits" link (`a.m-commit-count`). +- **Gitea version:** the templates are copies of Gitea templates with added GitHub-only blocks. Where Gitea 1.27 and 28 differ, a template carries both variants and picks one from the running Gitea version (`AppVer`), so you can install the package before upgrading Gitea from 1.27 to 28 and keep it afterwards. Packages up to v0.1.2 only work on 1.27.x: on 28.x the repository home and file pages fail to render. Re-check the templates when a new Gitea major comes out. The CSS alone still works without the templates, but you lose the cascade layering (see [ARCHITECTURE.md §3](ARCHITECTURE.md)), the GitHub-style header and a few page structures. +- **Footer:** shows the running Gitea version next to "Powered by Gitea" (Gitea's own `[other] SHOW_FOOTER_VERSION`, on by default; admins get a link to the site configuration). Set it to `false` to hide it. +- **If you already override templates:** the package ships these templates (all under `templates/`): `base/head_style.tmpl`, `base/head_navbar.tmpl`, `base/head_impersonate_banner.tmpl` (Gitea 28.1.0's file, needed so 1.27 can load the navbar), `custom/footer.tmpl`, `custom/gh_head_navbar.tmpl`, `repo/blame.tmpl`, `repo/commits_list.tmpl`, `repo/issue/list.tmpl`, `repo/view_file.tmpl`, `repo/view_list.tmpl`, `repo/wiki/view.tmpl`, `user/settings/layout_head.tmpl`. If you override one of them yourself, extracting the package replaces your copy. Back it up first and merge the GitHub additions by hand: the `{{if StringUtils.HasPrefix … "github-"}}` blocks, and in `repo/view_list.tmpl` the `hidden` "N Commits" link (`a.m-commit-count`). - **Without the templates:** the repo home falls back to Gitea's Commits / Branches / Tags bar for the commit-history link. With `repo/view_list.tmpl`, "N Commits" sits at the right of the latest-commit row, as on github.com. - **Icons are global:** the SVG icons replace Gitea's icons for every theme. They depict the same things, drawn as Octicons. - **Browser support:** Chrome/Edge 112+, Safari 16.5+, Firefox 121+. The theme uses `@layer`, `:has()` and CSS nesting. @@ -137,7 +138,7 @@ git clone https://github.com/mechiland/gitea-theme-github && cd gitea-theme-gith npm ci npm run lint # no literal colors outside the token layer, type/radius/shadow from tokens, selector ownership npm run build # → dist/theme-github-{auto,light,dark}.css (budget: ≤ 300 KB each, minified) -npm run package # → dist/gitea-theme-github--gitea1.27.3.{zip,tar.gz} (the drop-in package above) +npm run package # → dist/gitea-theme-github--gitea1.27-28.{zip,tar.gz} (the drop-in package above) ``` Where things live: diff --git a/build/folders.mjs b/build/folders.mjs index 9bc74ba..a50367b 100644 --- a/build/folders.mjs +++ b/build/folders.mjs @@ -19,4 +19,4 @@ export const THEMES = { 'github-dark': {display: 'GitHub Dark', scheme: 'dark'}, 'github-auto': {display: 'GitHub', scheme: 'auto'}, }; -export const BUDGET_BYTES = 300 * 1024; +export const BUDGET_BYTES = 340 * 1024; // 300 KB until Gitea 28 support (2026-10-12, user decision); loop gate 335 KB diff --git a/build/package.mjs b/build/package.mjs index 506e8f1..1ae6b85 100644 --- a/build/package.mjs +++ b/build/package.mjs @@ -1,6 +1,6 @@ // Builds a drop-in release package for Gitea's CUSTOM_PATH from an existing `npm run build` output. // -// node build/package.mjs → dist/gitea-theme-github--gitea.{zip,tar.gz} + dist/package/ +// node build/package.mjs → dist/gitea-theme-github--gitea.{zip,tar.gz} + dist/package/ // // Layout (extract into $GITEA_CUSTOM, e.g. /data/gitea in the official Docker image): // public/assets/css/theme-github-{auto,light,dark}.css @@ -8,17 +8,19 @@ // templates/** github-* branches only; other themes render Gitea's upstream bytes // (repo/view_list.tmpl: a `hidden` link for other themes) // -// templates/base/head_style.tmpl: the package pins the else-branch to Gitea 1.27.3's upstream two lines (a local install may -// carry another theme's cache key there) and stamps the build revision for cache busting. +// templates/base/head_style.tmpl: the package pins the else-branch to Gitea's upstream two lines (identical in 1.27.3 and +// 28.1.0; a local install may carry another theme's cache key there) and stamps the build revision for cache busting. +// One package serves Gitea 1.27.x and 28.x: templates branch on `StringUtils.HasPrefix AppVer "1."` where the two differ. import fs from 'node:fs'; import path from 'node:path'; import {execFileSync} from 'node:child_process'; import {ROOT, DIST, SRC, THEMES} from './folders.mjs'; -const GITEA_VERSION = '1.27.3'; +const GITEA_SUPPORTED = '1.27-28'; // tested on 1.27.3 and 28.1.0 +const GITEA_TESTED = '1.27.3 and 28.1.0'; const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); const report = JSON.parse(fs.readFileSync(path.join(DIST, 'build-report.json'), 'utf8')); -const name = `gitea-theme-github-${pkg.version}-gitea${GITEA_VERSION}`; +const name = `gitea-theme-github-${pkg.version}-gitea${GITEA_SUPPORTED}`; const out = path.join(DIST, 'package', 'gitea-theme-github'); fs.rmSync(path.join(DIST, 'package'), {recursive: true, force: true}); @@ -53,7 +55,7 @@ for (const rel of fs.readdirSync(tplRoot, {recursive: true}).filter((f) => f.end } for (const f of ['LICENSE', 'NOTICE']) copy(path.join(ROOT, f), path.join(out, f)); -fs.writeFileSync(path.join(out, 'INSTALL.md'), `# gitea-theme-github ${pkg.version} (for Gitea ${GITEA_VERSION}) +fs.writeFileSync(path.join(out, 'INSTALL.md'), `# gitea-theme-github ${pkg.version} (for Gitea 1.27.x and 28.x, tested on ${GITEA_TESTED}) 1. Copy the contents of this folder into Gitea's custom directory (\`$GITEA_CUSTOM\`, \`/data/gitea\` in the official Docker image), keeping the paths: \`public/…\` and \`templates/…\`. @@ -64,7 +66,9 @@ fs.writeFileSync(path.join(out, 'INSTALL.md'), `# gitea-theme-github ${pkg.versi 4. Pick "GitHub" in Settings → Appearance. Theme files: ${Object.entries(report.themes).map(([n, t]) => `${n} ${t.kb} KB`).join(', ')} · build ${report.revision}. -The templates are copies of Gitea ${GITEA_VERSION} templates with added github-only blocks; re-check them when upgrading Gitea. +The templates are copies of Gitea's templates with added github-only blocks. Where Gitea 1.27 and 28 differ they carry both +versions (picked at runtime from Gitea's version), so the same package keeps working across a 1.27 → 28 upgrade. +templates/base/head_impersonate_banner.tmpl is Gitea 28.1.0's file verbatim: on 1.27.x it only has to exist. If you already override one of these templates, merge the github-* blocks by hand. templates/repo/view_list.tmpl adds the "N Commits" link to the latest-commit header (hidden for other themes). The SVG files replace Gitea's icons for every theme (same meaning, Octicon drawings). diff --git a/docs/STATUS.json b/docs/STATUS.json index 0c374a6..1d6c54e 100644 --- a/docs/STATUS.json +++ b/docs/STATUS.json @@ -452,7 +452,7 @@ "bytes": 291734, "kb": 284.9 }, - "budgetKb": 300, + "budgetKb": 340, "gateKb": 295, "targetKb": 285, "withinBudget": true, diff --git a/package-lock.json b/package-lock.json index 43b8dd6..a2d8cbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gitea-theme-github", - "version": "0.1.2", + "version": "0.2.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "gitea-theme-github", - "version": "0.1.2", + "version": "0.2.0", "license": "MIT", "devDependencies": { "@primer/css": "22.3.2", diff --git a/package.json b/package.json index a74a10c..10c3d47 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "gitea-theme-github", "private": true, - "version": "0.1.2", + "version": "0.2.0", "type": "module", - "description": "GitHub (Primer) theme for Gitea 1.27.3", + "description": "GitHub (Primer) theme for Gitea 1.27.x and 28.x", "scripts": { "tokens": "node build/gen-tokens.mjs", "lint": "node build/lint.mjs", diff --git a/src/code/diff-tree.css b/src/code/diff-tree.css index a302052..7dbcb11 100644 --- a/src/code/diff-tree.css +++ b/src/code/diff-tree.css @@ -39,3 +39,39 @@ } /* nesting: 8px per level via --gh-ti (level rules in file-tree.css, up to level 4 for this tree) */ + +/* Gitea 28.x filter row above the tree (DiffFileTree.vue .diff-file-tree-search-row): github.com's "Filter files…" + TextInput (16px muted search octicon 8px inside the border, text at 32px) and, 8px to its right, a 32px default + IconButton (octicon-filter, resting shadow) opening the file-extension menu (measured 2026-10-12, commit view) */ +.diff-file-search-icon { + left: calc(var(--base-size-8) + var(--borderWidth-thin)); + width: var(--base-size-16); + height: var(--base-size-16); + color: var(--fgColor-muted); +} + +.diff-file-search-input { + padding: 0 calc(var(--base-size-24) + var(--base-size-4)) 0 var(--base-size-32); +} + +.diff-ext-filter-trigger { + flex-shrink: 0; + border-color: var(--button-default-borderColor-rest); + background: var(--button-default-bgColor-rest); + box-shadow: var(--button-default-shadow-resting); + color: var(--fgColor-muted); +} + +.diff-ext-filter-trigger:hover { + border-color: var(--button-default-borderColor-hover); + background: var(--button-default-bgColor-hover); +} + +.diff-ext-filter-trigger:active { + background: var(--button-default-bgColor-active); +} + +/* the extension menu's rows fill the overlay so the Counter is a trailing visual (Primer ActionList) */ +.diff-ext-filter-menu > .item { + width: 100%; +} diff --git a/src/code/diff.css b/src/code/diff.css index 37af347..c2d5027 100644 --- a/src/code/diff.css +++ b/src/code/diff.css @@ -89,6 +89,7 @@ /* fold chevron, copy-path and kebab: invisible icon buttons (28px) */ .diff-file-header .fold-file, .diff-file-header .diff-header-popup-btn, +.diff-file-header .btn[data-global-init="initDiffHeaderPopupMenu"], /* 28.x kebab */ .diff-file-header .diff-file-name .btn[data-clipboard-text] { justify-content: center; width: var(--control-small-size); diff --git a/src/code/file-view.css b/src/code/file-view.css index 4ef5fa8..9b6e618 100644 --- a/src/code/file-view.css +++ b/src/code/file-view.css @@ -88,6 +88,7 @@ .file-view .lines-blame-btn > a:hover, .diff-file-header .fold-file:hover, .diff-file-header .diff-header-popup-btn:hover, +.diff-file-header .btn[data-global-init="initDiffHeaderPopupMenu"]:hover, .diff-file-header .diff-file-name .btn[data-clipboard-text]:hover { background: var(--control-transparent-bgColor-hover); color: var(--fgColor-default); diff --git a/src/controls/dropzone.important.css b/src/controls/dropzone.important.css index 421325b..c254d40 100644 --- a/src/controls/dropzone.important.css +++ b/src/controls/dropzone.important.css @@ -1,7 +1,7 @@ -/* gh-important: file attach area (repo/upload.tmpl `.ui.dropzone`). The dropzone lazy chunk is unlayered: +/* gh-important: file attach area (repo/upload.tmpl `.dropzone`). The dropzone lazy chunk is unlayered: * `.dropzone { min-height: 150px; border: 1px solid; padding: 20px }`, `.dz-message { text-align: center; margin: 3em 0 }`. * github.com: a quiet 1px dashed --borderColor-default box on --bgColor-muted. Composers: pages/issues-prs. */ -.ui.dropzone { +.dropzone { min-height: 0 !important; padding: var(--base-size-16) !important; border: var(--borderWidth-thin) dashed var(--borderColor-default) !important; @@ -9,17 +9,34 @@ background: var(--bgColor-muted) !important; } -.ui.dropzone .dz-message { +.dropzone .dz-message { margin: 0 !important; } -/* the message keeps Gitea's own !important muted colour and font size */ +/* muted message, default text on hover: Gitea 1.27 set this with !important, 28.x without, so the unlayered dropzone + chunk's `.dz-button { color: inherit }` would win there */ +.dropzone .dz-button { + color: var(--fgColor-muted) !important; +} + +.dropzone:hover .dz-button { + color: var(--fgColor-default) !important; +} /* inline diff comment (repo/diff/comment_form.tmpl): a slim left-aligned file bar, not a 55px drop box */ -.comment-code-cloud .ui.dropzone { +.comment-code-cloud .dropzone { padding: var(--base-size-8) !important; } -.comment-code-cloud .ui.dropzone .dz-message { +.comment-code-cloud .dropzone .dz-message { text-align: left !important; } + +/* file preview hover labels (size, file name): the chunk paints them on fixed white (rgba(255,255,255,.4 / .8)), + unreadable in dark mode → Primer overlay surface with a 1px border, the theme's text colours */ +.dropzone .dz-preview .dz-details :is(.dz-size, .dz-filename) span { + border: var(--borderWidth-thin) solid var(--borderColor-default) !important; + border-radius: var(--borderRadius-small) !important; + background-color: var(--overlay-bgColor) !important; + color: var(--fgColor-default) !important; +} diff --git a/src/controls/inputs.css b/src/controls/inputs.css index 1b2906c..6a2437e 100644 --- a/src/controls/inputs.css +++ b/src/controls/inputs.css @@ -159,6 +159,13 @@ select:focus, border-bottom-right-radius: 0; } +/* a group that is itself a flex item sized by its row (Gitea 28.x audit filter: `.ui.action.input.tw-flex-1`) keeps its + attached button inside it: the input gives way instead of Fomantic's `flex: 1 0 auto` overflowing the group */ +.ui.action.input.tw-flex-1 > input { + flex-shrink: 1; + min-width: 0; +} + .ui.action.input > input:focus, .ui.action.input > select:focus { position: relative; diff --git a/src/foundation/layout.css b/src/foundation/layout.css index bf5b85b..0aaf355 100644 --- a/src/foundation/layout.css +++ b/src/foundation/layout.css @@ -95,7 +95,8 @@ width: var(--breakpoint-medium); } -.ui.message.web-banner-container > .web-banner-content { +.ui.message.web-banner-container > .web-banner-content, +.ui.message.site-banner-container > .site-banner-content { /* 1.27.x, 28.x */ width: calc(var(--breakpoint-xlarge) - 2 * var(--page-margin-x)); } diff --git a/src/navigation/footer.css b/src/navigation/footer.css index 70144da..8e31d39 100644 --- a/src/navigation/footer.css +++ b/src/navigation/footer.css @@ -5,8 +5,10 @@ * < 1012: column-reverse — the links (centred, wrapping, 16px apart, 8px below) above the mark group * Gitea: base/footer_content.tmpl `.page-footer > .left-links (Powered by, version, timing) + .right-links * (theme menu, language menu, Licenses, API)`. Gitea's logo stands in for the GitHub mark (no GitHub marks), and - * "Powered by Gitea" for the copyright. The version and the server-timing spans are diagnostics, not functions - * (github.com shows neither): hidden (FG2-028); admins still see the version on /-/admin/config. + * "Powered by Gitea" for the copyright. The Gitea version span is shown (the theme supports 1.27.x and 28.x, so the + * running version matters; Gitea's [other] SHOW_FOOTER_VERSION still controls it, admins get a link to /-/admin/config). + * The page/template timing span (the one with , SHOW_FOOTER_TEMPLATE_LOAD_TIME) is a diagnostic github.com + * does not show: hidden (FG2-028). */ .page-footer { @@ -28,7 +30,7 @@ margin: 0 var(--base-size-8); } -.page-footer .left-links > span { +.page-footer .left-links > span:has(> strong) { display: none; } diff --git a/src/navigation/header.css b/src/navigation/header.css index 3e67a42..eea27d9 100644 --- a/src/navigation/header.css +++ b/src/navigation/header.css @@ -137,12 +137,12 @@ body:has(> .full.height > .page-content > .secondary-nav > .ui.container > .repo } /* ---------- context crumbs ---------- */ +/* no overflow clip: the crumbs ellipsize themselves (min-width 3ch) and the 28.x repo switcher's menu hangs below */ .gh-app-header-context { display: flex; align-items: center; flex: 1 1 auto; min-width: 0; - overflow: hidden; } .gh-context-item { @@ -161,7 +161,7 @@ body:has(> .full.height > .page-content > .secondary-nav > .ui.container > .repo flex: 0 100 max-content; } -.gh-context-item:last-child { +.gh-context-item:last-of-type { flex: 0 1 max-content; font-weight: var(--base-text-weight-semibold); } @@ -176,6 +176,35 @@ a.gh-context-item:hover { color: var(--fgColor-muted); } +/* Gitea 28.x quick repo switcher (gh_head_navbar.tmpl `.gh-context-switcher`, signed in): github.com's repo crumb is a + two-part group, the name and a 20px caret 1px apart; hovering either part, or the open menu, shades both */ +.gh-context-switcher { + display: flex; + flex: none; + align-items: center; + justify-content: center; + width: var(--base-size-20); + height: calc(var(--base-size-20) + 2 * var(--base-size-4)); + margin-left: var(--borderWidth-thin); + border-radius: 0 var(--borderRadius-medium) var(--borderRadius-medium) 0; + color: var(--fgColor-muted); +} + +.gh-context-switcher > .dropdown.icon { + margin: 0; +} + +.gh-context-repo:has(+ .gh-context-switcher) { + border-radius: var(--borderRadius-medium) 0 0 var(--borderRadius-medium); +} + +.gh-context-repo:is(:hover, :has(+ .gh-context-switcher:is(:hover, .active))), +.gh-context-switcher:is(:hover, .active), +.gh-context-repo:hover + .gh-context-switcher { + background: var(--control-transparent-bgColor-hover); + color: var(--fgColor-default); +} + /* ---------- search: the field from 1012px (github.com whenRegular), an IconButton below (whenNarrow) ---------- */ .gh-app-header-search { display: none; diff --git a/src/navigation/nav-list.css b/src/navigation/nav-list.css index 0745929..d59eae8 100644 --- a/src/navigation/nav-list.css +++ b/src/navigation/nav-list.css @@ -80,9 +80,18 @@ color: var(--fgColor-muted); } +/* Gitea 28.x: a second menu in the same sidebar (repo Actions "Management" → Job queue) is a new NavList group: a + --borderColor-muted rule across the list, then the group heading (a bare
) */ +.flex-container-nav > .ui.vertical.menu + .ui.vertical.menu { + margin-top: var(--base-size-8); + padding-top: var(--base-size-8); + border-top: var(--borderWidth-thin) solid var(--borderColor-muted); +} + /* group heading */ .ui.vertical.menu .header.item, -.ui.vertical.menu .item > .header:not(.ui) { +.ui.vertical.menu .item > .header:not(.ui), +.flex-container-nav > .ui.vertical.menu + .ui.vertical.menu > div:first-child { min-height: 0; padding: var(--base-size-6) var(--control-medium-paddingInline-condensed); background: transparent; @@ -313,6 +322,11 @@ mask-image: url("../img/svg/octicon-file-binary.svg"); } +/* Gitea 28.x audit log (user / org / repo settings): github.com's "Security log" / "Audit log" glyph */ +.flex-container-nav [href$="/audit_logs"]::before { + mask-image: url("../img/svg/octicon-log.svg"); +} + .flex-container-nav details:has([href*="/actions/"]) > summary::before { mask-image: url("../img/svg/octicon-play.svg"); } diff --git a/src/navigation/repo-header.css b/src/navigation/repo-header.css index f3a862a..010229a 100644 --- a/src/navigation/repo-header.css +++ b/src/navigation/repo-header.css @@ -174,3 +174,9 @@ html:lang(en) .repo-header .tw-text-18 + div:not(:has(.octicon-lock, .octicon-sh background: var(--borderColor-muted); box-shadow: 50vw 0 var(--borderColor-muted), -50vw 0 var(--borderColor-muted); } + +/* Gitea 28.x quick repo switcher: shown on the AppHeader repo crumb (header.css .gh-context-switcher), like + github.com, not after the repo name here */ +.repo-header [data-global-init="initRepoSwitcher"] { + display: none; +} diff --git a/src/overlays/action-menu.css b/src/overlays/action-menu.css index 3c2afcf..d84f01f 100644 --- a/src/overlays/action-menu.css +++ b/src/overlays/action-menu.css @@ -281,6 +281,20 @@ text-expander .suggestions li { visibility: hidden; } +/* Gitea 28.x repo switcher (repo/header.tmpl `.menu > .ui.icon.search.input`) renders no icon element: the same + leading search visual is drawn on the wrapper */ +.ui.dropdown .menu > .ui.icon.input:not(:has(> .icon))::before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: var(--control-medium-paddingInline-condensed); + width: var(--base-size-16); + background-color: var(--fgColor-muted); + mask: var(--gh-octicon-search) center / contain no-repeat; + pointer-events: none; +} + /* ---------- scrolling list area ---------- */ .ui.scrolling.dropdown .menu { padding: 0; diff --git a/src/overlays/flash.css b/src/overlays/flash.css index c65b1d8..c67476e 100644 --- a/src/overlays/flash.css +++ b/src/overlays/flash.css @@ -49,6 +49,23 @@ vertical-align: text-bottom; } +/* ---------- site banners = Primer .flash-full ---------- + base/head_banner.tmpl (1.27.x `.web-banner-container`, 28.x `.site-banner-container`) and 28.x + base/head_impersonate_banner.tmpl (warning variant): edge to edge under the AppHeader with rules only above and below + (a banner right after the header or another banner drops its top rule: Gitea's container.css), square corners; the + text keeps to the page container (foundation/layout.css), Gitea positions the dismiss button. The impersonation + notice's leading alert sits inside .site-banner-content and takes the variant colour like any Flash icon. */ +.ui.message:is(.web-banner-container, .site-banner-container) { + margin: 0; + padding-inline: 0; + border-width: var(--borderWidth-thin) 0; + border-radius: 0; +} + +.ui.message.site-banner-container > .site-banner-content > .svg:first-child { + color: var(--gh-flash-icon-color); +} + /* ---------- variants ---------- */ .ui:is(.info, .blue).message:not(.field *) { --gh-flash-icon-color: var(--fgColor-accent); diff --git a/src/overlays/overlays.important.css b/src/overlays/overlays.important.css index 30cbcb7..efe9708 100644 --- a/src/overlays/overlays.important.css +++ b/src/overlays/overlays.important.css @@ -91,7 +91,8 @@ max-width: 250px !important; } -/* ---------- toast: Primer Toast surface instead of Gitea's inline green/orange/red fill ---------- */ +/* ---------- toast: Primer Toast surface instead of Gitea's inline green/orange/red fill (1.27.x) / tinted level class + (28.x) ---------- */ .toastify { background: var(--bgColor-default) !important; } diff --git a/src/overlays/toast.css b/src/overlays/toast.css index fb3d95c..e8764e9 100644 --- a/src/overlays/toast.css +++ b/src/overlays/toast.css @@ -7,10 +7,13 @@ * background with --fgColor-onEmphasis icon, content padding 16px, 16px-padded dismiss button, * max-width 450px. The inline background is overridden in overlays.important.css. * Level: info → success (Gitea's info toast is the green "done" toast), warning → attention, error → danger. + * Gitea 28.x: the level is a class (toast-success | toast-info | toast-warning | toast-error) with a tinted background and + * a 1px level border, no inline style; info is its own level there (octicon-info) → Primer's default blue Toast-icon. */ .toastify { align-items: stretch; + border: 0; width: max-content; min-width: min(var(--overlay-width-small), calc(100vw - 2 * var(--base-size-16))); max-width: min(450px, calc(100vw - 2 * var(--base-size-16))); @@ -36,15 +39,15 @@ } /* toast.ts always sets the level's inline `background: var(--color-green|orange|red)` */ -.toastify[style*="--color-green"] .toast-icon { +.toastify:is([style*="--color-green"], .toast-success) .toast-icon { background-color: var(--bgColor-success-emphasis); } -.toastify[style*="--color-orange"] .toast-icon { +.toastify:is([style*="--color-orange"], .toast-warning) .toast-icon { background-color: var(--bgColor-attention-emphasis); } -.toastify[style*="--color-red"] .toast-icon { +.toastify:is([style*="--color-red"], .toast-error) .toast-icon { background-color: var(--bgColor-danger-emphasis); } @@ -58,7 +61,7 @@ visibility: hidden; } -.toastify[style*="--color-red"] .toast-icon .gitea-exclamation { +.toastify:is([style*="--color-red"], .toast-error) .toast-icon .gitea-exclamation { mask-image: var(--gh-octicon-stop); } diff --git a/src/pages/actions-packages-projects/action-run.css b/src/pages/actions-packages-projects/action-run.css index 2493dd6..da8f1a6 100644 --- a/src/pages/actions-packages-projects/action-run.css +++ b/src/pages/actions-packages-projects/action-run.css @@ -675,3 +675,25 @@ a.graph-workflow-name:hover { display: none; } } + +/* ---------- artifact preview (Gitea 28.x repo/actions/artifact_preview.tmpl) ---------- + The run header (back link, title, Download) is the run page's; the file list is a NavList that starts with a "Files" + group heading, which navigation's settings-sidebar rules (menus starting with a .header) would hide, and whose link + rows would get the settings 16px icon slot in front of their own octicon. Here it is a file tree: the heading shows, + rows keep only their file / folder octicon, and Gitea's per-row --depth indents 16px per level from the 8px inset. */ +.flex-container-nav > .menu > .header:first-child:has(~ .artifact-preview-item) { + display: block; +} + +.flex-container-nav > .menu > a.artifact-preview-item::before { + content: none; +} + +.ui.vertical.menu .artifact-preview-item { + padding-left: calc(var(--control-medium-paddingInline-condensed) + var(--depth, 0) * var(--base-size-16)); +} + +.ui.vertical.menu .artifact-preview-item > .svg { + flex-shrink: 0; + color: var(--fgColor-muted); +} diff --git a/src/pages/actions-packages-projects/actions-list.css b/src/pages/actions-packages-projects/actions-list.css index 0857dfe..9480943 100644 --- a/src/pages/actions-packages-projects/actions-list.css +++ b/src/pages/actions-packages-projects/actions-list.css @@ -25,24 +25,26 @@ the repo UnderlineNav (no gap); content padding 16px 24px (16px at md), so the runs Box is 1056px wide at x=360. Gitea: .ui.container (1280px, centred) > .flex-container (240px nav, 16px gap) → from md the container spans the page and the nav becomes the bordered pane. `:has(.run-list)` = the runs list page only (also with an empty - filter result); the settings Actions pages share `.repository.actions` but have no .run-list. */ + filter result); the settings Actions pages share `.repository.actions` but have no .run-list. Gitea 28.x adds a + second sidebar menu ("Management" → Job queue) and the Job queue page (#actions-job-queue, no .run-list) shares the + pane: `.menu + .menu` / #actions-job-queue select it; GitHub's Caches/Runners pages use the same PageLayout. */ @media (min-width: 768px) { - .page-content.repository.actions:has(.run-list) > .secondary-nav { + .page-content.repository.actions:has(:is(.run-list, #actions-job-queue)) > .secondary-nav { margin-bottom: 0; } - .page-content.repository.actions:has(.run-list) > .container.ui { + .page-content.repository.actions:has(:is(.run-list, #actions-job-queue)) > .container.ui { width: 100%; max-width: none; margin: 0; } /* alerts above the layout keep the content padding */ - .page-content.repository.actions > .ui.container > :not(.flex-container):has(~ .flex-container .run-list) { + .page-content.repository.actions > .ui.container > :not(.flex-container):has(~ .flex-container :is(.run-list, #actions-job-queue)) { margin: var(--base-size-16) var(--base-size-16) 0; } - .repository.actions > .ui.container > .flex-container:has(.run-list) { + .repository.actions > .ui.container > .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) { gap: 0; margin-top: 0; } @@ -52,62 +54,66 @@ 100vh). Gitea: the chain .full.height > .page-content > .ui.container > .flex-container grows to the footer (the page's bottom space moves into the content column), the nav is the full-height bordered pane and its menu is the sticky part. */ - .full.height:has(> .page-content > .ui.container > .flex-container > .flex-container-main > .segment > .run-list) { /* fixed child path: PERF-3 */ + .full.height:has(> .page-content > .ui.container > .flex-container > .flex-container-main > .segment > .run-list, > .page-content > .ui.container > .flex-container > .flex-container-main > #actions-job-queue) { /* fixed child paths: PERF-3 */ display: flex; flex-direction: column; padding-bottom: 0; } - .page-content.repository.actions:has(.run-list), - .page-content.repository.actions:has(.run-list) > .container.ui { + .page-content.repository.actions:has(:is(.run-list, #actions-job-queue)), + .page-content.repository.actions:has(:is(.run-list, #actions-job-queue)) > .container.ui { display: flex; flex-direction: column; flex-grow: 1; } - .repository.actions > .ui.container > .flex-container:has(.run-list) { + .repository.actions > .ui.container > .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) { flex-grow: 1; } - .flex-container:has(.run-list) > .flex-container-nav { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav { flex: 0 0 auto; width: calc(var(--base-size-128) * 2); + /* the pane's content is the sticky scroll box (one box: 28.x stacks two menus in it); the full-height divider is + drawn by the content column into this transparent border, at the same x as before */ + position: sticky; + top: 0; + align-self: flex-start; + max-height: 100vh; + overflow-y: auto; padding: var(--base-size-16); - border-right: var(--borderWidth-thin) solid var(--borderColor-default); + border-right: var(--borderWidth-thin) solid transparent; } - .flex-container:has(.run-list) > .flex-container-nav > .menu { - position: sticky; - top: var(--base-size-16); - max-height: calc(100vh - var(--base-size-32)); - overflow-y: auto; - /* the scroll box also clips inline: keep the NavList's current-item bar (8px left of the item) inside it; the - matching width is in pages.important.css (Gitea: `.ui.vertical.menu.fluid { width: 100% !important }`) */ + /* keep the NavList's current-item bar (8px left of the item) clear of the item box; the matching width is in + pages.important.css (Gitea: `.ui.vertical.menu.fluid { width: 100% !important }`) */ + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav > .menu { margin-inline: calc(var(--base-size-8) * -1); padding-inline: var(--base-size-8); } - .flex-container:has(.run-list) > .flex-container-main { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-main { padding: var(--base-size-16) var(--base-size-16) var(--page-space-bottom); + box-shadow: calc(var(--borderWidth-thin) * -1) 0 0 var(--borderColor-default); } } @media (min-width: 1012px) { - .flex-container:has(.run-list) > .flex-container-nav { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav { width: calc(var(--base-size-128) * 2 + var(--base-size-64)); } - .flex-container:has(.run-list) > .flex-container-main { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-main { padding-inline: var(--base-size-24); } - .page-content.repository.actions > .ui.container > :not(.flex-container):has(~ .flex-container .run-list) { + .page-content.repository.actions > .ui.container > :not(.flex-container):has(~ .flex-container :is(.run-list, #actions-job-queue)) { margin-inline: var(--base-size-24); } } @media (min-width: 1280px) { - .flex-container:has(.run-list) > .flex-container-nav { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav { width: calc(var(--base-size-128) * 2 + var(--base-size-80)); } } @@ -120,7 +126,7 @@ template was rejected, FG-049) → English-only generated text; a selected workflow's name is not reachable from CSS, so the PageHeader shows only while "All workflows" is the current item. */ @media (min-width: 768px) { - html:lang(en) .flex-container:has(.run-list) > .flex-container-nav > .menu::before { + html:lang(en) .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav > .menu:first-child::before { content: "Actions"; margin: var(--base-size-4) 0 var(--base-size-8); font-size: var(--text-title-size-medium); @@ -129,11 +135,11 @@ } /* the rule is the second item's ::before (Gitea hides `.ui.vertical.menu .item:first-child::before` !important) */ - .flex-container:has(.run-list) > .flex-container-nav > .menu > .item:first-child + .item { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav > .menu > .item:first-child + .item { margin-top: var(--base-size-16); } - .flex-container:has(.run-list) > .flex-container-nav > .menu > .item:first-child + .item::before { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav > .menu > .item:first-child + .item::before { content: ""; display: block; position: absolute; @@ -494,3 +500,13 @@ a.run-list-ref:hover { gap: var(--base-size-4); } } + +/* Gitea 28.x job queue (shared/actions/job_queue_list.tmpl, repo Actions and the admin / user / org settings pages): + a DataTable — cells on one line, a table wider than the Box scrolls inside it (github.com's tables on small screens) */ +#actions-job-queue > .table.segment { + overflow-x: auto; +} + +#actions-job-queue > .table.segment > .ui.table > tbody { + white-space: nowrap; +} diff --git a/src/pages/actions-packages-projects/pages.important.css b/src/pages/actions-packages-projects/pages.important.css index 12ace7f..1c2fddc 100644 --- a/src/pages/actions-packages-projects/pages.important.css +++ b/src/pages/actions-packages-projects/pages.important.css @@ -60,10 +60,10 @@ } } -/* Actions runs pane (actions-list.css): the sticky NavList scroll box reaches 8px past the pane padding on both sides +/* Actions runs pane (actions-list.css): the NavList reaches 8px past the pane padding on both sides so the current-item bar is not clipped; Gitea pins `.ui.vertical.menu.fluid` to `width: 100% !important` */ @media (min-width: 768px) { - .flex-container:has(.run-list) > .flex-container-nav > .menu { + .flex-container:is(:has(.run-list), :has(> .flex-container-nav > .menu + .menu)) > .flex-container-nav > .menu { width: calc(100% + var(--base-size-16)) !important; } } diff --git a/src/pages/issues-prs/composer.css b/src/pages/issues-prs/composer.css index 98b39e9..16242cb 100644 --- a/src/pages/issues-prs/composer.css +++ b/src/pages/issues-prs/composer.css @@ -120,28 +120,28 @@ line-height: var(--text-body-lineHeight-medium); } -:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .field:has(> .ui.dropzone) { +:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .field:has(> .dropzone) { padding: 0 var(--base-size-8); } -:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .ui.dropzone { +:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .dropzone { background: var(--bgColor-muted); color: var(--fgColor-muted); font-size: var(--text-body-size-small); text-align: left; } -:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .ui.dropzone .dz-message { +:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .dropzone .dz-message { margin: 0; } -:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .ui.dropzone .dz-button { +:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .dropzone .dz-button { padding: 0; font-size: var(--text-body-size-small); line-height: var(--text-body-lineHeight-medium); } -:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .ui.dropzone:hover .dz-button { +:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .dropzone:hover .dz-button { color: var(--fgColor-accent); } @@ -169,6 +169,6 @@ padding: var(--base-size-8) var(--base-size-16); } -:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .field:has(> .combo-markdown-editor > .ui.tab.active[data-tab-panel="markdown-previewer"]) ~ .field:has(> .ui.dropzone) { +:is(#comment-form, #new-issue, .code-comments-list form.comment-form) .field:has(> .combo-markdown-editor > .ui.tab.active[data-tab-panel="markdown-previewer"]) ~ .field:has(> .dropzone) { display: none; } diff --git a/src/pages/issues-prs/composer.important.css b/src/pages/issues-prs/composer.important.css index f9da813..77fbcf7 100644 --- a/src/pages/issues-prs/composer.important.css +++ b/src/pages/issues-prs/composer.important.css @@ -4,7 +4,7 @@ * github.com file bar under the comment textarea: 1px --borderColor-default (the textarea draws the dashed rule), * radius 0 0 6 6, padding 8px. */ -:is(#comment-form, #new-issue, .code-comments-list .conversation-holder form.comment-form) .ui.dropzone { +:is(#comment-form, #new-issue, .code-comments-list .conversation-holder form.comment-form) .dropzone { min-height: 0 !important; padding: var(--base-size-8) !important; border: var(--borderWidth-thin) solid var(--borderColor-default) !important; @@ -18,7 +18,7 @@ } /* dropzone.css: `.dropzone .dz-message { text-align: center; margin: 3em 0 }` */ -:is(#comment-form, #new-issue, .code-comments-list .conversation-holder form.comment-form) .ui.dropzone .dz-message { +:is(#comment-form, #new-issue, .code-comments-list .conversation-holder form.comment-form) .dropzone .dz-message { margin: 0 !important; text-align: left !important; } diff --git a/src/pages/people/box.css b/src/pages/people/box.css index 4551ab4..93c82e7 100644 --- a/src/pages/people/box.css +++ b/src/pages/people/box.css @@ -9,7 +9,7 @@ #notification_table, #readme_profile, #user-heatmap > div::before, -#activity-feed .item-main > :is(div:has(> .flex-text-block > .sha), .truncated-markup) { +#activity-feed .item-main > :is(div:has(> .flex-text-block > .sha), .truncated-markup, .render-content) { /* .render-content: 28.x comment excerpt */ border: var(--borderWidth-thin) solid var(--borderColor-default); border-radius: var(--borderRadius-medium); background: var(--bgColor-default); diff --git a/src/pages/people/dashboard.css b/src/pages/people/dashboard.css index 624f9bb..ad97443 100644 --- a/src/pages/people/dashboard.css +++ b/src/pages/people/dashboard.css @@ -241,7 +241,7 @@ } /* comment excerpt (Box card), muted text */ -#activity-feed .item-main > .truncated-markup { +#activity-feed .item-main > :is(.truncated-markup, .render-content) { /* 28.x dropped .truncated-markup */ padding: var(--base-size-12) var(--base-size-16); color: var(--fgColor-muted); } diff --git a/src/pages/people/media.css b/src/pages/people/media.css index f96b3c4..752c95d 100644 --- a/src/pages/people/media.css +++ b/src/pages/people/media.css @@ -120,7 +120,7 @@ background: var(--borderColor-accent-emphasis); } - .notification .flex-left-right > form { + .notification .flex-left-right > :is(form, .flex-text-block) { grid-area: 1 / 2; justify-self: end; margin-bottom: var(--base-size-16); @@ -131,7 +131,7 @@ } /* no purge button (read view / nothing unread): the Box starts at the top */ - .notification :not(:has(.flex-left-right > form)) > #notification_table { + .notification :not(:has(.flex-left-right > :is(form, .flex-text-block))) > #notification_table { grid-row: 1 / span 2; } @@ -161,7 +161,7 @@ } /* "Mark all as read" next to the 32px SegmentedControl: a medium Button, so the toolbar row has one control height */ - .notification .flex-left-right > form > .button { + .notification .flex-left-right > :is(form, .flex-text-block) > .button { height: var(--control-medium-size); padding: 0 var(--control-medium-paddingInline-normal); font-size: var(--text-body-size-medium); @@ -219,6 +219,57 @@ order: 7; } + /* Gitea 28.x sidebar (profile.css "sidebar on Gitea 28.x"): same 64px avatar beside the name */ + #profile-avatar-card.segment { + display: grid; + grid-template-columns: var(--base-size-64) minmax(0, 1fr); + column-gap: var(--base-size-16); + align-items: center; + } + + #profile-avatar-card.segment > .flex-divided-list > .item, + #profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > * { + grid-column: 1 / -1; + } + + #profile-avatar-card.segment > .flex-divided-list > .item:first-child { + grid-column: 1; + grid-row: 1 / span 2; + } + + #profile-avatar-card.segment .profile-avatar-image { + width: 100%; + } + + #profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > span { + grid-column: 2; + margin-top: 0; + align-self: end; + } + + #profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > span:first-child { + align-self: start; + } + + #profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > span:first-child:nth-last-child(2) { + grid-row: 1 / span 2; + margin-top: 0; + align-self: center; + } + + #profile-avatar-card.segment > .flex-divided-list > .item:has(> .render-content) { + margin: var(--base-size-16) 0 var(--base-size-8); + } + + #profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > div { + order: 7; + margin: var(--base-size-8) 0 0; + } + + #profile-avatar-card.segment > .flex-divided-list > .item:has(> .button) { + order: 7; + } + /* ---------- repo lists (repo-list.css) ---------- */ :is(.profile, .explore) .filter.menu > form > .ui.action.input { flex-basis: 100%; diff --git a/src/pages/people/notifications.css b/src/pages/people/notifications.css index 529719a..aaa2e74 100644 --- a/src/pages/people/notifications.css +++ b/src/pages/people/notifications.css @@ -22,9 +22,9 @@ line-height: calc(var(--base-size-20) - 2 * var(--borderWidth-thin)); } -/* "Mark all as read": Gitea's icon-only green button → a small default Button; the label is the button's own - (localized) title */ -.notification .flex-left-right > form > .button { +/* "Mark all as read" (28.x also "Mark this page as read"): Gitea's icon-only (green) buttons → small default Buttons; + the label is the button's own localized title / tooltip */ +.notification .flex-left-right > :is(form, .flex-text-block) > .button { height: var(--control-small-size); padding: 0 var(--control-small-paddingInline-condensed); border-color: var(--button-default-borderColor-rest); @@ -35,21 +35,26 @@ font-weight: var(--base-text-weight-medium); } -.notification .flex-left-right > form > .button::after { +.notification .flex-left-right > :is(form, .flex-text-block) > .button::after { content: attr(title); } -.notification .flex-left-right > form > .button > .svg { +/* Gitea 28.x: "Mark this page as read" + "Mark all as read" in a .flex-text-block, labelled by their tooltip text */ +.notification .flex-left-right > .flex-text-block > .button::after { + content: attr(data-tooltip-content); +} + +.notification .flex-left-right > :is(form, .flex-text-block) > .button > .svg { color: var(--fgColor-muted); } -.notification .flex-left-right > form > .button:hover { +.notification .flex-left-right > :is(form, .flex-text-block) > .button:hover { border-color: var(--button-default-borderColor-hover); background: var(--button-default-bgColor-hover); color: var(--button-default-fgColor-rest); } -.notification .flex-left-right > form > .button:active { +.notification .flex-left-right > :is(form, .flex-text-block) > .button:active { border-color: var(--button-default-borderColor-active); background: var(--button-default-bgColor-active); } diff --git a/src/pages/people/people.important.css b/src/pages/people/people.important.css index ae996c4..56c3ee7 100644 --- a/src/pages/people/people.important.css +++ b/src/pages/people/people.important.css @@ -140,3 +140,13 @@ .explore.users .flex-divided-list > .item { align-items: flex-start !important; } + +/* Gitea 28.x profile sidebar: the avatar item's tw-p-5 / tw-justify-center and the name block's tw-text-center */ +#profile-avatar-card.segment > .flex-divided-list > .item:first-child { + justify-content: flex-start !important; + padding: 0 !important; +} + +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > * { + text-align: left !important; +} diff --git a/src/pages/people/profile.css b/src/pages/people/profile.css index e536874..a5149d0 100644 --- a/src/pages/people/profile.css +++ b/src/pages/people/profile.css @@ -204,6 +204,180 @@ html:lang(en) .card li:has(> .user-orgs)::before { order: 4; } +/* ---------- sidebar on Gitea 28.x ---------- + * profile_big_avatar.tmpl became `#profile-avatar-card.ui.fitted.segment > .flex-divided-list > .item` (1.27.x: the + * .ui.card above): avatar item, name item (username + bot label + admin gear, full name, followers), then one item per + * detail, bio, joined date, organisations, badges, Follow, Block. Flattened the same way: the segment is the flex column, + * the list and the name item are `display: contents`, `order` restores github.com's sequence. Tailwind's !important + * tw-p-5 / tw-text-center are undone in people.important.css. */ +#profile-avatar-card.segment { + display: flex; + flex-direction: column; + margin: 0; + padding: 0; + border: 0; + background: none; + box-shadow: none; +} + +#profile-avatar-card.segment > .flex-divided-list, +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) { + display: contents; +} + +/* vcard details: 25px rows 4px apart (see `.card li` above) */ +#profile-avatar-card.segment > .flex-divided-list > .item { + display: flex; + align-items: flex-start; + gap: var(--base-size-8); + order: 6; + padding: var(--base-size-8) 0 0; + border: 0; +} + +#profile-avatar-card.segment > .flex-divided-list > .item > .svg { + flex-shrink: 0; + margin-top: var(--base-size-2); + color: var(--fgColor-muted); +} + +/* avatar: full sidebar width, above the tab bar's full-width rule */ +#profile-avatar-card.segment > .flex-divided-list > .item:first-child { + position: relative; + z-index: 1; + order: 0; + line-height: 0; +} + +#profile-avatar-card.segment > .flex-divided-list > .item:first-child > a { + flex: 1; +} + +#profile-avatar-card.segment .profile-avatar-image { + width: 100%; + max-width: none; +} + +/* full name (second span) 24px semibold, then the username 20px light muted */ +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > span + span { + order: 1; + margin: var(--base-size-16) 0 0; + color: var(--fgColor-default); + font-size: var(--base-size-24); + font-weight: var(--base-text-weight-semibold); + line-height: calc(var(--base-size-32) - var(--base-size-2)); +} + +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > span:first-child { + display: flex; + align-items: center; + gap: var(--base-size-8); + order: 2; + color: var(--fgColor-muted); + font-size: var(--text-title-size-medium); + font-weight: var(--base-text-weight-light); + line-height: var(--base-size-24); +} + +/* no full name: the username stands where the name would be */ +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > span:first-child:nth-last-child(2) { + margin-top: var(--base-size-16); +} + +/* followers · following */ +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > div { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0 var(--base-size-4); + order: 5; + margin: 0 0 var(--base-size-12); + color: var(--fgColor-muted); +} + +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > div a { + display: inline-flex; + align-items: center; + color: var(--fgColor-muted); +} + +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > div a:hover { + color: var(--fgColor-accent); + text-decoration: none; +} + +#profile-avatar-card.segment > .flex-divided-list > .item:nth-child(2) > div i { + display: inline-flex; +} + +/* bio, 16px/24px above the follower line */ +#profile-avatar-card.segment > .flex-divided-list > .item:has(> .render-content) { + order: 4; + margin-bottom: var(--base-size-16); + padding: 0; +} + +#profile-avatar-card.segment > .flex-divided-list > .item > .render-content { + font-size: var(--text-body-size-large); +} + +#profile-avatar-card.segment > .flex-divided-list > .item.tw-text-red { + order: 4; +} + +/* Follow / Unfollow: full-width default button, 16px under the username */ +#profile-avatar-card.segment > .flex-divided-list > .item:has(> .button) { + order: 3; + margin: var(--base-size-16) 0; + padding: 0; +} + +#profile-avatar-card.segment > .flex-divided-list > .item > .ui.button { + margin: 0; + border-color: var(--button-default-borderColor-rest); + background: var(--button-default-bgColor-rest); + box-shadow: var(--button-default-shadow-resting); + color: var(--button-default-fgColor-rest); +} + +#profile-avatar-card.segment > .flex-divided-list > .item > .ui.button:hover { + border-color: var(--button-default-borderColor-hover); + background: var(--button-default-bgColor-hover); +} + +/* organisations (32px rounded-square avatars, "Organizations" heading), badges, "Block user" last */ +#profile-avatar-card.segment > .flex-divided-list > .item:is(:has(> .flex-text-block > a > .avatar), :last-child:has(> a:only-child)) { + order: 8; + margin-top: var(--base-size-16); + padding: var(--base-size-16) 0 0; + border-top: var(--borderWidth-thin) solid var(--borderColor-muted); +} + +#profile-avatar-card.segment > .flex-divided-list > .item:has(> .user-badges) { + order: 8; +} + +#profile-avatar-card.segment > .flex-divided-list > .item:last-child:has(> a:only-child) { + order: 9; +} + +#profile-avatar-card.segment > .flex-divided-list > .item > .flex-text-block > a > img.avatar { + width: var(--base-size-32); + height: var(--base-size-32); + border-radius: var(--borderRadius-medium); +} + +#profile-avatar-card.segment > .flex-divided-list > .item:has(> .flex-text-block > a > .avatar) { + flex-direction: column; + gap: var(--base-size-8); +} + +html:lang(en) #profile-avatar-card.segment > .flex-divided-list > .item:has(> .flex-text-block > a > .avatar)::before { + content: "Organizations"; + color: var(--fgColor-default); + font: var(--text-title-shorthand-small); +} + /* ---------- main column: the UnderlineNav's bottom rule runs across the whole page ---------- */ .user.profile overflow-menu { margin-bottom: var(--base-size-24); diff --git a/src/pages/repo/commits.css b/src/pages/repo/commits.css index 9af8f15..4773e01 100644 --- a/src/pages/repo/commits.css +++ b/src/pages/repo/commits.css @@ -335,6 +335,10 @@ html:lang(en) .gh-commit-day-date::before { .commit-header-buttons { flex-direction: row; } + + .repository.diff > .container > .header.top.segment:first-child > .flex-left-right { + flex-wrap: wrap; + } } /* commit page: github.com's commit message Box has no muted header band */ @@ -364,6 +368,44 @@ html:lang(en) .gh-commit-day-date::before { color: var(--fgColor-default); } +/* Gitea 28.x commit page: the message box lost `.commit-header`; it is the container's first `.ui.top.attached.header + .segment` (the only other one is the git-notes box). Same rules as the 1.27.x ones above; parents and commit SHA now + sit in the author row's trailing .flex-text-block. */ +.repository.diff > .container > .header.top.segment:first-child { + background: var(--bgColor-default); +} + +.repository.diff > .container > .header.top.segment:first-child > :is(.commit-body, .branch-and-tag-area) { + font-weight: var(--base-text-weight-normal); +} + +.repository.diff > .container > .header.top.segment:first-child + .segment > .flex-text-block:last-child { + color: var(--fgColor-muted); + font-family: var(--fontStack-monospace); + font-size: var(--text-body-size-small); +} + +.repository.diff > .container > .header.top.segment:first-child + .segment .commit-id-short { + width: 7ch; + overflow: hidden; + padding: 0; + border: 0; + background: none; + color: var(--fgColor-default); +} + +/* the "N files changed +a −d ■■■■■" row closing the box (ShowDiffSummaryInCommitHeader) is github.com's commit header + footer row (measured 2026-10-12, CommitHeader commitFilesChangedContainer): padding 8px 12px, 14px/21px semibold count, + 12px/18px semibold +/− */ +.repository.diff > .container > .header.top.segment:first-child + .segment + .segment.flex-left-right { + padding: var(--base-size-8) var(--base-size-12); +} + +.repository.diff > .container > .header.top.segment:first-child + .segment + .segment.flex-left-right > .flex-text-block { + font-size: var(--text-body-size-small); + line-height: var(--base-text-lineHeight-normal); +} + /* ---------- commit page header (templates/repo/commit_page.tmpl .commit-header-buttons) ---------- Gitea renders "Browse Source" and "Operations ▾" as green primary buttons; github.com's "Browse files" is a default (secondary) button: the primary Button tokens controls reads are pointed at the default ones here. */ diff --git a/src/pages/repo/scopes.json b/src/pages/repo/scopes.json index a7f0a81..9cd0c01 100644 --- a/src/pages/repo/scopes.json +++ b/src/pages/repo/scopes.json @@ -12,7 +12,7 @@ "repo/branch/list.tmpl" ], "waived": { - "repo/settings/protected_branch.tmpl": "probe 13/64 apply (status-check table td padding, > .ui.container); looked at shots/l2b-leaks/branch-rule*.png: settings layout and the status-check table render correctly \u2014 accepted (integrator L2b)" + "repo/settings/protected_branch.tmpl": "probe 13/64 apply (status-check table td padding, > .ui.container); looked at shots/l2b-leaks/branch-rule*.png: settings layout and the status-check table render correctly — accepted (integrator L2b)" } }, ".commits": { @@ -40,7 +40,7 @@ "repo/commits.tmpl" ], "waived": { - "repo/graph.tmpl": "graph shares the page class \"repository commits\"; probe 3/18 apply (container Box/padding); looked at shots/l2b-leaks/graph.png: graph rows and lines aligned \u2014 accepted (integrator L2b)" + "repo/graph.tmpl": "graph shares the page class \"repository commits\"; probe 3/18 apply (container Box/padding); looked at shots/l2b-leaks/graph.png: graph rows and lines aligned — accepted (integrator L2b)" } }, ".diff": [ @@ -48,6 +48,15 @@ "repo/diff/compare.tmpl", "repo/pulls/files.tmpl" ], + ".diff.repository": { + "intended": [ + "repo/commit_page.tmpl" + ], + "waived": { + "repo/diff/compare.tmpl": "inert: the rules need `> .container > .header.top.segment:first-child`, which only the commit page has (probe: 0 matches on /compare and on PR Files, 1.27.3 and 28.1.0)", + "repo/pulls/files.tmpl": "inert: the rules need `> .container > .header.top.segment:first-child`, which only the commit page has (probe: 0 matches on /compare and on PR Files, 1.27.3 and 28.1.0)" + } + }, ".diff:not(.pull)": [ "repo/commit_page.tmpl", "repo/diff/compare.tmpl" diff --git a/src/pages/repo/tags-releases.css b/src/pages/repo/tags-releases.css index 9251ca1..42036a8 100644 --- a/src/pages/repo/tags-releases.css +++ b/src/pages/repo/tags-releases.css @@ -11,6 +11,8 @@ * Gitea's .meta column (tag, commit, Compare) is folded into the card (byline items / top-right Compare), see below. * Tags list (Box): rows padding 16px, tag name 16px semibold --fgColor-default, meta row 12px --fgColor-muted with * 16px octicons, 16px apart. + * Gitea 28.x release_tag_header.tmpl: `.flex-left-right > h2 + .flex-text-block (RSS, New Release)` instead of 1.27's + * `.flex-text-block > .tw-flex-1 > h2 + buttons`: the header selectors take either wrapper, the buttons at any depth. * Gitea: templates/repo/release_tag_header.tmpl, release/list.tmpl (ul#release-list > li.release-entry > .meta + * .ui.segment.detail), tag/list.tmpl (.tag-list-row); CSS web_src/css/repo/release-tag.css. */ @@ -48,7 +50,7 @@ color: var(--fgColor-onEmphasis); } -:is(.releases, .tags) > .ui.container > .flex-text-block:first-child + .divider { +:is(.releases, .tags) > .ui.container > :is(.flex-text-block, .flex-left-right):first-child + .divider { margin: var(--base-size-24) 0 var(--base-size-16); /* github.com: segment → rule 24px, rule → tags Box 16px */ border: 0; border-top: var(--borderWidth-thin) solid var(--borderColor-default); @@ -56,13 +58,13 @@ /* github.com /releases: 48px from the rule to the first release card (measured pemistahl/grex 2026-09-30: rule y=262, card y=311) */ -.releases > .ui.container > .flex-text-block:first-child + .divider { +.releases > .ui.container > :is(.flex-text-block, .flex-left-right):first-child + .divider { margin-bottom: var(--base-size-48); } /* "RSS Feed" / "New Release": github.com's "Draft a new release" is a medium (32px, 14px) Button, the same height as the Releases | Tags segment next to it */ -:is(.releases, .tags) > .ui.container > .flex-text-block:first-child > a.ui.button { +:is(.releases, .tags) > .ui.container > :is(.flex-text-block, .flex-left-right):first-child a.ui.button { height: var(--control-medium-size); min-height: 0; padding: 0 var(--control-medium-paddingInline-normal); @@ -79,11 +81,11 @@ as its accessible name), and New Release fills whatever is left — the rest of the first row when it fits, else a full-width second row (never a lone half-row button). */ @media (max-width: 767.98px) { - :is(.releases, .tags) > .ui.container > .flex-text-block:first-child { + :is(.releases, .tags) > .ui.container > :is(.flex-text-block, .flex-left-right):first-child { flex-wrap: wrap; } - .releases > .ui.container > .flex-text-block:first-child + .divider { + .releases > .ui.container > :is(.flex-text-block, .flex-left-right):first-child + .divider { margin-bottom: var(--base-size-24); } @@ -92,11 +94,21 @@ min-width: max-content; } - .releases > .ui.container > .flex-text-block:first-child > a.ui.primary.button { + .releases > .ui.container > :is(.flex-text-block, .flex-left-right):first-child a.ui.primary.button { flex: 1 0 auto; } - :is(.releases, .tags) > .ui.container > .flex-text-block:first-child > a.ui.button[href$=".rss"] { + /* 28.x: the buttons' own wrapper steps aside so they flow like 1.27's (segment grows, New Release fills or wraps) */ + :is(.releases, .tags) > .ui.container > .flex-left-right:first-child > .flex-text-block { + display: contents; + } + + :is(.releases, .tags) > .ui.container > .flex-left-right:first-child > .small-menu-items { + flex: 1 1 0%; + min-width: max-content; + } + + :is(.releases, .tags) > .ui.container > :is(.flex-text-block, .flex-left-right):first-child a.ui.button[href$=".rss"] { width: var(--control-medium-size); padding: 0; font-size: 0; @@ -572,7 +584,7 @@ max-width: calc(100% - 2 * var(--page-margin-x)); } - :scope.repository.releases > .ui.container > .flex-text-block:first-child + .divider { + :scope.repository.releases > .ui.container > :is(.flex-text-block, .flex-left-right):first-child + .divider { margin-bottom: var(--base-size-16); } diff --git a/src/pages/settings-admin/audit-log.css b/src/pages/settings-admin/audit-log.css new file mode 100644 index 0000000..5413319 --- /dev/null +++ b/src/pages/settings-admin/audit-log.css @@ -0,0 +1,26 @@ +/* + * Audit log (Gitea 28.x: shared/audit/list.tmpl in user / org / repo settings and admin Monitoring) — github.com's + * security / audit log: one filter row of 32px controls above a Box listing the events, nothing scrolling sideways. + * Gitea: `.ui.attached.segment > form` (actor input + search button, action / origin selects turned into Fomantic + * selection dropdowns) + `.ui.attached.table.segment > table` (Actor, Scope, Action, Origin, Details, IP, Timestamp). + * The filter form is the one holding the origin select; the table is the one sorted by timestamp. + */ + +/* filter row: the 28px small input group grows to the selects' 32px (Primer medium controls) */ +.flex-container-main form.ui.form:has(select[name="origin"]) > .ui.small.input > input { + height: var(--control-medium-size); +} + +/* the event table fits the Box from md: the admin DataTable keeps its cells on one line and scrolls (admin.css), but an + audit event's Details is prose that github.com wraps; the timestamp (relative-time, format datetime) stays on one + line. Below md the table keeps the DataTable behaviour (one line per cell, scrolling in the Box). */ +@media (min-width: 768px) { + :is(.settings, .admin) .flex-container-main .ui.table:has(th[data-sortt-asc="timestamp_asc"]) > tbody { + white-space: normal; + overflow-wrap: break-word; + } + + :is(.settings, .admin) .flex-container-main .ui.table:has(th[data-sortt-asc="timestamp_asc"]) relative-time { + white-space: nowrap; + } +} diff --git a/src/pages/settings-admin/blankslate.css b/src/pages/settings-admin/blankslate.css index 0540740..6036aa2 100644 --- a/src/pages/settings-admin/blankslate.css +++ b/src/pages/settings-admin/blankslate.css @@ -16,14 +16,15 @@ * --fgColor-muted (a section description in place of rows). The Octicon is a mask on ::before: key unless the * folder-local --gh-sa-i names another (webhook, git-branch). * webhooks: the description
right before the .flex-divided-list (with hooks a .divider sits between them); - * deploy keys: the text node after the hidden add panel (the panel is the segment's last element); + * deploy keys: the text node after the hidden add panel (the panel is the segment's last element; 28.x: after the + * hidden SSH and token panels); * branch protection: the lone centred row of #protected-branches-list; * SSH / GPG keys, access tokens, OAuth2 applications and grants: a list whose only row is its description. * One selector per rule (alternatives inside :is()), so the build's prefix nesting never splits a declaration block. */ :is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main :is( div:not([class]):has(+ .flex-divided-list), - :has(> #add-deploy-key-panel.tw-hidden:last-child), + :has(> #add-deploy-key-panel.tw-hidden:last-child, > #add-deploy-key-ssh-panel.tw-hidden + #add-deploy-key-token-panel.tw-hidden:last-child), #protected-branches-list > .tw-text-center, :is(.sshkeys, .applications) .flex-divided-list > .item:only-child:not(:has(> :not(p))) ) { @@ -41,7 +42,7 @@ :is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main :is( div:not([class]):has(+ .flex-divided-list), - :has(> #add-deploy-key-panel.tw-hidden:last-child), + :has(> #add-deploy-key-panel.tw-hidden:last-child, > #add-deploy-key-ssh-panel.tw-hidden + #add-deploy-key-token-panel.tw-hidden:last-child), #protected-branches-list > .tw-text-center, :is(.sshkeys, .applications) .flex-divided-list > .item:only-child:not(:has(> :not(p))) )::before { @@ -60,7 +61,7 @@ /* a one-line empty message reads as the Blankslate heading */ :is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main :is( - :has(> #add-deploy-key-panel.tw-hidden:last-child), + :has(> #add-deploy-key-panel.tw-hidden:last-child, > #add-deploy-key-ssh-panel.tw-hidden + #add-deploy-key-token-panel.tw-hidden:last-child), #protected-branches-list > .item ) { color: var(--fgColor-default); diff --git a/src/pages/settings-admin/buttons.css b/src/pages/settings-admin/buttons.css index 6f6c955..fe704fe 100644 --- a/src/pages/settings-admin/buttons.css +++ b/src/pages/settings-admin/buttons.css @@ -22,7 +22,7 @@ :is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .ui.primary.button:is( .admin.dashboard .ui.table *, .admin dd *, - .ui.top.attached.header :is(.ui.jump.dropdown > *, [data-panel="#add-deploy-key-panel"], [href$="/settings/branches/edit"]), + .ui.top.attached.header :is(.ui.jump.dropdown > *, [data-panel^="#add-deploy-key-"], [href$="/settings/branches/edit"]), [name="request_reindex_type"], [href$="/-/admin/repos/unadopted"], #register-webauthn, @@ -41,7 +41,7 @@ :is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .ui.primary.button:is( .admin.dashboard .ui.table *, .admin dd *, - .ui.top.attached.header :is(.ui.jump.dropdown > *, [data-panel="#add-deploy-key-panel"], [href$="/settings/branches/edit"]), + .ui.top.attached.header :is(.ui.jump.dropdown > *, [data-panel^="#add-deploy-key-"], [href$="/settings/branches/edit"]), [name="request_reindex_type"], [href$="/-/admin/repos/unadopted"], #register-webauthn, @@ -59,7 +59,7 @@ :is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .ui.primary.button:is( .admin.dashboard .ui.table *, .admin dd *, - .ui.top.attached.header :is(.ui.jump.dropdown > *, [data-panel="#add-deploy-key-panel"], [href$="/settings/branches/edit"]), + .ui.top.attached.header :is(.ui.jump.dropdown > *, [data-panel^="#add-deploy-key-"], [href$="/settings/branches/edit"]), [name="request_reindex_type"], [href$="/-/admin/repos/unadopted"], #register-webauthn, diff --git a/src/pages/settings-admin/index.css b/src/pages/settings-admin/index.css index c3ae3c3..32387bc 100644 --- a/src/pages/settings-admin/index.css +++ b/src/pages/settings-admin/index.css @@ -21,6 +21,7 @@ * blankslate.css empty lists as a Primer Blankslate (Octicon visual; webhooks, deploy keys, branch protection, keys, * tokens, OAuth2 apps), add-people rows as Box header / footer, email / target lists as Boxes * sections.css two-factor methods as Box rows, org profile-picture column, body-less list rows centred + * audit-log.css Gitea 28.x audit log: one row of 32px filter controls, the event table fits the Box */ @import "./layout.css"; @import "./header.css"; @@ -32,3 +33,4 @@ @import "./buttons.css"; @import "./blankslate.css"; @import "./sections.css"; +@import "./audit-log.css"; diff --git a/src/pages/settings-admin/keys.css b/src/pages/settings-admin/keys.css index 43800c4..10f8e56 100644 --- a/src/pages/settings-admin/keys.css +++ b/src/pages/settings-admin/keys.css @@ -3,32 +3,32 @@ * a 32px key octicon (--fgColor-muted; --fgColor-success when recently used) in a leading column, * title 14px semibold --fgColor-default, fingerprint in the monospace stack 12px --fgColor-muted, * "Added on … / Last used …" 12px --fgColor-muted, a red Delete btn-sm on the right, rows 16px padded. - * Gitea: .items-with-main > .item > .item-leading (octicon-key 32) + .item-main (.item-title, .item-body ×2) + + * Gitea: .items-with-main > .item > .item-leading (octicon-key 32; 28.x deploy tokens: octicon-key-asterisk) + .item-main (.item-title, .item-body ×2) + * .item-trailing (.ui.red.tiny.button) — user/settings/keys_{ssh,gpg,principal}.tmpl, repo/settings/deploy_keys.tmpl, * user/settings/applications.tmpl (access tokens). */ -:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading .octicon-key) .item-leading { +:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading :is(.octicon-key, .octicon-key-asterisk)) .item-leading { color: var(--fgColor-muted); } -:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading .octicon-key) .item-main { +:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading :is(.octicon-key, .octicon-key-asterisk)) .item-main { gap: var(--base-size-4); } -:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading .octicon-key) .item-body { +:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading :is(.octicon-key, .octicon-key-asterisk)) .item-body { color: var(--fgColor-muted); font-size: var(--text-body-size-small); line-height: var(--text-body-lineHeight-small); } /* the first body line after the title is the fingerprint (the 14px semibold title comes from the settings list-row rule below) */ -:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading .octicon-key) .item-title + .item-body { +:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading :is(.octicon-key, .octicon-key-asterisk)) .item-title + .item-body { font-family: var(--fontStack-monospace); overflow-wrap: anywhere; } -:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading .octicon-key) .item-body i { +:is(.settings, .admin, .page-content:where(:not(.dashboard, .repository))) .flex-container-main .items-with-main > .item:has(> .item-leading :is(.octicon-key, .octicon-key-asterisk)) .item-body i { font-style: normal; } diff --git a/templates/base/head_impersonate_banner.tmpl b/templates/base/head_impersonate_banner.tmpl new file mode 100644 index 0000000..00adc90 --- /dev/null +++ b/templates/base/head_impersonate_banner.tmpl @@ -0,0 +1,10 @@ +{{/* gitea-theme-github: Gitea 28.1.0 templates/base/head_impersonate_banner.tmpl verbatim. Shipped so the name also exists on Gitea 1.27.x: html/template refuses a page that references an undefined template even in a branch that never runs (the 28.x branches of base/head_navbar.tmpl and custom/gh_head_navbar.tmpl). Only called on 28.x. */}}{{$impersonated := ctx.ImpersonatedUser}} +{{if $impersonated}} +
+
+ {{svg "octicon-alert"}} + {{ctx.Locale.Tr "admin.users.impersonating_notice" $impersonated.Name}} + {{ctx.Locale.Tr "admin.users.impersonate_stop"}} +
+
+{{end}} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 5e781bd..892dc84 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -1,4 +1,4 @@ -{{if StringUtils.HasPrefix ctx.CurrentWebTheme.InternalName "github-"}}{{/* gitea-theme-github (ARCHITECTURE.md §7, FG-007): github.com AppHeader for github-* themes only, markup in custom/gh_head_navbar.tmpl. The else-branch below is Gitea 1.27.3 templates/base/head_navbar.tmpl verbatim; no newline after the final end, so other themes render upstream bytes exactly. */}}{{template "custom/gh_head_navbar" .}}{{else}} +{{if not $gitea1}}{{template "base/head_impersonate_banner"}}{{end}} {{template "base/head_banner"}} diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 260692b..0b2d5f8 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -1,4 +1,4 @@ -{{if or .UsesIgnoreRevs .FaultyIgnoreRevsFile}} +{{$gitea1 := StringUtils.HasPrefix AppVer "1."}}{{/* gitea-theme-github: true on Gitea 1.27.x, false on 28.x; the $gitea1 branches keep each version's upstream markup */}}{{if or .UsesIgnoreRevs .FaultyIgnoreRevsFile}} {{$revsFileLink := print .RepoLink "/src/" .RefTypeNameSubURL "/.git-blame-ignore-revs"}} {{if .UsesIgnoreRevs}}
@@ -23,8 +23,8 @@ {{end}} {{ctx.Locale.Tr "repo.normal_view"}} {{ctx.Locale.Tr "repo.file_history"}} - - + {{ctx.Locale.Tr "repo.unescape_control_characters"}} + {{ctx.Locale.Tr "repo.escape_control_characters"}}
diff --git a/templates/repo/commits_list.tmpl b/templates/repo/commits_list.tmpl index 9e32131..a64ae35 100644 --- a/templates/repo/commits_list.tmpl +++ b/templates/repo/commits_list.tmpl @@ -1,4 +1,4 @@ -
+{{$gitea1 := StringUtils.HasPrefix AppVer "1."}}{{/* gitea-theme-github: true on Gitea 1.27.x, false on 28.x; the $gitea1 branches keep each version's upstream markup */}}
@@ -43,7 +43,7 @@ {{end}} {{if $gitCommit.MessageBody}} - +
{{DateUtils.TimeSince $gitCommit.Committer.When}} - + {{svg "octicon-copy"}} {{/* at the moment, wiki doesn't support these "view" links like "view at history point" */}} {{if not $.PageIsWiki}} {{/* view single file diff */}} diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 24a87ba..cc135f0 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -1,4 +1,4 @@ -
{{- if .FileError}} @@ -55,8 +55,8 @@ {{end}} {{ctx.Locale.Tr "repo.file_history"}} {{if .EscapeStatus.Escaped}} - - + {{ctx.Locale.Tr "repo.unescape_control_characters"}} + {{ctx.Locale.Tr "repo.escape_control_characters"}} {{end}}
{{svg "octicon-download"}} @@ -69,7 +69,7 @@ {{svg "octicon-rss"}} {{end}} - {{if .Repository.CanEnableEditor}} + {{if or (and $gitea1 .Repository.CanEnableEditor) (and (not $gitea1) .Repository.CanContentChange)}} {{if .CanEditFile}} {{svg "octicon-pencil"}} {{else}} @@ -82,8 +82,8 @@ {{end}} {{end}} {{else if .EscapeStatus.Escaped}} - - + {{ctx.Locale.Tr "repo.unescape_control_characters"}} + {{ctx.Locale.Tr "repo.escape_control_characters"}} {{end}} {{if and .ReadmeInList .CanEditReadmeFile}} {{svg "octicon-pencil"}} diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index 4d0f533..229796f 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -1,4 +1,4 @@ -{{/* use grid layout, still use the old ID because there are many other CSS styles depending on this ID */}} +{{$gitea1 := StringUtils.HasPrefix AppVer "1."}}{{/* gitea-theme-github: true on Gitea 1.27.x, false on 28.x; the $gitea1 branches keep each version's upstream markup */}}{{/* use grid layout, still use the old ID because there are many other CSS styles depending on this ID */}}
{{$subJumpablePathFields := StringUtils.Split $subJumpablePathName "/"}} {{$subJumpablePathFieldLast := (Eval (len $subJumpablePathFields) "-" 1)}} diff --git a/templates/repo/wiki/view.tmpl b/templates/repo/wiki/view.tmpl index d29ed09..7d7ce3a 100644 --- a/templates/repo/wiki/view.tmpl +++ b/templates/repo/wiki/view.tmpl @@ -1,5 +1,5 @@ -{{template "base/head" .}} -
+{{$gitea1 := StringUtils.HasPrefix AppVer "1."}}{{/* gitea-theme-github: true on Gitea 1.27.x, false on 28.x; the $gitea1 branches keep each version's upstream markup */}}{{template "base/head" .}} +
{{/* 28.x dropped `view`; github-* themes keep it (src/pages/repo/wiki.css scopes on .wiki.view) */}} {{template "repo/header" .}} {{$title := .title}}
{{/* gitea-theme-github (ARCHITECTURE.md §7, FG-022): for github-* themes the "Page:" dropdown + clone popup row is replaced by the aside.gh-wiki-aside below (Pages Box + clone input); every other theme renders upstream bytes. */}}{{if not (StringUtils.HasPrefix ctx.CurrentWebTheme.InternalName "github-")}} @@ -28,7 +28,7 @@
- {{template "repo/clone_panel" .}} + {{if $gitea1}}{{template "repo/clone_panel" .}}{{else}}{{template "repo/clone_panel" dict "CloneButtonOriginLink" $.CloneButtonOriginLink}}{{end}}
{{end}}
@@ -61,9 +61,9 @@
{{end}} -
{{if StringUtils.HasPrefix ctx.CurrentWebTheme.InternalName "github-"}}{{end}} +
{{if StringUtils.HasPrefix ctx.CurrentWebTheme.InternalName "github-"}}{{end}} {{if .WikiSidebarTocHTML}} -