Skip to content

Commit 7d467f1

Browse files
authored
Merge pull request #16 from berzniz/scroll_spy
Add Scroll Spy to highlight current visible file
2 parents 8e5cac1 + 4eca87e commit 7d467f1

File tree

4 files changed

+70
-10
lines changed

4 files changed

+70
-10
lines changed

src/js/components/branch.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ import React from 'react'
22
import TreeView from 'react-treeview'
33
import File from './file'
44

5-
const Branch = ({ nodeLabel, list, href, hasComments }) => {
5+
const Branch = ({ nodeLabel, list, href, hasComments, diffElement, visibleElement }) => {
66
if (href) {
7-
return <File name={nodeLabel} href={href} hasComments={hasComments} />
7+
const isVisible = (diffElement === visibleElement)
8+
return <File name={nodeLabel} href={href} hasComments={hasComments} isVisible={isVisible} />
89
}
910

1011
return (
1112
<TreeView nodeLabel={nodeLabel} defaultCollapsed={false}>
1213
{list.map(node => (
1314
<span key={node.nodeLabel}>
14-
<Branch {...node} />
15+
<Branch {...node} visibleElement={visibleElement} />
1516
</span>
1617
))}
1718
</TreeView>

src/js/components/file.jsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import React from 'react'
22
import fileIcons from 'file-icons-js'
33

4-
const File = ({ name, href, hasComments }) => {
4+
const highlightColor = '#ebebeb'
5+
const transparentColor = 'transparent'
6+
7+
const File = ({ name, href, hasComments, isVisible }) => {
58
const className = fileIcons.getClassWithColor(name)
69
return (
7-
<div className='github-pr-file'>
10+
<div className='github-pr-file' style={{ background: isVisible ? highlightColor : transparentColor }}>
811
<span className={`icon ${className}`} />
912
<a href={href} className='link-gray-dark'>{name}</a> {hasComments ? ' 💬' : ''}
1013
</div>

src/js/components/tree.jsx

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,43 @@
11
import React from 'react'
22
import Branch from './branch.jsx'
3+
import { isElementVisible } from '../lib'
34

45
class Tree extends React.Component {
56
constructor (props) {
67
super(props)
78

89
this.onClose = this.onClose.bind(this)
10+
this.onScroll = this.onScroll.bind(this)
911

1012
this.state = {
11-
show: true
13+
show: true,
14+
visibleElement: null
15+
}
16+
}
17+
18+
componentDidMount () {
19+
window.addEventListener('DOMContentLoaded', this.onScroll, false)
20+
window.addEventListener('load', this.onScroll, false)
21+
window.addEventListener('scroll', this.onScroll, false)
22+
window.addEventListener('resize', this.onScroll, false)
23+
}
24+
25+
componentWillUnmount () {
26+
window.removeEventListener('DOMContentLoaded', this.onScroll, false)
27+
window.removeEventListener('load', this.onScroll, false)
28+
window.removeEventListener('scroll', this.onScroll, false)
29+
window.removeEventListener('resize', this.onScroll, false)
30+
}
31+
32+
onScroll () {
33+
const { visibleElement } = this.state
34+
const { root } = this.props
35+
const { diffElements = [] } = root
36+
const nextVisibleElement = diffElements.find(isElementVisible)
37+
if (nextVisibleElement !== visibleElement) {
38+
this.setState({
39+
visibleElement: nextVisibleElement
40+
})
1241
}
1342
}
1443

@@ -20,7 +49,7 @@ class Tree extends React.Component {
2049

2150
render () {
2251
const { root } = this.props
23-
const { show } = this.state
52+
const { show, visibleElement } = this.state
2453

2554
if (!show) {
2655
return null
@@ -31,7 +60,7 @@ class Tree extends React.Component {
3160
<button onClick={this.onClose} className='close_button'></button>
3261
{root.list.map(node => (
3362
<span key={node.nodeLabel}>
34-
<Branch {...node} />
63+
<Branch {...node} visibleElement={visibleElement} />
3564
</span>
3665
))}
3766
</div>

src/js/lib.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ export const createFileTree = () => {
4242
})
4343
const tree = {
4444
nodeLabel: '/',
45-
list: []
45+
list: [],
46+
diffElements: []
4647
}
4748

4849
files.forEach(({ parts, href }, fileIndex) => {
@@ -51,7 +52,15 @@ export const createFileTree = () => {
5152
let node = location.list.find(node => node.nodeLabel === part)
5253
if (!node) {
5354
const hasComments = (hasCommentsForFileIndex(fileIndex) > 0)
54-
node = { nodeLabel: part, list: [], href: (index === parts.length - 1) ? href : null, hasComments }
55+
const diffElement = document.getElementById(`diff-${fileIndex}`)
56+
tree.diffElements.push(diffElement)
57+
node = {
58+
nodeLabel: part,
59+
list: [],
60+
href: (index === parts.length - 1) ? href : null,
61+
hasComments,
62+
diffElement
63+
}
5564
location.list.push(node)
5665
}
5766
location.list = location.list.sort(sorter)
@@ -63,3 +72,21 @@ export const createFileTree = () => {
6372
count: fileInfo.length
6473
}
6574
}
75+
76+
export const isElementVisible = (el) => {
77+
if (!el) {
78+
return false
79+
}
80+
81+
const GITHUB_HEADER_HEIGHT = 60
82+
83+
const rect = el.getBoundingClientRect()
84+
85+
const windowHeight = (window.innerHeight || document.documentElement.clientHeight)
86+
const windowWidth = (window.innerWidth || document.documentElement.clientWidth)
87+
88+
const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= GITHUB_HEADER_HEIGHT)
89+
const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0)
90+
91+
return (vertInView && horInView)
92+
}

0 commit comments

Comments
 (0)