wip: refactor

This commit is contained in:
reya 2024-02-17 16:01:53 +07:00
parent f47eba5af7
commit 0f06522c28
18 changed files with 168 additions and 525 deletions

View File

@ -1,5 +1,6 @@
import { ArkProvider } from "@lume/ark";
import { StorageProvider } from "@lume/storage";
import { useArk } from "@lume/ark";
import { ArkProvider } from "./ark";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { RouterProvider, createRouter } from "@tanstack/react-router";
import React, { StrictMode } from "react";
@ -12,34 +13,50 @@ import i18n from "./locale";
import { routeTree } from "./router.gen";
const queryClient = new QueryClient();
// Set up a Router instance
const router = createRouter({
routeTree,
context: {
queryClient,
},
routeTree,
context: {
ark: undefined!,
queryClient,
},
});
// Register things for typesafety
declare module "@tanstack/react-router" {
interface Register {
router: typeof router;
}
interface Register {
router: typeof router;
}
}
// biome-ignore lint/style/noNonNullAssertion: <explanation>
const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<I18nextProvider i18n={i18n} defaultNS={"translation"}>
<QueryClientProvider client={queryClient}>
<StorageProvider>
<ArkProvider>
<StrictMode>
<RouterProvider router={router} />
</StrictMode>
</ArkProvider>
</StorageProvider>
</QueryClientProvider>
</I18nextProvider>,
);
function InnerApp() {
const ark = useArk();
return <RouterProvider router={router} context={{ ark }} />;
}
function App() {
return (
<ArkProvider>
<InnerApp />
</ArkProvider>
);
}
// biome-ignore lint/style/noNonNullAssertion: idk
const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<I18nextProvider i18n={i18n} defaultNS={"translation"}>
<QueryClientProvider client={queryClient}>
<StorageProvider>
<StrictMode>
<App />
</StrictMode>
</StorageProvider>
</QueryClientProvider>
</I18nextProvider>,
);
}

View File

@ -0,0 +1,7 @@
import { Ark, ArkContext } from "@lume/ark";
import { PropsWithChildren, useMemo } from "react";
export const ArkProvider = ({ children }: PropsWithChildren<object>) => {
const ark = useMemo(() => new Ark(), []);
return <ArkContext.Provider value={ark}>{children}</ArkContext.Provider>;
};

View File

@ -1,25 +1,32 @@
import { LoaderIcon } from "@lume/icons";
import {
Outlet,
ScrollRestoration,
createRootRoute,
Outlet,
ScrollRestoration,
createRootRouteWithContext,
} from "@tanstack/react-router";
import { type Ark } from "@lume/ark";
import { type QueryClient } from "@tanstack/react-query";
export const Route = createRootRoute({
component: () => (
<>
<ScrollRestoration />
<Outlet />
</>
),
pendingComponent: Pending,
wrapInSuspense: true,
interface RouterContext {
ark: Ark;
queryClient: QueryClient;
}
export const Route = createRootRouteWithContext<RouterContext>()({
component: () => (
<>
<ScrollRestoration />
<Outlet />
</>
),
pendingComponent: Pending,
wrapInSuspense: true,
});
function Pending() {
return (
<div className="flex flex-col items-center justify-center w-screen h-screen">
<LoaderIcon className="size-5 animate-spin" />
</div>
);
return (
<div className="flex h-screen w-screen flex-col items-center justify-center">
<LoaderIcon className="size-5 animate-spin" />
</div>
);
}

View File

@ -1,19 +1,19 @@
import { createFileRoute, redirect } from "@tanstack/react-router";
import { invoke } from "@tauri-apps/api/core";
export const Route = createFileRoute("/")({
beforeLoad: async ({ location }) => {
const signer = await invoke("verify_signer");
if (!signer) {
throw redirect({
to: "/landing",
search: {
redirect: location.href,
},
});
}
throw redirect({
to: "/app/space",
});
},
beforeLoad: async ({ location, context }) => {
const ark = context.ark;
const signer = await ark.verify_signer();
if (!signer) {
throw redirect({
to: "/landing",
search: {
redirect: location.href,
},
});
}
throw redirect({
to: "/app/space",
});
},
});

View File

@ -3,57 +3,57 @@ import { Link, createFileRoute } from "@tanstack/react-router";
import { useTranslation } from "react-i18next";
export const Route = createFileRoute("/landing/")({
component: Screen,
component: Screen,
});
function Screen() {
const storage = useStorage();
const { t } = useTranslation();
const storage = useStorage();
const { t } = useTranslation();
return (
<div className="flex w-screen h-screen bg-black">
<div className="flex flex-col items-center justify-between w-full h-full">
<div />
<div className="flex flex-col items-center w-full max-w-4xl gap-10 mx-auto">
<div className="flex flex-col items-center text-center">
<img
src={`/heading-${storage.locale}.png`}
srcSet={`/heading-${storage.locale}@2x.png 2x`}
alt="lume"
className="w-2/3"
/>
<p className="mt-5 text-lg font-medium leading-snug whitespace-pre-line text-neutral-700">
{t("welcome.title")}
</p>
</div>
<div className="flex flex-col w-full max-w-sm gap-2 mx-auto">
<Link
to="/auth/create"
className="inline-flex items-center justify-center w-full text-lg font-medium text-white bg-blue-500 h-11 rounded-xl hover:bg-blue-600"
>
{t("welcome.signup")}
</Link>
<Link
to="/auth/import"
className="inline-flex items-center justify-center w-full text-lg font-medium text-white h-11 rounded-xl bg-neutral-950 hover:bg-neutral-900"
>
{t("welcome.login")}
</Link>
</div>
</div>
<div className="flex items-center justify-center h-11">
<p className="text-neutral-800">
{t("welcome.footer")}{" "}
<Link
to="https://nostr.com"
target="_blank"
className="text-blue-500"
>
here
</Link>
</p>
</div>
</div>
</div>
);
return (
<div className="flex h-screen w-screen bg-black">
<div className="flex h-full w-full flex-col items-center justify-between">
<div />
<div className="mx-auto flex w-full max-w-4xl flex-col items-center gap-10">
<div className="flex flex-col items-center text-center">
<img
src={`/heading-${storage.locale}.png`}
srcSet={`/heading-${storage.locale}@2x.png 2x`}
alt="lume"
className="w-2/3"
/>
<p className="mt-5 whitespace-pre-line text-lg font-medium leading-snug text-neutral-700">
{t("welcome.title")}
</p>
</div>
<div className="mx-auto flex w-full max-w-sm flex-col gap-2">
<Link
to="/auth/create"
className="inline-flex h-11 w-full items-center justify-center rounded-xl bg-blue-500 text-lg font-medium text-white hover:bg-blue-600"
>
{t("welcome.signup")}
</Link>
<Link
to="/auth/import"
className="inline-flex h-11 w-full items-center justify-center rounded-xl bg-neutral-950 text-lg font-medium text-white hover:bg-neutral-900"
>
{t("welcome.login")}
</Link>
</div>
</div>
<div className="flex h-11 items-center justify-center">
<p className="text-neutral-800">
{t("welcome.footer")}{" "}
<Link
to="https://nostr.com"
target="_blank"
className="text-blue-500"
>
here
</Link>
</p>
</div>
</div>
</div>
);
}

View File

@ -1,9 +0,0 @@
import { createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/splash")({
component: Screen,
});
function Screen() {
return <div>Loading..</div>;
}

View File

@ -15,14 +15,20 @@ export class Ark {
this.account = { npub: "" };
}
public async load_account() {
public async verify_signer() {
try {
const cmd: string = await invoke("load_account");
if (cmd) {
this.account.npub = cmd;
const signer: boolean = await invoke("verify_signer");
if (signer) {
const account: string = await invoke("load_account");
this.account.npub = account;
return true;
} else {
return false;
}
} catch (e) {
console.error(String(e));
return false;
}
}

View File

@ -0,0 +1,4 @@
import { createContext } from "react";
import { type Ark } from "./ark";
export const ArkContext = createContext<Ark | null>(undefined);

View File

@ -0,0 +1,10 @@
import { useContext } from "react";
import { ArkContext } from "../context";
export const useArk = () => {
const context = useContext(ArkContext);
if (context === undefined) {
throw new Error("useArk must be used within an ArkProvider");
}
return context;
};

View File

@ -1,5 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import { useArk } from "../provider";
import { useArk } from "./useArk";
export function useEvent(id: string) {
const ark = useArk();

View File

@ -1,5 +1,5 @@
import { useQuery } from "@tanstack/react-query";
import { useArk } from "../provider";
import { useArk } from "./useArk";
export function useProfile(pubkey: string) {
const ark = useArk();

View File

@ -1,3 +1,5 @@
export * from "./provider";
export * from "./ark";
export * from "./context";
export * from "./hooks/useArk";
export * from "./hooks/useEvent";
export * from "./hooks/useProfile";

View File

@ -1,17 +0,0 @@
import { PropsWithChildren, createContext, useContext, useMemo } from "react";
import { Ark } from "./ark";
export const ArkContext = createContext<Ark>(undefined);
export const ArkProvider = ({ children }: PropsWithChildren<object>) => {
const ark = useMemo(() => new Ark(), []);
return <ArkContext.Provider value={ark}>{children}</ArkContext.Provider>;
};
export const useArk = () => {
const context = useContext(ArkContext);
if (context === undefined) {
throw new Error("Ark Provider is not import");
}
return context;
};

View File

@ -22,6 +22,7 @@ export class LumeStorage {
translateApiKey: "",
instantZap: false,
defaultZapAmount: 21,
nwc: "",
};
}

379
src-tauri/Cargo.lock generated
View File

@ -389,28 +389,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "async-stream"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
dependencies = [
"async-stream-impl",
"futures-core",
"pin-project-lite",
]
[[package]]
name = "async-stream-impl"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]]
name = "async-task"
version = "4.7.0"
@ -515,51 +493,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "axum"
version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [
"async-trait",
"axum-core",
"bitflags 1.3.2",
"bytes",
"futures-util",
"http 0.2.11",
"http-body",
"hyper",
"itoa 1.0.10",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"rustversion",
"serde",
"sync_wrapper",
"tower",
"tower-layer",
"tower-service",
]
[[package]]
name = "axum-core"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c"
dependencies = [
"async-trait",
"bytes",
"futures-util",
"http 0.2.11",
"http-body",
"mime",
"rustversion",
"tower-layer",
"tower-service",
]
[[package]]
name = "backtrace"
version = "0.3.69"
@ -1071,16 +1004,6 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
]
[[package]]
name = "combine"
version = "4.6.6"
@ -1444,43 +1367,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "devtools-core"
version = "0.3.0"
source = "git+https://github.com/crabnebula-dev/devtools#3c9f774f1d4972d6ef5e482592e8e35aeab72c37"
dependencies = [
"async-stream",
"bytes",
"devtools-wire-format",
"futures",
"http 0.2.11",
"prost-types",
"ringbuf",
"thiserror",
"tokio",
"tokio-stream",
"tonic",
"tonic-health",
"tonic-web",
"tower-http",
"tower-layer",
"tracing",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "devtools-wire-format"
version = "0.4.0"
source = "git+https://github.com/crabnebula-dev/devtools#3c9f774f1d4972d6ef5e482592e8e35aeab72c37"
dependencies = [
"bitflags 2.4.2",
"prost",
"prost-types",
"tonic",
"tracing-core",
]
[[package]]
name = "digest"
version = "0.10.7"
@ -2623,12 +2509,6 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573"
[[package]]
name = "http-range-header"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f"
[[package]]
name = "httparse"
version = "1.8.0"
@ -2679,18 +2559,6 @@ dependencies = [
"tokio-rustls 0.24.1",
]
[[package]]
name = "hyper-timeout"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1"
dependencies = [
"hyper",
"pin-project-lite",
"tokio",
"tokio-io-timeout",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
@ -2950,15 +2818,6 @@ dependencies = [
"once_cell",
]
[[package]]
name = "itertools"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
@ -3239,18 +3098,6 @@ dependencies = [
"serde_json",
]
[[package]]
name = "local-ip-address"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "612ed4ea9ce5acfb5d26339302528a5e1e59dfed95e9e11af3c083236ff1d15d"
dependencies = [
"libc",
"neli",
"thiserror",
"windows-sys 0.48.0",
]
[[package]]
name = "lock_api"
version = "0.4.11"
@ -3305,7 +3152,6 @@ dependencies = [
"tauri-plugin-autostart",
"tauri-plugin-cli",
"tauri-plugin-clipboard-manager",
"tauri-plugin-devtools",
"tauri-plugin-dialog",
"tauri-plugin-fs",
"tauri-plugin-http",
@ -3391,12 +3237,6 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "matchit"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
[[package]]
name = "memchr"
version = "2.7.1"
@ -3540,31 +3380,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe"
[[package]]
name = "neli"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43"
dependencies = [
"byteorder",
"libc",
"log",
"neli-proc-macros",
]
[[package]]
name = "neli-proc-macros"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4"
dependencies = [
"either",
"proc-macro2",
"quote",
"serde",
"syn 1.0.109",
]
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
@ -4485,38 +4300,6 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "prost"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c289cda302b98a28d40c8b3b90498d6e526dd24ac2ecea73e4e491685b94a"
dependencies = [
"bytes",
"prost-derive",
]
[[package]]
name = "prost-derive"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e"
dependencies = [
"anyhow",
"itertools",
"proc-macro2",
"quote",
"syn 2.0.48",
]
[[package]]
name = "prost-types"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "193898f59edcf43c26227dcd4c8427f00d99d61e95dcde58dabd49fa291d470e"
dependencies = [
"prost",
]
[[package]]
name = "quick-xml"
version = "0.30.0"
@ -4796,15 +4579,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "ringbuf"
version = "0.4.0-rc.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdbd88a807ef07d0f243843ecccf4e7383638e536284fc0adf1663790faec4ef"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "rusqlite"
version = "0.30.0"
@ -5755,7 +5529,6 @@ dependencies = [
"tauri-utils",
"thiserror",
"tokio",
"tracing",
"tray-icon",
"url",
"webkit2gtk",
@ -5888,31 +5661,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "tauri-plugin-devtools"
version = "2.0.0-beta.0"
source = "git+https://github.com/crabnebula-dev/devtools#3c9f774f1d4972d6ef5e482592e8e35aeab72c37"
dependencies = [
"async-stream",
"bytes",
"cocoa",
"colored",
"devtools-core",
"futures",
"local-ip-address",
"objc",
"serde",
"serde_json",
"swift-rs",
"tauri",
"tauri-plugin",
"tokio",
"tonic",
"tonic-health",
"tracing",
"tracing-subscriber",
]
[[package]]
name = "tauri-plugin-dialog"
version = "2.0.0-beta.0"
@ -6166,7 +5914,6 @@ dependencies = [
"tao",
"tauri-runtime",
"tauri-utils",
"tracing",
"webkit2gtk",
"webview2-com",
"windows 0.52.0",
@ -6393,16 +6140,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "tokio-io-timeout"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf"
dependencies = [
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-macros"
version = "2.2.0"
@ -6457,17 +6194,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842"
dependencies = [
"futures-core",
"pin-project-lite",
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.21.0"
@ -6566,110 +6292,6 @@ dependencies = [
"winnow",
]
[[package]]
name = "tonic"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e"
dependencies = [
"async-stream",
"async-trait",
"axum",
"base64",
"bytes",
"h2",
"http 0.2.11",
"http-body",
"hyper",
"hyper-timeout",
"percent-encoding",
"pin-project",
"prost",
"tokio",
"tokio-stream",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tonic-health"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f80db390246dfb46553481f6024f0082ba00178ea495dbb99e70ba9a4fafb5e1"
dependencies = [
"async-stream",
"prost",
"tokio",
"tokio-stream",
"tonic",
]
[[package]]
name = "tonic-web"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fddb2a37b247e6adcb9f239f4e5cefdcc5ed526141a416b943929f13aea2cce"
dependencies = [
"base64",
"bytes",
"http 0.2.11",
"http-body",
"hyper",
"pin-project",
"tokio-stream",
"tonic",
"tower-http",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
dependencies = [
"futures-core",
"futures-util",
"indexmap 1.9.3",
"pin-project",
"pin-project-lite",
"rand 0.8.5",
"slab",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-http"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
dependencies = [
"bitflags 2.4.2",
"bytes",
"futures-core",
"futures-util",
"http 0.2.11",
"http-body",
"http-range-header",
"pin-project-lite",
"tower-layer",
"tower-service",
]
[[package]]
name = "tower-layer"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0"
[[package]]
name = "tower-service"
version = "0.3.2"
@ -7692,7 +7314,6 @@ dependencies = [
"soup3",
"tao-macros",
"thiserror",
"tracing",
"url",
"webkit2gtk",
"webkit2gtk-sys",

View File

@ -21,7 +21,6 @@ tauri = { version = "2.0.0-beta", features = [
"native-tls-vendored",
"protocol-asset",
] }
tauri-plugin-devtools = { git = "https://github.com/crabnebula-dev/devtools" }
tauri-plugin-cli = "2.0.0-beta"
tauri-plugin-clipboard-manager = "2.0.0-beta"
tauri-plugin-dialog = "2.0.0-beta"

File diff suppressed because one or more lines are too long

View File

@ -28,11 +28,7 @@ pub struct Nostr {
}
fn main() {
#[cfg(debug_assertions)]
let devtools = tauri_plugin_devtools::init();
let mut ctx = tauri::generate_context!();
tauri::Builder::default()
.setup(|app| {
let handle = app.handle().clone();
@ -130,7 +126,6 @@ fn main() {
Ok(())
})
.plugin(devtools)
.plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_theme::init(ctx.config_mut()))
.plugin(tauri_plugin_clipboard_manager::init())