Skip to content

Commit

Permalink
add Terminal component
Browse files Browse the repository at this point in the history
  • Loading branch information
jcubic committed Sep 12, 2024
1 parent b58c2a1 commit 30d715d
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 13 deletions.
65 changes: 65 additions & 0 deletions docs/src/components/Terminal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useLayoutEffect, useRef, CSSProperties } from 'react';
import useIsBrowser from '@docusaurus/useIsBrowser';
import Head from '@docusaurus/Head';

import useScripts from '@site/src/hooks/useScripts';
import './styles.css';

const replReady = () => {
return (
globalThis.jQuery &&
globalThis.jQuery.terminal
);
}

import { initTerminal, destroyTerminal } from './terminal';

export interface TerminalProps extends CSSProperties {
'--rows': number;
}

export default function Interpreter(): JSX.Element {
const ref = useRef<HTMLDivElement>();

const isProd = process.env.NODE_ENV === 'production';
const isBrowser = useIsBrowser();
const isStatic = isProd && !isBrowser && !globalThis.jQuery;

useScripts(!globalThis.jQuery && [
'https://cdn.jsdelivr.net/npm/jquery',
'https://cdn.jsdelivr.net/combine/npm/jquery.terminal/js/jquery.terminal.min.js,npm/js-polyfills/keyboard.js'
]);

useLayoutEffect(() => {
(function loop() {
if (replReady() && styleReady()) {
initTerminal();
} else {
setTimeout(loop, 100);
}
})();
return destroyTerminal;
}, []);

function styleReady() {
// hack to prevent initalizaing of jQuery Terminal before style is loaded
return !!getComputedStyle(ref.current).getPropertyValue('--base-background');
}

const terminalStyle = {
'--rows': 15
} as TerminalProps;

return (
<>
<Head>
<link rel="preconnect" href="https://cdn.jsdelivr.net" />
<link href="https://cdn.jsdelivr.net/npm/jquery.terminal/css/jquery.terminal.min.css" rel="stylesheet"/>
{isStatic && <script src="https://cdn.jsdelivr.net/npm/jquery" />}
{isStatic && <script src="https://cdn.jsdelivr.net/combine/npm/jquery.terminal/js/jquery.terminal.min.js,npm/js-polyfills/keyboard.js" />}
</Head>
<div className="terminal marker" ref={ref}></div>
<div className="term" style={terminalStyle} />
</>
);
};
18 changes: 18 additions & 0 deletions docs/src/components/Terminal/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.term {
--background: white;
--color:#14232d;
}
[data-theme='dark'] .term {
--background: #14232d;
--color: white;
}
.terminal.marker {
position: absolute;
left: -9999999999px;
}
.term {
--rows: 11;
text-align: left;
resize: vertical;
overflow: hidden;
}
15 changes: 15 additions & 0 deletions docs/src/components/Terminal/terminal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function initTerminal() {
const $ = globalThis.$;
const $term = $('.term');
$term.empty();

$term.terminal();

return $term;
};

export function destroyTerminal() {
const $ = globalThis.$;
const $term = $('.term');
$term.terminal().destroy();
}
22 changes: 22 additions & 0 deletions docs/src/hooks/useScripts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useEffect } from 'react';

function getScript(script: string) {
return new Promise((resolve, reject) => {
const $script = document.createElement("script");
$script.onload = resolve;
$script.onerror = reject;
$script.src = script;
document.head.appendChild($script);
});
}

export default function useScripts(scripts?: string[]) {
useEffect(() => {
(function loop() {
if (scripts?.length) {
const script = scripts.shift();
getScript(script).then(loop);
}
})();
}, []);
}
17 changes: 4 additions & 13 deletions docs/src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
import Heading from '@theme/Heading';

import Terminal from '@site/src/components/Terminal';

import styles from './index.module.css';

function HomepageHeader() {
const {siteConfig} = useDocusaurusContext();
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<div className="container">
<Heading as="h1" className="hero__title">
{siteConfig.title}
</Heading>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<div className={styles.buttons}>
<Link
className="button button--secondary button--lg"
to="/docs/intro">
Docusaurus Tutorial - 5min ⏱️
</Link>
</div>
<Terminal />
</div>
</header>
);
Expand All @@ -33,7 +24,7 @@ export default function Home(): JSX.Element {
return (
<Layout
title={`Hello from ${siteConfig.title}`}
description="Description will go into a meta tag in <head />">
description="Description will go into a meta tag">
<HomepageHeader />
<main>
<HomepageFeatures />
Expand Down

0 comments on commit 30d715d

Please sign in to comment.