diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue index fffad3db577cdcb5bfd53ef41609e6fae2452aa9..5d97faf5e1fe658fd06c15694745371993286ddc 100644 --- a/app/assets/javascripts/repository/components/blob_content_viewer.vue +++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue @@ -389,7 +389,8 @@ export default { :show-blame="showBlame" :project-path="projectPath" :current-ref="currentRef" - class="blob-viewer" + class="blob-viewer gl-grid" + :class="{ 'blob-viewer-blame': showBlame }" @error="onError" /> { + this.$refs.syncScrollBar.scrollLeft = this.$refs.syncScrollContainer.scrollLeft; + }); + }, + setContainerPosition() { + requestAnimationFrame(() => { + this.$refs.syncScrollContainer.scrollLeft = this.$refs.syncScrollBar.scrollLeft; + }); + }, + async initSyncScrollBar() { + await this.$nextTick(); + + const lineWidth = + `${this.$refs.syncScroll.querySelectorAll('.line')[0]?.offsetWidth}px` || '100%'; + this.$refs.syncScrollWidth.style.width = lineWidth; + }, async handleChunkAppear(chunkIndex, handleOverlappingChunk = true) { if (!this.renderedChunks.includes(chunkIndex)) { this.renderedChunks.push(chunkIndex); @@ -109,6 +127,8 @@ export default { // request the blame information for overlapping chunk incase it is visible in the DOM this.handleChunkAppear(chunkIndex - 1, false); } + + await this.initSyncScrollBar(); } }, async requestBlameInfo(chunkIndex) { @@ -141,19 +161,21 @@ export default { diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 6a7c32080adec4e7d40582e3da9b36dabf4b338c..2ea09a5c0f4df07c99d4417c70959ae2b72a79c1 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -2,6 +2,8 @@ * File content holder * */ +$blame-width: 400px; + .file-holder { @apply gl-border gl-rounded-base; @@ -457,7 +459,7 @@ span.idiff { } .blame-commit { - width: 400px; + width: $blame-width; flex: none; background: $gray-10; border-left: 3px solid; @@ -543,3 +545,43 @@ span.idiff { background: linear-gradient(to top, $white, transparent); } } + +.blob-viewer { + grid-template-columns: 1fr; +} + +.blob-viewer-blame { + grid-template-columns: $blame-width 1fr; + + .scrollbar { + grid-column-start: 2; + } +} + +.syncscroll { + will-change: scroll-position; + -webkit-overflow-scrolling: touch; +} + +.syncscroll.scrollbar { + z-index: 3; + position: sticky; + left: 0; + bottom: 0; + width: auto; + height: 1rem; + margin-top: -1rem; + pointer-events: auto; + overflow: auto hidden; + // Use fixed values as fallback so it + // doesn't change in darkmode + // as it's related to the + // color theme of the + // Syntax highlighting theme + // stylelint-disable-next-line scale-unlimited/declaration-strict-value + scrollbar-color: #606060 rgba(0, 0, 0, 0.15); + + .scrollbar-indicator { + height: 1px; + } +} diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss index 11a07df9a9649afe0cc281b5f9d18a6f5e58b4db..dbe9abab2cc7aa722f7357244aa3932b4d589557 100644 --- a/app/assets/stylesheets/highlight/themes/dark.scss +++ b/app/assets/stylesheets/highlight/themes/dark.scss @@ -390,3 +390,8 @@ $dark-il: #de935f; .vi { color: $dark-vi; } /* Name.Variable.Instance */ .il { color: $dark-il; } /* Literal.Number.Integer.Long */ } + +.syncscroll.scrollbar { + color-scheme: dark; + scrollbar-color: $gray-200 rgba(255, 255, 255, 0.15); +} diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss index 0fda4073b200c9824aae3bf3149bccc1b54dbaaf..eb4779eed1fdc3c0a7a13aa9ed867e5c93838a3c 100644 --- a/app/assets/stylesheets/highlight/themes/monokai.scss +++ b/app/assets/stylesheets/highlight/themes/monokai.scss @@ -375,3 +375,8 @@ $monokai-gh: #75715e; .gi { color: $monokai-gi; } /* Generic.Inserted & Diff Inserted */ .gh { color: $monokai-gh; } /* Generic.Heading */ } + +.syncscroll.scrollbar { + color-scheme: dark; + scrollbar-color: $gray-200 rgba(255, 255, 255, 0.15); +} diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss index 8fb561fba31b9d841ade87d7ea3d7da32aaf5c6b..36a89d347f101dd4957d0a864dbfc9881ec05838 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss @@ -401,3 +401,8 @@ $solarized-dark-il: #2aa198; .vi { color: $solarized-dark-vi; } /* Name.Variable.Instance */ .il { color: $solarized-dark-il; } /* Literal.Number.Integer.Long */ } + +.syncscroll.scrollbar { + color-scheme: dark; + scrollbar-color: $gray-200 rgba(255, 255, 255, 0.15); +} diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss index 609d7efd6f04829a1c65ad43f314b99bb69fe964..497e05a5c528694be8d2acba313ff83491fcf110 100644 --- a/app/assets/stylesheets/highlight/themes/solarized-light.scss +++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss @@ -389,3 +389,7 @@ $solarized-light-il: #2aa198; .vi { color: $solarized-light-vi; } /* Name.Variable.Instance */ .il { color: $solarized-light-il; } /* Literal.Number.Integer.Long */ } + +.syncscroll.scrollbar { + scrollbar-color: $gray-600 rgba(0, 0, 0, 0.15); +}