From 390aee8f6f1a28e7c3f0d9505e904a1bb3410ed3 Mon Sep 17 00:00:00 2001 From: Cecilia Sanare Date: Sun, 20 Aug 2023 21:09:51 -0500 Subject: [PATCH] feat: added support for commands and going back in history --- app/components/common/Prism.tsx | 31 +++ app/components/common/Typography.tsx | 2 +- app/components/terminal/WSH.module.scss | 1 + app/components/terminal/WSH.tsx | 7 +- app/components/terminal/WSHInput.module.scss | 37 +++ app/components/terminal/WSHInput.tsx | 65 ++++++ app/components/web-osx/Window.module.scss | 10 + app/components/web-osx/Window.tsx | 42 ++-- app/components/web-osx/WindowResizer.tsx | 13 +- app/services/history.ts | 71 ++++++ app/services/storage.ts | 25 ++ app/utils/guards.ts | 9 + package.json | 4 +- tsconfig.json | 2 +- yarn.lock | 232 +++++++++++++++++++ 15 files changed, 525 insertions(+), 26 deletions(-) create mode 100644 app/components/common/Prism.tsx create mode 100644 app/components/terminal/WSHInput.module.scss create mode 100644 app/components/terminal/WSHInput.tsx create mode 100644 app/services/history.ts create mode 100644 app/services/storage.ts create mode 100644 app/utils/guards.ts diff --git a/app/components/common/Prism.tsx b/app/components/common/Prism.tsx new file mode 100644 index 0000000..ceabed3 --- /dev/null +++ b/app/components/common/Prism.tsx @@ -0,0 +1,31 @@ +import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism'; + +export type PrismProps = { + className?: string; + children: string | string[]; +}; + +export function Prism({ className, children }: PrismProps) { + return ( +
+ + {children} + +
+ ); +} diff --git a/app/components/common/Typography.tsx b/app/components/common/Typography.tsx index 0169411..362c1fd 100644 --- a/app/components/common/Typography.tsx +++ b/app/components/common/Typography.tsx @@ -25,7 +25,7 @@ export function Typography< const Element: React.ElementType = as ?? type ?? TypographyDefaultElement; const className = useReadOnlyCachedState(() => { - return classnames(styles.typography, styles[type], externalClassName); + return classnames(styles.typography, styles[type as string], externalClassName); }, [type, externalClassName]); return ( diff --git a/app/components/terminal/WSH.module.scss b/app/components/terminal/WSH.module.scss index 989ce29..8c09359 100644 --- a/app/components/terminal/WSH.module.scss +++ b/app/components/terminal/WSH.module.scss @@ -1,2 +1,3 @@ .shell { + font-family: 'Roboto Mono', monospace; } diff --git a/app/components/terminal/WSH.tsx b/app/components/terminal/WSH.tsx index bc20854..90e48b2 100644 --- a/app/components/terminal/WSH.tsx +++ b/app/components/terminal/WSH.tsx @@ -1,9 +1,14 @@ import { Window } from '../web-osx/Window'; +import { WSHInput } from './WSHInput'; export type WSHProps = { demo?: boolean; }; export function WSH({ demo }: WSHProps) { - return ; + return ( + + + + ); } diff --git a/app/components/terminal/WSHInput.module.scss b/app/components/terminal/WSHInput.module.scss new file mode 100644 index 0000000..1dfc6e9 --- /dev/null +++ b/app/components/terminal/WSHInput.module.scss @@ -0,0 +1,37 @@ +.container { + position: relative; + font-family: 'Roboto Mono', monospace; + font-size: 16px; + margin-left: 20px; + line-height: 1.5; + + .prism { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + pointer-events: none; + } + + &:before { + content: '$'; + user-select: none; + position: absolute; + top: 0; + left: -20px; + } + + .input { + color: transparent; + caret-color: white; + background: transparent; + padding: 0; + border: none; + width: 100%; + height: 100%; + outline: none; + font: inherit; + resize: none; + } +} diff --git a/app/components/terminal/WSHInput.tsx b/app/components/terminal/WSHInput.tsx new file mode 100644 index 0000000..fdc9be1 --- /dev/null +++ b/app/components/terminal/WSHInput.tsx @@ -0,0 +1,65 @@ +import { KeyboardEvent, useCallback, useState } from 'react'; +import * as styles from './WSHInput.module.scss'; +import { History } from '../../services/history'; +import { Prism } from '../common/Prism'; + +export type WSHInputProps = { + onSubmit?: (value: string) => void; +}; + +export function WSHInput({ onSubmit }: WSHInputProps) { + const [value, setValue] = useState(''); + + const onSubmitInternal = useCallback( + (e: KeyboardEvent, value: string, ignore: boolean = false) => { + e.preventDefault(); + + if (!ignore) { + History.add(value); + } + + onSubmit?.(value); + setValue(''); + }, + [onSubmit] + ); + + return ( +
+ {value} +