From a579a0f318b9d6b975e2b6feac1aa0a9054f4945 Mon Sep 17 00:00:00 2001 From: silverwind Date: Sun, 24 Mar 2024 13:14:03 +0100 Subject: [PATCH] [Port] gitea#30014: Various code view improvements 1. Restore missing styles for message close icon 2. Move `code-line-button` so that it does not go off-screen on small viewports 3. Make `code-line-button` look and behave like other buttons 4. Make `code-line-button` work in blame 5. Make the active selection span the whole line, not just the code part 6. Tweak colors, make dark theme code bg darker, make line numbers same color in diff and file view. 7. Move code background to parent, fixing border radius and other problems 8. Enable code wrap in blame 9. Improve blame responsiveness 10. Remove `--color-code-sidebar-bg` in blame, now it uses same background as code 11. Rename `--color-active-line` to `--color-highlight-bg` 12. Add `--color-highlight-bg` 13. Fix button group borders on hover and border-right on last button. Screenshot 2024-03-23 at 22 34 13 Screenshot 2024-03-23 at 22 34 26 Screenshot 2024-03-23 at 22 34 57 Screenshot 2024-03-23 at 22 34 42 Fixes: https://github.com/go-gitea/gitea/issues/18074 --- Conflict resolution: Trivial. Ref: https://codeberg.org/forgejo/forgejo/issues/2776 (cherry picked from commit db01bf6cc88a8a7b5132b9306b3af1649566b10f) --- routers/web/repo/blame.go | 2 +- templates/devtest/gitea-ui.tmpl | 7 ++ templates/repo/blame.tmpl | 12 +++- web_src/css/base.css | 80 ++++++++++++--------- web_src/css/chroma/base.css | 4 -- web_src/css/modules/button.css | 12 +++- web_src/css/modules/message.css | 12 ++++ web_src/css/repo.css | 1 - web_src/css/repo/linebutton.css | 8 +-- web_src/css/themes/theme-gitea-dark.css | 12 ++-- web_src/css/themes/theme-gitea-light.css | 8 +-- web_src/js/features/repo-code.js | 90 ++++++++++++------------ 12 files changed, 145 insertions(+), 103 deletions(-) diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 0f464ad07..809a5009b 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -258,7 +258,7 @@ func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames var avatar string if commit.User != nil { - avatar = string(avatarUtils.Avatar(commit.User, 18, "gt-mr-3")) + avatar = string(avatarUtils.Avatar(commit.User, 18)) } else { avatar = string(avatarUtils.AvatarByEmail(commit.Author.Email, commit.Author.Name, 18, "gt-mr-3")) } diff --git a/templates/devtest/gitea-ui.tmpl b/templates/devtest/gitea-ui.tmpl index 9ef0aa675..26eaddae6 100644 --- a/templates/devtest/gitea-ui.tmpl +++ b/templates/devtest/gitea-ui.tmpl @@ -2,6 +2,13 @@
+

Link

+
+ normal + muted + suppressed + silenced +

Button

Style: diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl index 67046b814..9eb98f75f 100644 --- a/templates/repo/blame.tmpl +++ b/templates/repo/blame.tmpl @@ -50,11 +50,11 @@ {{$row.Avatar}}
-
+
{{$row.CommitSince}}
@@ -62,7 +62,7 @@ {{if $row.PreviousSha}} - + {{svg "octicon-versions"}} {{end}} @@ -84,6 +84,12 @@ {{end}} +
+ {{if $.Permission.CanRead $.UnitTypeIssues}} + {{ctx.Locale.Tr "repo.issues.context.reference_issue"}} + {{end}} + {{ctx.Locale.Tr "repo.file_copy_permalink"}} +
{{end}}
diff --git a/web_src/css/base.css b/web_src/css/base.css index e61311abd..ac451c4bc 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -226,10 +226,14 @@ h1.error-code { a { color: var(--color-primary); cursor: pointer; - text-decoration: none; + text-decoration-line: none; text-decoration-skip-ink: all; } +a:hover { + text-decoration-line: underline; +} + /* a = always colored, underlined on hover */ /* a.muted = colored on hover, underlined on hover */ /* a.suppressed = never colored, underlined on hover */ @@ -256,7 +260,7 @@ a.suppressed:hover { } a.silenced:hover { - text-decoration: none; + text-decoration-line: none; } a.label, @@ -264,7 +268,7 @@ a.label, .ui .menu a, .ui.cards a.card, .issue-keyword a { - text-decoration: none !important; + text-decoration-line: none !important; } .ui.search > .results { @@ -1433,18 +1437,15 @@ a.ui.active.label:hover { } .lines-blame-btn { - padding-left: 10px; - padding-right: 10px; - text-align: right !important; - background-color: var(--color-code-sidebar-bg); - width: 2%; + padding: 0 0 0 5px; + display: flex; + justify-content: center; } .lines-num { - padding-left: 10px; - padding-right: 10px; + padding: 0 8px; text-align: right !important; - color: var(--color-text-light-1); + color: var(--color-text-light-2); width: 1%; font-family: var(--fonts-monospace); } @@ -1498,22 +1499,34 @@ a.ui.active.label:hover { } .lines-code { - background-color: var(--color-code-bg); padding-left: 5px; } -.lines-code.active, -.lines-code .active { - background: var(--color-active-line) !important; +.file-view tr.active { + color: inherit !important; + background: inherit !important; } -.blame .lines-num { - padding: 0 !important; - background-color: var(--color-code-sidebar-bg); +.file-view tr.active .lines-num, +.file-view tr.active .lines-code { + background: var(--color-highlight-bg) !important; } -.blame .lines-code { - padding: 0 !important; +.file-view tr.active:last-of-type .lines-code { + border-bottom-right-radius: var(--border-radius); +} + +.file-view tr.active .lines-num { + position: relative; +} + +.file-view tr.active .lines-num::before { + content: ""; + position: absolute; + left: 0; + width: 2px; + height: 100%; + background: var(--color-highlight-fg); } .code-inner { @@ -1524,24 +1537,21 @@ a.ui.active.label:hover { } .blame .code-inner { - white-space: pre; - word-break: normal; - word-wrap: normal; /* not using overflow-wrap because safari does not treat is an an alias */ + white-space: pre-wrap; + overflow-wrap: anywhere; } .lines-commit { vertical-align: top; - color: var(--color-text-light-2); + color: var(--color-text-light-1); padding: 0 !important; - background: var(--color-code-sidebar-bg); width: 1%; } .lines-commit .blame-info { - width: 350px; - max-width: 350px; + width: min(26vw, 300px); display: block; - padding: 0 0 0 10px; + padding: 0 0 0 6px; line-height: 20px; box-sizing: content-box; } @@ -1563,11 +1573,10 @@ a.ui.active.label:hover { flex-shrink: 0; } -.lines-commit .ui.avatar { - height: 18px; - width: 18px; - display: block; - margin-top: 1px; +.blame-avatar { + display: flex; + align-items: center; + margin-right: 4px; } .top-line-blame { @@ -1583,6 +1592,11 @@ a.ui.active.label:hover { border-bottom: 1px solid var(--color-secondary); } +.code-view { + background: var(--color-code-bg); + border-radius: var(--border-radius); +} + .code-view table { width: 100%; } diff --git a/web_src/css/chroma/base.css b/web_src/css/chroma/base.css index 26d128775..bce13332f 100644 --- a/web_src/css/chroma/base.css +++ b/web_src/css/chroma/base.css @@ -1,7 +1,3 @@ -.chroma { - background-color: var(--color-code-bg); -} - /* LineTableTD */ .chroma .lntd { vertical-align: top; diff --git a/web_src/css/modules/button.css b/web_src/css/modules/button.css index a06cab446..452791cf0 100644 --- a/web_src/css/modules/button.css +++ b/web_src/css/modules/button.css @@ -11,6 +11,7 @@ .ui.button:focus { background: var(--color-hover); color: var(--color-text); + border-color: var(--color-secondary-dark-2); } .page-content .ui.button { @@ -63,11 +64,17 @@ It needs some tricks to tweak the left/right borders with active state */ border-right: none; } -.ui.buttons .button:first-child { +.ui.buttons .button:hover + .button { + border-left: 1px solid var(--color-secondary-dark-2); +} + +.ui.buttons .button:first-child, +.ui.buttons .button.gt-hidden:first-child + .button { border-left: 1px solid var(--color-light-border); } -.ui.buttons .button:last-child { +.ui.buttons .button:last-child, +.ui.buttons .button:nth-last-child(2):has(+ .button.gt-hidden) { border-right: 1px solid var(--color-light-border); } @@ -107,6 +114,7 @@ It needs some tricks to tweak the left/right borders with active state */ .ui.basic.button:focus { color: var(--color-text); background: var(--color-hover); + border-color: var(--color-secondary-dark-2); } .ui.basic.buttons .button:active, diff --git a/web_src/css/modules/message.css b/web_src/css/modules/message.css index a29603cd9..c62dbddd2 100644 --- a/web_src/css/modules/message.css +++ b/web_src/css/modules/message.css @@ -100,3 +100,15 @@ color: var(--color-warning-text); border-color: var(--color-warning-border); } + +.ui.message > .close.icon { + cursor: pointer; + position: absolute; + top: 9px; + right: 9px; + opacity: .7; +} + +.ui.message > .close.icon:hover { + opacity: 1; +} diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 6ccbbb49d..c1a798040 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -1601,7 +1601,6 @@ .repository .diff-file-box .file-body.file-code .lines-num { text-align: right; - color: var(--color-text-light); width: 1%; min-width: 50px; } diff --git a/web_src/css/repo/linebutton.css b/web_src/css/repo/linebutton.css index 79be5a7a9..e99d0399d 100644 --- a/web_src/css/repo/linebutton.css +++ b/web_src/css/repo/linebutton.css @@ -3,18 +3,16 @@ } .code-line-button { - background-color: var(--color-menu); - color: var(--color-text-light); border: 1px solid var(--color-secondary); border-radius: var(--border-radius); - padding: 1px 10px; + padding: 1px 4px !important; position: absolute; font-family: var(--fonts-regular); left: 0; - transform: translateX(-50%); + transform: translateX(calc(-50% + 6px)); cursor: pointer; } .code-line-button:hover { - color: var(--color-primary); + background: var(--color-secondary) !important; } diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index c769c51cd..626590ca5 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -183,7 +183,7 @@ --color-body: #1c1f25; --color-box-header: #1a1d1f; --color-box-body: #14171a; - --color-box-body-highlight: #121517; + --color-box-body-highlight: #1c2227; --color-text-dark: #f8f8f9; --color-text: #d1d5d8; --color-text-light: #bdc3c7; @@ -207,11 +207,10 @@ --color-markup-table-row: #e8e8ff06; --color-markup-code-block: #e8e8ff16; --color-button: #151a1e; - --color-code-bg: #191d20; - --color-code-sidebar-bg: #1b1f22; + --color-code-bg: #14171a; --color-shadow: #00001758; - --color-secondary-bg: #2f3135; - --color-expand-button: #414348; + --color-secondary-bg: #2f3138; + --color-expand-button: #2b353e; --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-5); --color-project-board-bg: var(--color-secondary-light-2); @@ -233,7 +232,8 @@ --color-label-active-bg: #73828eff; --color-accent: var(--color-primary-light-1); --color-small-accent: var(--color-primary-light-5); - --color-active-line: #534d1b; + --color-highlight-fg: #87651e; + --color-highlight-bg: #352c1c; --color-overlay-backdrop: #080808c0; accent-color: var(--color-accent); color-scheme: dark; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 2d9ab8e72..f6913fbe2 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -183,7 +183,7 @@ --color-body: #ffffff; --color-box-header: #f1f3f5; --color-box-body: #ffffff; - --color-box-body-highlight: #f4faff; + --color-box-body-highlight: #ecf5fd; --color-text-dark: #01050a; --color-text: #181c21; --color-text-light: #30363b; @@ -208,10 +208,9 @@ --color-markup-code-block: #00001710; --color-button: #f8f9fb; --color-code-bg: #fafdff; - --color-code-sidebar-bg: #f2f5f8; --color-shadow: #00001726; --color-secondary-bg: #f2f5f8; - --color-expand-button: #d8efff; + --color-expand-button: #cfe8fa; --color-placeholder-text: var(--color-text-light-3); --color-editor-line-highlight: var(--color-primary-light-6); --color-project-board-bg: var(--color-secondary-light-4); @@ -233,7 +232,8 @@ --color-label-active-bg: #949da6ff; --color-accent: var(--color-primary-light-1); --color-small-accent: var(--color-primary-light-6); - --color-active-line: #fffbdd; + --color-highlight-fg: #eed200; + --color-highlight-bg: #fffbdd; --color-overlay-backdrop: #080808c0; accent-color: var(--color-accent); color-scheme: light; diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js index 08fae763b..befa09000 100644 --- a/web_src/js/features/repo-code.js +++ b/web_src/js/features/repo-code.js @@ -16,8 +16,16 @@ function changeHash(hash) { } } -function selectRange($list, $select, $from) { - $list.removeClass('active'); +function isBlame() { + return Boolean(document.querySelector('div.blame')); +} + +function getLineEls() { + return document.querySelectorAll(`.code-view td.lines-code${isBlame() ? '.blame-code' : ''}`); +} + +function selectRange($linesEls, $selectionEndEl, $selectionStartEls) { + $linesEls.closest('tr').removeClass('active'); // add hashchange to permalink const $refInNewIssue = $('a.ref-in-new-issue'); @@ -25,7 +33,7 @@ function selectRange($list, $select, $from) { const $viewGitBlame = $('a.view_git_blame'); const updateIssueHref = function (anchor) { - if ($refInNewIssue.length === 0) { + if (!$refInNewIssue.length) { return; } const urlIssueNew = $refInNewIssue.attr('data-url-issue-new'); @@ -35,9 +43,7 @@ function selectRange($list, $select, $from) { }; const updateViewGitBlameFragment = function (anchor) { - if ($viewGitBlame.length === 0) { - return; - } + if (!$viewGitBlame.length) return; let href = $viewGitBlame.attr('href'); href = `${href.replace(/#L\d+$|#L\d+-L\d+$/, '')}`; if (anchor.length !== 0) { @@ -47,17 +53,15 @@ function selectRange($list, $select, $from) { }; const updateCopyPermalinkUrl = function(anchor) { - if ($copyPermalink.length === 0) { - return; - } + if (!$copyPermalink.length) return; let link = $copyPermalink.attr('data-url'); link = `${link.replace(/#L\d+$|#L\d+-L\d+$/, '')}#${anchor}`; $copyPermalink.attr('data-url', link); }; - if ($from) { - let a = parseInt($select.attr('rel').slice(1)); - let b = parseInt($from.attr('rel').slice(1)); + if ($selectionStartEls) { + let a = parseInt($selectionEndEl.attr('rel').slice(1)); + let b = parseInt($selectionStartEls.attr('rel').slice(1)); let c; if (a !== b) { if (a > b) { @@ -69,7 +73,9 @@ function selectRange($list, $select, $from) { for (let i = a; i <= b; i++) { classes.push(`[rel=L${i}]`); } - $list.filter(classes.join(',')).addClass('active'); + $linesEls.filter(classes.join(',')).each(function () { + $(this).closest('tr').addClass('active'); + }); changeHash(`#L${a}-L${b}`); updateIssueHref(`L${a}-L${b}`); @@ -78,12 +84,12 @@ function selectRange($list, $select, $from) { return; } } - $select.addClass('active'); - changeHash(`#${$select.attr('rel')}`); + $selectionEndEl.closest('tr').addClass('active'); + changeHash(`#${$selectionEndEl.attr('rel')}`); - updateIssueHref($select.attr('rel')); - updateViewGitBlameFragment($select.attr('rel')); - updateCopyPermalinkUrl($select.attr('rel')); + updateIssueHref($selectionEndEl.attr('rel')); + updateViewGitBlameFragment($selectionEndEl.attr('rel')); + updateCopyPermalinkUrl($selectionEndEl.attr('rel')); } function showLineButton() { @@ -96,10 +102,10 @@ function showLineButton() { } // find active row and add button - const tr = document.querySelector('.code-view td.lines-code.active').closest('tr'); - const td = tr.querySelector('td'); + const tr = document.querySelector('.code-view tr.active'); + const td = tr.querySelector('td.lines-num'); const btn = document.createElement('button'); - btn.classList.add('code-line-button'); + btn.classList.add('code-line-button', 'ui', 'basic', 'button'); btn.innerHTML = svg('octicon-kebab-horizontal'); td.prepend(btn); @@ -123,14 +129,18 @@ function showLineButton() { export function initRepoCodeView() { if ($('.code-view .lines-num').length > 0) { $(document).on('click', '.lines-num span', function (e) { - const $select = $(this); - let $list; - if ($('div.blame').length) { - $list = $('.code-view td.lines-code.blame-code'); - } else { - $list = $('.code-view td.lines-code'); + const linesEls = getLineEls(); + const selectedEls = Array.from(linesEls).filter((el) => { + return el.matches(`[rel=${this.getAttribute('id')}]`); + }); + + let from; + if (e.shiftKey) { + from = Array.from(linesEls).filter((el) => { + return el.closest('tr').classList.contains('active'); + }); } - selectRange($list, $list.filter(`[rel=${$select.attr('id')}]`), (e.shiftKey ? $list.filter('.active').eq(0) : null)); + selectRange($(linesEls), $(selectedEls), from ? $(from) : null); if (window.getSelection) { window.getSelection().removeAllRanges(); @@ -138,28 +148,20 @@ export function initRepoCodeView() { document.selection.empty(); } - // show code view menu marker (don't show in blame page) - if ($('div.blame').length === 0) { - showLineButton(); - } + showLineButton(); }); $(window).on('hashchange', () => { let m = window.location.hash.match(rangeAnchorRegex); - let $list; - if ($('div.blame').length) { - $list = $('.code-view td.lines-code.blame-code'); - } else { - $list = $('.code-view td.lines-code'); - } + const $linesEls = $(getLineEls()); let $first; if (m) { - $first = $list.filter(`[rel=${m[1]}]`); + $first = $linesEls.filter(`[rel=${m[1]}]`); if ($first.length) { - selectRange($list, $first, $list.filter(`[rel=${m[2]}]`)); + selectRange($linesEls, $first, $linesEls.filter(`[rel=${m[2]}]`)); // show code view menu marker (don't show in blame page) - if ($('div.blame').length === 0) { + if (!isBlame()) { showLineButton(); } @@ -169,12 +171,12 @@ export function initRepoCodeView() { } m = window.location.hash.match(singleAnchorRegex); if (m) { - $first = $list.filter(`[rel=L${m[2]}]`); + $first = $linesEls.filter(`[rel=L${m[2]}]`); if ($first.length) { - selectRange($list, $first); + selectRange($linesEls, $first); // show code view menu marker (don't show in blame page) - if ($('div.blame').length === 0) { + if (!isBlame()) { showLineButton(); }