diff --git a/demo/index.tsx b/demo/index.tsx index 79109d8..767289f 100644 --- a/demo/index.tsx +++ b/demo/index.tsx @@ -1,6 +1,6 @@ import React, { useState, MouseEvent } from 'react' import ReactDOM from 'react-dom'; -import Terminal, { ColorMode, TerminalInput, TerminalOutput } from '../src/index'; +import Terminal, { ColorMode, TerminalInput, TerminalOutput, TerminalProgress } from '../src/index'; import './style.css'; @@ -13,6 +13,7 @@ const TerminalController = (props = {}) => { 'view-source' will navigate to the React Terminal UI github source., 'view-react-docs' will navigate to the react docs., 'clear' will clear the terminal., + ]); function toggleColorMode (e: MouseEvent) { diff --git a/src/index.tsx b/src/index.tsx index a615135..32c06ce 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,8 @@ import React, { useState, useEffect, useRef, KeyboardEvent, ChangeEvent, ReactNode, ReactNodeArray } from 'react'; import TerminalInput from './linetypes/TerminalInput'; import TerminalOutput from './linetypes/TerminalOutput'; +import TerminalProgress from './linetypes/TerminalProgress'; +import TerminalLoader from './linetypes/TerminalLoader' import './style.css'; export enum ColorMode { @@ -19,9 +21,10 @@ export interface Props { redBtnCallback?: () => void; yellowBtnCallback?: () => void; greenBtnCallback?: () => void; + loading?: boolean; } -const Terminal = ({name, prompt, height = "600px", colorMode, onInput, children, startingInputValue = "", redBtnCallback, yellowBtnCallback, greenBtnCallback}: Props) => { +const Terminal = ({name, prompt, height = "600px", colorMode, onInput, children, startingInputValue = "", redBtnCallback, yellowBtnCallback, greenBtnCallback, loading}: Props) => { const [currentLineInput, setCurrentLineInput] = useState(''); const [cursorPos, setCursorPos] = useState(0); @@ -120,13 +123,13 @@ const Terminal = ({name, prompt, height = "600px", colorMode, onInput, children,
{ children } - { typeof onInput === 'function' &&
{ currentLineInput }
} + { typeof onInput === 'function' && !loading &&
{ currentLineInput }
}
- + {!loading && } ); } -export { TerminalInput, TerminalOutput }; +export { TerminalInput, TerminalOutput, TerminalProgress, TerminalLoader }; export default Terminal; diff --git a/src/linetypes/TerminalLoader.tsx b/src/linetypes/TerminalLoader.tsx new file mode 100644 index 0000000..c6c4a9a --- /dev/null +++ b/src/linetypes/TerminalLoader.tsx @@ -0,0 +1,26 @@ +import React, { PropsWithChildren, useEffect, useState } from "react"; +export const loaderChars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + +type TerminalLoaderProps = PropsWithChildren<{ + loaderCharacters?: Array +}>; + + +const TerminalLoader = ({ loaderCharacters = loaderChars }: TerminalLoaderProps) => { + const [loaderIndex, setLoaderIndex] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setLoaderIndex((loaderIndex + 1) % loaderCharacters.length); + }, 100); + return () => clearInterval(interval); + }, [loaderIndex]); + + return ( +
+ {loaderCharacters[loaderIndex]} +
+ ); +}; + +export default TerminalLoader; diff --git a/src/linetypes/TerminalProgress.tsx b/src/linetypes/TerminalProgress.tsx new file mode 100644 index 0000000..b397261 --- /dev/null +++ b/src/linetypes/TerminalProgress.tsx @@ -0,0 +1,34 @@ +import React, { PropsWithChildren } from "react"; +import TerminalLoader from "./TerminalLoader"; + +type TerminalProgressProps = PropsWithChildren<{ + progressPercentage?: number; + progressLength?: number; + progressChar?: string; +}>; + +const TerminalProgress = ({ + progressPercentage = 0, + progressLength = 20, + progressChar = "█", +}: TerminalProgressProps) => { + return ( +
+ + {progressChar.repeat(progressPercentage * progressLength)} + + + {progressChar.repeat( + progressLength - progressPercentage * progressLength + )} + + + {Math.round(progressPercentage * 100).toString()}% +
+ ); +}; + +export default TerminalProgress; diff --git a/src/style.css b/src/style.css index d6a4b92..20cc4e7 100644 --- a/src/style.css +++ b/src/style.css @@ -145,3 +145,36 @@ .react-terminal-wrapper.react-terminal-light .react-terminal-progress-bar { background-color: #000; } */ + +.react-terminal-progress { + display: flex; + margin: .5rem 0; + align-items: center; +} + +.react-terminal-progress-filled { + color: #fff; +} + +.react-terminal-progress-empty { + color: #000; +} + +.react-terminal-light .react-terminal-progress-filled { + color: #1a1e24; +} + +.react-terminal-light .react-terminal-progress-empty { + color: #fff; +} + +.react-terminal-loader { + font-size: 20px; + margin-bottom: -2px; + margin-left: 0.5rem; +} + +.react-terminal-progress-label { + margin-left: 1rem; + font-size: 16px; +} \ No newline at end of file