add webview threaded api

This commit is contained in:
Johannes Kirschbauer
2024-05-15 14:27:18 +02:00
committed by hsjobeki
parent 3b3426d219
commit 484247de6d
27 changed files with 359 additions and 80 deletions

View File

@@ -0,0 +1,36 @@
import { Match, Switch, createSignal, type Component } from "solid-js";
import { CountProvider } from "./Config";
import { Nested } from "./nested";
type Route = "home" | "graph";
const App: Component = () => {
const [route, setRoute] = createSignal<Route>("home");
return (
<CountProvider>
<div class="w-full flex items-center flex-col gap-2 my-2">
<div>Clan</div>
<p>Current route: {route()}</p>
<div class="flex items-center">
<button
onClick={() => setRoute((o) => (o === "graph" ? "home" : "graph"))}
class="btn btn-link"
>
Navigate to {route() === "home" ? "graph" : "home"}
</button>
</div>
<Switch fallback={<p>{route()} not found</p>}>
<Match when={route() == "home"}>
<Nested />
</Match>
<Match when={route() == "graph"}>
<p></p>
</Match>
</Switch>
</div>
</CountProvider>
);
};
export default App;

View File

@@ -0,0 +1,42 @@
import { createSignal, createContext, useContext, JSXElement } from "solid-js";
import { PYAPI } from "./message";
export const makeCountContext = () => {
const [machines, setMachines] = createSignal<string[]>([]);
const [loading, setLoading] = createSignal(false);
PYAPI.list_machines.receive((machines) => {
setLoading(false);
setMachines(machines);
});
return [
{ loading, machines },
{
getMachines: () => {
// When the gtk function sends its data the loading state will be set to false
setLoading(true);
PYAPI.list_machines.dispatch(null);
},
},
] as const;
// `as const` forces tuple type inference
};
type CountContextType = ReturnType<typeof makeCountContext>;
export const CountContext = createContext<CountContextType>([
{ loading: () => false, machines: () => [] },
{
getMachines: () => {},
},
]);
export const useCountContext = () => useContext(CountContext);
export function CountProvider(props: { children: JSXElement }) {
return (
<CountContext.Provider value={makeCountContext()}>
{props.children}
</CountContext.Provider>
);
}

View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1,18 @@
/* @refresh reload */
import { render } from "solid-js/web";
import "./index.css";
import App from "./App";
const root = document.getElementById("app");
// @ts-ignore: add the clan scope to the window object so we can register callbacks for gtk
window.clan = window.clan || {};
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
throw new Error(
"Root element not found. Did you forget to add it to your index.html? Or maybe the id attribute got misspelled?"
);
}
render(() => <App />, root!);

View File

@@ -0,0 +1,22 @@
const deserialize = (fn: Function) => (str: string) => {
try {
fn(JSON.parse(str));
} catch (e) {
alert(`Error parsing JSON: ${e}`);
}
};
export const PYAPI = {
list_machines: {
dispatch: (data: null) =>
// @ts-ignore
window.webkit.messageHandlers.gtk.postMessage({
method: "list_machines",
data,
}),
receive: (fn: (response: string[]) => void) => {
// @ts-ignore
window.clan.list_machines = deserialize(fn);
},
},
};

View File

@@ -0,0 +1,29 @@
import { For, Match, Switch, type Component } from "solid-js";
import { useCountContext } from "./Config";
export const Nested: Component = () => {
const [{ machines, loading }, { getMachines }] = useCountContext();
return (
<div>
<button onClick={() => getMachines()} class="btn btn-primary">
Get machines
</button>
<hr />
<Switch>
<Match when={loading()}>Loading...</Match>
<Match when={!loading() && machines().length === 0}>
No machines found
</Match>
<Match when={!loading() && machines().length}>
<For each={machines()}>
{(machine, i) => (
<li>
{i() + 1}: {machine}
</li>
)}
</For>
</Match>
</Switch>
</div>
);
};