Clan-app: dynamic router concept
This commit is contained in:
9
pkgs/webview-ui/app/package-lock.json
generated
9
pkgs/webview-ui/app/package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"@floating-ui/dom": "^1.6.8",
|
||||
"@modular-forms/solid": "^0.21.0",
|
||||
"@solid-primitives/storage": "^3.7.1",
|
||||
"@solidjs/router": "^0.14.2",
|
||||
"@tanstack/eslint-plugin-query": "^5.51.12",
|
||||
"@tanstack/solid-query": "^5.51.2",
|
||||
"material-icons": "^1.13.12",
|
||||
@@ -1551,6 +1552,14 @@
|
||||
"solid-js": "^1.6.12"
|
||||
}
|
||||
},
|
||||
"node_modules/@solidjs/router": {
|
||||
"version": "0.14.2",
|
||||
"resolved": "https://registry.npmjs.org/@solidjs/router/-/router-0.14.2.tgz",
|
||||
"integrity": "sha512-JaJe7XJcZTyOfMOIVHmLO+3wP3akm5QQesrDU4XLn/JRMxozBzCaNXBsK7F8pBuDgxzRRxTV8RvXeS09HGXv6Q==",
|
||||
"peerDependencies": {
|
||||
"solid-js": "^1.8.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@tailwindcss/typography": {
|
||||
"version": "0.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.13.tgz",
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"@floating-ui/dom": "^1.6.8",
|
||||
"@modular-forms/solid": "^0.21.0",
|
||||
"@solid-primitives/storage": "^3.7.1",
|
||||
"@solidjs/router": "^0.14.2",
|
||||
"@tanstack/eslint-plugin-query": "^5.51.12",
|
||||
"@tanstack/solid-query": "^5.51.2",
|
||||
"material-icons": "^1.13.12",
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import { type Component, createEffect, createSignal } from "solid-js";
|
||||
import { Layout } from "./layout/layout";
|
||||
import { Route, Router } from "./Routes";
|
||||
import { Toaster } from "solid-toast";
|
||||
import { effect } from "solid-js/web";
|
||||
import { createSignal } from "solid-js";
|
||||
import { makePersisted } from "@solid-primitives/storage";
|
||||
|
||||
// Some global state
|
||||
const [route, setRoute] = createSignal<Route>("machines");
|
||||
|
||||
export { route, setRoute };
|
||||
|
||||
const [activeURI, setActiveURI] = makePersisted(
|
||||
createSignal<string | null>(null),
|
||||
{
|
||||
@@ -26,21 +17,3 @@ const [clanList, setClanList] = makePersisted(createSignal<string[]>([]), {
|
||||
});
|
||||
|
||||
export { clanList, setClanList };
|
||||
|
||||
const App: Component = () => {
|
||||
effect(() => {
|
||||
if (clanList().length === 0) {
|
||||
setRoute("welcome");
|
||||
}
|
||||
});
|
||||
return (
|
||||
<div class="h-screen bg-gradient-to-b from-white to-base-100 p-4">
|
||||
<Toaster position="top-right" />
|
||||
<Layout>
|
||||
<Router route={route} />
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import { Accessor, For, Match, Switch } from "solid-js";
|
||||
import { MachineListView } from "./routes/machines/view";
|
||||
import { colors } from "./routes/colors/view";
|
||||
import { CreateClan } from "./routes/clan/view";
|
||||
import { HostList } from "./routes/hosts/view";
|
||||
import { BlockDevicesView } from "./routes/blockdevices/view";
|
||||
import { Flash } from "./routes/flash/view";
|
||||
import { Settings } from "./routes/settings";
|
||||
import { Welcome } from "./routes/welcome";
|
||||
import { Deploy } from "./routes/deploy";
|
||||
import { CreateMachine } from "./routes/machines/create";
|
||||
import { DiskView } from "./routes/disk/view";
|
||||
|
||||
export type Route = keyof typeof routes;
|
||||
|
||||
export const routes = {
|
||||
createClan: {
|
||||
child: CreateClan,
|
||||
label: "Create Clan",
|
||||
icon: "groups",
|
||||
},
|
||||
machines: {
|
||||
child: MachineListView,
|
||||
label: "Machines",
|
||||
icon: "devices_other",
|
||||
},
|
||||
"machines/add": {
|
||||
child: CreateMachine,
|
||||
label: "create Machine",
|
||||
icon: "add",
|
||||
},
|
||||
hosts: {
|
||||
child: HostList,
|
||||
label: "hosts",
|
||||
icon: "devices_other",
|
||||
},
|
||||
flash: {
|
||||
child: Flash,
|
||||
label: "create_flash_installer",
|
||||
icon: "devices_other",
|
||||
},
|
||||
blockdevices: {
|
||||
child: BlockDevicesView,
|
||||
label: "blockdevices",
|
||||
icon: "devices_other",
|
||||
},
|
||||
colors: {
|
||||
child: colors,
|
||||
label: "Colors",
|
||||
icon: "color_lens",
|
||||
},
|
||||
settings: {
|
||||
child: Settings,
|
||||
label: "Settings",
|
||||
icon: "settings",
|
||||
},
|
||||
welcome: {
|
||||
child: Welcome,
|
||||
label: "welcome",
|
||||
icon: "settings",
|
||||
},
|
||||
deploy: {
|
||||
child: Deploy,
|
||||
label: "deploy",
|
||||
icon: "content_copy",
|
||||
},
|
||||
diskConfig: {
|
||||
child: DiskView,
|
||||
label: "diskConfig",
|
||||
icon: "disk",
|
||||
},
|
||||
"machines/edit": {
|
||||
child: CreateMachine,
|
||||
label: "Edit Machine",
|
||||
icon: "edit",
|
||||
},
|
||||
};
|
||||
|
||||
interface RouterProps {
|
||||
route: Accessor<Route>;
|
||||
}
|
||||
export const Router = (props: RouterProps) => {
|
||||
const { route } = props;
|
||||
return (
|
||||
<Switch fallback={<p>route {route()} not found</p>}>
|
||||
<For each={Object.entries(routes)}>
|
||||
{([key, { child }]) => <Match when={route() === key}>{child}</Match>}
|
||||
</For>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
@@ -1,14 +1,11 @@
|
||||
import { Accessor, For, Setter } from "solid-js";
|
||||
import { Route, routes } from "./Routes";
|
||||
import { For, Show } from "solid-js";
|
||||
import { activeURI } from "./App";
|
||||
import { createQuery } from "@tanstack/solid-query";
|
||||
import { callApi } from "./api";
|
||||
import { A, RouteSectionProps } from "@solidjs/router";
|
||||
import { AppRoute, routes } from "./index";
|
||||
|
||||
interface SidebarProps {
|
||||
route: Accessor<Route>;
|
||||
setRoute: Setter<Route>;
|
||||
}
|
||||
export const Sidebar = (props: SidebarProps) => {
|
||||
export const Sidebar = (props: RouteSectionProps) => {
|
||||
const query = createQuery(() => ({
|
||||
queryKey: [activeURI(), "meta"],
|
||||
queryFn: async () => {
|
||||
@@ -20,29 +17,57 @@ export const Sidebar = (props: SidebarProps) => {
|
||||
}
|
||||
},
|
||||
}));
|
||||
const { route, setRoute } = props;
|
||||
|
||||
return (
|
||||
<aside class="w-80 rounded-xl border border-slate-900 bg-slate-800 pb-10">
|
||||
<div class="m-4 flex flex-col text-center capitalize text-white">
|
||||
<span class="text-lg">{query.data?.name}</span>
|
||||
<span class="text-sm">{query.data?.description}</span>
|
||||
<RouteMenu class="menu px-4 py-2" routes={routes} />
|
||||
</div>
|
||||
<ul class="menu px-4 py-0">
|
||||
<For each={Object.entries(routes)}>
|
||||
{([key, { label, icon }]) => (
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
const RouteMenu = (props: {
|
||||
class?: string;
|
||||
routes: AppRoute[];
|
||||
prefix?: string;
|
||||
}) => (
|
||||
<ul class={props?.class}>
|
||||
<For each={props.routes.filter((r) => !r.hidden)}>
|
||||
{(route) => (
|
||||
<li>
|
||||
<button
|
||||
onClick={() => setRoute(key as Route)}
|
||||
class="group text-white"
|
||||
classList={{ "!bg-primary !text-white": route() === key }}
|
||||
>
|
||||
<span class="material-icons">{icon}</span>
|
||||
{label}
|
||||
<Show
|
||||
when={route.children}
|
||||
fallback={
|
||||
<A href={[props.prefix, route.path].filter(Boolean).join("")}>
|
||||
<button class="text-white">
|
||||
{route.icon && (
|
||||
<span class="material-icons">{route.icon}</span>
|
||||
)}
|
||||
{route.label}
|
||||
</button>
|
||||
</A>
|
||||
}
|
||||
>
|
||||
{(children) => (
|
||||
<details id={`disclosure-${route.label}`} open={true}>
|
||||
<summary class="group">
|
||||
{route.icon && (
|
||||
<span class="material-icons">{route.icon}</span>
|
||||
)}
|
||||
{route.label}
|
||||
</summary>
|
||||
<RouteMenu
|
||||
routes={children()}
|
||||
prefix={[props.prefix, route.path].filter(Boolean).join("")}
|
||||
/>
|
||||
</details>
|
||||
)}
|
||||
</Show>
|
||||
</li>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
</aside>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Accessor, createSignal, Show } from "solid-js";
|
||||
import { createSignal, Show } from "solid-js";
|
||||
import { callApi, SuccessData } from "../api";
|
||||
import { Menu } from "./Menu";
|
||||
import { activeURI, setRoute } from "../App";
|
||||
import { activeURI } from "../App";
|
||||
import toast from "solid-toast";
|
||||
|
||||
type MachineDetails = SuccessData<"list_inventory_machines">["data"][string];
|
||||
@@ -63,9 +63,9 @@ export const MachineListItem = (props: MachineListItemProps) => {
|
||||
<ul class="menu z-[1] w-52 rounded-box bg-base-100 p-2 shadow">
|
||||
<li>
|
||||
<a
|
||||
onClick={() => {
|
||||
setRoute("machines/edit");
|
||||
}}
|
||||
// onClick={() => {
|
||||
// setRoute("machines/edit");
|
||||
// }}
|
||||
>
|
||||
Edit
|
||||
</a>
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
/* @refresh reload */
|
||||
import { render } from "solid-js/web";
|
||||
import { RouteDefinition, Router } from "@solidjs/router";
|
||||
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/solid-query";
|
||||
import { MachineDetails } from "./routes/machines/[name]/view";
|
||||
import { Layout } from "./layout/layout";
|
||||
import { MachineListView } from "./routes/machines/view";
|
||||
import { CreateClan } from "./routes/clan/view";
|
||||
import { Settings } from "./routes/settings";
|
||||
import { EditClanForm } from "./routes/clan/editClan";
|
||||
import { Flash } from "./routes/flash/view";
|
||||
import { CreateMachine } from "./routes/machines/create";
|
||||
import { HostList } from "./routes/hosts/view";
|
||||
import { Welcome } from "./routes/welcome";
|
||||
|
||||
const client = new QueryClient();
|
||||
|
||||
@@ -23,10 +33,88 @@ if (import.meta.env.DEV) {
|
||||
await import("solid-devtools");
|
||||
}
|
||||
|
||||
export type AppRoute = Omit<RouteDefinition, "children"> & {
|
||||
label: string;
|
||||
icon?: string;
|
||||
children?: AppRoute[];
|
||||
hidden?: boolean;
|
||||
};
|
||||
|
||||
export const routes: AppRoute[] = [
|
||||
{
|
||||
path: "/machines",
|
||||
label: "Machines",
|
||||
icon: "devices_other",
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
label: "Overview",
|
||||
component: () => <MachineListView />,
|
||||
},
|
||||
{
|
||||
path: "/create",
|
||||
label: "Create",
|
||||
component: () => <CreateMachine />,
|
||||
},
|
||||
{
|
||||
path: "/:id",
|
||||
label: "Details",
|
||||
hidden: true,
|
||||
component: () => <MachineDetails />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/clan",
|
||||
label: "Clans",
|
||||
icon: "groups",
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
label: "Overview",
|
||||
component: () => <Settings />,
|
||||
},
|
||||
{
|
||||
path: "/create",
|
||||
label: "Create",
|
||||
component: () => <CreateClan />,
|
||||
},
|
||||
{
|
||||
path: "/:id",
|
||||
label: "Details",
|
||||
hidden: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/tools",
|
||||
label: "Tools",
|
||||
icon: "bolt",
|
||||
children: [
|
||||
{
|
||||
path: "/flash",
|
||||
label: "Clan Installer",
|
||||
component: () => <Flash />,
|
||||
},
|
||||
{
|
||||
path: "/hosts",
|
||||
label: "Local Hosts",
|
||||
component: () => <HostList />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/welcome",
|
||||
label: "",
|
||||
hidden: true,
|
||||
component: () => <Welcome />,
|
||||
},
|
||||
];
|
||||
|
||||
render(
|
||||
() => (
|
||||
<QueryClientProvider client={client}>
|
||||
<App />
|
||||
<Router root={Layout}>{routes}</Router>
|
||||
</QueryClientProvider>
|
||||
),
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createQuery } from "@tanstack/solid-query";
|
||||
import { activeURI, setRoute } from "../App";
|
||||
import { activeURI } from "../App";
|
||||
import { callApi } from "../api";
|
||||
import { Accessor, Show } from "solid-js";
|
||||
|
||||
@@ -63,7 +63,7 @@ export const Header = (props: HeaderProps) => {
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<span class="tooltip tooltip-bottom" data-tip="Settings">
|
||||
<button class="link" onClick={() => setRoute("settings")}>
|
||||
<button class="link">
|
||||
<span class="material-icons">settings</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { Component, JSXElement, Show } from "solid-js";
|
||||
import { Component, createEffect, Show } from "solid-js";
|
||||
import { Header } from "./header";
|
||||
import { Sidebar } from "../Sidebar";
|
||||
import { activeURI, clanList, route, setRoute } from "../App";
|
||||
import { activeURI, clanList } from "../App";
|
||||
import { RouteSectionProps } from "@solidjs/router";
|
||||
|
||||
interface LayoutProps {
|
||||
children: JSXElement;
|
||||
}
|
||||
|
||||
export const Layout: Component<LayoutProps> = (props) => {
|
||||
export const Layout: Component<RouteSectionProps> = (props) => {
|
||||
return (
|
||||
<>
|
||||
<div class="h-screen bg-gradient-to-b from-white to-base-100 p-4">
|
||||
<div class="drawer lg:drawer-open ">
|
||||
<input
|
||||
id="toplevel-drawer"
|
||||
@@ -17,7 +14,7 @@ export const Layout: Component<LayoutProps> = (props) => {
|
||||
class="drawer-toggle hidden"
|
||||
/>
|
||||
<div class="drawer-content">
|
||||
<Show when={route() !== "welcome"}>
|
||||
<Show when={props.location.pathname !== "welcome"}>
|
||||
<Header clan_dir={activeURI} />
|
||||
</Show>
|
||||
{props.children}
|
||||
@@ -25,7 +22,8 @@ export const Layout: Component<LayoutProps> = (props) => {
|
||||
<div
|
||||
class="drawer-side z-40 h-full"
|
||||
classList={{
|
||||
"!hidden": route() === "welcome" || clanList().length === 0,
|
||||
"!hidden":
|
||||
props.location.pathname === "welcome" || clanList().length === 0,
|
||||
}}
|
||||
>
|
||||
<label
|
||||
@@ -33,9 +31,9 @@ export const Layout: Component<LayoutProps> = (props) => {
|
||||
aria-label="close sidebar"
|
||||
class="drawer-overlay"
|
||||
></label>
|
||||
<Sidebar route={route} setRoute={setRoute} />
|
||||
<Sidebar {...props} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { callApi, OperationResponse, pyApi } from "@/src/api";
|
||||
import { callApi, OperationResponse } from "@/src/api";
|
||||
import { Show } from "solid-js";
|
||||
import {
|
||||
createForm,
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
SubmitHandler,
|
||||
} from "@modular-forms/solid";
|
||||
import toast from "solid-toast";
|
||||
import { setActiveURI, setRoute } from "@/src/App";
|
||||
import { setActiveURI } from "@/src/App";
|
||||
|
||||
type CreateForm = Meta & {
|
||||
template_url: string;
|
||||
@@ -53,7 +53,7 @@ export const ClanForm = () => {
|
||||
},
|
||||
});
|
||||
setActiveURI(target_dir[0]);
|
||||
setRoute("machines");
|
||||
// setRoute("machines");
|
||||
})(),
|
||||
{
|
||||
loading: "Creating clan...",
|
||||
|
||||
@@ -2,7 +2,6 @@ import { callApi } from "@/src/api";
|
||||
import { activeURI } from "@/src/App";
|
||||
import { createQuery } from "@tanstack/solid-query";
|
||||
import { createEffect } from "solid-js";
|
||||
import toast from "solid-toast";
|
||||
|
||||
export function DiskView() {
|
||||
const query = createQuery(() => ({
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
type Component,
|
||||
createEffect,
|
||||
createSignal,
|
||||
For,
|
||||
Show,
|
||||
} from "solid-js";
|
||||
import { route } from "@/src/App";
|
||||
import { type Component, createSignal, For, Show } from "solid-js";
|
||||
import { OperationResponse, pyApi } from "@/src/api";
|
||||
|
||||
type ServiceModel = Extract<
|
||||
@@ -16,16 +9,6 @@ type ServiceModel = Extract<
|
||||
export const HostList: Component = () => {
|
||||
const [services, setServices] = createSignal<ServiceModel>();
|
||||
|
||||
// pyApi.show_mdns.receive((r) => {
|
||||
// const { status } = r;
|
||||
// if (status === "error") return console.error(r.errors);
|
||||
// setServices(r.data.services);
|
||||
// });
|
||||
|
||||
// createEffect(() => {
|
||||
// if (route() === "hosts") pyApi.show_mdns.dispatch({});
|
||||
// });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div class="tooltip tooltip-bottom" data-tip="Refresh install targets">
|
||||
|
||||
6
pkgs/webview-ui/app/src/routes/machines/[name]/view.tsx
Normal file
6
pkgs/webview-ui/app/src/routes/machines/[name]/view.tsx
Normal file
@@ -0,0 +1,6 @@
|
||||
import { useParams } from "@solidjs/router";
|
||||
|
||||
export const MachineDetails = () => {
|
||||
const params = useParams();
|
||||
return <div>Machine Details: {params.id}</div>;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { callApi, OperationArgs, pyApi, OperationResponse } from "@/src/api";
|
||||
import { activeURI, setRoute } from "@/src/App";
|
||||
import { callApi, OperationArgs } from "@/src/api";
|
||||
import { activeURI } from "@/src/App";
|
||||
import { TextInput } from "@/src/components/TextInput";
|
||||
import { createForm, required, reset } from "@modular-forms/solid";
|
||||
import { createQuery, useQueryClient } from "@tanstack/solid-query";
|
||||
@@ -49,7 +49,7 @@ export function CreateMachine() {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [activeURI(), "list_machines"],
|
||||
});
|
||||
setRoute("machines");
|
||||
// setRoute("machines");
|
||||
} else {
|
||||
toast.error(
|
||||
`Error: ${response.errors[0].message}. Machine ${values.machine.name} could not be created`,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { type Component, createEffect, For, Match, Switch } from "solid-js";
|
||||
import { activeURI, setRoute } from "@/src/App";
|
||||
import { type Component, For, Match, Switch } from "solid-js";
|
||||
import { activeURI } from "@/src/App";
|
||||
import { callApi, OperationResponse } from "@/src/api";
|
||||
import toast from "solid-toast";
|
||||
import { MachineListItem } from "@/src/components/MachineListItem";
|
||||
@@ -83,7 +83,10 @@ export const MachineListView: Component = () => {
|
||||
</button>
|
||||
</div>
|
||||
<div class="tooltip tooltip-bottom" data-tip="Create machine">
|
||||
<button class="btn btn-ghost" onClick={() => setRoute("machines/add")}>
|
||||
<button
|
||||
class="btn btn-ghost"
|
||||
// onClick={() => setRoute("machines/add")}
|
||||
>
|
||||
<span class="material-icons ">add</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
import { callApi } from "@/src/api";
|
||||
import {
|
||||
activeURI,
|
||||
clanList,
|
||||
setActiveURI,
|
||||
setClanList,
|
||||
setRoute,
|
||||
} from "@/src/App";
|
||||
import { activeURI, clanList, setActiveURI, setClanList } from "@/src/App";
|
||||
import { createSignal, For, Match, Setter, Show, Switch } from "solid-js";
|
||||
import { createQuery } from "@tanstack/solid-query";
|
||||
import { useFloating } from "@/src/floating";
|
||||
@@ -17,7 +11,6 @@ export const registerClan = async () => {
|
||||
const loc = await callApi("open_file", {
|
||||
file_request: { mode: "select_folder" },
|
||||
});
|
||||
console.log({ loc }, loc.status);
|
||||
if (loc.status === "success" && loc.data) {
|
||||
const data = loc.data[0];
|
||||
setClanList((s) => {
|
||||
@@ -25,10 +18,10 @@ export const registerClan = async () => {
|
||||
return Array.from(res);
|
||||
});
|
||||
setActiveURI(data);
|
||||
setRoute((r) => {
|
||||
if (r === "welcome") return "machines";
|
||||
return r;
|
||||
});
|
||||
// setRoute((r) => {
|
||||
// if (r === "welcome") return "machines";
|
||||
// return r;
|
||||
// });
|
||||
return data;
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { setActiveURI, setRoute } from "@/src/App";
|
||||
import { setActiveURI } from "@/src/App";
|
||||
import { registerClan } from "../settings";
|
||||
|
||||
export const Welcome = () => {
|
||||
@@ -11,7 +11,7 @@ export const Welcome = () => {
|
||||
<div class="flex flex-col items-start gap-2">
|
||||
<button
|
||||
class="btn btn-primary w-full"
|
||||
onClick={() => setRoute("createClan")}
|
||||
// onClick={() => setRoute("createClan")}
|
||||
>
|
||||
Build your own
|
||||
</button>
|
||||
@@ -27,7 +27,7 @@ export const Welcome = () => {
|
||||
<button
|
||||
class="link w-full text-right text-secondary"
|
||||
onClick={async () => {
|
||||
setRoute("machines");
|
||||
// setRoute("machines");
|
||||
}}
|
||||
>
|
||||
Skip (Debug)
|
||||
|
||||
Reference in New Issue
Block a user