feat: add theme switcher

This commit is contained in:
reya 2024-05-26 16:11:27 +07:00
parent 4dc13385a5
commit 5ca9444358
12 changed files with 564 additions and 619 deletions

View File

@ -2,6 +2,7 @@ import { NostrQuery } from "@lume/system";
import type { Settings } from "@lume/types"; import type { Settings } from "@lume/types";
import * as Switch from "@radix-ui/react-switch"; import * as Switch from "@radix-ui/react-switch";
import { createFileRoute } from "@tanstack/react-router"; import { createFileRoute } from "@tanstack/react-router";
import { invoke } from "@tauri-apps/api/core";
import { requestPermission } from "@tauri-apps/plugin-notification"; import { requestPermission } from "@tauri-apps/plugin-notification";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce"; import { useDebouncedCallback } from "use-debounce";
@ -61,6 +62,19 @@ function Screen() {
})); }));
}; };
const changeTheme = (theme: string) => {
if (theme === "auto" || theme === "light" || theme === "dark") {
invoke("plugin:theme|set_theme", {
theme: theme,
}).then(() =>
setNewSettings((prev) => ({
...prev,
theme,
})),
);
}
};
const updateSettings = useDebouncedCallback(() => { const updateSettings = useDebouncedCallback(() => {
NostrQuery.setSettings(newSettings); NostrQuery.setSettings(newSettings);
}, 200); }, 200);
@ -173,7 +187,6 @@ function Screen() {
Interface Interface
</h2> </h2>
<div className="flex flex-col divide-y divide-black/10 dark:divide-white/10 bg-black/5 dark:bg-white/5 rounded-xl px-3"> <div className="flex flex-col divide-y divide-black/10 dark:divide-white/10 bg-black/5 dark:bg-white/5 rounded-xl px-3">
<div className="flex flex-col gap-4">
<div className="flex w-full items-start justify-between gap-4 py-3"> <div className="flex w-full items-start justify-between gap-4 py-3">
<div className="flex-1"> <div className="flex-1">
<h3 className="font-semibold">Zap</h3> <h3 className="font-semibold">Zap</h3>
@ -192,6 +205,25 @@ function Screen() {
</Switch.Root> </Switch.Root>
</div> </div>
</div> </div>
<div className="flex w-full items-start justify-between gap-4 py-3">
<div className="flex-1">
<h3 className="font-semibold">Appearance</h3>
<p className="text-sm text-neutral-700 dark:text-neutral-300">
* Require restarting the app to take effect.
</p>
</div>
<div className="w-36 flex justify-end shrink-0">
<select
name="theme"
className="bg-transparent shadow-none outline-none rounded-lg border-1 border-black/10 dark:border-white/10 py-1 w-24"
defaultValue={settings.theme}
onChange={(e) => changeTheme(e.target.value)}
>
<option value="auto">Auto</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -11,10 +11,7 @@ export const commands = {
}, },
async connectRelay(relay: string) : Promise<Result<boolean, null>> { async connectRelay(relay: string) : Promise<Result<boolean, null>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("connect_relay", { relay }) };
status: "ok",
data: await TAURI_INVOKE("connect_relay", { relay }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -22,10 +19,7 @@ export const commands = {
}, },
async removeRelay(relay: string) : Promise<Result<boolean, null>> { async removeRelay(relay: string) : Promise<Result<boolean, null>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("remove_relay", { relay }) };
status: "ok",
data: await TAURI_INVOKE("remove_relay", { relay }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -47,43 +41,25 @@ export const commands = {
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async saveAccount( async saveAccount(nsec: string, password: string) : Promise<Result<string, string>> {
nsec: string,
password: string,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("save_account", { nsec, password }) };
status: "ok",
data: await TAURI_INVOKE("save_account", { nsec, password }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getEncryptedKey( async getEncryptedKey(npub: string, password: string) : Promise<Result<string, string>> {
npub: string,
password: string,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_encrypted_key", { npub, password }) };
status: "ok",
data: await TAURI_INVOKE("get_encrypted_key", { npub, password }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async nostrConnect( async nostrConnect(npub: string, uri: string) : Promise<Result<string, string>> {
npub: string,
uri: string,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("nostr_connect", { npub, uri }) };
status: "ok",
data: await TAURI_INVOKE("nostr_connect", { npub, uri }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -91,38 +67,23 @@ export const commands = {
}, },
async loadAccount(npub: string) : Promise<Result<boolean, string>> { async loadAccount(npub: string) : Promise<Result<boolean, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("load_account", { npub }) };
status: "ok",
data: await TAURI_INVOKE("load_account", { npub }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async eventToBech32( async eventToBech32(id: string, relays: string[]) : Promise<Result<string, null>> {
id: string,
relays: string[],
): Promise<Result<string, null>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("event_to_bech32", { id, relays }) };
status: "ok",
data: await TAURI_INVOKE("event_to_bech32", { id, relays }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async userToBech32( async userToBech32(key: string, relays: string[]) : Promise<Result<string, null>> {
key: string,
relays: string[],
): Promise<Result<string, null>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("user_to_bech32", { key, relays }) };
status: "ok",
data: await TAURI_INVOKE("user_to_bech32", { key, relays }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -136,15 +97,9 @@ export const commands = {
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async verifyNip05( async verifyNip05(key: string, nip05: string) : Promise<Result<boolean, string>> {
key: string,
nip05: string,
): Promise<Result<boolean, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("verify_nip05", { key, nip05 }) };
status: "ok",
data: await TAURI_INVOKE("verify_nip05", { key, nip05 }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -152,24 +107,15 @@ export const commands = {
}, },
async runNotification(accounts: string[]) : Promise<Result<null, null>> { async runNotification(accounts: string[]) : Promise<Result<null, null>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("run_notification", { accounts }) };
status: "ok",
data: await TAURI_INVOKE("run_notification", { accounts }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getActivities( async getActivities(account: string, kind: string) : Promise<Result<string[], string>> {
account: string,
kind: string,
): Promise<Result<string[], string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_activities", { account, kind }) };
status: "ok",
data: await TAURI_INVOKE("get_activities", { account, kind }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -177,10 +123,7 @@ export const commands = {
}, },
async getCurrentUserProfile() : Promise<Result<string, string>> { async getCurrentUserProfile() : Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_current_user_profile") };
status: "ok",
data: await TAURI_INVOKE("get_current_user_profile"),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -204,53 +147,23 @@ export const commands = {
}, },
async setContactList(pubkeys: string[]) : Promise<Result<boolean, string>> { async setContactList(pubkeys: string[]) : Promise<Result<boolean, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("set_contact_list", { pubkeys }) };
status: "ok",
data: await TAURI_INVOKE("set_contact_list", { pubkeys }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async createProfile( async createProfile(name: string, displayName: string, about: string, picture: string, banner: string, nip05: string, lud16: string, website: string) : Promise<Result<string, string>> {
name: string,
displayName: string,
about: string,
picture: string,
banner: string,
nip05: string,
lud16: string,
website: string,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("create_profile", { name, displayName, about, picture, banner, nip05, lud16, website }) };
status: "ok",
data: await TAURI_INVOKE("create_profile", {
name,
displayName,
about,
picture,
banner,
nip05,
lud16,
website,
}),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async follow( async follow(id: string, alias: string | null) : Promise<Result<string, string>> {
id: string,
alias: string | null,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("follow", { id, alias }) };
status: "ok",
data: await TAURI_INVOKE("follow", { id, alias }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -272,15 +185,9 @@ export const commands = {
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async setNstore( async setNstore(key: string, content: string) : Promise<Result<string, string>> {
key: string,
content: string,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("set_nstore", { key, content }) };
status: "ok",
data: await TAURI_INVOKE("set_nstore", { key, content }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -310,31 +217,17 @@ export const commands = {
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async zapProfile( async zapProfile(id: string, amount: string, message: string) : Promise<Result<boolean, string>> {
id: string,
amount: string,
message: string,
): Promise<Result<boolean, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("zap_profile", { id, amount, message }) };
status: "ok",
data: await TAURI_INVOKE("zap_profile", { id, amount, message }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async zapEvent( async zapEvent(id: string, amount: string, message: string) : Promise<Result<boolean, string>> {
id: string,
amount: string,
message: string,
): Promise<Result<boolean, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("zap_event", { id, amount, message }) };
status: "ok",
data: await TAURI_INVOKE("zap_event", { id, amount, message }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -342,10 +235,7 @@ export const commands = {
}, },
async friendToFriend(npub: string) : Promise<Result<boolean, string>> { async friendToFriend(npub: string) : Promise<Result<boolean, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("friend_to_friend", { npub }) };
status: "ok",
data: await TAURI_INVOKE("friend_to_friend", { npub }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -367,70 +257,41 @@ export const commands = {
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getEventsBy( async getEventsBy(publicKey: string, asOf: string | null) : Promise<Result<string[], string>> {
publicKey: string,
asOf: string | null,
): Promise<Result<string[], string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_events_by", { publicKey, asOf }) };
status: "ok",
data: await TAURI_INVOKE("get_events_by", { publicKey, asOf }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getLocalEvents( async getLocalEvents(pubkeys: string[], until: string | null) : Promise<Result<string[], string>> {
pubkeys: string[],
until: string | null,
): Promise<Result<string[], string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_local_events", { pubkeys, until }) };
status: "ok",
data: await TAURI_INVOKE("get_local_events", { pubkeys, until }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getGlobalEvents( async getGlobalEvents(until: string | null) : Promise<Result<string[], string>> {
until: string | null,
): Promise<Result<string[], string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_global_events", { until }) };
status: "ok",
data: await TAURI_INVOKE("get_global_events", { until }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async getHashtagEvents( async getHashtagEvents(hashtags: string[], until: string | null) : Promise<Result<string[], string>> {
hashtags: string[],
until: string | null,
): Promise<Result<string[], string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("get_hashtag_events", { hashtags, until }) };
status: "ok",
data: await TAURI_INVOKE("get_hashtag_events", { hashtags, until }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async publish( async publish(content: string, tags: string[][]) : Promise<Result<string, string>> {
content: string,
tags: string[][],
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("publish", { content, tags }) };
status: "ok",
data: await TAURI_INVOKE("publish", { content, tags }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -447,26 +308,9 @@ export const commands = {
async showInFolder(path: string) : Promise<void> { async showInFolder(path: string) : Promise<void> {
await TAURI_INVOKE("show_in_folder", { path }); await TAURI_INVOKE("show_in_folder", { path });
}, },
async createColumn( async createColumn(label: string, x: number, y: number, width: number, height: number, url: string) : Promise<Result<string, string>> {
label: string,
x: number,
y: number,
width: number,
height: number,
url: string,
): Promise<Result<string, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("create_column", { label, x, y, width, height, url }) };
status: "ok",
data: await TAURI_INVOKE("create_column", {
label,
x,
y,
width,
height,
url,
}),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -474,63 +318,31 @@ export const commands = {
}, },
async closeColumn(label: string) : Promise<Result<boolean, null>> { async closeColumn(label: string) : Promise<Result<boolean, null>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("close_column", { label }) };
status: "ok",
data: await TAURI_INVOKE("close_column", { label }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async repositionColumn( async repositionColumn(label: string, x: number, y: number) : Promise<Result<null, string>> {
label: string,
x: number,
y: number,
): Promise<Result<null, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("reposition_column", { label, x, y }) };
status: "ok",
data: await TAURI_INVOKE("reposition_column", { label, x, y }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async resizeColumn( async resizeColumn(label: string, width: number, height: number) : Promise<Result<null, string>> {
label: string,
width: number,
height: number,
): Promise<Result<null, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("resize_column", { label, width, height }) };
status: "ok",
data: await TAURI_INVOKE("resize_column", { label, width, height }),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
} }
}, },
async openWindow( async openWindow(label: string, title: string, url: string, width: number, height: number) : Promise<Result<null, string>> {
label: string,
title: string,
url: string,
width: number,
height: number,
): Promise<Result<null, string>> {
try { try {
return { return { status: "ok", data: await TAURI_INVOKE("open_window", { label, title, url, width, height }) };
status: "ok",
data: await TAURI_INVOKE("open_window", {
label,
title,
url,
width,
height,
}),
};
} catch (e) { } catch (e) {
if(e instanceof Error) throw e; if(e instanceof Error) throw e;
else return { status: "error", error: e as any }; else return { status: "error", error: e as any };
@ -538,18 +350,15 @@ export const commands = {
}, },
async setBadge(count: number) : Promise<void> { async setBadge(count: number) : Promise<void> {
await TAURI_INVOKE("set_badge", { count }); await TAURI_INVOKE("set_badge", { count });
}, }
}; }
/** user-defined types **/ /** user-defined types **/
export type Account = { npub: string; nsec: string }; export type Account = { npub: string; nsec: string }
export type Relays = { export type Relays = { connected: string[]; read: string[] | null; write: string[] | null; both: string[] | null }
connected: string[];
read: string[] | null;
write: string[] | null;
both: string[] | null;
};
/** tauri-specta globals **/ /** tauri-specta globals **/
@ -559,10 +368,10 @@ import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webview
type __EventObj__<T> = { type __EventObj__<T> = {
listen: ( listen: (
cb: TAURI_API_EVENT.EventCallback<T>, cb: TAURI_API_EVENT.EventCallback<T>
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>; ) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
once: ( once: (
cb: TAURI_API_EVENT.EventCallback<T>, cb: TAURI_API_EVENT.EventCallback<T>
) => ReturnType<typeof TAURI_API_EVENT.once<T>>; ) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
emit: T extends null emit: T extends null
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit> ? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
@ -574,7 +383,7 @@ export type Result<T, E> =
| { status: "error"; error: E }; | { status: "error"; error: E };
function __makeEvents__<T extends Record<string, any>>( function __makeEvents__<T extends Record<string, any>>(
mappings: Record<keyof T, string>, mappings: Record<keyof T, string>
) { ) {
return new Proxy( return new Proxy(
{} as unknown as { {} as unknown as {
@ -604,6 +413,8 @@ function __makeEvents__<T extends Record<string, any>>(
}, },
}); });
}, },
}, }
); );
} }

View File

@ -5,6 +5,7 @@ import { readFile, readTextFile } from "@tauri-apps/plugin-fs";
import { isPermissionGranted } from "@tauri-apps/plugin-notification"; import { isPermissionGranted } from "@tauri-apps/plugin-notification";
import { open } from "@tauri-apps/plugin-dialog"; import { open } from "@tauri-apps/plugin-dialog";
import { dedupEvents } from "./dedup"; import { dedupEvents } from "./dedup";
import { invoke } from "@tauri-apps/api/core";
enum NSTORE_KEYS { enum NSTORE_KEYS {
settings = "lume_user_settings", settings = "lume_user_settings",
@ -201,8 +202,11 @@ export class NostrQuery {
if (query.status === "ok") { if (query.status === "ok") {
const settings: Settings = query.data ? JSON.parse(query.data) : null; const settings: Settings = query.data ? JSON.parse(query.data) : null;
const isGranted = await isPermissionGranted(); const isGranted = await isPermissionGranted();
const theme: "auto" | "light" | "dark" = await invoke(
"plugin:theme|get_theme",
);
return { ...settings, notification: isGranted }; return { ...settings, theme, notification: isGranted };
} else { } else {
const initial: Settings = { const initial: Settings = {
autoUpdate: false, autoUpdate: false,
@ -210,6 +214,8 @@ export class NostrQuery {
notification: false, notification: false,
zap: false, zap: false,
nsfw: false, nsfw: false,
gossip: false,
theme: "auto",
}; };
return initial; return initial;

View File

@ -5,6 +5,7 @@ export interface Settings {
zap: boolean; zap: boolean;
nsfw: boolean; nsfw: boolean;
gossip: boolean; gossip: boolean;
theme: "auto" | "light" | "dark";
[key: string]: string | number | boolean; [key: string]: string | number | boolean;
} }

29
src-tauri/Cargo.lock generated
View File

@ -2907,6 +2907,7 @@ dependencies = [
"tauri-plugin-os", "tauri-plugin-os",
"tauri-plugin-process", "tauri-plugin-process",
"tauri-plugin-shell", "tauri-plugin-shell",
"tauri-plugin-theme",
"tauri-plugin-updater", "tauri-plugin-updater",
"tauri-plugin-upload", "tauri-plugin-upload",
"tauri-plugin-window-state", "tauri-plugin-window-state",
@ -5514,6 +5515,24 @@ dependencies = [
"tokio", "tokio",
] ]
[[package]]
name = "tauri-plugin-theme"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c23856e93f56cd8d1868e7dd8a4b529b836fd5da315cefd7702b252a850cdf5a"
dependencies = [
"cocoa",
"dirs-next",
"futures-lite 2.3.0",
"gtk",
"once_cell",
"serde",
"tauri",
"tauri-plugin",
"tintanum",
"tokio",
]
[[package]] [[package]]
name = "tauri-plugin-updater" name = "tauri-plugin-updater"
version = "2.0.0-beta.5" version = "2.0.0-beta.5"
@ -5805,6 +5824,16 @@ dependencies = [
"time-core", "time-core",
] ]
[[package]]
name = "tintanum"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7abbcf9173afc80733c20b7e27a30bc9284d6535bdbde2a70904032de63e16e8"
dependencies = [
"futures-lite 1.13.0",
"zbus 3.15.1",
]
[[package]] [[package]]
name = "tinyvec" name = "tinyvec"
version = "1.6.0" version = "1.6.0"

View File

@ -39,6 +39,7 @@ keyring = "2"
keyring-search = "0.2.0" keyring-search = "0.2.0"
specta = "=2.0.0-rc.12" specta = "=2.0.0-rc.12"
tauri-specta = { version = "=2.0.0-rc.10", features = ["typescript"] } tauri-specta = { version = "=2.0.0-rc.10", features = ["typescript"] }
tauri-plugin-theme = "0.4.1"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.25.0" cocoa = "0.25.0"

View File

@ -56,6 +56,8 @@
"dialog:allow-message", "dialog:allow-message",
"process:allow-restart", "process:allow-restart",
"fs:allow-read-file", "fs:allow-read-file",
"theme:allow-set-theme",
"theme:allow-get-theme",
"shell:allow-open", "shell:allow-open",
{ {
"identifier": "http:default", "identifier": "http:default",

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
{"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","splash","settings","search","nwc","activity","zap-*","event-*","user-*","editor-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","os:allow-os-type","updater:default","updater:allow-check","updater:allow-download-and-install","window:allow-start-dragging","window:allow-create","window:allow-close","window:allow-set-focus","window:allow-center","window:allow-minimize","window:allow-maximize","window:allow-set-size","window:allow-set-focus","window:allow-start-dragging","decorum:allow-show-snap-overlay","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","webview:allow-create-webview-window","webview:allow-create-webview","webview:allow-set-webview-size","webview:allow-set-webview-position","webview:allow-webview-close","dialog:allow-open","dialog:allow-ask","dialog:allow-message","process:allow-restart","fs:allow-read-file","shell:allow-open",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}} {"desktop-capability":{"identifier":"desktop-capability","description":"Capability for the desktop","local":true,"windows":["main","splash","settings","search","nwc","activity","zap-*","event-*","user-*","editor-*","column-*"],"permissions":["path:default","event:default","window:default","app:default","resources:default","menu:default","tray:default","notification:allow-is-permission-granted","notification:allow-request-permission","notification:default","os:allow-locale","os:allow-platform","os:allow-os-type","updater:default","updater:allow-check","updater:allow-download-and-install","window:allow-start-dragging","window:allow-create","window:allow-close","window:allow-set-focus","window:allow-center","window:allow-minimize","window:allow-maximize","window:allow-set-size","window:allow-set-focus","window:allow-start-dragging","decorum:allow-show-snap-overlay","clipboard-manager:allow-write-text","clipboard-manager:allow-read-text","webview:allow-create-webview-window","webview:allow-create-webview","webview:allow-set-webview-size","webview:allow-set-webview-position","webview:allow-webview-close","dialog:allow-open","dialog:allow-ask","dialog:allow-message","process:allow-restart","fs:allow-read-file","theme:allow-set-theme","theme:allow-get-theme","shell:allow-open",{"identifier":"http:default","allow":[{"url":"http://**/"},{"url":"https://**/"}]},{"identifier":"fs:allow-read-text-file","allow":[{"path":"$RESOURCE/locales/*"},{"path":"$RESOURCE/resources/*"}]}],"platforms":["linux","macOS","windows"]}}

View File

@ -5654,6 +5654,40 @@
"shell:deny-stdin-write" "shell:deny-stdin-write"
] ]
}, },
{
"type": "string",
"enum": [
"theme:default"
]
},
{
"description": "theme:allow-get-theme -> Enables the get_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:allow-get-theme"
]
},
{
"description": "theme:allow-set-theme -> Enables the set_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:allow-set-theme"
]
},
{
"description": "theme:deny-get-theme -> Denies the get_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:deny-get-theme"
]
},
{
"description": "theme:deny-set-theme -> Denies the set_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:deny-set-theme"
]
},
{ {
"description": "tray:default -> Default permissions for the plugin.", "description": "tray:default -> Default permissions for the plugin.",
"type": "string", "type": "string",

View File

@ -5654,6 +5654,40 @@
"shell:deny-stdin-write" "shell:deny-stdin-write"
] ]
}, },
{
"type": "string",
"enum": [
"theme:default"
]
},
{
"description": "theme:allow-get-theme -> Enables the get_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:allow-get-theme"
]
},
{
"description": "theme:allow-set-theme -> Enables the set_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:allow-set-theme"
]
},
{
"description": "theme:deny-get-theme -> Denies the get_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:deny-get-theme"
]
},
{
"description": "theme:deny-set-theme -> Denies the set_theme command without any pre-configured scope.",
"type": "string",
"enum": [
"theme:deny-set-theme"
]
},
{ {
"description": "tray:default -> Default permissions for the plugin.", "description": "tray:default -> Default permissions for the plugin.",
"type": "string", "type": "string",

View File

@ -24,6 +24,7 @@ pub struct Nostr {
} }
fn main() { fn main() {
let mut ctx = tauri::generate_context!();
let invoke_handler = { let invoke_handler = {
let builder = tauri_specta::ts::builder().commands(tauri_specta::collect_commands![ let builder = tauri_specta::ts::builder().commands(tauri_specta::collect_commands![
nostr::relay::get_relays, nostr::relay::get_relays,
@ -135,13 +136,7 @@ fn main() {
Ok(()) Ok(())
}) })
.on_window_event(|window, event| match event { .plugin(tauri_plugin_theme::init(ctx.config_mut()))
tauri::WindowEvent::CloseRequested { api, .. } => {
window.hide().unwrap();
api.prevent_close();
}
_ => {}
})
.plugin(tauri_plugin_decorum::init()) .plugin(tauri_plugin_decorum::init())
.plugin(tauri_plugin_clipboard_manager::init()) .plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_dialog::init())
@ -154,6 +149,6 @@ fn main() {
.plugin(tauri_plugin_upload::init()) .plugin(tauri_plugin_upload::init())
.plugin(tauri_plugin_updater::Builder::new().build()) .plugin(tauri_plugin_updater::Builder::new().build())
.invoke_handler(invoke_handler) .invoke_handler(invoke_handler)
.run(tauri::generate_context!()) .run(ctx)
.expect("error while running tauri application") .expect("error while running tauri application")
} }