Skip to content

Commit 0ca26e5

Browse files
committed
feat(typing): scroll to the cursor when typing
1 parent a6dd73f commit 0ca26e5

File tree

4 files changed

+61
-12
lines changed

4 files changed

+61
-12
lines changed

components/Application.js

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Header from './Header';
1111

1212
if (process.env.BROWSER === true) {
1313
require('gsap');
14+
require('gsap/src/minified/plugins/ScrollToPlugin.min.js');
1415
require('../styles/app.scss');
1516
}
1617

components/SourceCode.js

+53-11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export default class SourceCode extends React.Component {
44

55
constructor (props) {
66
super(props);
7+
this.scrolledY = 0;
8+
this.scrolledX = 0;
79
}
810

911
componentDidMount () {
@@ -18,15 +20,55 @@ export default class SourceCode extends React.Component {
1820

1921
follow () {
2022
if (this.props.isFinished) { return; }
21-
let box = React.findDOMNode(this.refs.box);
22-
let follow = React.findDOMNode(this.refs.follow);
23+
24+
// boxes
25+
let box = React.findDOMNode(this);
26+
let pre = React.findDOMNode(this.refs.pre);
27+
28+
// cursor
2329
let cur = React.findDOMNode(this.refs.cur);
24-
let rectBox = box.getBoundingClientRect();
25-
let rect = cur.getBoundingClientRect();
26-
TweenMax.to(follow, 0.15, {
27-
scaleX: rect.width + 5,
28-
x: rect.left - rectBox.left - 2,
29-
y: rect.top - rectBox.top + 30
30+
let letter = React.findDOMNode(this.refs.letter);
31+
32+
// follower
33+
let follow = React.findDOMNode(this.refs.follow);
34+
35+
// get rectangles
36+
let containerRect = box.getBoundingClientRect();
37+
let cursorRect = cur.getBoundingClientRect();
38+
let letterRect = letter.getBoundingClientRect();
39+
40+
// create timeline
41+
const t = new TimelineMax();
42+
43+
// calc cursor offset
44+
let offsetTop = cursorRect.top - containerRect.top;
45+
let offsetLeft = letterRect.left - containerRect.left;
46+
47+
let scroll = {};
48+
49+
// vertical scroll
50+
if (offsetTop > containerRect.height / 2) {
51+
this.scrolledY += offsetTop / 2;
52+
scroll.y = this.scrolledY;
53+
}
54+
55+
// horizontal scroll
56+
if (offsetLeft > containerRect.width / 2) {
57+
this.scrolledX += offsetLeft / 2;
58+
scroll.x = this.scrolledX;
59+
}
60+
if (offsetLeft < 0) {
61+
this.scrolledX = 0;
62+
scroll.x = this.scrolledX;
63+
}
64+
65+
t.set(pre, { scrollTo: scroll });
66+
67+
// update follow
68+
t.to(follow, 0.15, {
69+
scaleX: cursorRect.width + 5,
70+
x: cursorRect.left - containerRect.left - 2,
71+
y: cursorRect.top - containerRect.top + 30
3072
});
3173
}
3274

@@ -79,7 +121,7 @@ export default class SourceCode extends React.Component {
79121
<span style={styleByType.no} key={1}>
80122
{onCursor.substr(0, typedWord.length)}
81123
</span>,
82-
<span style={styleByType.cur} key={2}>
124+
<span style={styleByType.cur} key={2} ref='letter'>
83125
{onCursor.substr(typedWord.length, 1)}
84126
</span>,
85127
<span style={styleByType.no} key={3}>
@@ -101,14 +143,14 @@ export default class SourceCode extends React.Component {
101143
afterCursor = afterCursor.join('');
102144

103145
return (
104-
<div className='SourceCode' ref='box'>
146+
<div className='SourceCode'>
105147
{!this.props.isFinished && (
106148
<div
107149
style={followStyle}
108150
className='follow'
109151
ref='follow' />
110152
)}
111-
<pre>
153+
<pre ref='pre'>
112154
<span style={{ color: 'rgba(255, 255, 255, 0.6)' }}>{beforeCursor}</span>
113155
<span ref='cur' style={{ color: isBad ? 'red' : 'white' }}>
114156
{onCursor}

stores/GameStore.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class GameStore extends BaseStore {
6363
],
6464

6565
// the text used
66-
text: GameStore.buildText('if (id === 5) {\n console.log(\'yallah\');\n}'),
66+
text: GameStore.buildText('server.use(\'/public\', express.static(path.join(__dirname, \'/build\')));\nserver.use(compression());\nserver.use(bodyParser.json());\n\n/**\n * Isomorphic data fetching\n */\n\nimport textService from \'./services/TextService\';\nimport userService from \'./services/UserService\';\n\nconst fetchrPlugin = app.getPlugin(\'FetchrPlugin\');\nfetchrPlugin.registerService(textService);\nfetchrPlugin.registerService(userService);\n\nserver.use(fetchrPlugin.getXhrPath(), fetchrPlugin.getMiddleware());\n'),
6767

6868
// used to show a progress while loading text
6969
isLoadingText: false

styles/SourceCode.scss

+6
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
background: $cdarken;
99
color: $clight;
1010
text-shadow: rgba(black, 0.8) 0 1px 0;
11+
max-height: 450px;
12+
overflow: auto;
13+
&::-webkit-scrollbar {
14+
width: 0;
15+
height: 0;
16+
}
1117
}
1218
.follow {
1319
transform-origin: center left;

0 commit comments

Comments
 (0)