aboutsummaryrefslogtreecommitdiff
path: root/src/lib/CommandPalette
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/CommandPalette')
-rw-r--r--src/lib/CommandPalette/authActions.ts48
-rw-r--r--src/lib/CommandPalette/syncActions.ts106
-rw-r--r--src/lib/CommandPalette/toggleActions.ts160
3 files changed, 314 insertions, 0 deletions
diff --git a/src/lib/CommandPalette/authActions.ts b/src/lib/CommandPalette/authActions.ts
new file mode 100644
index 00000000..c306eb34
--- /dev/null
+++ b/src/lib/CommandPalette/authActions.ts
@@ -0,0 +1,48 @@
+import { env } from "$env/dynamic/public";
+import root from "$lib/Utility/root";
+import localforage from "localforage";
+import type { CommandPaletteAction } from "./actions";
+
+export const authActions = (
+ user: string | undefined,
+): CommandPaletteAction[] => {
+ if (user)
+ return [
+ {
+ name: "Log Out",
+ url: "#",
+ preventDefault: true,
+ tags: ["auth", "sign", "out", "user"],
+ onClick: async () => {
+ await localforage.removeItem("identity");
+ await localforage.removeItem("commit");
+
+ document.cookie =
+ "user=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
+
+ window.location.href = root("/api/authentication/log-out");
+ },
+ },
+ ];
+
+ const loginUrl = `https://anilist.co/api/v2/oauth/authorize?client_id=${env.PUBLIC_ANILIST_CLIENT_ID}&redirect_uri=${env.PUBLIC_ANILIST_REDIRECT_URI}&response_type=code`;
+
+ return [
+ {
+ name: "Log In",
+ url: loginUrl,
+ preventDefault: true,
+ tags: ["auth", "sign", "in", "anilist"],
+ onClick: async () => {
+ await localforage.setItem(
+ "redirect",
+ window.location.origin +
+ window.location.pathname +
+ window.location.search,
+ );
+
+ window.location.href = loginUrl;
+ },
+ },
+ ];
+};
diff --git a/src/lib/CommandPalette/syncActions.ts b/src/lib/CommandPalette/syncActions.ts
new file mode 100644
index 00000000..c787f348
--- /dev/null
+++ b/src/lib/CommandPalette/syncActions.ts
@@ -0,0 +1,106 @@
+import { addNotification } from "$lib/Notification/store";
+import { options } from "$lib/Notification/options";
+import root from "$lib/Utility/root";
+import settings from "$stores/settings";
+import settingsSyncPulled from "$stores/settingsSyncPulled";
+import settingsSyncTimes from "$stores/settingsSyncTimes";
+import { get } from "svelte/store";
+import type { CommandPaletteAction } from "./actions";
+
+export const syncActions = (
+ identityId: number,
+ syncEnabled: boolean,
+): CommandPaletteAction[] => {
+ if (identityId <= 0) return [];
+
+ const actions: CommandPaletteAction[] = [
+ {
+ name: "Push Settings Now",
+ url: "#",
+ preventDefault: true,
+ tags: ["settings", "sync", "push", "upload", "remote"],
+ onClick: () => {
+ settings.setKey("settingsSync", true);
+
+ fetch(root(`/api/configuration`), {
+ method: "PUT",
+ body: JSON.stringify(get(settings)),
+ })
+ .then((response) => {
+ if (!response.ok) return;
+
+ addNotification(
+ options({
+ heading: "Settings Sync",
+ description: "Pushed local configuration to remote",
+ }),
+ );
+
+ settingsSyncTimes.update((times) => ({
+ ...times,
+ lastPush: new Date(),
+ }));
+ })
+ .catch((error) =>
+ console.error("Settings sync push failed", error),
+ );
+ },
+ },
+ {
+ name: "Pull Settings Now",
+ url: "#",
+ preventDefault: true,
+ tags: ["settings", "sync", "pull", "download", "remote"],
+ onClick: () => {
+ settings.setKey("settingsSync", true);
+
+ fetch(root(`/api/configuration?id=${identityId}`))
+ .then((response) => {
+ if (!response.ok) return;
+
+ return response.json().then((data) => {
+ if (!data?.configuration) {
+ addNotification(
+ options({
+ heading: "Settings Sync",
+ description: "No remote configuration found",
+ }),
+ );
+
+ return;
+ }
+
+ settings.set(data.configuration);
+ settingsSyncPulled.set(true);
+ settingsSyncTimes.set({
+ lastPull: new Date(),
+ lastPush: new Date(`${data.updated_at}Z`),
+ });
+
+ addNotification(
+ options({ heading: "Pulled remote configuration" }),
+ );
+ });
+ })
+ .catch((error) =>
+ console.error("Settings sync pull failed", error),
+ );
+ },
+ },
+ ];
+
+ if (syncEnabled)
+ actions.push({
+ name: "Disable Settings Sync",
+ url: "#",
+ preventDefault: true,
+ tags: ["settings", "sync", "disable", "off", "stop"],
+ onClick: () => {
+ settings.setKey("settingsSync", false);
+
+ addNotification(options({ heading: "Settings sync disabled" }));
+ },
+ });
+
+ return actions;
+};
diff --git a/src/lib/CommandPalette/toggleActions.ts b/src/lib/CommandPalette/toggleActions.ts
new file mode 100644
index 00000000..b93b5626
--- /dev/null
+++ b/src/lib/CommandPalette/toggleActions.ts
@@ -0,0 +1,160 @@
+import settings, { type Settings } from "$stores/settings";
+import type { CommandPaletteAction } from "./actions";
+
+const TITLE_FORMATS: Settings["displayTitleFormat"][] = [
+ "english",
+ "romaji",
+ "native",
+];
+
+const OUTBOUND_TARGETS: Settings["displayOutboundLinksTo"][] = [
+ "anilist",
+ "livechartme",
+ "animeschedule",
+ "myanimelist",
+];
+
+const OUTBOUND_LABELS: Record<Settings["displayOutboundLinksTo"], string> = {
+ anilist: "AniList",
+ livechartme: "LiveChart",
+ animeschedule: "AnimeSchedule",
+ myanimelist: "MyAnimeList",
+};
+
+type BooleanKey = NonNullable<
+ {
+ [K in keyof Settings]: Settings[K] extends boolean ? K : never;
+ }[keyof Settings]
+>;
+
+const boolToggle = (
+ current: boolean,
+ key: BooleanKey,
+ enableLabel: string,
+ disableLabel: string,
+ tags: string[],
+): CommandPaletteAction => ({
+ name: current ? disableLabel : enableLabel,
+ url: "#",
+ preventDefault: true,
+ tags,
+ onClick: () => settings.setKey(key, !current),
+});
+
+export const toggleActions = (current: Settings): CommandPaletteAction[] => {
+ const titleIndex = TITLE_FORMATS.indexOf(current.displayTitleFormat);
+ const nextTitle = TITLE_FORMATS[(titleIndex + 1) % TITLE_FORMATS.length];
+
+ const outboundIndex = OUTBOUND_TARGETS.indexOf(current.displayOutboundLinksTo);
+ const nextOutbound =
+ OUTBOUND_TARGETS[(outboundIndex + 1) % OUTBOUND_TARGETS.length];
+
+ return [
+ boolToggle(
+ current.display24HourTime,
+ "display24HourTime",
+ "Switch to 24-hour time",
+ "Switch to 12-hour time",
+ ["time", "clock", "24h", "12h", "format"],
+ ),
+ boolToggle(
+ current.displayDisableAnimations,
+ "displayDisableAnimations",
+ "Disable animations",
+ "Enable animations",
+ ["motion", "animation", "accessibility"],
+ ),
+ boolToggle(
+ current.displayBlurAdultContent,
+ "displayBlurAdultContent",
+ "Blur adult content",
+ "Show adult content unblurred",
+ ["nsfw", "adult", "blur", "censor"],
+ ),
+ boolToggle(
+ current.displayCoverModeAnime,
+ "displayCoverModeAnime",
+ "Show anime covers",
+ "Hide anime covers",
+ ["cover", "image", "anime", "display"],
+ ),
+ boolToggle(
+ current.displayCoverModeManga,
+ "displayCoverModeManga",
+ "Show manga covers",
+ "Hide manga covers",
+ ["cover", "image", "manga", "novels", "display"],
+ ),
+ boolToggle(
+ current.displayHoverCover,
+ "displayHoverCover",
+ "Enable hover cover preview",
+ "Disable hover cover preview",
+ ["cover", "hover", "preview"],
+ ),
+ boolToggle(
+ current.displayScheduleListMode,
+ "displayScheduleListMode",
+ "Schedule: list mode",
+ "Schedule: grid mode",
+ ["schedule", "list", "grid", "view"],
+ ),
+ boolToggle(
+ current.displayReverseSort,
+ "displayReverseSort",
+ "Reverse sort order",
+ "Restore default sort order",
+ ["sort", "reverse", "order"],
+ ),
+ boolToggle(
+ current.displayDataSaver,
+ "displayDataSaver",
+ "Enable data saver",
+ "Disable data saver",
+ ["data", "bandwidth", "saver", "performance"],
+ ),
+ boolToggle(
+ current.displayDisableNotifications,
+ "displayDisableNotifications",
+ "Disable in-app notifications",
+ "Enable in-app notifications",
+ ["notifications", "alerts", "toast"],
+ ),
+ {
+ name:
+ current.displayLanguage === "en"
+ ? "Switch language to 日本語"
+ : "Switch language to English",
+ url: "#",
+ preventDefault: true,
+ tags: ["language", "locale", "translate", "japanese", "english"],
+ onClick: () =>
+ settings.setKey(
+ "displayLanguage",
+ current.displayLanguage === "en" ? "ja" : "en",
+ ),
+ },
+ {
+ name: `Title format: ${current.displayTitleFormat} → ${nextTitle}`,
+ url: "#",
+ preventDefault: true,
+ tags: ["title", "format", "english", "romaji", "native"],
+ onClick: () => settings.setKey("displayTitleFormat", nextTitle),
+ },
+ {
+ name: `Outbound links: ${OUTBOUND_LABELS[current.displayOutboundLinksTo]} → ${OUTBOUND_LABELS[nextOutbound]}`,
+ url: "#",
+ preventDefault: true,
+ tags: [
+ "outbound",
+ "links",
+ "anilist",
+ "livechart",
+ "animeschedule",
+ "myanimelist",
+ "mal",
+ ],
+ onClick: () => settings.setKey("displayOutboundLinksTo", nextOutbound),
+ },
+ ];
+};