Skip to content

Commit

Permalink
feat: start animation when user scrolls the terminal into view
Browse files Browse the repository at this point in the history
  • Loading branch information
jerelmiller committed Oct 15, 2020
1 parent 8a767a7 commit e13c8fe
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 15 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"react-shadow": "^18.4.2",
"react-simple-code-editor": "^0.11.0",
"react-typist": "^2.0.5",
"react-use": "^15.3.4",
"snyk": "^1.401.0",
"use-dark-mode": "^2.3.1",
"use-media": "^1.4.0",
Expand Down
34 changes: 24 additions & 10 deletions src/components/Terminal/Shell.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
import React, { useState, useRef, useLayoutEffect } from 'react';
import React, {
forwardRef,
useState,
useRef,
useLayoutEffect,
useImperativeHandle,
} from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/core';
import Command from './Command';
import theme from './theme';
import rollupIntoCommands from './rollupIntoCommands';

const Shell = ({ animate, highlight, code }) => {
const ref = useRef();
const Shell = forwardRef(({ animate, highlight, code }, ref) => {
const shellRef = useRef();
const [animated, setAnimated] = useState(false);
const [height, setHeight] = useState(null);
const [step, setStep] = useState(1);
const { tokens, getTokenProps } = highlight;
const commands = rollupIntoCommands(tokens, code);
const shownCommands = animated ? commands.slice(0, step) : commands;
const [shownCommands, setShownCommands] = useState(commands);

useImperativeHandle(ref, () => ({
startAnimation: () => {
setAnimated(true);
setShownCommands(commands.slice(0, 1));
},
}));

useLayoutEffect(() => {
const { height } = ref.current.getBoundingClientRect();
const { height } = shellRef.current.getBoundingClientRect();
setHeight(height);

if (animate) {
setAnimated(true);
setShownCommands([]);
}
}, [animate]);

return (
<pre
ref={ref}
ref={shellRef}
css={css`
${theme};
Expand Down Expand Up @@ -67,14 +79,16 @@ const Shell = ({ animate, highlight, code }) => {
getTokenProps={getTokenProps}
typingDelay={idx === 0 ? 2000 : 500}
onDone={() => {
setStep((step) => step + 1);
setShownCommands((shownCommands) =>
commands.slice(0, shownCommands.length)
);
}}
/>
))}
</code>
</pre>
);
};
});

Shell.propTypes = {
animate: PropTypes.bool,
Expand Down
23 changes: 21 additions & 2 deletions src/components/Terminal/Terminal.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,31 @@
import React from 'react';
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { css } from '@emotion/core';
import { Button, useClipboard } from '@newrelic/gatsby-theme-newrelic';
import Highlight from 'prism-react-renderer';
import Prism from 'prismjs';
import Shell from './Shell';
import { useIntersection } from 'react-use';

const Terminal = ({ animate, children }) => {
const ref = useRef();
const shellRef = useRef();
const code = children.trim();
const [copied, copy] = useClipboard();
const intersection = useIntersection(ref, {
root: null,
rootMargin: '0px 0px -33% 0px',
});

useEffect(() => {
if (animate && intersection?.isIntersecting) {
shellRef.current.startAnimation();
}
}, [animate, intersection]);

return (
<div
ref={ref}
css={css`
--chrome-color: #252526;
--border-radius: 0.25rem;
Expand Down Expand Up @@ -61,7 +75,12 @@ const Terminal = ({ animate, children }) => {
</div>
<Highlight Prism={Prism} code={code} language="shell">
{(highlight) => (
<Shell animate={animate} code={code} highlight={highlight} />
<Shell
ref={shellRef}
animate={animate}
code={code}
highlight={highlight}
/>
)}
</Highlight>
</div>
Expand Down

0 comments on commit e13c8fe

Please sign in to comment.