feat(terminal): terminal wrapper and context

This commit is contained in:
Pihkaal
2024-01-22 11:50:37 +01:00
parent 070e198b43
commit f7b43b47bf
2 changed files with 73 additions and 16 deletions

View File

@@ -1,20 +1,62 @@
import { type FunctionComponent, type PropsWithChildren } from "react";
import { useRef, useState, useEffect, type ReactNode } from "react";
import clsx from "clsx";
import { TerminalContextProvider } from "~/context/TerminalContext";
type TerminalProps = PropsWithChildren<{
export const Terminal = (props: {
children?: ReactNode;
className?: string;
}>;
}) => {
const terminalRef = useRef<HTMLDivElement>(null);
export const Terminal: FunctionComponent<TerminalProps> = ({
children,
className,
}) => (
const [size, setSize] = useState<{ cols: number; rows: number }>();
useEffect(() => {
const precision = 300;
const calculateSize = () => {
if (!terminalRef.current) return;
const node = document.createElement("span");
node.style.color = "transparent";
node.style.position = "absolute";
node.textContent = "A".repeat(precision);
terminalRef.current.appendChild(node);
setSize({
cols: Math.floor(
(terminalRef.current.offsetWidth - 4) /
(node.offsetWidth / precision),
),
rows: Math.floor(
(terminalRef.current.offsetHeight - 4) / node.offsetHeight,
),
});
node.remove();
};
calculateSize();
window.addEventListener("resize", calculateSize);
return () => {
window.removeEventListener("resize", calculateSize);
};
}, []);
return (
<TerminalContextProvider value={size}>
<div
ref={terminalRef}
className={clsx(
"rounded-lg border-2 border-[#595959] bg-[#1e1e2e] bg-opacity-95 px-1 text-[#cdd6f4] shadow-window transition-colors duration-[500ms] ease-out hover:border-[#cdd6f4] hover:duration-[200ms]",
className,
"overflow-hidden rounded-lg border-2 border-borderInactive bg-background bg-opacity-80 text-lg text-color7 text-foreground shadow-window transition-colors duration-[500ms] ease-out hover:border-borderActive hover:duration-[200ms]",
props.className,
)}
style={{ backdropFilter: "blur(2px)" }}
>
{children}
{size && props.children}
</div>
</TerminalContextProvider>
);
};

View File

@@ -0,0 +1,15 @@
import { createContext, useContext } from "react";
const TerminalContext = createContext<{ cols: number; height: number } | null>(
null,
);
export const TerminalContextProvider = TerminalContext.Provider;
export const useTerminal = () => {
const context = useContext(TerminalContext);
if (!context)
throw new Error("useTerminal must be used inside a Terminal component");
return context;
};