-
- );
-};
diff --git a/src/app/CompletionList.tsx b/src/app/CompletionList.tsx
new file mode 100644
index 0000000..7303a4c
--- /dev/null
+++ b/src/app/CompletionList.tsx
@@ -0,0 +1,72 @@
+import classNames from "classnames";
+import { useEffect, useRef } from "react";
+
+export type ICompletion = {
+ completion: string;
+ start: number;
+};
+
+const CompletionItem = ({
+ active,
+ completion,
+ ...props
+}: {
+ active: boolean;
+ completion: ICompletion;
+}) => {
+ const ref = useRef
- {workingDir}
-
-
-
-
-
-
-
-
-
- {
- handleHistory(-1);
- }}
- onHistoryDown={() => {
- handleHistory(1);
- }}
- onChangeInput={(value) => {
- setInput(value);
- }}
- />
-
-
- {output !== undefined && (
-
-
-
- )}
- -
+ {completions.map((completion, index) => (
+
+ {children} ++ ); +}; + const Record = ({ value: { cols, vals } }: { value: any }) => ( -
{cols[i]} | -
+ {cols[i]} |
+
|
- |
---|
{col} | ++ {col} + | ))} -||
---|---|---|---|
+ | )) ) : ( - | + | )} - |
{value.String.val}: <> >; + return value.String.val ?
{value.String.val}: <> >; } else if (value.Filesize) { return humanFileSize(value.Filesize.val); } else if (value.Duration) { @@ -97,5 +157,5 @@ export const Output = ({ value }: { value: any }): any => { } // todo: use rehype-sanitize - return ; + return ; }; diff --git a/src/app/Prompt.tsx b/src/app/Prompt.tsx index d81f2eb..8dc9662 100644 --- a/src/app/Prompt.tsx +++ b/src/app/Prompt.tsx @@ -1,105 +1,211 @@ -import { KeyboardEvent, useRef } from "react"; +import { forwardRef, KeyboardEvent, useRef, useState } from "react"; import { complete, simpleCommandWithResult } from "../support/nana"; - -export type ICompletion = { - completion: string; - start: number; -}; +import { CompletionList, ICompletion } from "./CompletionList"; +import { Spinner } from "./Spinner"; type PromptPropType = { input: string; + workingDir: string | null; onChangeInput: (input: string) => void; - onSubmit: (output: string) => void; + onSubmit: (output: string, duration: number) => void; onSubmitError: (output: string) => void; onHistoryUp: () => void; onHistoryDown: () => void; }; -export const Prompt = ({ - input, - onChangeInput, - onSubmit, - onSubmitError, - onHistoryUp, - onHistoryDown, -}: PromptPropType) => { - const inputRef = useRef
+
+ );
+ }
+);
diff --git a/src/app/Result.tsx b/src/app/Result.tsx
new file mode 100644
index 0000000..30b6400
--- /dev/null
+++ b/src/app/Result.tsx
@@ -0,0 +1,54 @@
+import classNames from "classnames";
+import { HTMLAttributes } from "react";
+import { humanDuration } from "../support/formatting";
+import { Output } from "./Output";
+
+export type IResult = {
+ id: number;
+ workingDir: string;
+ input: string;
+ output?: string;
+ duration?: number;
+};
+
+const Indicator = ({ className }: HTMLAttributes
+ {workingDir}
+
+
+
+ )}
+
+
+ {isLoading && }
+
+ {
+ handleChange(e.target.value);
+ }}
+ />
+ {completions.length > 0 && (
+
+
+);
diff --git a/src/app/ResultList.tsx b/src/app/ResultList.tsx
new file mode 100644
index 0000000..e730421
--- /dev/null
+++ b/src/app/ResultList.tsx
@@ -0,0 +1,13 @@
+import { IResult, Result } from "./Result";
+
+export const ResultList = ({ results }: { results: IResult[] }) => {
+ if (results.length === 0) return null;
+
+ return (
+
+
+
+
+
+
+
+
+ {input}
+ {duration ? (
+
+ {humanDuration(duration)}
+
+ ) : null}
+
+
+ {workingDir}
+
+
+ {results.map(({ ...props }) => (
+
+ ))}
+
+ );
+};
diff --git a/src/app/Spinner.tsx b/src/app/Spinner.tsx
new file mode 100644
index 0000000..9c3a812
--- /dev/null
+++ b/src/app/Spinner.tsx
@@ -0,0 +1,7 @@
+import classNames from "classnames";
+import { IconBaseProps } from "react-icons";
+import { CgSpinner } from "react-icons/cg";
+
+export const Spinner = ({ className }: IconBaseProps) => (
+