diff options
Diffstat (limited to 'src/lib/CommandPalette')
| -rw-r--r-- | src/lib/CommandPalette/authActions.ts | 48 | ||||
| -rw-r--r-- | src/lib/CommandPalette/syncActions.ts | 106 | ||||
| -rw-r--r-- | src/lib/CommandPalette/toggleActions.ts | 160 |
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), + }, + ]; +}; |