wip: migrate to desktop2

This commit is contained in:
reya 2024-02-12 20:04:45 +07:00
parent 1950cb59a2
commit ed52105c02
18 changed files with 172 additions and 177 deletions

View File

@ -10,10 +10,15 @@
}, },
"dependencies": { "dependencies": {
"@lume/ark": "workspace:^", "@lume/ark": "workspace:^",
"@lume/icons": "workspace:^",
"@lume/storage": "workspace:^", "@lume/storage": "workspace:^",
"@lume/ui": "workspace:^",
"@lume/utils": "workspace:^",
"@tanstack/react-query": "^5.18.1",
"@tanstack/react-router": "^1.16.0", "@tanstack/react-router": "^1.16.0",
"i18next": "^23.8.2", "i18next": "^23.8.2",
"i18next-resources-to-backend": "^1.2.0", "i18next-resources-to-backend": "^1.2.0",
"jotai": "^2.6.4",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-i18next": "^14.0.2" "react-i18next": "^14.0.2"

View File

@ -1,5 +1,6 @@
import { ArkProvider } from "@lume/ark"; import { ArkProvider } from "@lume/ark";
import { StorageProvider } from "@lume/storage"; import { StorageProvider } from "@lume/storage";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { RouterProvider, createRouter } from "@tanstack/react-router"; import { RouterProvider, createRouter } from "@tanstack/react-router";
import React, { StrictMode } from "react"; import React, { StrictMode } from "react";
import ReactDOM from "react-dom/client"; import ReactDOM from "react-dom/client";
@ -10,30 +11,37 @@ import i18n from "./i18n";
// Import the generated route tree // Import the generated route tree
import { routeTree } from "./tree.gen"; import { routeTree } from "./tree.gen";
// Create a new router instance const queryClient = new QueryClient();
const router = createRouter({ routeTree }); const router = createRouter({
routeTree,
context: {
queryClient,
},
defaultPreload: "intent",
defaultPreloadStaleTime: 0,
});
// Register the router instance for type safety
declare module "@tanstack/react-router" { declare module "@tanstack/react-router" {
interface Register { interface Register {
router: typeof router; router: typeof router;
} }
} }
// Render the app
// biome-ignore lint/style/noNonNullAssertion: <explanation> // biome-ignore lint/style/noNonNullAssertion: <explanation>
const rootElement = document.getElementById("root")!; const rootElement = document.getElementById("root")!;
if (!rootElement.innerHTML) { if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement); const root = ReactDOM.createRoot(rootElement);
root.render( root.render(
<I18nextProvider i18n={i18n} defaultNS={"translation"}> <I18nextProvider i18n={i18n} defaultNS={"translation"}>
<StorageProvider> <QueryClientProvider client={queryClient}>
<ArkProvider> <StorageProvider>
<StrictMode> <ArkProvider>
<RouterProvider router={router} /> <StrictMode>
</StrictMode> <RouterProvider router={router} />
</ArkProvider> </StrictMode>
</StorageProvider> </ArkProvider>
</StorageProvider>
</QueryClientProvider>
</I18nextProvider>, </I18nextProvider>,
); );
} }

View File

@ -1,3 +1,4 @@
import { LoaderIcon } from "@lume/icons";
import { import {
Outlet, Outlet,
ScrollRestoration, ScrollRestoration,
@ -11,4 +12,14 @@ export const Route = createRootRoute({
<Outlet /> <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>
);
}

View File

@ -0,0 +1,20 @@
import { Navigation } from "@lume/ui";
import { Outlet, createFileRoute } from "@tanstack/react-router";
export const Route = createFileRoute("/app")({
component: App,
});
function App() {
return (
<div className="flex flex-col w-screen h-screen bg-gradient-to-tl from-gray-1 to-gray-2 dark:from-graydark-1 dark:to-graydark-2">
<div data-tauri-drag-region className="h-9 shrink-0" />
<div className="flex w-full h-full min-h-0">
<Navigation />
<div className="flex-1 h-full pb-2 pl-1 pr-2">
<Outlet />
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,13 @@
import { createLazyFileRoute } from "@tanstack/react-router";
export const Route = createLazyFileRoute("/app/space")({
component: Space,
});
function Space() {
return (
<div className="h-full w-full rounded-xl overflow-hidden bg-white shadow-[rgba(50,_50,_105,_0.15)_0px_2px_5px_0px,_rgba(0,_0,_0,_0.05)_0px_1px_1px_0px] dark:bg-black dark:shadow-none dark:ring-1 dark:ring-white/5">
<p>Hello</p>
</div>
);
}

View File

@ -2,7 +2,6 @@ import { createFileRoute, redirect } from "@tanstack/react-router";
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
export const Route = createFileRoute("/")({ export const Route = createFileRoute("/")({
component: Index,
beforeLoad: async ({ location }) => { beforeLoad: async ({ location }) => {
const signer = await invoke("verify_signer"); const signer = await invoke("verify_signer");
if (!signer) { if (!signer) {
@ -13,13 +12,8 @@ export const Route = createFileRoute("/")({
}, },
}); });
} }
throw redirect({
to: "/app/space",
});
}, },
}); });
function Index() {
return (
<div className="p-2">
<h3>Welcome Home!</h3>
</div>
);
}

View File

@ -13,6 +13,7 @@ import { createFileRoute } from '@tanstack/react-router'
// Import Routes // Import Routes
import { Route as rootRoute } from './routes/__root' import { Route as rootRoute } from './routes/__root'
import { Route as AppImport } from './routes/app'
import { Route as IndexImport } from './routes/index' import { Route as IndexImport } from './routes/index'
import { Route as LandingIndexImport } from './routes/landing/index' import { Route as LandingIndexImport } from './routes/landing/index'
@ -20,9 +21,15 @@ import { Route as LandingIndexImport } from './routes/landing/index'
const AuthImportLazyImport = createFileRoute('/auth/import')() const AuthImportLazyImport = createFileRoute('/auth/import')()
const AuthCreateLazyImport = createFileRoute('/auth/create')() const AuthCreateLazyImport = createFileRoute('/auth/create')()
const AppSpaceLazyImport = createFileRoute('/app/space')()
// Create/Update Routes // Create/Update Routes
const AppRoute = AppImport.update({
path: '/app',
getParentRoute: () => rootRoute,
} as any)
const IndexRoute = IndexImport.update({ const IndexRoute = IndexImport.update({
path: '/', path: '/',
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
@ -43,6 +50,11 @@ const AuthCreateLazyRoute = AuthCreateLazyImport.update({
getParentRoute: () => rootRoute, getParentRoute: () => rootRoute,
} as any).lazy(() => import('./routes/auth/create.lazy').then((d) => d.Route)) } as any).lazy(() => import('./routes/auth/create.lazy').then((d) => d.Route))
const AppSpaceLazyRoute = AppSpaceLazyImport.update({
path: '/space',
getParentRoute: () => AppRoute,
} as any).lazy(() => import('./routes/app/space.lazy').then((d) => d.Route))
// Populate the FileRoutesByPath interface // Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' { declare module '@tanstack/react-router' {
@ -51,6 +63,14 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexImport preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
} }
'/app': {
preLoaderRoute: typeof AppImport
parentRoute: typeof rootRoute
}
'/app/space': {
preLoaderRoute: typeof AppSpaceLazyImport
parentRoute: typeof AppImport
}
'/auth/create': { '/auth/create': {
preLoaderRoute: typeof AuthCreateLazyImport preLoaderRoute: typeof AuthCreateLazyImport
parentRoute: typeof rootRoute parentRoute: typeof rootRoute
@ -70,6 +90,7 @@ declare module '@tanstack/react-router' {
export const routeTree = rootRoute.addChildren([ export const routeTree = rootRoute.addChildren([
IndexRoute, IndexRoute,
AppRoute.addChildren([AppSpaceLazyRoute]),
AuthCreateLazyRoute, AuthCreateLazyRoute,
AuthImportLazyRoute, AuthImportLazyRoute,
LandingIndexRoute, LandingIndexRoute,

View File

@ -54,7 +54,7 @@ export class Ark {
const event = JSON.parse(cmd) as Event; const event = JSON.parse(cmd) as Event;
return event; return event;
} catch (e) { } catch (e) {
console.error(String(e)); return null;
} }
} }
@ -66,7 +66,7 @@ export class Ark {
const cmd: Event[] = await invoke("get_text_events", { limit, until }); const cmd: Event[] = await invoke("get_text_events", { limit, until });
return cmd; return cmd;
} catch (e) { } catch (e) {
console.error(String(e)); return [];
} }
} }
@ -120,7 +120,7 @@ export class Ark {
const cmd: Event[] = await invoke("get_event_thread", { id }); const cmd: Event[] = await invoke("get_event_thread", { id });
return cmd; return cmd;
} catch (e) { } catch (e) {
console.error(String(e)); return [];
} }
} }
@ -165,8 +165,8 @@ export class Ark {
try { try {
const cmd: Metadata = await invoke("get_profile", { id }); const cmd: Metadata = await invoke("get_profile", { id });
return cmd; return cmd;
} catch (e) { } catch {
console.error(String(e)); return null;
} }
} }

View File

@ -7,19 +7,14 @@ export function UserCover({ className }: { className?: string }) {
if (!user) { if (!user) {
return ( return (
<div <div
className={cn( className={cn("animate-pulse bg-gray-3 dark:bg-gray-7", className)}
"animate-pulse bg-neutral-300 dark:bg-neutral-700",
className,
)}
/> />
); );
} }
if (user && !user.profile.banner) { if (user && !user.profile.banner) {
return ( return (
<div <div className={cn("bg-gradient-to-b from-sky-4 to-blue-2", className)} />
className={cn("bg-gradient-to-b from-sky-400 to-sky-200", className)}
/>
); );
} }

View File

@ -2,11 +2,14 @@ import { LoaderIcon } from "@lume/icons";
import { cn } from "@lume/utils"; import { cn } from "@lume/utils";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useArk } from "../../provider";
export function UserFollowButton({ export function UserFollowButton({
target, target,
className, className,
}: { target: string; className?: string }) { }: { target: string; className?: string }) {
const ark = useArk();
const [t] = useTranslation(); const [t] = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [followed, setFollowed] = useState(false); const [followed, setFollowed] = useState(false);

View File

@ -37,7 +37,7 @@ export function UserNip05({ className }: { className?: string }) {
: user?.profile.nip05} : user?.profile.nip05}
</p> </p>
{!isLoading && verified ? ( {!isLoading && verified ? (
<VerifiedIcon className="size-4 text-teal-500" /> <VerifiedIcon className="size-4 text-green-10" />
) : null} ) : null}
</div> </div>
); );

View File

@ -1,90 +0,0 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useArk } from "../provider";
export function useRelaylist() {
const ark = useArk();
const queryClient = useQueryClient();
const connectRelay = useMutation({
mutationFn: async (
relay: WebSocket["url"],
purpose?: "read" | "write" | undefined,
) => {
// Cancel any outgoing refetches
await queryClient.cancelQueries({
queryKey: ["relay-personal"],
});
const relayUrl = normalizeRelayUrl(relay);
// Snapshot the previous value
const prevRelays: NDKTag[] = queryClient.getQueryData(["relay-personal"]);
// create new relay list if not exist
if (!prevRelays) {
await ark.createEvent({
kind: NDKKind.RelayList,
tags: [["r", relay, purpose ?? ""]],
});
}
// add relay to exist list
const index = prevRelays.findIndex((el) => el[1] === relay);
if (index > -1) return;
await ark.createEvent({
kind: NDKKind.RelayList,
tags: [...prevRelays, ["r", relayUrl, purpose ?? ""]],
});
// Optimistically update to the new value
queryClient.setQueryData(["relay-personal"], (prev: NDKTag[]) => [
...prev,
["r", relayUrl, purpose ?? ""],
]);
// Return a context object with the snapshotted value
return { prevRelays };
},
onSettled: () => {
queryClient.invalidateQueries({
queryKey: ["relay-personal"],
});
},
});
const removeRelay = useMutation({
mutationFn: async (relay: WebSocket["url"]) => {
// Cancel any outgoing refetches
await queryClient.cancelQueries({
queryKey: ["relay-personal"],
});
// Snapshot the previous value
const prevRelays: NDKTag[] = queryClient.getQueryData(["relay-personal"]);
if (!prevRelays) return;
const index = prevRelays.findIndex((el) => el[1] === relay);
if (index > -1) prevRelays.splice(index, 1);
await ark.createEvent({
kind: NDKKind.RelayList,
tags: prevRelays,
});
// Optimistically update to the new value
queryClient.setQueryData(["relay-personal"], prevRelays);
// Return a context object with the snapshotted value
return { prevRelays };
},
onSettled: () => {
queryClient.invalidateQueries({
queryKey: ["relay-personal"],
});
},
});
return { connectRelay, removeRelay };
}

View File

@ -18,6 +18,7 @@
"@radix-ui/react-hover-card": "^1.0.7", "@radix-ui/react-hover-card": "^1.0.7",
"@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-popover": "^1.0.7",
"@tanstack/react-query": "^5.18.1", "@tanstack/react-query": "^5.18.1",
"@tanstack/react-router": "^1.16.0",
"framer-motion": "^11.0.3", "framer-motion": "^11.0.3",
"jotai": "^2.6.4", "jotai": "^2.6.4",
"minidenticons": "^4.2.0", "minidenticons": "^4.2.0",

View File

@ -15,13 +15,13 @@ export function ActiveAccount() {
const svgURI = useMemo( const svgURI = useMemo(
() => () =>
`data:image/svg+xml;utf8,${encodeURIComponent( `data:image/svg+xml;utf8,${encodeURIComponent(
minidenticon(ark.account.pubkey, 90, 50), minidenticon(ark.account.npub, 90, 50),
)}`, )}`,
[], [],
); );
const { t } = useTranslation(); const { t } = useTranslation();
const { user } = useProfile(ark.account.pubkey); const { user } = useProfile(ark.account.npub);
return ( return (
<DropdownMenu.Root> <DropdownMenu.Root>
@ -30,24 +30,24 @@ export function ActiveAccount() {
<Avatar.Root> <Avatar.Root>
<Avatar.Image <Avatar.Image
src={user?.picture} src={user?.picture}
alt={ark.account.pubkey} alt={ark.account.npub}
loading="lazy" loading="lazy"
decoding="async" decoding="async"
style={{ contentVisibility: "auto" }} style={{ contentVisibility: "auto" }}
className="aspect-square h-auto w-full rounded-xl object-cover" className="object-cover w-full h-auto aspect-square rounded-xl"
/> />
<Avatar.Fallback delayMs={150}> <Avatar.Fallback delayMs={150}>
<img <img
src={svgURI} src={svgURI}
alt={ark.account.pubkey} alt={ark.account.npub}
className="aspect-square h-auto w-full rounded-xl bg-black dark:bg-white" className="w-full h-auto bg-black aspect-square rounded-xl dark:bg-white"
/> />
</Avatar.Fallback> </Avatar.Fallback>
</Avatar.Root> </Avatar.Root>
<span <span
className={cn( className={cn(
"absolute bottom-0 right-0 block h-2 w-2 rounded-full ring-2 ring-neutral-100 dark:ring-neutral-900", "absolute bottom-0 right-0 block h-2 w-2 rounded-full ring-2 ring-gray-1 dark:ring-graydark-1",
isOnline ? "bg-teal-500" : "bg-red-500", isOnline ? "bg-green-9" : "bg-red-9",
)} )}
/> />
</div> </div>

View File

@ -2,8 +2,6 @@ import {
ArrowUpSquareIcon, ArrowUpSquareIcon,
BellFilledIcon, BellFilledIcon,
BellIcon, BellIcon,
DepotFilledIcon,
DepotIcon,
HomeFilledIcon, HomeFilledIcon,
HomeIcon, HomeIcon,
PlusIcon, PlusIcon,
@ -13,13 +11,13 @@ import {
SettingsIcon, SettingsIcon,
} from "@lume/icons"; } from "@lume/icons";
import { cn, editorAtom, searchAtom } from "@lume/utils"; import { cn, editorAtom, searchAtom } from "@lume/utils";
import { Link } from "@tanstack/react-router";
import { confirm } from "@tauri-apps/plugin-dialog"; import { confirm } from "@tauri-apps/plugin-dialog";
import { relaunch } from "@tauri-apps/plugin-process"; import { relaunch } from "@tauri-apps/plugin-process";
import { Update, check } from "@tauri-apps/plugin-updater"; import { Update, check } from "@tauri-apps/plugin-updater";
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook"; import { useHotkeys } from "react-hotkeys-hook";
import { NavLink } from "react-router-dom";
import { ActiveAccount } from "./account/active"; import { ActiveAccount } from "./account/active";
import { UnreadActivity } from "./unread"; import { UnreadActivity } from "./unread";
@ -65,20 +63,19 @@ export function Navigation() {
type="button" type="button"
onClick={() => setIsEditorOpen((state) => !state)} onClick={() => setIsEditorOpen((state) => !state)}
className={cn( className={cn(
"flex items-center justify-center h-auto w-full text-black aspect-square rounded-xl hover:text-white dark:text-white", "flex items-center justify-center h-auto w-full aspect-square rounded-xl text-gray-normal",
isEditorOpen isEditorOpen
? "bg-blue-500 text-white" ? "bg-blue-solid text-white"
: "bg-black/5 hover:bg-blue-500 dark:bg-white/5 dark:hover:bg-blue-500", : "bg-gray-4 hover:bg-blue-solid dark:bg-graydark-4",
)} )}
> >
<PlusIcon className="size-5" /> <PlusIcon className="size-5" />
</button> </button>
</div> </div>
<div className="my-5 w-2/3 mx-auto h-px bg-black/10 dark:bg-white/10" /> <div className="w-2/3 h-px mx-auto my-5 bg-black/10 dark:bg-white/10" />
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
<NavLink <Link
to="/" to="/app/space"
preventScrollReset={true}
className="inline-flex flex-col items-center justify-center" className="inline-flex flex-col items-center justify-center"
> >
{({ isActive }) => ( {({ isActive }) => (
@ -97,10 +94,9 @@ export function Navigation() {
)} )}
</div> </div>
)} )}
</NavLink> </Link>
<NavLink <Link
to="/activity/" to="/app/activity"
preventScrollReset={true}
className="inline-flex flex-col items-center justify-center" className="inline-flex flex-col items-center justify-center"
> >
{({ isActive }) => ( {({ isActive }) => (
@ -120,29 +116,7 @@ export function Navigation() {
<UnreadActivity /> <UnreadActivity />
</div> </div>
)} )}
</NavLink> </Link>
<NavLink
to="/relays/"
preventScrollReset={true}
className="inline-flex flex-col items-center justify-center"
>
{({ isActive }) => (
<div
className={cn(
"inline-flex aspect-square h-auto w-full items-center justify-center rounded-xl",
isActive
? "bg-black/10 text-black dark:bg-white/10 dark:text-white"
: "text-black/50 dark:text-neutral-400",
)}
>
{isActive ? (
<DepotFilledIcon className="size-6" />
) : (
<DepotIcon className="size-6" />
)}
</div>
)}
</NavLink>
</div> </div>
</div> </div>
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
@ -152,10 +126,10 @@ export function Navigation() {
onClick={installNewUpdate} onClick={installNewUpdate}
className="relative inline-flex flex-col items-center justify-center" className="relative inline-flex flex-col items-center justify-center"
> >
<span className="inline-flex items-center rounded-full bg-teal-500/60 ring-teal-500/80 text-teal-50 dark:bg-teal-500/10 px-2 py-1 text-xs font-semibold dark:text-teal-400 ring-1 ring-inset dark:ring-teal-500/20"> <span className="inline-flex items-center px-2 py-1 text-xs font-semibold rounded-full bg-teal-500/60 ring-teal-500/80 text-teal-50 dark:bg-teal-500/10 dark:text-teal-400 ring-1 ring-inset dark:ring-teal-500/20">
Update Update
</span> </span>
<div className="inline-flex aspect-square h-auto w-full items-center justify-center rounded-xl text-black/50 dark:text-neutral-400"> <div className="inline-flex items-center justify-center w-full h-auto aspect-square rounded-xl text-black/50 dark:text-neutral-400">
<ArrowUpSquareIcon className="size-6" /> <ArrowUpSquareIcon className="size-6" />
</div> </div>
</button> </button>
@ -180,9 +154,8 @@ export function Navigation() {
)} )}
</div> </div>
</button> </button>
<NavLink <Link
to="/settings/" to="/settings"
preventScrollReset={true}
className="inline-flex flex-col items-center justify-center" className="inline-flex flex-col items-center justify-center"
> >
{({ isActive }) => ( {({ isActive }) => (
@ -201,7 +174,7 @@ export function Navigation() {
)} )}
</div> </div>
)} )}
</NavLink> </Link>
</div> </div>
</div> </div>
); );

View File

@ -259,9 +259,21 @@ importers:
'@lume/ark': '@lume/ark':
specifier: workspace:^ specifier: workspace:^
version: link:../../packages/ark version: link:../../packages/ark
'@lume/icons':
specifier: workspace:^
version: link:../../packages/icons
'@lume/storage': '@lume/storage':
specifier: workspace:^ specifier: workspace:^
version: link:../../packages/storage version: link:../../packages/storage
'@lume/ui':
specifier: workspace:^
version: link:../../packages/ui
'@lume/utils':
specifier: workspace:^
version: link:../../packages/utils
'@tanstack/react-query':
specifier: ^5.18.1
version: 5.18.1(react@18.2.0)
'@tanstack/react-router': '@tanstack/react-router':
specifier: ^1.16.0 specifier: ^1.16.0
version: 1.16.0(react-dom@18.2.0)(react@18.2.0) version: 1.16.0(react-dom@18.2.0)(react@18.2.0)
@ -271,6 +283,9 @@ importers:
i18next-resources-to-backend: i18next-resources-to-backend:
specifier: ^1.2.0 specifier: ^1.2.0
version: 1.2.0 version: 1.2.0
jotai:
specifier: ^2.6.4
version: 2.6.4(@types/react@18.2.55)(react@18.2.0)
react: react:
specifier: ^18.2.0 specifier: ^18.2.0
version: 18.2.0 version: 18.2.0
@ -1157,6 +1172,9 @@ importers:
'@tanstack/react-query': '@tanstack/react-query':
specifier: ^5.18.1 specifier: ^5.18.1
version: 5.18.1(react@18.2.0) version: 5.18.1(react@18.2.0)
'@tanstack/react-router':
specifier: ^1.16.0
version: 1.16.0(react-dom@18.2.0)(react@18.2.0)
framer-motion: framer-motion:
specifier: ^11.0.3 specifier: ^11.0.3
version: 11.0.3(react-dom@18.2.0)(react@18.2.0) version: 11.0.3(react-dom@18.2.0)(react@18.2.0)
@ -3616,7 +3634,6 @@ packages:
'@types/prop-types': 15.7.11 '@types/prop-types': 15.7.11
'@types/scheduler': 0.16.8 '@types/scheduler': 0.16.8
csstype: 3.1.3 csstype: 3.1.3
dev: true
/@types/scheduler@0.16.8: /@types/scheduler@0.16.8:
resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==}
@ -5099,6 +5116,22 @@ packages:
react: 18.2.0 react: 18.2.0
dev: false dev: false
/jotai@2.6.4(@types/react@18.2.55)(react@18.2.0):
resolution: {integrity: sha512-RniwQPX4893YlNR1muOtyUGHYaTD1fhEN4qnOuZJSrDHj6xdEMrqlRSN/hCm2fshwk78ruecB/P2l+NCVWe6TQ==}
engines: {node: '>=12.20.0'}
peerDependencies:
'@types/react': '>=17.0.0'
react: '>=17.0.0'
peerDependenciesMeta:
'@types/react':
optional: true
react:
optional: true
dependencies:
'@types/react': 18.2.55
react: 18.2.0
dev: false
/js-tokens@4.0.0: /js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}

View File

@ -164,8 +164,14 @@ fn main() {
commands::folder::show_in_folder, commands::folder::show_in_folder,
commands::opg::fetch_opg, commands::opg::fetch_opg,
]) ])
.run(ctx) .build(ctx)
.expect("error while running tauri application"); .expect("error while running tauri application")
.run(|_app_handle, event| match event {
tauri::RunEvent::ExitRequested { api, .. } => {
api.prevent_exit();
}
_ => {}
});
} }
fn get_nsec_paths(dir: &Path) -> Result<Vec<PathBuf>, Box<dyn Error>> { fn get_nsec_paths(dir: &Path) -> Result<Vec<PathBuf>, Box<dyn Error>> {

View File

@ -32,6 +32,8 @@
} }
}, },
"trayIcon": { "trayIcon": {
"id": "lume-tray",
"tooltip": "Lume",
"iconPath": "icons/tray.png" "iconPath": "icons/tray.png"
} }
}, },