Diff improvements (#23553)

- Avoid flash of wrong tree toggle icon on page load by setting icon
based on sync state
- Avoid "pop-in" of tree on page load by leaving space based on sync
state
- Use the same border/box-shadow combo used on comment `:target` also
for file `:target`.
- Refactor `DiffFileTree.vue` to use `toggleElem` instead of hardcoded
class name.
- Left-align inline comment boxes and make them fit the same amount of
markup content on a line as GitHub.
- Fix height of `diff-file-list`

Fixes: https://github.com/go-gitea/gitea/issues/23593

<img width="1250" alt="Screenshot 2023-03-18 at 00 52 04"
src="https://user-images.githubusercontent.com/115237/226071392-6789a644-aead-4756-a77e-aba3642150a0.png">
<img width="1246" alt="Screenshot 2023-03-18 at 00 59 43"
src="https://user-images.githubusercontent.com/115237/226071443-8bcba924-458b-48bd-b2f0-0de59cb180ac.png">
<img width="1250" alt="Screenshot 2023-03-18 at 01 27 14"
src="https://user-images.githubusercontent.com/115237/226073121-ccb99f9a-d3ac-40b7-9589-43580c4a01c9.png">
<img width="1231" alt="Screenshot 2023-03-19 at 21 44 16"
src="https://user-images.githubusercontent.com/115237/226207951-81bcae1b-6b41-4e39-83a7-0f37951df6be.png">

(Yes I'm aware the border-radius in bottom corners is suboptimal, but
this would be notorously hard to fix without relying on `overflow:
hidden`).
This commit is contained in:
silverwind 2023-03-30 14:06:10 +02:00 committed by GitHub
parent 35cb786ca1
commit aa4d1d94f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 40 deletions

View File

@ -2280,6 +2280,8 @@ diff.image.side_by_side = Side by Side
diff.image.swipe = Swipe diff.image.swipe = Swipe
diff.image.overlay = Overlay diff.image.overlay = Overlay
diff.has_escaped = This line has hidden Unicode characters diff.has_escaped = This line has hidden Unicode characters
diff.show_file_tree = Show file tree
diff.hide_file_tree = Hide file tree
releases.desc = Track project versions and downloads. releases.desc = Track project versions and downloads.
release.releases = Releases release.releases = Releases

View File

@ -15,11 +15,18 @@
<div> <div>
<div class="diff-detail-box diff-box sticky gt-df gt-sb gt-ac gt-fw"> <div class="diff-detail-box diff-box sticky gt-df gt-sb gt-ac gt-fw">
<div class="gt-df gt-ac gt-fw"> <div class="gt-df gt-ac gt-fw">
<a class="diff-toggle-file-tree-button muted gt-df gt-ac"> <button class="diff-toggle-file-tree-button gt-df gt-ac" data-show-text="{{.locale.Tr "repo.diff.show_file_tree"}}" data-hide-text="{{.locale.Tr "repo.diff.hide_file_tree"}}">
{{/* the icon meaning is reversed here, "octicon-sidebar-collapse" means show the file tree */}} {{/* the icon meaning is reversed here, "octicon-sidebar-collapse" means show the file tree */}}
{{svg "octicon-sidebar-collapse" 20 "icon hide"}} {{svg "octicon-sidebar-collapse" 20 "icon gt-hidden"}}
{{svg "octicon-sidebar-expand" 20 "icon"}} {{svg "octicon-sidebar-expand" 20 "icon gt-hidden"}}
</a> </button>
<script>
const diffTreeVisible = localStorage?.getItem('diff_file_tree_visible') === 'true';
const diffTreeBtn = document.querySelector('.diff-toggle-file-tree-button');
const diffTreeIcon = `.octicon-sidebar-${diffTreeVisible ? 'expand' : 'collapse'}`;
diffTreeBtn.querySelector(diffTreeIcon).classList.remove('gt-hidden');
diffTreeBtn.setAttribute('data-tooltip-content', diffTreeBtn.getAttribute(diffTreeVisible ? 'data-hide-text' : 'data-show-text'));
</script>
<div class="diff-detail-stats gt-df gt-ac gt-ml-3"> <div class="diff-detail-stats gt-df gt-ac gt-ml-3">
{{svg "octicon-diff" 16 "gt-mr-2"}}{{.locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}} {{svg "octicon-diff" 16 "gt-mr-2"}}{{.locale.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}}
</div> </div>
@ -68,6 +75,9 @@
<div id="diff-file-list"></div> <div id="diff-file-list"></div>
<div id="diff-container"> <div id="diff-container">
<div id="diff-file-tree" class="gt-hidden"></div> <div id="diff-file-tree" class="gt-hidden"></div>
<script>
if (diffTreeVisible) document.getElementById('diff-file-tree').classList.remove('gt-hidden');
</script>
<div id="diff-file-boxes" class="sixteen wide column"> <div id="diff-file-boxes" class="sixteen wide column">
{{range $i, $file := .Diff.Files}} {{range $i, $file := .Diff.Files}}
{{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}} {{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}}

View File

@ -238,6 +238,10 @@ table {
border-collapse: collapse; border-collapse: collapse;
} }
button {
cursor: pointer;
}
details summary { details summary {
cursor: pointer; cursor: pointer;
} }

View File

@ -1616,14 +1616,12 @@
padding: 7px 0; padding: 7px 0;
background: var(--color-body); background: var(--color-body);
line-height: 30px; line-height: 30px;
height: 47px; /* match .ui.attached.header.diff-file-header.sticky-2nd-row */
} }
@media (max-width: 991px) { @media (max-width: 991px) {
.repository .diff-detail-box { .repository .diff-detail-box {
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
height: 77px; /* match .ui.attached.header.diff-file-header.sticky-2nd-row */
} }
} }
@ -1679,6 +1677,13 @@
} }
} }
.diff-detail-actions {
/* prevent font-size from increasing element height so that .diff-detail-box comes
out with height of 47px (one line) and 77px (two lines), which is important for
position: sticky */
height: 33px;
}
.repository .diff-detail-box .diff-detail-actions > * { .repository .diff-detail-box .diff-detail-actions > * {
margin-right: 0; margin-right: 0;
} }
@ -1853,10 +1858,24 @@
padding-bottom: 5px; padding-bottom: 5px;
} }
.diff-file-box {
border: 1px solid transparent;
border-radius: var(--border-radius);
}
/* TODO: this can potentially be made "global" by removing the class prefix */
.diff-file-box .ui.attached.header,
.diff-file-box .ui.attached.table {
margin: 0; /* remove fomantic negative margins */;
width: initial; /* remove fomantic over 100% width */;
max-width: initial; /* remove fomantic over 100% width */;
}
.repository .diff-stats { .repository .diff-stats {
clear: both; clear: both;
margin-bottom: 5px; margin-bottom: 5px;
max-height: 400px; max-height: 200px;
height: fit-content;
overflow: auto; overflow: auto;
padding-left: 0; padding-left: 0;
} }
@ -2652,7 +2671,8 @@
filter: drop-shadow(-3px 0 0 var(--color-primary-alpha-30)) !important; filter: drop-shadow(-3px 0 0 var(--color-primary-alpha-30)) !important;
} }
.code-comment:target { .code-comment:target,
.diff-file-box:target {
border-color: var(--color-primary) !important; border-color: var(--color-primary) !important;
border-radius: var(--border-radius) !important; border-radius: var(--border-radius) !important;
box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important; box-shadow: 0 0 0 3px var(--color-primary-alpha-30) !important;
@ -3226,17 +3246,28 @@ td.blob-excerpt {
} }
#diff-file-tree { #diff-file-tree {
width: 20%; flex: 0 0 20%;
max-width: 380px; max-width: 380px;
line-height: inherit; line-height: inherit;
position: sticky; position: sticky;
padding-top: 0; padding-top: 0;
top: 47px; top: 47px;
max-height: calc(100vh - 50px); max-height: calc(100vh - 47px);
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
} }
.diff-toggle-file-tree-button {
background: none;
border: none;
user-select: none;
color: inherit;
}
.diff-toggle-file-tree-button:hover {
color: var(--color-primary);
}
@media (max-width: 991px) { @media (max-width: 991px) {
#diff-file-tree { #diff-file-tree {
display: none !important; display: none !important;

View File

@ -67,8 +67,7 @@
.comment-code-cloud { .comment-code-cloud {
padding: 0.5rem 1rem !important; padding: 0.5rem 1rem !important;
position: relative; position: relative;
margin: 0 auto; max-width: 820px;
max-width: 1000px;
} }
@media (max-width: 767px) { @media (max-width: 767px) {
@ -308,11 +307,3 @@ a.blob-excerpt:hover {
width: 72px; width: 72px;
height: 10px; height: 10px;
} }
.diff-file-box {
border-radius: 0.285rem; /* Just like ui.top.attached.header */
}
.diff-file-box:target {
box-shadow: 0 0 0 3px var(--color-accent);
}

View File

@ -16,6 +16,7 @@
<script> <script>
import DiffFileTreeItem from './DiffFileTreeItem.vue'; import DiffFileTreeItem from './DiffFileTreeItem.vue';
import {doLoadMoreFiles} from '../features/repo-diff.js'; import {doLoadMoreFiles} from '../features/repo-diff.js';
import {toggleElem} from '../utils/dom.js';
const {pageData} = window.config; const {pageData} = window.config;
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible'; const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';
@ -92,8 +93,6 @@ export default {
} }
}, },
mounted() { mounted() {
// ensure correct buttons when we are mounted to the dom
this.adjustToggleButton(this.fileTreeIsVisible);
// replace the pageData.diffFileInfo.files with our watched data so we get updates // replace the pageData.diffFileInfo.files with our watched data so we get updates
pageData.diffFileInfo.files = this.files; pageData.diffFileInfo.files = this.files;
@ -109,15 +108,17 @@ export default {
updateVisibility(visible) { updateVisibility(visible) {
this.fileTreeIsVisible = visible; this.fileTreeIsVisible = visible;
localStorage.setItem(LOCAL_STORAGE_KEY, this.fileTreeIsVisible); localStorage.setItem(LOCAL_STORAGE_KEY, this.fileTreeIsVisible);
this.adjustToggleButton(this.fileTreeIsVisible); this.updateState(this.fileTreeIsVisible);
}, },
adjustToggleButton(visible) { updateState(visible) {
const [toShow, toHide] = document.querySelectorAll('.diff-toggle-file-tree-button .icon'); const btn = document.querySelector('.diff-toggle-file-tree-button');
toShow.classList.toggle('gt-hidden', visible); // hide the toShow icon if the tree is visible const [toShow, toHide] = btn.querySelectorAll('.icon');
toHide.classList.toggle('gt-hidden', !visible); // similarly const tree = document.getElementById('diff-file-tree');
const newTooltip = btn.getAttribute(visible ? 'data-hide-text' : 'data-show-text');
const diffTree = document.getElementById('diff-file-tree'); btn.setAttribute('data-tooltip-content', newTooltip);
diffTree.classList.toggle('gt-hidden', !visible); toggleElem(tree, visible);
toggleElem(toShow, !visible);
toggleElem(toHide, visible);
}, },
loadMoreData() { loadMoreData() {
this.isLoadingNewData = true; this.isLoadingNewData = true;

View File

@ -1,7 +1,7 @@
<template> <template>
<div v-show="show" :title="item.name"> <div v-show="show" :title="item.name">
<!--title instead of tooltip above as the tooltip needs too much work with the current methods, i.e. not being loaded or staying open for "too long"--> <!--title instead of tooltip above as the tooltip needs too much work with the current methods, i.e. not being loaded or staying open for "too long"-->
<div class="item" :class="item.isFile ? 'filewrapper gt-p-1' : ''"> <div class="item" :class="item.isFile ? 'filewrapper gt-p-1 gt-ac' : ''">
<!-- Files --> <!-- Files -->
<SvgIcon <SvgIcon
v-if="item.isFile" v-if="item.isFile"
@ -10,7 +10,7 @@
/> />
<a <a
v-if="item.isFile" v-if="item.isFile"
class="file gt-ellipsis muted" class="file gt-ellipsis"
:href="item.isFile ? '#diff-' + item.file.NameHash : ''" :href="item.isFile ? '#diff-' + item.file.NameHash : ''"
>{{ item.name }}</a> >{{ item.name }}</a>
<SvgIcon <SvgIcon
@ -20,7 +20,7 @@
/> />
<!-- Directories --> <!-- Directories -->
<div v-if="!item.isFile" class="directory gt-p-1" @click.stop="handleClick(item.isFile)"> <div v-if="!item.isFile" class="directory gt-p-1 gt-ac" @click.stop="handleClick(item.isFile)">
<SvgIcon <SvgIcon
class="svg-icon" class="svg-icon"
:name="collapsed ? 'octicon-chevron-right' : 'octicon-chevron-down'" :name="collapsed ? 'octicon-chevron-right' : 'octicon-chevron-down'"
@ -79,31 +79,31 @@ export default {
</script> </script>
<style scoped> <style scoped>
span.svg-icon.status { .svg-icon.status {
float: right; float: right;
} }
span.svg-icon.file { .svg-icon.file {
color: var(--color-secondary-dark-7); color: var(--color-secondary-dark-7);
} }
span.svg-icon.directory { .svg-icon.directory {
color: var(--color-primary); color: var(--color-primary);
} }
span.svg-icon.octicon-diff-modified { .svg-icon.octicon-diff-modified {
color: var(--color-yellow); color: var(--color-yellow);
} }
span.svg-icon.octicon-diff-added { .svg-icon.octicon-diff-added {
color: var(--color-green); color: var(--color-green);
} }
span.svg-icon.octicon-diff-removed { .svg-icon.octicon-diff-removed {
color: var(--color-red); color: var(--color-red);
} }
span.svg-icon.octicon-diff-renamed { .svg-icon.octicon-diff-renamed {
color: var(--color-teal); color: var(--color-teal);
} }
@ -139,9 +139,11 @@ div.list {
a { a {
text-decoration: none; text-decoration: none;
color: var(--color-text);
} }
a:hover { a:hover {
text-decoration: none; text-decoration: none;
color: var(--color-text);
} }
</style> </style>