diff --git a/src/js/components/tree.jsx b/src/js/components/tree.jsx
index 6525c08..032d701 100644
--- a/src/js/components/tree.jsx
+++ b/src/js/components/tree.jsx
@@ -2,12 +2,29 @@ import React from 'react'
import Branch from './branch.jsx'
import { isElementVisible } from '../lib'
+const MIN_RESIZE_WIDTH = 55
+const MAX_RESIZE_WIDTH = 700
+
+const widthLocalStorageKey = '__better_github_pr_tree_width'
+
class Tree extends React.Component {
constructor (props) {
super(props)
this.onClose = this.onClose.bind(this)
this.onScroll = this.onScroll.bind(this)
+ this.onResizerMouseDown = this.onResizerMouseDown.bind(this)
+ this.onMouseMove = this.onMouseMove.bind(this)
+ this.onMouseUp = this.onMouseUp.bind(this)
+ this.toggleDocumentFullWidth = this.toggleDocumentFullWidth.bind(this)
+
+ this.isResizing = false
+ this.resizeDelta = 0
+
+ this.treeContainer = document.querySelector('.__better_github_pr')
+ this.reviewContainers = document.querySelectorAll('.enable_better_github_pr .diff-view, .enable_better_github_pr .commit.full-commit.prh-commit')
+
+ this.setInitialWidth()
this.state = {
show: true,
@@ -20,6 +37,10 @@ class Tree extends React.Component {
window.addEventListener('load', this.onScroll, false)
window.addEventListener('scroll', this.onScroll, false)
window.addEventListener('resize', this.onScroll, false)
+
+ this.resizer.addEventListener('mousedown', this.onResizerMouseDown, false)
+ document.addEventListener('mousemove', this.onMouseMove, false)
+ document.addEventListener('mouseup', this.onMouseUp, false)
}
componentWillUnmount () {
@@ -27,6 +48,33 @@ class Tree extends React.Component {
window.removeEventListener('load', this.onScroll, false)
window.removeEventListener('scroll', this.onScroll, false)
window.removeEventListener('resize', this.onScroll, false)
+
+ this.resizer.removeEventListener('mousedown', this.onResizerMouseDown, false)
+ document.removeEventListener('mousemove', this.onMouseMove, false)
+ document.removeEventListener('mouseup', this.onMouseUp, false)
+ }
+
+ onResizerMouseDown () {
+ this.isResizing = true
+ this.treeContainer.classList.add('__better_github_pr_noselect')
+ this.prevWidth = this.treeContainer.offsetWidth
+ this.startResizeX = this.resizer.getBoundingClientRect().x
+ }
+
+ onMouseMove (e) {
+ if (!this.isResizing) return
+
+ this.resizeDelta = e.clientX - this.startResizeX
+ let newWidth = this.prevWidth + this.resizeDelta
+ setTimeout(() => this.setWidth(newWidth), 0)
+ }
+
+ onMouseUp () {
+ if (!this.isResizing) return
+
+ this.isResizing = false
+ this.treeContainer.classList.remove('__better_github_pr_noselect')
+ window.localStorage.setItem(widthLocalStorageKey, this.treeContainer.offsetWidth)
}
onScroll () {
@@ -45,6 +93,30 @@ class Tree extends React.Component {
const show = false
this.setState({ show })
document.body.classList.toggle('enable_better_github_pr', show)
+ this.setWidth(0, false)
+ }
+
+ setInitialWidth () {
+ const savedWitdh = window.localStorage.getItem(widthLocalStorageKey)
+ if (savedWitdh) {
+ this.setWidth(parseInt(savedWitdh, 10))
+ }
+ }
+
+ setWidth (width, withConstraints = true) {
+ if (withConstraints) {
+ if (width <= MIN_RESIZE_WIDTH) width = MIN_RESIZE_WIDTH
+ if (width >= MAX_RESIZE_WIDTH) width = MAX_RESIZE_WIDTH
+ }
+
+ this.treeContainer.style.width = `${width}px`
+ this.reviewContainers.forEach((element) => {
+ element.style['margin-left'] = `${width + 10}px`
+ })
+ }
+
+ toggleDocumentFullWidth () {
+ document.querySelector('body').classList.toggle('__better_github_pr_wide')
}
render () {
@@ -56,13 +128,17 @@ class Tree extends React.Component {
}
return (
-
+
+
- {root.list.map(node => (
-
-
-
- ))}
+
+
{ this.resizer = node }} />
+ {root.list.map(node => (
+
+
+
+ ))}
+
)
}
diff --git a/src/js/lib.js b/src/js/lib.js
index 82a6380..5cd7080 100644
--- a/src/js/lib.js
+++ b/src/js/lib.js
@@ -34,6 +34,28 @@ const hasCommentsForFileIndex = (fileIndex) => {
return diffTable.querySelectorAll('.inline-comments').length
}
+export const folderConcat = (node) => {
+ const isFileOrEmpty = (node.list === undefined || node.list.length === 0 || (node.href !== null && node.href !== undefined))
+ if (isFileOrEmpty) {
+ return node
+ }
+
+ const hasSingleChild = (node.list.length === 1)
+ if (hasSingleChild) {
+ const collapsed = folderConcat(node.list[0])
+ const isLastCollapsedIsFolder = node.nodeLabel !== '/' && (collapsed.href === null || collapsed.href === undefined)
+ if (isLastCollapsedIsFolder) {
+ node.nodeLabel = node.nodeLabel + '/' + collapsed.nodeLabel
+ node.hasComments = collapsed.hasComments || node.hasComments
+ node.list = collapsed.list
+ }
+ return node
+ }
+
+ node.list.map(x => folderConcat(x))
+ return node
+}
+
export const createFileTree = () => {
const fileInfo = [...document.querySelectorAll('.file-info > a')]
const files = fileInfo.map(({ title, href }) => {
@@ -68,7 +90,7 @@ export const createFileTree = () => {
})
})
return {
- tree,
+ tree: folderConcat(tree),
count: fileInfo.length
}
}
diff --git a/src/js/style.css b/src/js/style.css
index f790752..f7399eb 100644
--- a/src/js/style.css
+++ b/src/js/style.css
@@ -7,13 +7,29 @@
display: none;
}
+._better_github_pr_resizer {
+ position: absolute;
+ width: 5px;
+ height: 100%;
+ background: lightgray;
+ right: 0;
+ top: 0;
+ cursor: col-resize;
+ opacity: .4;
+ transition: opacity .2s ease;
+ z-index: 1;
+}
+
+._better_github_pr_resizer:hover {
+ opacity: 1;
+}
+
.enable_better_github_pr .__better_github_pr {
display: block;
position: relative;
margin-top: 20px;
- padding: 10px;
- width: 240px;
- overflow: auto;
+ padding: 30px 10px 0;
+ width: 330px;
height: calc(100vh - 61px);
background-color: #fafbfc;
border: 1px solid #e1e4e8;
@@ -22,23 +38,65 @@
}
.__better_github_pr > div {
- display: inline-block;
+ overflow: auto;
+ height: 100%;
+ padding-bottom: 10px;
+}
+
+.__better_github_pr > div > div {
+ width: fit-content;
}
.__better_github_pr .close_button {
background: none;
border: none;
position: absolute;
- top: 0;
- right: 0;
+ top: 1px;
+ right: 10px;
padding: 5px 2px;
}
+.__better_github_pr_full_width {
+ width: 16px;
+ height: 16px;
+ background-size: cover;
+ position: absolute;
+ top: 6px;
+ right: 40px;
+ cursor: pointer;
+ background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDMyIDMyIiBoZWlnaHQ9IjMycHgiIGlkPSLQodC70L7QuV8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzMiAzMiIgd2lkdGg9IjMycHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxnIGlkPSJGdWxsc2NyZWVuIj48cGF0aCBkPSJNMzIsMWMwLTAuNTU4LTAuNDQyLTEtMS0xbC04Ljk4NSwwYy0wLjU2OCwwLTAuOTkxLDAuNDQ4LTAuOTkyLDEuMDE2QzIxLjAyMywxLjU4MywyMS40NDcsMiwyMi4wMTUsMkwzMCwyICAgbC0wLjAxNiw4LjAyM2MwLDAuNTY4LDAuNDMyLDEsMSwxYzAuNTY4LTAuMDAxLDEtMC40MzIsMS0xTDMyLDEuMDE1YzAtMC4wMDMtMC4wMDEtMC4wMDUtMC4wMDEtMC4wMDdDMzEuOTk5LDEuMDA1LDMyLDEuMDAzLDMyLDF6ICAgIiBmaWxsPSIjMTIxMzEzIi8+PHBhdGggZD0iTTEwLjAxNiwwSDEuMDMxQzEuMDI4LDAsMS4wMjYsMC4wMDEsMS4wMjMsMC4wMDFDMS4wMjEsMC4wMDEsMS4wMTgsMCwxLjAxNiwwYy0wLjU1OCwwLTEsMC40NDItMSwxICAgTDAsMTAuMDA4QzAsMTAuNTc2LDAuNDQ4LDExLDEuMDE2LDExQzEuNTgzLDExLDIsMTAuNTc2LDIsMTAuMDA4TDIuMDE2LDJoOGMwLjU2OCwwLDEtMC40MzIsMS0xQzExLjAxNSwwLjQzMiwxMC41ODMsMCwxMC4wMTYsMHoiIGZpbGw9IiMxMjEzMTMiLz48cGF0aCBkPSJNOS45ODUsMzBIMnYtOGMwLTAuNTY4LTAuNDMyLTEtMS0xYy0wLjU2OCwwLTEsMC40MzItMSwxdjguOTg1YzAsMC4wMDMsMC4wMDEsMC4wMDUsMC4wMDEsMC4wMDcgICBDMC4wMDEsMzAuOTk1LDAsMzAuOTk3LDAsMzFjMCwwLjU1OCwwLjQ0MiwxLDEsMWg4Ljk4NWMwLjU2OCwwLDAuOTkxLTAuNDQ4LDAuOTkyLTEuMDE2QzEwLjk3NywzMC40MTcsMTAuNTUzLDMwLDkuOTg1LDMweiIgZmlsbD0iIzEyMTMxMyIvPjxwYXRoIGQ9Ik0zMC45ODQsMjEuMDIzYy0wLjU2OCwwLTAuOTg1LDAuNDI0LTAuOTg0LDAuOTkyVjMwbC04LDBjLTAuNTY4LDAtMSwwLjQzMi0xLDFjMCwwLjU2OCwwLjQzMiwxLDEsMSAgIGw4Ljk4NSwwYzAuMDAzLDAsMC4wMDUtMC4wMDEsMC4wMDctMC4wMDFDMzAuOTk1LDMxLjk5OCwzMC45OTcsMzIsMzEsMzJjMC41NTgsMCwxLTAuNDQyLDEtMXYtOC45ODUgICBDMzIsMjEuNDQ3LDMxLjU1MiwyMS4wMjMsMzAuOTg0LDIxLjAyM3oiIGZpbGw9IiMxMjEzMTMiLz48L2c+PGcvPjxnLz48Zy8+PGcvPjxnLz48Zy8+PC9zdmc+');
+ background-color: transparent;
+ border: none;
+}
+
+.__better_github_pr_noselect {
+ -webkit-touch-callout: none; /* iOS Safari */
+ -webkit-user-select: none; /* Safari */
+ -khtml-user-select: none; /* Konqueror HTML */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* Internet Explorer/Edge */
+ user-select: none; /* Non-prefixed version, currently
+ supported by Chrome and Opera */
+}
+
+.__better_github_pr_wide .container {
+ min-width: 980px;
+ width: 96% !important;
+}
+
+.__better_github_pr_wide .repository-content .discussion-timeline {
+ width: calc(100% - 220px) !important;
+}
+
+.__better_github_pr_wide .repository-content .discussion-timeline .timeline-new-comment {
+ max-width: 100% !important;
+}
+
/* GitHub page changes */
.enable_better_github_pr .diff-view,
.enable_better_github_pr .commit.full-commit.prh-commit {
- margin-left: 250px;
+ margin-left: 340px;
}
.enable_better_github_pr .diff-view .file-header {
@@ -51,6 +109,10 @@
max-width: 708px;
}
+.enable_better_github_pr .container {
+ transition: width .2s ease;
+}
+
/* react-treeview */
.tree-view_item {