diff --git a/src/components/Toaster.svelte b/src/components/Toaster.svelte new file mode 100644 index 0000000..90c08fd --- /dev/null +++ b/src/components/Toaster.svelte @@ -0,0 +1,51 @@ + + +
+ {#each $toasts as { id, data } (id)} +
+
+
+ {data.message} +
+ +
+
+ {/each} +
diff --git a/src/lib/fetch.ts b/src/lib/browserFetch.ts similarity index 73% rename from src/lib/fetch.ts rename to src/lib/browserFetch.ts index e76b05d..a395773 100644 --- a/src/lib/fetch.ts +++ b/src/lib/browserFetch.ts @@ -1,15 +1,10 @@ -export enum MaybeType { - Ok = 'ok', - Error = 'error' -} - interface Some { - type: MaybeType.Ok; + type: 'ok'; value: T; } interface None { - type: MaybeType.Error; + type: 'error'; value: Error; } @@ -17,20 +12,19 @@ export type Maybe = Some | None; export function some(value: T): Some { return { - type: MaybeType.Ok, + type: 'ok', value }; } export function none(message: string): None { return { - type: MaybeType.Error, + type: 'error', value: new Error(message) }; } interface FetchOptions { - getBearerToken?: () => Promise; shouldParse?: boolean; } @@ -40,14 +34,11 @@ export async function tryFetch( options?: FetchOptions ): Promise> { try { - const token = options?.getBearerToken ? await options.getBearerToken() : null; - const response = await fetch(input, { ...init, headers: { ...init?.headers, - 'Content-Type': 'application/json', - ...(token ? { Authorization: `Bearer ${token}` } : {}) + 'Content-Type': 'application/json' } }); @@ -63,6 +54,7 @@ export async function tryFetch( const rawText = await response.text(); return none(rawText); } catch (error: unknown) { + console.error('Failed to fetch', error); if (error instanceof Error) { return none(error.message); } diff --git a/src/lib/icons.ts b/src/lib/icons.ts index d1e15be..3eb5959 100644 --- a/src/lib/icons.ts +++ b/src/lib/icons.ts @@ -48,5 +48,11 @@ export const icons = { }, users: { path: 'M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z' + }, + 'x-circle': { + path: 'm9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z' + }, + 'x-mark': { + path: 'M6 18 18 6M6 6l12 12' } }; diff --git a/src/lib/state/toastMessages.svelte.ts b/src/lib/state/toastMessages.svelte.ts new file mode 100644 index 0000000..92356e1 --- /dev/null +++ b/src/lib/state/toastMessages.svelte.ts @@ -0,0 +1,32 @@ +import { getContext, setContext } from 'svelte'; +import { nanoid } from 'nanoid'; + +import { type ToastMessage } from '$lib/types'; + +type ToastMessageWithId = ToastMessage & { id: string; isShown: boolean }; + +export class ToastMessages { + messages: ToastMessageWithId[] = $state([]); + + constructor() {} + + addMessage(message: ToastMessage) { + const id = nanoid(); + + this.messages.push({ + ...message, + id, + isShown: false + }); + } +} + +const ToastMessagesKey = Symbol('ToastMessages'); + +export function setToastMessages() { + return setContext(ToastMessagesKey, new ToastMessages()); +} + +export function getToastMessages() { + return getContext>(ToastMessagesKey); +} diff --git a/src/lib/types.ts b/src/lib/types.ts index 85af10a..a22ace6 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -174,3 +174,8 @@ export type ToggleFriendShare = { noteId: string; selected: boolean; }; + +export type ToastMessage = { + message: string; + type: 'success' | 'error'; +}; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index bf83302..cbd414a 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,9 +1,13 @@ + {@render children()} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index b54dc87..2b3baa8 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -60,7 +60,7 @@