diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6197a1af..abcd660d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -67,6 +67,9 @@ jobs:
with:
clang-format-version: '20'
check-path: 'src'
+
+ - name: Verify Page Formatting
+ run: cd page && npx --yes prettier . --check
build-apiset-dumper:
name: Build API Set Dumper
diff --git a/page/.prettierignore b/page/.prettierignore
new file mode 100644
index 00000000..e17b023c
--- /dev/null
+++ b/page/.prettierignore
@@ -0,0 +1,2 @@
+# Ignore artifacts:
+dist
diff --git a/page/.prettierrc b/page/.prettierrc
new file mode 100644
index 00000000..0967ef42
--- /dev/null
+++ b/page/.prettierrc
@@ -0,0 +1 @@
+{}
diff --git a/page/components.json b/page/components.json
index 73afbdbc..13e1db0b 100644
--- a/page/components.json
+++ b/page/components.json
@@ -18,4 +18,4 @@
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
-}
\ No newline at end of file
+}
diff --git a/page/eslint.config.js b/page/eslint.config.js
index 092408a9..79a552ea 100644
--- a/page/eslint.config.js
+++ b/page/eslint.config.js
@@ -1,28 +1,28 @@
-import js from '@eslint/js'
-import globals from 'globals'
-import reactHooks from 'eslint-plugin-react-hooks'
-import reactRefresh from 'eslint-plugin-react-refresh'
-import tseslint from 'typescript-eslint'
+import js from "@eslint/js";
+import globals from "globals";
+import reactHooks from "eslint-plugin-react-hooks";
+import reactRefresh from "eslint-plugin-react-refresh";
+import tseslint from "typescript-eslint";
export default tseslint.config(
- { ignores: ['dist'] },
+ { ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
- files: ['**/*.{ts,tsx}'],
+ files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
- 'react-hooks': reactHooks,
- 'react-refresh': reactRefresh,
+ "react-hooks": reactHooks,
+ "react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
- 'react-refresh/only-export-components': [
- 'warn',
+ "react-refresh/only-export-components": [
+ "warn",
{ allowConstantExport: true },
],
},
},
-)
+);
diff --git a/page/index.html b/page/index.html
index 0393cae0..13e01b85 100644
--- a/page/index.html
+++ b/page/index.html
@@ -3,22 +3,58 @@
-
-
+
+
Sogen - Windows User Space Emulator
-
-
-
-
+
+
+
+
-
+
-
-
-
+
+
+
diff --git a/page/package-lock.json b/page/package-lock.json
index 2a8edaff..965ccf18 100644
--- a/page/package-lock.json
+++ b/page/package-lock.json
@@ -44,6 +44,7 @@
"eslint-plugin-react-hooks": "^6.0.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.0.0",
+ "prettier": "3.5.3",
"typescript": "~5.8.3",
"typescript-eslint": "^8.31.0",
"vite": "^6.3.1"
@@ -4424,6 +4425,22 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
diff --git a/page/package.json b/page/package.json
index 54a9862a..76dc86a0 100644
--- a/page/package.json
+++ b/page/package.json
@@ -46,6 +46,7 @@
"eslint-plugin-react-hooks": "^6.0.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.0.0",
+ "prettier": "3.5.3",
"typescript": "~5.8.3",
"typescript-eslint": "^8.31.0",
"vite": "^6.3.1"
diff --git a/page/public/emulator-worker.js b/page/public/emulator-worker.js
index ed047e63..65af92a1 100644
--- a/page/public/emulator-worker.js
+++ b/page/public/emulator-worker.js
@@ -1,57 +1,57 @@
-var logLines = [];
-var lastFlush = new Date().getTime();
-
-onmessage = async (event) => {
- const data = event.data;
- if (data.message == "run") {
- const payload = data.data;
- runEmulation(payload.filesystem, payload.file, payload.options);
- }
-};
-
-function flushLines() {
- const lines = logLines;
- logLines = [];
- lastFlush = new Date().getTime();
- postMessage({ message: "log", data: lines });
-}
-
-function logLine(text) {
- logLines.push(text);
-
- const now = new Date().getTime();
-
- if(lastFlush + 15 < now) {
- flushLines();
- }
-}
-
-function runEmulation(filesystem, file, options) {
- globalThis.Module = {
- arguments: [...options, "-e", "./root", file],
- onRuntimeInitialized: function () {
- filesystem.forEach(e => {
- if (e.name.endsWith("/")) {
- FS.mkdir(e.name.slice(0, -1));
- } else {
- const dirs = e.name.split("/")
- const file = dirs.pop();
- const buffer = new Uint8Array(e.data);
- if (FS.analyzePath(e.name).exists) {
- FS.unlink(e.name);
- }
- FS.createDataFile("/" + dirs.join('/'), file, buffer, true, true);
- }
- })
- },
- print: logLine,
- printErr: logLine,
- postRun: () => {
- flushLines();
- postMessage({ message: "end", data: null });
- self.close();
- },
- };
-
- importScripts('./analyzer.js?1');
-}
+var logLines = [];
+var lastFlush = new Date().getTime();
+
+onmessage = async (event) => {
+ const data = event.data;
+ if (data.message == "run") {
+ const payload = data.data;
+ runEmulation(payload.filesystem, payload.file, payload.options);
+ }
+};
+
+function flushLines() {
+ const lines = logLines;
+ logLines = [];
+ lastFlush = new Date().getTime();
+ postMessage({ message: "log", data: lines });
+}
+
+function logLine(text) {
+ logLines.push(text);
+
+ const now = new Date().getTime();
+
+ if (lastFlush + 15 < now) {
+ flushLines();
+ }
+}
+
+function runEmulation(filesystem, file, options) {
+ globalThis.Module = {
+ arguments: [...options, "-e", "./root", file],
+ onRuntimeInitialized: function () {
+ filesystem.forEach((e) => {
+ if (e.name.endsWith("/")) {
+ FS.mkdir(e.name.slice(0, -1));
+ } else {
+ const dirs = e.name.split("/");
+ const file = dirs.pop();
+ const buffer = new Uint8Array(e.data);
+ if (FS.analyzePath(e.name).exists) {
+ FS.unlink(e.name);
+ }
+ FS.createDataFile("/" + dirs.join("/"), file, buffer, true, true);
+ }
+ });
+ },
+ print: logLine,
+ printErr: logLine,
+ postRun: () => {
+ flushLines();
+ postMessage({ message: "end", data: null });
+ self.close();
+ },
+ };
+
+ importScripts("./analyzer.js?1");
+}
diff --git a/page/src/App.css b/page/src/App.css
index 5d4ad00b..8cab0f2d 100644
--- a/page/src/App.css
+++ b/page/src/App.css
@@ -1,70 +1,70 @@
-@media (pointer:fine) {
- ::-webkit-scrollbar {
- width: 20px;
- }
-
- ::-webkit-scrollbar-track {
- background-color: transparent;
- }
-
- ::-webkit-scrollbar-thumb {
- background-color: rgba(97, 97, 97, 0.7);
- border-radius: 20px;
- min-height: 50px;
- border: 6px solid transparent;
- background-clip: content-box;
- transition: all 0.1s linear;
- }
-
- ::-webkit-scrollbar-thumb:hover {
- background-color: rgba(97, 97, 97, 0.9);
- }
-}
-
-button {
- cursor: pointer;
-}
-
-.terminal-output {
- line-height: 1.5;
- font-weight: 600;
- font-size: 1.05em;
- font-family: monospace;
- height: 100%;
-}
-
-.terminal-black {
- color: #0C0C0C;
-}
-
-.terminal-red {
- color: #FF3131;
-}
-
-.terminal-green {
- color: #86C000;
-}
-
-.terminal-yellow {
- color: #FFB940;
-}
-
-.terminal-blue {
- color: #3A96DD;
-}
-
-.terminal-cyan {
- color: #00ADF7;
-}
-
-.terminal-pink {
- color: #9750DD;
-}
-
-.terminal-white {
- color: #ECECEC;
-}
-
-.terminal-dark-gray {
- color: rgb(81, 81, 81);
-}
+@media (pointer: fine) {
+ ::-webkit-scrollbar {
+ width: 20px;
+ }
+
+ ::-webkit-scrollbar-track {
+ background-color: transparent;
+ }
+
+ ::-webkit-scrollbar-thumb {
+ background-color: rgba(97, 97, 97, 0.7);
+ border-radius: 20px;
+ min-height: 50px;
+ border: 6px solid transparent;
+ background-clip: content-box;
+ transition: all 0.1s linear;
+ }
+
+ ::-webkit-scrollbar-thumb:hover {
+ background-color: rgba(97, 97, 97, 0.9);
+ }
+}
+
+button {
+ cursor: pointer;
+}
+
+.terminal-output {
+ line-height: 1.5;
+ font-weight: 600;
+ font-size: 1.05em;
+ font-family: monospace;
+ height: 100%;
+}
+
+.terminal-black {
+ color: #0c0c0c;
+}
+
+.terminal-red {
+ color: #ff3131;
+}
+
+.terminal-green {
+ color: #86c000;
+}
+
+.terminal-yellow {
+ color: #ffb940;
+}
+
+.terminal-blue {
+ color: #3a96dd;
+}
+
+.terminal-cyan {
+ color: #00adf7;
+}
+
+.terminal-pink {
+ color: #9750dd;
+}
+
+.terminal-white {
+ color: #ececec;
+}
+
+.terminal-dark-gray {
+ color: rgb(81, 81, 81);
+}
diff --git a/page/src/Header.tsx b/page/src/Header.tsx
index 61475bdf..973b14e7 100644
--- a/page/src/Header.tsx
+++ b/page/src/Header.tsx
@@ -1,11 +1,12 @@
-import { Helmet } from 'react-helmet';
+import { Helmet } from "react-helmet";
export interface HeaderProps {
title: string;
description: string;
}
-const image = "https://repository-images.githubusercontent.com/842883987/9e56f43b-4afd-464d-85b9-d7e555751a39";
+const image =
+ "https://repository-images.githubusercontent.com/842883987/9e56f43b-4afd-464d-85b9-d7e555751a39";
export function Header(props: HeaderProps) {
return (
diff --git a/page/src/Playground.tsx b/page/src/Playground.tsx
index e479fa4f..e86061e7 100644
--- a/page/src/Playground.tsx
+++ b/page/src/Playground.tsx
@@ -97,7 +97,10 @@ export function Playground() {
return (
<>
-
+
diff --git a/page/src/components/app-sidebar.tsx b/page/src/components/app-sidebar.tsx
index 08967930..de7b708c 100644
--- a/page/src/components/app-sidebar.tsx
+++ b/page/src/components/app-sidebar.tsx
@@ -1,53 +1,51 @@
-import * as React from "react"
-
-import {
- Sidebar,
- SidebarContent,
- SidebarGroup,
- SidebarGroupLabel,
- SidebarHeader,
- /*SidebarMenu,
- SidebarGroupContent,
- SidebarMenuButton,
- SidebarMenuItem,*/
- SidebarRail,
-} from "@/components/ui/sidebar"
-
-// This is sample data.
-const data = {
- navMain: [
- {
- title: "TODO",
- },
- ],
-}
-
-export function AppSidebar({ ...props }: React.ComponentProps) {
- return (
-
-
- Filesystem
-
-
- {/* We create a SidebarGroup for each parent. */}
- {data.navMain.map((item) => (
-
- {item.title}
- {/*
-
- {item.items.map((item) => (
-
-
- {item.title}
-
-
- ))}
-
- */}
-
- ))}
-
-
-
- )
-}
+import * as React from "react";
+
+import {
+ Sidebar,
+ SidebarContent,
+ SidebarGroup,
+ SidebarGroupLabel,
+ SidebarHeader,
+ /*SidebarMenu,
+ SidebarGroupContent,
+ SidebarMenuButton,
+ SidebarMenuItem,*/
+ SidebarRail,
+} from "@/components/ui/sidebar";
+
+// This is sample data.
+const data = {
+ navMain: [
+ {
+ title: "TODO",
+ },
+ ],
+};
+
+export function AppSidebar({ ...props }: React.ComponentProps) {
+ return (
+
+ Filesystem
+
+ {/* We create a SidebarGroup for each parent. */}
+ {data.navMain.map((item) => (
+
+ {item.title}
+ {/*
+
+ {item.items.map((item) => (
+
+
+ {item.title}
+
+
+ ))}
+
+ */}
+
+ ))}
+
+
+
+ );
+}
diff --git a/page/src/components/output.tsx b/page/src/components/output.tsx
index 5188cd95..a9c3677d 100644
--- a/page/src/components/output.tsx
+++ b/page/src/components/output.tsx
@@ -1,244 +1,255 @@
-import React from 'react';
-import { FixedSizeList as List } from 'react-window';
-
-interface OutputProps { }
-
-interface ColorState {
- color: string;
-}
-
-interface OutputState extends ColorState {
- lines: LogLine[];
-}
-
-interface FullOutputState extends OutputState {
- grouper: OutputGrouper;
- height: number,
- width: number,
-}
-
-interface LogLine {
- text: string;
- classNames: string;
-};
-
-function removeSubstringFromStart(str: string, substring: string): string {
- if (str.startsWith(substring)) {
- return str.slice(substring.length);
- }
- return str;
-}
-
-function removeSubstringFromEnd(str: string, substring: string): string {
- if (str.endsWith(substring)) {
- return str.slice(0, -substring.length);
- }
- return str;
-}
-
-function removeSpanFromStart(str: string, color: string) {
- const pattern = /^/;
- const match = str.match(pattern);
-
- if (match) {
- const terminalValue = match[1];
- const cleanedString = str.replace(pattern, '');
- return [cleanedString, terminalValue];
- }
-
- return [str, color];
-}
-
-function extractColor(line: string, colorState: ColorState) {
- while (true) {
- const newLine = removeSubstringFromStart(line, "");
- if (newLine == line) {
- break
- }
-
- line = newLine;
- colorState.color = '';
- }
-
- const [nextLine, color] = removeSpanFromStart(line, colorState.color);
-
- const finalLine = removeSubstringFromEnd(nextLine, "");
- if (finalLine != nextLine) {
- colorState.color = '';
- } else {
- colorState.color = color;
- }
-
- return [finalLine, color];
-}
-
-function renderLine(line: string, colorState: ColorState) {
- const [newLine, color] = extractColor(line, colorState);
-
- return {
- text: newLine,
- classNames: 'whitespace-nowrap block ' + color
- };
-}
-
-function renderLines(lines: string[], color: string): OutputState {
- var state: ColorState = {
- color
- };
-
- const resultLines = lines.map(line => renderLine(line, state));
-
- return {
- lines: resultLines,
- color: state.color,
- };
-}
-
-function mergeLines(previousState: OutputState, newLines: string[]): OutputState {
- const result = renderLines(newLines, previousState.color);
- return { lines: previousState.lines.concat(result.lines), color: result.color };
-}
-
-class OutputGrouper {
- private lines: string[];
- private flushQueued: boolean;
- handler: (lines: string[]) => void;
-
- constructor() {
- this.lines = [];
- this.flushQueued = false;
- this.handler = () => { };
- }
-
- clear() {
- this.lines = [];
- this.flushQueued = false;
- }
-
- flush() {
- const lines = this.lines;
- this.lines = [];
- this.handler(lines);
- }
-
- queueFlush() {
- if (this.flushQueued) {
- return false;
- }
-
- this.flushQueued = true;
-
- requestAnimationFrame(() => {
- if (!this.flushQueued) {
- return;
- }
-
- this.flushQueued = false;
- this.flush();
- });
- }
-
- storeLines(lines: string[]) {
- this.lines = this.lines.concat(lines);
- this.queueFlush();
- }
-}
-
-export class Output extends React.Component {
- private outputRef: React.RefObject;
- private listRef: React.RefObject;
- private resizeObserver: ResizeObserver;
-
- constructor(props: OutputProps) {
- super(props);
-
- this.clear = this.clear.bind(this);
- this.logLine = this.logLine.bind(this);
- this.logLines = this.logLines.bind(this);
- this.updateDimensions = this.updateDimensions.bind(this);
-
- this.outputRef = React.createRef();
- this.listRef = React.createRef();
- this.resizeObserver = new ResizeObserver(this.updateDimensions);
-
- this.state = {
- lines: [],
- color: '',
- grouper: new OutputGrouper(),
- height: 10,
- width: 10,
- };
-
- this.state.grouper.handler = (lines: string[]) => {
- this.setState((s) => mergeLines(s, lines));
- };
- }
-
- componentDidMount() {
- this.updateDimensions();
-
- if (this.outputRef.current) {
- this.resizeObserver.observe(this.outputRef.current);
- }
- }
-
- componentWillUnmount() {
- this.resizeObserver.disconnect();
- }
-
- componentDidUpdate(_: OutputProps, prevState: FullOutputState) {
- if (prevState.lines.length == this.state.lines.length || !this.listRef.current) {
- return;
- }
-
- this.listRef.current.scrollToItem(this.state.lines.length - 1);
- }
-
- clear() {
- this.state.grouper.clear();
- this.setState({
- lines: [],
- color: '',
- });
- }
-
- updateDimensions() {
- if (!this.outputRef.current) {
- return;
- }
-
- this.setState({
- width: this.outputRef.current.offsetWidth,
- height: this.outputRef.current.offsetHeight,
- });
- }
-
- logLines(lines: string[]) {
- this.state.grouper.storeLines(lines);
- }
-
- logLine(line: string) {
- this.logLines([line]);
- }
-
- render() {
- return (
-
-
- {({ index, style }) => {
- const line = this.state.lines[index];
- return (
-
- {line.text}
-
- )
- }}
-
-
- );
- }
-}
+import React from "react";
+import { FixedSizeList as List } from "react-window";
+
+interface OutputProps {}
+
+interface ColorState {
+ color: string;
+}
+
+interface OutputState extends ColorState {
+ lines: LogLine[];
+}
+
+interface FullOutputState extends OutputState {
+ grouper: OutputGrouper;
+ height: number;
+ width: number;
+}
+
+interface LogLine {
+ text: string;
+ classNames: string;
+}
+
+function removeSubstringFromStart(str: string, substring: string): string {
+ if (str.startsWith(substring)) {
+ return str.slice(substring.length);
+ }
+ return str;
+}
+
+function removeSubstringFromEnd(str: string, substring: string): string {
+ if (str.endsWith(substring)) {
+ return str.slice(0, -substring.length);
+ }
+ return str;
+}
+
+function removeSpanFromStart(str: string, color: string) {
+ const pattern = /^/;
+ const match = str.match(pattern);
+
+ if (match) {
+ const terminalValue = match[1];
+ const cleanedString = str.replace(pattern, "");
+ return [cleanedString, terminalValue];
+ }
+
+ return [str, color];
+}
+
+function extractColor(line: string, colorState: ColorState) {
+ while (true) {
+ const newLine = removeSubstringFromStart(line, "");
+ if (newLine == line) {
+ break;
+ }
+
+ line = newLine;
+ colorState.color = "";
+ }
+
+ const [nextLine, color] = removeSpanFromStart(line, colorState.color);
+
+ const finalLine = removeSubstringFromEnd(nextLine, "");
+ if (finalLine != nextLine) {
+ colorState.color = "";
+ } else {
+ colorState.color = color;
+ }
+
+ return [finalLine, color];
+}
+
+function renderLine(line: string, colorState: ColorState) {
+ const [newLine, color] = extractColor(line, colorState);
+
+ return {
+ text: newLine,
+ classNames: "whitespace-nowrap block " + color,
+ };
+}
+
+function renderLines(lines: string[], color: string): OutputState {
+ var state: ColorState = {
+ color,
+ };
+
+ const resultLines = lines.map((line) => renderLine(line, state));
+
+ return {
+ lines: resultLines,
+ color: state.color,
+ };
+}
+
+function mergeLines(
+ previousState: OutputState,
+ newLines: string[],
+): OutputState {
+ const result = renderLines(newLines, previousState.color);
+ return {
+ lines: previousState.lines.concat(result.lines),
+ color: result.color,
+ };
+}
+
+class OutputGrouper {
+ private lines: string[];
+ private flushQueued: boolean;
+ handler: (lines: string[]) => void;
+
+ constructor() {
+ this.lines = [];
+ this.flushQueued = false;
+ this.handler = () => {};
+ }
+
+ clear() {
+ this.lines = [];
+ this.flushQueued = false;
+ }
+
+ flush() {
+ const lines = this.lines;
+ this.lines = [];
+ this.handler(lines);
+ }
+
+ queueFlush() {
+ if (this.flushQueued) {
+ return false;
+ }
+
+ this.flushQueued = true;
+
+ requestAnimationFrame(() => {
+ if (!this.flushQueued) {
+ return;
+ }
+
+ this.flushQueued = false;
+ this.flush();
+ });
+ }
+
+ storeLines(lines: string[]) {
+ this.lines = this.lines.concat(lines);
+ this.queueFlush();
+ }
+}
+
+export class Output extends React.Component {
+ private outputRef: React.RefObject;
+ private listRef: React.RefObject;
+ private resizeObserver: ResizeObserver;
+
+ constructor(props: OutputProps) {
+ super(props);
+
+ this.clear = this.clear.bind(this);
+ this.logLine = this.logLine.bind(this);
+ this.logLines = this.logLines.bind(this);
+ this.updateDimensions = this.updateDimensions.bind(this);
+
+ this.outputRef = React.createRef();
+ this.listRef = React.createRef();
+ this.resizeObserver = new ResizeObserver(this.updateDimensions);
+
+ this.state = {
+ lines: [],
+ color: "",
+ grouper: new OutputGrouper(),
+ height: 10,
+ width: 10,
+ };
+
+ this.state.grouper.handler = (lines: string[]) => {
+ this.setState((s) => mergeLines(s, lines));
+ };
+ }
+
+ componentDidMount() {
+ this.updateDimensions();
+
+ if (this.outputRef.current) {
+ this.resizeObserver.observe(this.outputRef.current);
+ }
+ }
+
+ componentWillUnmount() {
+ this.resizeObserver.disconnect();
+ }
+
+ componentDidUpdate(_: OutputProps, prevState: FullOutputState) {
+ if (
+ prevState.lines.length == this.state.lines.length ||
+ !this.listRef.current
+ ) {
+ return;
+ }
+
+ this.listRef.current.scrollToItem(this.state.lines.length - 1);
+ }
+
+ clear() {
+ this.state.grouper.clear();
+ this.setState({
+ lines: [],
+ color: "",
+ });
+ }
+
+ updateDimensions() {
+ if (!this.outputRef.current) {
+ return;
+ }
+
+ this.setState({
+ width: this.outputRef.current.offsetWidth,
+ height: this.outputRef.current.offsetHeight,
+ });
+ }
+
+ logLines(lines: string[]) {
+ this.state.grouper.storeLines(lines);
+ }
+
+ logLine(line: string) {
+ this.logLines([line]);
+ }
+
+ render() {
+ return (
+
+
+ {({ index, style }) => {
+ const line = this.state.lines[index];
+ return (
+
+ {line.text}
+
+ );
+ }}
+
+
+ );
+ }
+}
diff --git a/page/src/components/settings-menu.tsx b/page/src/components/settings-menu.tsx
index c42476ad..aa80d528 100644
--- a/page/src/components/settings-menu.tsx
+++ b/page/src/components/settings-menu.tsx
@@ -1,72 +1,87 @@
-import React from "react";
-import { Checkbox } from "./ui/checkbox";
-import { Label } from "./ui/label";
-
-import { Settings } from "@/settings";
-
-interface SettingsMenuProps {
- settings: Settings;
- onChange: (settings: Settings) => void;
- };
-
-export class SettingsMenu extends React.Component {
-
- constructor(props: SettingsMenuProps) {
- super(props);
- this.getSettings = this.getSettings.bind(this);
- this.state = props.settings;
- }
-
- getSettings() {
- return this.state;
- }
-
- updateSettings(settings: Settings) {
- this.setState(() => settings);
- }
-
- componentDidUpdate() {
- this.props.onChange(this.state);
- }
-
- render() {
- return (
-
-
-
Settings
-
- Set the settings for the emulation.
-
-
-
-
- {
- this.setState({ verbose: checked });
- }} />
-
-
-
-
- {
- this.setState({ concise: checked });
- }} />
-
-
-
-
- {
- this.setState({ silent: checked });
- }} />
-
-
-
-
- {
- this.setState({ bufferStdout: checked });
- }} />
-
-
-
- );
- }
-};
+import React from "react";
+import { Checkbox } from "./ui/checkbox";
+import { Label } from "./ui/label";
+
+import { Settings } from "@/settings";
+
+interface SettingsMenuProps {
+ settings: Settings;
+ onChange: (settings: Settings) => void;
+}
+
+export class SettingsMenu extends React.Component {
+ constructor(props: SettingsMenuProps) {
+ super(props);
+ this.getSettings = this.getSettings.bind(this);
+ this.state = props.settings;
+ }
+
+ getSettings() {
+ return this.state;
+ }
+
+ updateSettings(settings: Settings) {
+ this.setState(() => settings);
+ }
+
+ componentDidUpdate() {
+ this.props.onChange(this.state);
+ }
+
+ render() {
+ return (
+
+
+
Settings
+
+ Set the settings for the emulation.
+
+
+
+
+ {
+ this.setState({ verbose: checked });
+ }}
+ />
+
+
+
+
+ {
+ this.setState({ concise: checked });
+ }}
+ />
+
+
+
+
+ {
+ this.setState({ silent: checked });
+ }}
+ />
+
+
+
+
+ {
+ this.setState({ bufferStdout: checked });
+ }}
+ />
+
+
+
+ );
+ }
+}
diff --git a/page/src/components/status-indicator.tsx b/page/src/components/status-indicator.tsx
index c12b497d..4bd469b5 100644
--- a/page/src/components/status-indicator.tsx
+++ b/page/src/components/status-indicator.tsx
@@ -1,21 +1,28 @@
-import { Badge } from '@/components/ui/badge'
-import { CircleFill } from 'react-bootstrap-icons';
-
-export interface StatusIndicatorProps {
- running: boolean;
-};
-
-export function StatusIndicator(props: StatusIndicatorProps) {
-
- const getText = () => {
- return props.running ? " Running" : " Stopped";
- };
-
- const getColor = () => {
- return props.running ? "bg-lime-600" : "bg-orange-600";
- }
-
- return (
- {getText()}
- );
-}
\ No newline at end of file
+import { Badge } from "@/components/ui/badge";
+import { CircleFill } from "react-bootstrap-icons";
+
+export interface StatusIndicatorProps {
+ running: boolean;
+}
+
+export function StatusIndicator(props: StatusIndicatorProps) {
+ const getText = () => {
+ return props.running ? " Running" : " Stopped";
+ };
+
+ const getColor = () => {
+ return props.running ? "bg-lime-600" : "bg-orange-600";
+ };
+
+ return (
+
+
+ {getText()}
+
+ );
+}
diff --git a/page/src/components/theme-provider.tsx b/page/src/components/theme-provider.tsx
index 9d0f2dbc..e18440d7 100644
--- a/page/src/components/theme-provider.tsx
+++ b/page/src/components/theme-provider.tsx
@@ -1,73 +1,73 @@
-import { createContext, useContext, useEffect, useState } from "react"
-
-type Theme = "dark" | "light" | "system"
-
-type ThemeProviderProps = {
- children: React.ReactNode
- defaultTheme?: Theme
- storageKey?: string
-}
-
-type ThemeProviderState = {
- theme: Theme
- setTheme: (theme: Theme) => void
-}
-
-const initialState: ThemeProviderState = {
- theme: "system",
- setTheme: () => null,
-}
-
-const ThemeProviderContext = createContext(initialState)
-
-export function ThemeProvider({
- children,
- defaultTheme = "system",
- storageKey = "vite-ui-theme",
- ...props
-}: ThemeProviderProps) {
- const [theme, setTheme] = useState(
- () => (localStorage.getItem(storageKey) as Theme) || defaultTheme
- )
-
- useEffect(() => {
- const root = window.document.documentElement
-
- root.classList.remove("light", "dark")
-
- if (theme === "system") {
- const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
- .matches
- ? "dark"
- : "light"
-
- root.classList.add(systemTheme)
- return
- }
-
- root.classList.add(theme)
- }, [theme])
-
- const value = {
- theme,
- setTheme: (theme: Theme) => {
- localStorage.setItem(storageKey, theme)
- setTheme(theme)
- },
- }
-
- return (
-
- {children}
-
- )
-}
-
-export const useTheme = () => {
- const context = useContext(ThemeProviderContext)
-
- if (context === undefined)
- throw new Error("useTheme must be used within a ThemeProvider")
-
- return context
-}
+import { createContext, useContext, useEffect, useState } from "react";
+
+type Theme = "dark" | "light" | "system";
+
+type ThemeProviderProps = {
+ children: React.ReactNode;
+ defaultTheme?: Theme;
+ storageKey?: string;
+};
+
+type ThemeProviderState = {
+ theme: Theme;
+ setTheme: (theme: Theme) => void;
+};
+
+const initialState: ThemeProviderState = {
+ theme: "system",
+ setTheme: () => null,
+};
+
+const ThemeProviderContext = createContext(initialState);
+
+export function ThemeProvider({
+ children,
+ defaultTheme = "system",
+ storageKey = "vite-ui-theme",
+ ...props
+}: ThemeProviderProps) {
+ const [theme, setTheme] = useState(
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
+ );
+
+ useEffect(() => {
+ const root = window.document.documentElement;
+
+ root.classList.remove("light", "dark");
+
+ if (theme === "system") {
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
+ .matches
+ ? "dark"
+ : "light";
+
+ root.classList.add(systemTheme);
+ return;
+ }
+
+ root.classList.add(theme);
+ }, [theme]);
+
+ const value = {
+ theme,
+ setTheme: (theme: Theme) => {
+ localStorage.setItem(storageKey, theme);
+ setTheme(theme);
+ },
+ };
+
+ return (
+
+ {children}
+
+ );
+}
+
+export const useTheme = () => {
+ const context = useContext(ThemeProviderContext);
+
+ if (context === undefined)
+ throw new Error("useTheme must be used within a ThemeProvider");
+
+ return context;
+};
diff --git a/page/src/components/ui/badge.tsx b/page/src/components/ui/badge.tsx
index 02054139..46f988c2 100644
--- a/page/src/components/ui/badge.tsx
+++ b/page/src/components/ui/badge.tsx
@@ -1,8 +1,8 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const badgeVariants = cva(
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
@@ -22,8 +22,8 @@ const badgeVariants = cva(
defaultVariants: {
variant: "default",
},
- }
-)
+ },
+);
function Badge({
className,
@@ -32,7 +32,7 @@ function Badge({
...props
}: React.ComponentProps<"span"> &
VariantProps & { asChild?: boolean }) {
- const Comp = asChild ? Slot : "span"
+ const Comp = asChild ? Slot : "span";
return (
- )
+ );
}
-export { Badge, badgeVariants }
+export { Badge, badgeVariants };
diff --git a/page/src/components/ui/breadcrumb.tsx b/page/src/components/ui/breadcrumb.tsx
index eb88f321..f63ae19a 100644
--- a/page/src/components/ui/breadcrumb.tsx
+++ b/page/src/components/ui/breadcrumb.tsx
@@ -1,11 +1,11 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { ChevronRight, MoreHorizontal } from "lucide-react"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { ChevronRight, MoreHorizontal } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
- return
+ return ;
}
function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
@@ -14,11 +14,11 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
data-slot="breadcrumb-list"
className={cn(
"text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
@@ -28,7 +28,7 @@ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
className={cn("inline-flex items-center gap-1.5", className)}
{...props}
/>
- )
+ );
}
function BreadcrumbLink({
@@ -36,9 +36,9 @@ function BreadcrumbLink({
className,
...props
}: React.ComponentProps<"a"> & {
- asChild?: boolean
+ asChild?: boolean;
}) {
- const Comp = asChild ? Slot : "a"
+ const Comp = asChild ? Slot : "a";
return (
- )
+ );
}
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
@@ -59,7 +59,7 @@ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
className={cn("text-foreground font-normal", className)}
{...props}
/>
- )
+ );
}
function BreadcrumbSeparator({
@@ -77,7 +77,7 @@ function BreadcrumbSeparator({
>
{children ?? }
- )
+ );
}
function BreadcrumbEllipsis({
@@ -95,7 +95,7 @@ function BreadcrumbEllipsis({
More
- )
+ );
}
export {
@@ -106,4 +106,4 @@ export {
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
-}
+};
diff --git a/page/src/components/ui/button.tsx b/page/src/components/ui/button.tsx
index a2df8dce..2adaf00d 100644
--- a/page/src/components/ui/button.tsx
+++ b/page/src/components/ui/button.tsx
@@ -1,8 +1,8 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { cva, type VariantProps } from "class-variance-authority";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
@@ -32,8 +32,8 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
- }
-)
+ },
+);
function Button({
className,
@@ -43,9 +43,9 @@ function Button({
...props
}: React.ComponentProps<"button"> &
VariantProps & {
- asChild?: boolean
+ asChild?: boolean;
}) {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot : "button";
return (
- )
+ );
}
-export { Button, buttonVariants }
+export { Button, buttonVariants };
diff --git a/page/src/components/ui/card.tsx b/page/src/components/ui/card.tsx
index d05bbc6c..113d66c7 100644
--- a/page/src/components/ui/card.tsx
+++ b/page/src/components/ui/card.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Card({ className, ...props }: React.ComponentProps<"div">) {
return (
@@ -8,11 +8,11 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
@@ -21,11 +21,11 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
@@ -35,7 +35,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
className={cn("leading-none font-semibold", className)}
{...props}
/>
- )
+ );
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
@@ -45,7 +45,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
- )
+ );
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
@@ -54,11 +54,11 @@ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
data-slot="card-action"
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
@@ -68,7 +68,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
className={cn("px-6", className)}
{...props}
/>
- )
+ );
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
@@ -78,7 +78,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
{...props}
/>
- )
+ );
}
export {
@@ -89,4 +89,4 @@ export {
CardAction,
CardDescription,
CardContent,
-}
+};
diff --git a/page/src/components/ui/checkbox.tsx b/page/src/components/ui/checkbox.tsx
index defeb01f..29c5f2ed 100644
--- a/page/src/components/ui/checkbox.tsx
+++ b/page/src/components/ui/checkbox.tsx
@@ -1,8 +1,8 @@
-import * as React from "react"
-import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
-import { CheckIcon } from "lucide-react"
+import * as React from "react";
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
+import { CheckIcon } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Checkbox({
className,
@@ -13,7 +13,7 @@ function Checkbox({
data-slot="checkbox"
className={cn(
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -24,7 +24,7 @@ function Checkbox({
- )
+ );
}
-export { Checkbox }
+export { Checkbox };
diff --git a/page/src/components/ui/input.tsx b/page/src/components/ui/input.tsx
index 03295ca6..b1a060f5 100644
--- a/page/src/components/ui/input.tsx
+++ b/page/src/components/ui/input.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Input({ className, type, ...props }: React.ComponentProps<"input">) {
return (
@@ -11,11 +11,11 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
-export { Input }
+export { Input };
diff --git a/page/src/components/ui/label.tsx b/page/src/components/ui/label.tsx
index ef7133a7..4ef28a9b 100644
--- a/page/src/components/ui/label.tsx
+++ b/page/src/components/ui/label.tsx
@@ -1,7 +1,7 @@
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
+import * as React from "react";
+import * as LabelPrimitive from "@radix-ui/react-label";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Label({
className,
@@ -12,11 +12,11 @@ function Label({
data-slot="label"
className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
-export { Label }
+export { Label };
diff --git a/page/src/components/ui/popover.tsx b/page/src/components/ui/popover.tsx
index 6d51b6ce..ef5bfd04 100644
--- a/page/src/components/ui/popover.tsx
+++ b/page/src/components/ui/popover.tsx
@@ -1,18 +1,18 @@
-import * as React from "react"
-import * as PopoverPrimitive from "@radix-ui/react-popover"
+import * as React from "react";
+import * as PopoverPrimitive from "@radix-ui/react-popover";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Popover({
...props
}: React.ComponentProps) {
- return
+ return ;
}
function PopoverTrigger({
...props
}: React.ComponentProps) {
- return
+ return ;
}
function PopoverContent({
@@ -29,18 +29,18 @@ function PopoverContent({
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function PopoverAnchor({
...props
}: React.ComponentProps) {
- return
+ return ;
}
-export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
+export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
diff --git a/page/src/components/ui/scroll-area.tsx b/page/src/components/ui/scroll-area.tsx
index 9376f594..51ecedcd 100644
--- a/page/src/components/ui/scroll-area.tsx
+++ b/page/src/components/ui/scroll-area.tsx
@@ -1,7 +1,7 @@
-import * as React from "react"
-import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
+import * as React from "react";
+import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function ScrollArea({
className,
@@ -23,7 +23,7 @@ function ScrollArea({
- )
+ );
}
function ScrollBar({
@@ -41,7 +41,7 @@ function ScrollBar({
"h-full w-2.5 border-l border-l-transparent",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent",
- className
+ className,
)}
{...props}
>
@@ -50,7 +50,7 @@ function ScrollBar({
className="bg-border relative flex-1 rounded-full"
/>
- )
+ );
}
-export { ScrollArea, ScrollBar }
+export { ScrollArea, ScrollBar };
diff --git a/page/src/components/ui/separator.tsx b/page/src/components/ui/separator.tsx
index 67c73e5a..06d1380a 100644
--- a/page/src/components/ui/separator.tsx
+++ b/page/src/components/ui/separator.tsx
@@ -1,9 +1,9 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
+import * as React from "react";
+import * as SeparatorPrimitive from "@radix-ui/react-separator";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Separator({
className,
@@ -18,11 +18,11 @@ function Separator({
orientation={orientation}
className={cn(
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
-export { Separator }
+export { Separator };
diff --git a/page/src/components/ui/sheet.tsx b/page/src/components/ui/sheet.tsx
index 6906f5b2..609cff0e 100644
--- a/page/src/components/ui/sheet.tsx
+++ b/page/src/components/ui/sheet.tsx
@@ -1,29 +1,29 @@
-import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { XIcon } from "lucide-react"
+import * as React from "react";
+import * as SheetPrimitive from "@radix-ui/react-dialog";
+import { XIcon } from "lucide-react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Sheet({ ...props }: React.ComponentProps) {
- return
+ return ;
}
function SheetTrigger({
...props
}: React.ComponentProps) {
- return
+ return ;
}
function SheetClose({
...props
}: React.ComponentProps) {
- return
+ return ;
}
function SheetPortal({
...props
}: React.ComponentProps) {
- return
+ return ;
}
function SheetOverlay({
@@ -35,11 +35,11 @@ function SheetOverlay({
data-slot="sheet-overlay"
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
- className
+ className,
)}
{...props}
/>
- )
+ );
}
function SheetContent({
@@ -48,7 +48,7 @@ function SheetContent({
side = "right",
...props
}: React.ComponentProps & {
- side?: "top" | "right" | "bottom" | "left"
+ side?: "top" | "right" | "bottom" | "left";
}) {
return (
@@ -65,7 +65,7 @@ function SheetContent({
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
side === "bottom" &&
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
- className
+ className,
)}
{...props}
>
@@ -76,7 +76,7 @@ function SheetContent({
- )
+ );
}
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
@@ -86,7 +86,7 @@ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
className={cn("flex flex-col gap-1.5 p-4", className)}
{...props}
/>
- )
+ );
}
function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
@@ -96,7 +96,7 @@ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
- )
+ );
}
function SheetTitle({
@@ -109,7 +109,7 @@ function SheetTitle({
className={cn("text-foreground font-semibold", className)}
{...props}
/>
- )
+ );
}
function SheetDescription({
@@ -122,7 +122,7 @@ function SheetDescription({
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
- )
+ );
}
export {
@@ -134,4 +134,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
-}
+};
diff --git a/page/src/components/ui/sidebar.tsx b/page/src/components/ui/sidebar.tsx
index 22393149..ca2d372f 100644
--- a/page/src/components/ui/sidebar.tsx
+++ b/page/src/components/ui/sidebar.tsx
@@ -1,54 +1,54 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { VariantProps, cva } from "class-variance-authority"
-import { PanelLeftIcon } from "lucide-react"
+import * as React from "react";
+import { Slot } from "@radix-ui/react-slot";
+import { VariantProps, cva } from "class-variance-authority";
+import { PanelLeftIcon } from "lucide-react";
-import { useIsMobile } from "@/hooks/use-mobile"
-import { cn } from "@/lib/utils"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Separator } from "@/components/ui/separator"
+import { useIsMobile } from "@/hooks/use-mobile";
+import { cn } from "@/lib/utils";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Separator } from "@/components/ui/separator";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
-} from "@/components/ui/sheet"
-import { Skeleton } from "@/components/ui/skeleton"
+} from "@/components/ui/sheet";
+import { Skeleton } from "@/components/ui/skeleton";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
-} from "@/components/ui/tooltip"
+} from "@/components/ui/tooltip";
-const SIDEBAR_COOKIE_NAME = "sidebar_state"
-const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
-const SIDEBAR_WIDTH = "16rem"
-const SIDEBAR_WIDTH_MOBILE = "18rem"
-const SIDEBAR_WIDTH_ICON = "3rem"
-const SIDEBAR_KEYBOARD_SHORTCUT = "b"
+const SIDEBAR_COOKIE_NAME = "sidebar_state";
+const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
+const SIDEBAR_WIDTH = "16rem";
+const SIDEBAR_WIDTH_MOBILE = "18rem";
+const SIDEBAR_WIDTH_ICON = "3rem";
+const SIDEBAR_KEYBOARD_SHORTCUT = "b";
type SidebarContextProps = {
- state: "expanded" | "collapsed"
- open: boolean
- setOpen: (open: boolean) => void
- openMobile: boolean
- setOpenMobile: (open: boolean) => void
- isMobile: boolean
- toggleSidebar: () => void
-}
+ state: "expanded" | "collapsed";
+ open: boolean;
+ setOpen: (open: boolean) => void;
+ openMobile: boolean;
+ setOpenMobile: (open: boolean) => void;
+ isMobile: boolean;
+ toggleSidebar: () => void;
+};
-const SidebarContext = React.createContext(null)
+const SidebarContext = React.createContext(null);
function useSidebar() {
- const context = React.useContext(SidebarContext)
+ const context = React.useContext(SidebarContext);
if (!context) {
- throw new Error("useSidebar must be used within a SidebarProvider.")
+ throw new Error("useSidebar must be used within a SidebarProvider.");
}
- return context
+ return context;
}
function SidebarProvider({
@@ -60,36 +60,36 @@ function SidebarProvider({
children,
...props
}: React.ComponentProps<"div"> & {
- defaultOpen?: boolean
- open?: boolean
- onOpenChange?: (open: boolean) => void
+ defaultOpen?: boolean;
+ open?: boolean;
+ onOpenChange?: (open: boolean) => void;
}) {
- const isMobile = useIsMobile()
- const [openMobile, setOpenMobile] = React.useState(false)
+ const isMobile = useIsMobile();
+ const [openMobile, setOpenMobile] = React.useState(false);
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
- const [_open, _setOpen] = React.useState(defaultOpen)
- const open = openProp ?? _open
+ const [_open, _setOpen] = React.useState(defaultOpen);
+ const open = openProp ?? _open;
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
- const openState = typeof value === "function" ? value(open) : value
+ const openState = typeof value === "function" ? value(open) : value;
if (setOpenProp) {
- setOpenProp(openState)
+ setOpenProp(openState);
} else {
- _setOpen(openState)
+ _setOpen(openState);
}
// This sets the cookie to keep the sidebar state.
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
},
- [setOpenProp, open]
- )
+ [setOpenProp, open],
+ );
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
- return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open)
- }, [isMobile, setOpen, setOpenMobile])
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
+ }, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
@@ -98,18 +98,18 @@ function SidebarProvider({
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
(event.metaKey || event.ctrlKey)
) {
- event.preventDefault()
- toggleSidebar()
+ event.preventDefault();
+ toggleSidebar();
}
- }
+ };
- window.addEventListener("keydown", handleKeyDown)
- return () => window.removeEventListener("keydown", handleKeyDown)
- }, [toggleSidebar])
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [toggleSidebar]);
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
- const state = open ? "expanded" : "collapsed"
+ const state = open ? "expanded" : "collapsed";
const contextValue = React.useMemo(
() => ({
@@ -121,8 +121,8 @@ function SidebarProvider({
setOpenMobile,
toggleSidebar,
}),
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
- )
+ [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar],
+ );
return (
@@ -138,7 +138,7 @@ function SidebarProvider({
}
className={cn(
"group/sidebar-wrapper has-data-[variant=inset]:bg-sidebar flex min-h-svh w-full",
- className
+ className,
)}
{...props}
>
@@ -146,7 +146,7 @@ function SidebarProvider({
- )
+ );
}
function Sidebar({
@@ -157,11 +157,11 @@ function Sidebar({
children,
...props
}: React.ComponentProps<"div"> & {
- side?: "left" | "right"
- variant?: "sidebar" | "floating" | "inset"
- collapsible?: "offcanvas" | "icon" | "none"
+ side?: "left" | "right";
+ variant?: "sidebar" | "floating" | "inset";
+ collapsible?: "offcanvas" | "icon" | "none";
}) {
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
if (collapsible === "none") {
return (
@@ -169,13 +169,13 @@ function Sidebar({
data-slot="sidebar"
className={cn(
"bg-sidebar text-sidebar-foreground flex h-full w-(--sidebar-width) flex-col",
- className
+ className,
)}
{...props}
>
{children}
- )
+ );
}
if (isMobile) {
@@ -200,7 +200,7 @@ function Sidebar({
{children}
- )
+ );
}
return (
@@ -221,7 +221,7 @@ function Sidebar({
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+(--spacing(4)))]"
- : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)"
+ : "group-data-[collapsible=icon]:w-(--sidebar-width-icon)",
)}
/>
@@ -248,7 +248,7 @@ function Sidebar({
- )
+ );
}
function SidebarTrigger({
@@ -256,7 +256,7 @@ function SidebarTrigger({
onClick,
...props
}: React.ComponentProps) {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar();
return (
- )
+ );
}
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar();
return (