Updating dependencies, upgrade latest svelte 5, and updating to use svelte 5 in most places.

This commit is contained in:
Bradley Shellnut 2024-07-06 23:12:36 -07:00
parent 8c47357605
commit 63ac7dfd76
22 changed files with 1000 additions and 1145 deletions

View file

@ -23,48 +23,48 @@
"devDependencies": { "devDependencies": {
"@melt-ui/pp": "^0.3.2", "@melt-ui/pp": "^0.3.2",
"@melt-ui/svelte": "^0.81.0", "@melt-ui/svelte": "^0.81.0",
"@playwright/test": "^1.44.1", "@playwright/test": "^1.45.1",
"@resvg/resvg-js": "^2.6.2", "@resvg/resvg-js": "^2.6.2",
"@sveltejs/adapter-auto": "^3.2.2", "@sveltejs/adapter-auto": "^3.2.2",
"@sveltejs/enhanced-img": "^0.2.1", "@sveltejs/enhanced-img": "^0.2.1",
"@sveltejs/kit": "^2.5.14", "@sveltejs/kit": "^2.5.18",
"@sveltejs/vite-plugin-svelte": "^3.1.1", "@sveltejs/vite-plugin-svelte": "^3.1.1",
"@types/cookie": "^0.6.0", "@types/cookie": "^0.6.0",
"@types/node": "^20.14.2", "@types/node": "^20.14.10",
"@types/pg": "^8.11.6", "@types/pg": "^8.11.6",
"@typescript-eslint/eslint-plugin": "^7.12.0", "@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.12.0", "@typescript-eslint/parser": "^7.13.0",
"autoprefixer": "^10.4.19", "autoprefixer": "^10.4.19",
"drizzle-kit": "^0.22.7", "drizzle-kit": "^0.22.8",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.39.3", "eslint-plugin-svelte": "^2.41.0",
"just-clone": "^6.2.0", "just-clone": "^6.2.0",
"just-debounce-it": "^3.2.0", "just-debounce-it": "^3.2.0",
"postcss": "^8.4.38", "postcss": "^8.4.39",
"postcss-import": "^16.1.0", "postcss-import": "^16.1.0",
"postcss-load-config": "^5.1.0", "postcss-load-config": "^5.1.0",
"postcss-preset-env": "^9.5.14", "postcss-preset-env": "^9.5.16",
"prettier": "^3.3.2", "prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.4", "prettier-plugin-svelte": "^3.2.5",
"sass": "^1.77.5", "sass": "^1.77.6",
"satori": "^0.10.13", "satori": "^0.10.13",
"satori-html": "^0.3.2", "satori-html": "^0.3.2",
"svelte": "^4.2.18", "svelte": "5.0.0-next.175",
"svelte-check": "^3.8.0", "svelte-check": "^3.8.4",
"svelte-headless-table": "^0.18.2", "svelte-headless-table": "^0.18.2",
"svelte-meta-tags": "^3.1.2", "svelte-meta-tags": "^3.1.2",
"svelte-preprocess": "^5.1.4", "svelte-preprocess": "^5.1.4",
"svelte-sequential-preprocessor": "^2.0.1", "svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.4.4", "sveltekit-flash-message": "^2.4.4",
"sveltekit-rate-limiter": "^0.5.1", "sveltekit-rate-limiter": "^0.5.1",
"sveltekit-superforms": "^2.15.1", "sveltekit-superforms": "^2.15.2",
"tailwindcss": "^3.4.4", "tailwindcss": "^3.4.4",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tslib": "^2.6.3", "tslib": "^2.6.3",
"tsx": "^4.15.4", "tsx": "^4.16.2",
"typescript": "^5.4.5", "typescript": "^5.5.3",
"vite": "^5.3.1", "vite": "^5.3.3",
"vitest": "^1.6.0", "vitest": "^1.6.0",
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
@ -79,12 +79,12 @@
"@iconify-icons/mdi": "^1.2.48", "@iconify-icons/mdi": "^1.2.48",
"@lucia-auth/adapter-drizzle": "^1.0.7", "@lucia-auth/adapter-drizzle": "^1.0.7",
"@lukeed/uuid": "^2.0.1", "@lukeed/uuid": "^2.0.1",
"@neondatabase/serverless": "^0.9.3", "@neondatabase/serverless": "^0.9.4",
"@paralleldrive/cuid2": "^2.2.2", "@paralleldrive/cuid2": "^2.2.2",
"@sveltejs/adapter-vercel": "^5.3.2", "@sveltejs/adapter-vercel": "^5.4.1",
"@types/feather-icons": "^4.29.4", "@types/feather-icons": "^4.29.4",
"@vercel/og": "^0.5.20", "@vercel/og": "^0.5.20",
"bits-ui": "^0.21.10", "bits-ui": "^0.21.11",
"boardgamegeekclient": "^1.9.1", "boardgamegeekclient": "^1.9.1",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
@ -93,7 +93,7 @@
"dotenv-expand": "^11.0.6", "dotenv-expand": "^11.0.6",
"drizzle-orm": "^0.31.2", "drizzle-orm": "^0.31.2",
"feather-icons": "^4.29.2", "feather-icons": "^4.29.2",
"formsnap": "^1.0.0", "formsnap": "^1.0.1",
"html-entities": "^2.5.2", "html-entities": "^2.5.2",
"iconify-icon": "^2.1.0", "iconify-icon": "^2.1.0",
"just-capitalize": "^3.2.0", "just-capitalize": "^3.2.0",
@ -101,8 +101,8 @@
"loader": "^2.1.1", "loader": "^2.1.1",
"lucia": "3.2.0", "lucia": "3.2.0",
"lucide-svelte": "^0.390.0", "lucide-svelte": "^0.390.0",
"open-props": "^1.7.4", "open-props": "^1.7.5",
"oslo": "^1.2.0", "oslo": "^1.2.1",
"pg": "^8.12.0", "pg": "^8.12.0",
"postgres": "^3.4.4", "postgres": "^3.4.4",
"qrcode": "^1.5.3", "qrcode": "^1.5.3",
@ -112,6 +112,6 @@
"tailwind-merge": "^2.3.0", "tailwind-merge": "^2.3.0",
"tailwind-variants": "^0.2.1", "tailwind-variants": "^0.2.1",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"zod-to-json-schema": "^3.23.0" "zod-to-json-schema": "^3.23.1"
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -41,6 +41,16 @@ export default async function seed(db: db) {
console.log('Admin user created.', adminUser); console.log('Admin user created.', adminUser);
await db
.insert(schema.collections)
.values({ user_id: adminUser[0].id })
.onConflictDoNothing();
await db
.insert(schema.wishlists)
.values({ user_id: adminUser[0].id })
.onConflictDoNothing();
await db await db
.insert(schema.userRoles) .insert(schema.userRoles)
.values({ .values({

View file

@ -1,4 +1,6 @@
<script lang="ts"> <script lang="ts">
const { children } = $props();
function portal(node: HTMLElement) { function portal(node: HTMLElement) {
let target; let target;
@ -25,5 +27,5 @@
</script> </script>
<div use:portal hidden> <div use:portal hidden>
<slot /> {@render children()}
</div> </div>

View file

@ -1,112 +1,112 @@
<script> <script>
/** /**
* @event {boolean} check * @event {boolean} check
*/ */
/** /**
* Specify the value of the checkbox * Specify the value of the checkbox
* @type {any} * @type {any}
*/ */
export let value = ''; export let value = '';
/** Specify whether the checkbox is checked */ /** Specify whether the checkbox is checked */
export let checked = false; export let checked = false;
/** /**
* Specify the bound group * Specify the bound group
* @type {any[]} * @type {any[]}
*/ */
export let group = undefined; export let group = undefined;
/** Specify whether the checkbox is indeterminate */ /** Specify whether the checkbox is indeterminate */
export let indeterminate = false; export let indeterminate = false;
/** Set to `true` to display the skeleton state */ /** Set to `true` to display the skeleton state */
export let skeleton = false; export let skeleton = false;
/** Set to `true` to mark the field as required */ /** Set to `true` to mark the field as required */
export let required = false; export let required = false;
/** Set to `true` for the checkbox to be read-only */ /** Set to `true` for the checkbox to be read-only */
export let readonly = false; export let readonly = false;
/** Set to `true` to disable the checkbox */ /** Set to `true` to disable the checkbox */
export let disabled = false; export let disabled = false;
/** Specify the label text */ /** Specify the label text */
export let labelText = ''; export let labelText = '';
/** Set to `true` to visually hide the label text */ /** Set to `true` to visually hide the label text */
export let hideLabel = false; export let hideLabel = false;
/** Set a name for the input element */ /** Set a name for the input element */
export let name = ''; export let name = '';
/** /**
* Specify the title attribute for the label element * Specify the title attribute for the label element
* @type {string} * @type {string}
*/ */
export let title = undefined; export let title = undefined;
/** Set an id for the input label */ /** Set an id for the input label */
export let id = 'ccs-' + Math.random().toString(36); export let id = 'ccs-' + Math.random().toString(36);
/** Obtain a reference to the input HTML element */ /** Obtain a reference to the input HTML element */
export let ref = null; export let ref = null;
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import CheckboxSkeleton from './CheckboxSkeleton.svelte'; import CheckboxSkeleton from './CheckboxSkeleton.svelte';
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
$: useGroup = Array.isArray(group); $: useGroup = Array.isArray(group);
$: checked = useGroup ? group.includes(value) : checked; $: checked = useGroup ? group.includes(value) : checked;
$: dispatch('check', checked); $: dispatch('check', checked);
</script> </script>
<!-- svelte-ignore a11y-mouse-events-have-key-events --> <!-- svelte-ignore a11y-mouse-events-have-key-events -->
{#if skeleton} {#if skeleton}
<CheckboxSkeleton {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave /> <CheckboxSkeleton {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave />
{:else} {:else}
<div <div
class:bx--form-item={true} class:bx--form-item={true}
class:bx--checkbox-wrapper={true} class:bx--checkbox-wrapper={true}
{...$$restProps} {...$$restProps}
on:click on:click
on:mouseover on:mouseover
on:mouseenter on:mouseenter
on:mouseleave on:mouseleave
> >
<input <input
bind:this={ref} bind:this={ref}
type="checkbox" type="checkbox"
{value} {value}
{checked} {checked}
{disabled} {disabled}
{id} {id}
{indeterminate} {indeterminate}
{name} {name}
{required} {required}
{readonly} {readonly}
class:bx--checkbox={true} class:bx--checkbox={true}
on:change={() => { on:change={() => {
if (useGroup) { if (useGroup) {
group = group.includes(value) group = group.includes(value)
? group.filter((_value) => _value !== value) ? group.filter((_value) => _value !== value)
: [...group, value]; : [...group, value];
} else { } else {
checked = !checked; checked = !checked;
} }
}} }}
on:change on:change
on:blur on:blur
/> />
<label for={id} {title} class:bx--checkbox-label={true}> <label for={id} {title} class:bx--checkbox-label={true}>
<span class:bx--checkbox-label-text={true} class:bx--visually-hidden={hideLabel}> <span class:bx--checkbox-label-text={true} class:bx--visually-hidden={hideLabel}>
<slot name="labelText"> <slot name="labelText">
{labelText} {labelText}
</slot> </slot>
</span> </span>
</label> </label>
</div> </div>
{/if} {/if}

View file

@ -8,15 +8,13 @@
import Logo from '$components/logo.svelte'; import Logo from '$components/logo.svelte';
import type { Users } from '$db/schema'; import type { Users } from '$db/schema';
export let user: Users | null = null; type HeaderProps = {
user: Users | null;
};
console.log('header user', user); let { user = null }: HeaderProps = $props();
let avatar: string; let avatar: string = $derived(user?.username?.slice(0, 1).toUpperCase() || ':)');
$: if (user) {
avatar = user.username?.slice(0, 1).toUpperCase() || ':)';
}
</script> </script>
<header> <header>

View file

@ -1,7 +1,5 @@
<script lang="ts"> <script lang="ts">
export let url: string; const { url, ariaLabel = `Link to ${url}`, external = false, children }: { url: string; ariaLabel?: string; external?: boolean; children: any } = $props();
export let ariaLabel = `Link to ${url}`;
export let external = false;
</script> </script>
<a <a
@ -10,7 +8,7 @@
rel="noreferrer" rel="noreferrer"
aria-label={`Board Game Atlas Link for ${ariaLabel}`} aria-label={`Board Game Atlas Link for ${ariaLabel}`}
> >
<slot /> {@render children()}
</a> </a>
<style> <style>

View file

@ -1,11 +1,5 @@
<script lang="ts"> <script lang="ts">
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
// import {
// Dialog,
// DialogDescription,
// DialogOverlay,
// DialogTitle
// } from '@rgossiaux/svelte-headlessui';
import { boredState } from '$lib/stores/boredState'; import { boredState } from '$lib/stores/boredState';
import { collectionStore } from '$lib/stores/collectionStore'; import { collectionStore } from '$lib/stores/collectionStore';
import { browser } from '$app/environment'; import { browser } from '$app/environment';

View file

@ -27,10 +27,24 @@ export function userNotFullyAuthenticated(user: User | null, session: Session |
return user && session && session.isTwoFactorAuthEnabled && !session.isTwoFactorAuthenticated; return user && session && session.isTwoFactorAuthEnabled && !session.isTwoFactorAuthenticated;
} }
/**
* Checks if the user is not fully authenticated.
*
* @param {User | null} user - The user object.
* @param {Session | null} session - The session object.
* @returns {boolean} True if the user is not fully authenticated, otherwise false.
*/
export function userNotAuthenticated(user: User | null, session: Session | null) { export function userNotAuthenticated(user: User | null, session: Session | null) {
return !user || !session || userNotFullyAuthenticated(user, session); return !user || !session || userNotFullyAuthenticated(user, session);
} }
/**
* Checks if the user is fully authenticated.
*
* @param {User | null} user - The user object.
* @param {Session | null} session - The session object.
* @returns {boolean} True if the user is fully authenticated, otherwise false.
*/
export function userFullyAuthenticated(user: User | null, session: Session | null) { export function userFullyAuthenticated(user: User | null, session: Session | null) {
return !userNotAuthenticated(user, session); return !userNotAuthenticated(user, session);
} }

View file

@ -5,8 +5,8 @@
import { theme } from '$state/theme'; import { theme } from '$state/theme';
import toast, { Toaster } from 'svelte-french-toast'; import toast, { Toaster } from 'svelte-french-toast';
export let data; const { data } = $props();
$: ({ user } = data); const { user } = data;
const flash = getFlash(page, { const flash = getFlash(page, {
clearOnNavigate: true, clearOnNavigate: true,
@ -14,26 +14,27 @@
clearArray: true clearArray: true
}); });
onMount(() => { $effect(() => {
// set the theme to the user's active theme // set the theme to the user's active theme
$theme = user?.theme || 'system'; $theme = user?.theme || 'system';
document.querySelector('html')?.setAttribute('data-theme', $theme); document.querySelector('html')?.setAttribute('data-theme', $theme);
}); });
$effect(() => {
if ($flash) {
if ($flash.type === 'success') {
toast.success($flash.message);
} else {
toast.error($flash.message, {
duration: 5000
});
}
$: if ($flash) { // Clearing the flash message could sometimes
if ($flash.type === 'success') { // be required here to avoid double-toasting.
toast.success($flash.message); flash.set(undefined);
} else {
toast.error($flash.message, {
duration: 5000
});
} }
});
// Clearing the flash message could sometimes
// be required here to avoid double-toasting.
flash.set(undefined);
}
</script> </script>
<h1>Do the admin stuff</h1> <h1>Do the admin stuff</h1>

View file

@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import DataTable from './user-table.svelte'; import DataTable from './user-table.svelte';
export let data; const { data } = $props();
</script> </script>
<h1>Users</h1> <h1>Users</h1>

View file

@ -4,7 +4,7 @@
import { Button } from '$lib/components/ui/button'; import { Button } from '$lib/components/ui/button';
// import AddRolesForm from './add-roles-form.svelte'; // import AddRolesForm from './add-roles-form.svelte';
export let data; const { data } = $props();
const { user, availableRoles } = data; const { user, availableRoles } = data;
const { user_roles }: { user_roles: { role: { name: string, cuid: string } }[] } = user; const { user_roles }: { user_roles: { role: { name: string, cuid: string } }[] } = user;

View file

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
export let data; const { data } = $props();
let collections = data?.collections || []; let collections = data?.collections || [];
</script> </script>

View file

@ -56,10 +56,8 @@ export const actions: Actions = {
return fail(401); return fail(401);
} }
const user = event.locals.user;
const dbUser = await db.query.users.findFirst({ const dbUser = await db.query.users.findFirst({
where: eq(users.id, user.id), where: eq(users.id, user!.id),
}); });
if (!dbUser?.hashed_password) { if (!dbUser?.hashed_password) {

View file

@ -3,7 +3,7 @@
import Header from '$components/Header.svelte'; import Header from '$components/Header.svelte';
import Footer from '$components/Footer.svelte'; import Footer from '$components/Footer.svelte';
export let data; const { data, children } = $props();
console.log('layout data user', data.user); console.log('layout data user', data.user);
</script> </script>
@ -11,7 +11,7 @@
<Header user={data.user} /> <Header user={data.user} />
<main> <main>
<slot /> {@render children()}
</main> </main>
<Footer /> <Footer />

View file

@ -2,7 +2,7 @@ import type { MetaTagsProps } from 'svelte-meta-tags';
import { eq } from 'drizzle-orm'; import { eq } from 'drizzle-orm';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
import db from '../../db'; import db from '../../db';
import { collections, wishlists } from '$db/schema'; import { collections, users, wishlists } from '$db/schema';
import { userFullyAuthenticated } from '$lib/server/auth-utils'; import { userFullyAuthenticated } from '$lib/server/auth-utils';
export const load: PageServerLoad = async (event) => { export const load: PageServerLoad = async (event) => {
@ -42,6 +42,10 @@ export const load: PageServerLoad = async (event) => {
}); });
if (userFullyAuthenticated(user, session)) { if (userFullyAuthenticated(user, session)) {
const dbUser = await db.query.users.findFirst({
where: eq(users.id, user!.id!),
});
console.log('Sending back user details'); console.log('Sending back user details');
const userWishlists = await db.query.wishlists.findMany({ const userWishlists = await db.query.wishlists.findMany({
columns: { columns: {
@ -60,7 +64,16 @@ export const load: PageServerLoad = async (event) => {
console.log('Wishlists', userWishlists); console.log('Wishlists', userWishlists);
console.log('Collections', userCollection); console.log('Collections', userCollection);
return { metaTagsChild: metaTags, user, wishlists: userWishlists, collections: userCollection }; return {
metaTagsChild: metaTags,
user: {
firstName: dbUser?.first_name,
lastName: dbUser?.last_name,
username: dbUser?.username,
},
wishlists: userWishlists,
collections: userCollection,
};
} }
return { metaTagsChild: metaTags, user: null, wishlists: [], collections: [] }; return { metaTagsChild: metaTags, user: null, wishlists: [], collections: [] };

View file

@ -1,12 +1,15 @@
<script lang="ts"> <script lang="ts">
export let data; const { data } = $props();
const { user, wishlists = [], collections = []} = data; const { user, wishlists = [], collections = []} = data;
const welcome = $derived(`${data?.user?.firstName} ${data?.user?.lastName}` || user?.username)
$inspect(data);
</script> </script>
<div class="container"> <div class="container">
{#if user} {#if user}
<h1>Welcome, {user.username}!</h1> <h1>Welcome, {welcome}!</h1>
<div> <div>
<h2>You wishlists:</h2> <h2>You wishlists:</h2>
{#each wishlists as wishlist} {#each wishlists as wishlist}

View file

@ -1,25 +1,15 @@
<script lang="ts"> <script lang="ts">
import { Image } from 'svelte-lazy-loader'; import { Image } from 'svelte-lazy-loader';
import { Dices, ExternalLinkIcon, MinusIcon, PlusIcon } from 'lucide-svelte'; import { Dices, ExternalLinkIcon, MinusIcon, PlusIcon } from 'lucide-svelte';
import type { SavedGameType } from '$lib/types';
import { collectionStore } from '$lib/stores/collectionStore';
import { wishlistStore } from '$lib/stores/wishlistStore';
import type { PageData } from './$types'; import type { PageData } from './$types';
import { Button } from '$components/ui/button'; import { Button } from '$components/ui/button';
import AddToList from '$components/AddToList.svelte'; import AddToList from '$components/AddToList.svelte';
import Badge from '$components/ui/badge/badge.svelte'; import Badge from '$components/ui/badge/badge.svelte';
$: existsInCollection = $collectionStore.find((item: SavedGameType) => item.id === game.id); const { data } = $props();
$: existsInWishlist = $wishlistStore.find((item: SavedGameType) => item.id === game.id); const { game, user, in_collection, in_wishlist } = data;
// $: collectionText = existsInCollection ? 'Remove from collection' : 'Add to collection';
// $: wishlistText = existsInWishlist ? 'Remove from wishlist' : 'Add to wishlist';
export let data: PageData; let seeMore: boolean = $state(false);
console.log('data', data);
$: ({ game, user, wishlist, collection, in_collection, in_wishlist } = data);
let seeMore: boolean = false;
</script> </script>
<svelte:head> <svelte:head>
@ -86,7 +76,7 @@
<section class="description" class:show={seeMore} class:hide={!seeMore} style="margin-top: 2rem;"> <section class="description" class:show={seeMore} class:hide={!seeMore} style="margin-top: 2rem;">
{@html game?.description} {@html game?.description}
</section> </section>
<button class="btn button-icon" type="button" on:click={() => (seeMore = !seeMore)} <button class="btn button-icon" type="button" onclick={() => (seeMore = !seeMore)}
>See >See
{#if !seeMore} {#if !seeMore}
More More

View file

@ -1,6 +1,3 @@
import { redirect } from 'sveltekit-flash-message/server';
import { notSignedInMessage } from '$lib/flashMessages';
export async function load(event) { export async function load(event) {
const { url, locals } = event; const { url, locals } = event;

View file

@ -4,7 +4,7 @@
import Logo from "$lib/components/logo.svelte"; import Logo from "$lib/components/logo.svelte";
import Transition from '$lib/components/transition.svelte'; import Transition from '$lib/components/transition.svelte';
export let data; let { data, children } = $props();
</script> </script>
<div class="container"> <div class="container">
@ -31,7 +31,7 @@
style=" style="
background-image: background-image:
url(https://images.unsplash.com/photo-1588591795084-1770cb3be374?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80" url(https://images.unsplash.com/photo-1588591795084-1770cb3be374?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2070&q=80"
/> ></div>
<div class="quote-wrapper"> <div class="quote-wrapper">
<blockquote class="quote"> <blockquote class="quote">
<p> <p>
@ -43,7 +43,7 @@
</div> </div>
<div class="auth-form"> <div class="auth-form">
<Transition url={data.url} transition={{ type: 'page' }}> <Transition url={data.url} transition={{ type: 'page' }}>
<slot /> {@render children()}
</Transition> </Transition>
</div> </div>
</div> </div>

View file

@ -11,7 +11,7 @@
import * as Alert from "$components/ui/alert"; import * as Alert from "$components/ui/alert";
import { boredState } from '$lib/stores/boredState.js'; import { boredState } from '$lib/stores/boredState.js';
export let data; let { data } = $props();
const superLoginForm = superForm(data.form, { const superLoginForm = superForm(data.form, {
onSubmit: () => boredState.update((n) => ({ ...n, loading: true })), onSubmit: () => boredState.update((n) => ({ ...n, loading: true })),

View file

@ -13,10 +13,10 @@
const dev = process.env.NODE_ENV !== 'production'; const dev = process.env.NODE_ENV !== 'production';
export let data; const { data, children } = $props();
$: ({ user } = data); const { user } = data;
$: metaTags = { const metaTags = $derived({
titleTemplate: '%s | Bored Game', titleTemplate: '%s | Bored Game',
description: 'Bored Game, keep track of your games.', description: 'Bored Game, keep track of your games.',
openGraph: { openGraph: {
@ -26,7 +26,7 @@
description: 'Bored Game, keep track of your games', description: 'Bored Game, keep track of your games',
}, },
...$page.data.metaTagsChild ...$page.data.metaTagsChild
} });
const flash = getFlash(page, { const flash = getFlash(page, {
clearOnNavigate: true, clearOnNavigate: true,
@ -41,34 +41,21 @@
}); });
$: if ($flash) { $effect(() => {
if ($flash.type === 'success') { if ($flash) {
toast.success($flash.message); if ($flash.type === 'success') {
} else { toast.success($flash.message);
toast.error($flash.message, { } else {
duration: 5000 toast.error($flash.message, {
}); duration: 5000
});
}
// Clearing the flash message could sometimes
// be required here to avoid double-toasting.
flash.set(undefined);
} }
});
// Clearing the flash message could sometimes
// be required here to avoid double-toasting.
flash.set(undefined);
}
// flash.subscribe(($flash) => {
// if (!$flash) return;
// if ($flash.type === 'success') {
// toast.success($flash.message);
// } else {
// toast.error($flash.message, {
// duration: 5000
// });
// }
// // Clearing the flash message could sometimes
// // be required here to avoid double-toasting.
// flash.set(undefined);
// });
onNavigate(async (navigation) => { onNavigate(async (navigation) => {
if (!document.startViewTransition) return; if (!document.startViewTransition) return;
@ -91,7 +78,7 @@
<PageLoadingIndicator /> <PageLoadingIndicator />
<div class="layout"> <div class="layout">
<slot /> {@render children()}
</div> </div>
<Toaster /> <Toaster />