mirror of
https://github.com/open-goal/launcher.git
synced 2024-10-19 14:47:36 -04:00
Toast updates (#405)
Toast improvements: - Icon and color based on toast level (info, warn, error) - Animates out - Made it a component, removing logic from `app.svelte` - handles multiple toast messages better using a queue Sidebar styling logic: This was kinda gross so I revised it a bit. I'm considering doing an overhaul of the sidebar in the future.
This commit is contained in:
parent
d85a4af9fa
commit
0cfbd3609a
|
@ -8,11 +8,9 @@
|
|||
import Background from "./components/background/Background.svelte";
|
||||
import Header from "./components/header/Header.svelte";
|
||||
import Update from "./routes/Update.svelte";
|
||||
import GameInProgress from "./components/games/GameInProgress.svelte";
|
||||
import { isInDebugMode } from "$lib/utils/common";
|
||||
import { Toast } from "flowbite-svelte";
|
||||
import Toast from "./components/toast/Toast.svelte";
|
||||
import Help from "./routes/Help.svelte";
|
||||
import { toastStore } from "$lib/stores/ToastStore";
|
||||
import { isLoading } from "svelte-i18n";
|
||||
import { getLocale, setLocale } from "$lib/rpc/config";
|
||||
import GameFeature from "./routes/GameFeature.svelte";
|
||||
|
@ -95,16 +93,7 @@
|
|||
<Route path="/update" component={Update} primary={false} />
|
||||
</div>
|
||||
</div>
|
||||
{#if $toastStore.msg !== undefined}
|
||||
<!-- TODO - make these look nice for info/warn/error levels -->
|
||||
<Toast
|
||||
color="green"
|
||||
position="top-right"
|
||||
class="w-full max-w-xs p-2 pl-4 z-50 top-20"
|
||||
>
|
||||
{$toastStore.msg}
|
||||
</Toast>
|
||||
{/if}
|
||||
<Toast />
|
||||
{/if}
|
||||
</div>
|
||||
</Router>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import { VersionStore } from "$lib/stores/VersionStore";
|
||||
import { exceptionLog, infoLog } from "$lib/rpc/logging";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { toastStore } from "$lib/stores/ToastStore";
|
||||
|
||||
let launcherVerison = null;
|
||||
|
||||
|
@ -53,6 +54,7 @@
|
|||
changeLog: changeLog,
|
||||
};
|
||||
infoLog(`Launcher Update Available`);
|
||||
toastStore.makeToast("Launcher update available!", "info");
|
||||
} else {
|
||||
$UpdateStore.launcher = {
|
||||
updateAvailable: false,
|
||||
|
|
|
@ -12,37 +12,24 @@
|
|||
$: $location.pathname;
|
||||
|
||||
function getNavStyle(pathname: string): string {
|
||||
let style = "grow-0 shrink-0 basis-1/10 h-full bg-[#101010] px-1 z-10";
|
||||
if (
|
||||
!pathname.startsWith("/settings") &&
|
||||
!pathname.startsWith("/faq") &&
|
||||
!pathname.startsWith("/update")
|
||||
) {
|
||||
style += " opacity-50 hover:opacity-100 duration-500";
|
||||
}
|
||||
return style;
|
||||
const baseStyle =
|
||||
"grow-0 shrink-0 basis-1/10 h-full bg-[#101010] px-1 z-10";
|
||||
const isOpaque =
|
||||
pathname.startsWith("/settings") ||
|
||||
pathname.startsWith("/faq") ||
|
||||
pathname.startsWith("/update");
|
||||
return isOpaque
|
||||
? baseStyle
|
||||
: `${baseStyle} opacity-50 hover:opacity-100 duration-500`;
|
||||
}
|
||||
|
||||
function getNavItemStyle(itemName: string, pathName: string): string {
|
||||
let style =
|
||||
"flex items-center hover:grayscale-0 hover:opacity-100 duration-500 text-orange-400 duration-500";
|
||||
if (
|
||||
itemName === "jak1" &&
|
||||
(pathName.startsWith("/jak1") || pathName === "/")
|
||||
) {
|
||||
return style;
|
||||
} else if (itemName === "jak2" && pathName.startsWith("/jak2")) {
|
||||
return style;
|
||||
} else if (itemName === "jak3" && pathName.startsWith("/jak3")) {
|
||||
return style;
|
||||
} else if (itemName === "jakx" && pathName.startsWith("/jakx")) {
|
||||
return style;
|
||||
} else if (itemName === "settings" && pathName.startsWith("/settings")) {
|
||||
return style;
|
||||
} else if (itemName === "faq" && pathName === "/faq") {
|
||||
return style;
|
||||
}
|
||||
return style + " grayscale";
|
||||
const baseStyle =
|
||||
"flex items-center hover:grayscale-0 hover:opacity-100 duration-500 text-orange-400";
|
||||
const isActive =
|
||||
pathName.startsWith(`/${itemName}`) ||
|
||||
(itemName === "jak1" && pathName === "/");
|
||||
return isActive ? baseStyle : `${baseStyle} grayscale`;
|
||||
}
|
||||
|
||||
function modifyGameTitleName(gameName: string): string {
|
||||
|
|
50
src/components/toast/Toast.svelte
Normal file
50
src/components/toast/Toast.svelte
Normal file
|
@ -0,0 +1,50 @@
|
|||
<script>
|
||||
import { Toast } from "flowbite-svelte";
|
||||
import { toastStore } from "$lib/stores/ToastStore";
|
||||
import { fly } from "svelte/transition";
|
||||
import IconCheck from "~icons/mdi/check";
|
||||
import IconAlert from "~icons/mdi/stop-alert";
|
||||
import IconAlertCircle from "~icons/mdi/alert-circle";
|
||||
|
||||
let open = false;
|
||||
let counter;
|
||||
let currentToast = null;
|
||||
|
||||
$: if ($toastStore.length > 0 && !currentToast) {
|
||||
currentToast = $toastStore[0];
|
||||
open = true;
|
||||
counter = 6;
|
||||
timeout();
|
||||
}
|
||||
|
||||
function timeout() {
|
||||
if (--counter > 0) return setTimeout(timeout, 1000);
|
||||
open = false;
|
||||
toastStore.removeToast();
|
||||
currentToast = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if currentToast}
|
||||
<Toast
|
||||
{open}
|
||||
dismissable={false}
|
||||
position="top-right"
|
||||
class="z-50 top-20"
|
||||
transition={fly}
|
||||
params={{ y: 200 }}
|
||||
>
|
||||
<svelte:fragment slot="icon">
|
||||
{#if currentToast.level == "info"}
|
||||
<IconCheck class="text-green-500 text-5xl" />
|
||||
{:else if currentToast.level == "warn"}
|
||||
<IconAlertCircle class="text-orange-500 text-5xl" />
|
||||
{:else if currentToast.level == "error"}
|
||||
<IconAlert class="text-red-500 text-5xl" />
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<div class="ps-4 text-sm font-semibold">
|
||||
{currentToast.msg}
|
||||
</div>
|
||||
</Toast>
|
||||
{/if}
|
|
@ -1,6 +1,6 @@
|
|||
import { toastStore } from "$lib/stores/ToastStore";
|
||||
import { invoke_rpc } from "./rpc";
|
||||
|
||||
// TODO - toasts
|
||||
// TODO - just make this a generic interface for both binaries/feature jobs
|
||||
interface FeatureJobOutput {
|
||||
msg: string | null;
|
||||
|
@ -8,6 +8,7 @@ interface FeatureJobOutput {
|
|||
}
|
||||
|
||||
function failed(msg: string): FeatureJobOutput {
|
||||
toastStore.makeToast(msg, "error");
|
||||
return { success: false, msg };
|
||||
}
|
||||
|
||||
|
|
|
@ -2,43 +2,28 @@ import { writable } from "svelte/store";
|
|||
|
||||
export type ToastLevel = "error" | "warn" | "info" | undefined;
|
||||
|
||||
interface ToastStore {
|
||||
msg: string | undefined;
|
||||
interface ToastMessage {
|
||||
msg: string;
|
||||
level: ToastLevel;
|
||||
interval: any;
|
||||
interval?: any;
|
||||
}
|
||||
|
||||
const storeValue: ToastStore = {
|
||||
msg: undefined,
|
||||
level: undefined,
|
||||
interval: undefined,
|
||||
};
|
||||
type ToastArray = ToastMessage[];
|
||||
const messageArray: ToastArray = [];
|
||||
|
||||
function createToastStore() {
|
||||
// TODO - the TTL isn't correct still, look into it
|
||||
const { subscribe, set, update } = writable<ToastStore>(storeValue);
|
||||
|
||||
const ttl = 5000;
|
||||
let timeoutId: NodeJS.Timer;
|
||||
|
||||
function ttlCheck() {
|
||||
return setTimeout(() => {
|
||||
update((val) => {
|
||||
val.msg = undefined;
|
||||
val.level = undefined;
|
||||
timeoutId = undefined;
|
||||
return val;
|
||||
});
|
||||
}, ttl);
|
||||
}
|
||||
const { subscribe, update } = writable<ToastArray>(messageArray);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
removeToast: () =>
|
||||
update((val) => {
|
||||
val = val.slice(1);
|
||||
return val;
|
||||
}),
|
||||
makeToast: (msg: string, level: ToastLevel) =>
|
||||
update((val) => {
|
||||
val.msg = msg;
|
||||
val.level = level;
|
||||
timeoutId = ttlCheck();
|
||||
val.push({ msg, level });
|
||||
return val;
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import { VersionStore } from "$lib/stores/VersionStore";
|
||||
import { saveActiveVersionChange } from "$lib/rpc/config";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { toastStore } from "$lib/stores/ToastStore";
|
||||
|
||||
let versionsLoaded = false;
|
||||
|
||||
|
@ -61,6 +62,7 @@
|
|||
$VersionStore.activeVersionName = $VersionStore.selectedVersions.devel;
|
||||
$VersionStore.selectedVersions.official = null;
|
||||
$VersionStore.selectedVersions.unofficial = null;
|
||||
toastStore.makeToast("Saved game version!", "info");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import { VersionStore } from "$lib/stores/VersionStore";
|
||||
import { saveActiveVersionChange } from "$lib/rpc/config";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { toastStore } from "$lib/stores/ToastStore";
|
||||
|
||||
let versionsLoaded = false;
|
||||
|
||||
|
@ -64,6 +65,7 @@
|
|||
$VersionStore.selectedVersions.unofficial;
|
||||
$VersionStore.selectedVersions.official = null;
|
||||
$VersionStore.selectedVersions.devel = null;
|
||||
toastStore.makeToast("Saved game version!", "info");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue