mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Fixing utils helper, changing header for logged in to be a dropdown menu, adding list and signout to dropdown, adding spinner to logout.
This commit is contained in:
parent
7b9b9a1d64
commit
66ef49436f
17 changed files with 439 additions and 199 deletions
|
|
@ -1,10 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { enhance } from '$app/forms';
|
import { enhance } from '$app/forms';
|
||||||
import { LogOut } from 'lucide-svelte';
|
import { ListChecks, ListTodo, LogOut, User } from 'lucide-svelte';
|
||||||
import { Button } from '$lib/components/ui/button';
|
import { Button } from '$lib/components/ui/button';
|
||||||
// import { Toggle } from "$lib/components/ui/toggle"; -- TODO: Add light/dark toggle
|
import * as DropdownMenu from "$lib/components/ui/dropdown-menu";
|
||||||
import * as Avatar from "$lib/components/ui/avatar";
|
import * as Avatar from "$lib/components/ui/avatar";
|
||||||
import * as Sheet from "$lib/components/ui/sheet";
|
|
||||||
import Logo from '$components/logo.svelte';
|
import Logo from '$components/logo.svelte';
|
||||||
|
|
||||||
export let user: any;
|
export let user: any;
|
||||||
|
|
@ -23,57 +22,49 @@
|
||||||
{#if user}
|
{#if user}
|
||||||
<a href="/collection" title="Go to your collection" data-sveltekit-preload-data>Collection</a>
|
<a href="/collection" title="Go to your collection" data-sveltekit-preload-data>Collection</a>
|
||||||
<a href="/wishlist" title="Go to your wishlist" data-sveltekit-preload-data>Wishlist</a>
|
<a href="/wishlist" title="Go to your wishlist" data-sveltekit-preload-data>Wishlist</a>
|
||||||
<Sheet.Root>
|
<DropdownMenu.Root>
|
||||||
<Sheet.Trigger>
|
<DropdownMenu.Trigger>
|
||||||
<Avatar.Root asChild>
|
<Avatar.Root asChild>
|
||||||
<Avatar.Fallback class="text-3xl font-medium text-magnum-700 h-16 w-16 bg-neutral-100">
|
<Avatar.Fallback class="text-3xl font-medium text-magnum-700 h-16 w-16 bg-neutral-100">
|
||||||
{avatar}
|
{avatar}
|
||||||
</Avatar.Fallback>
|
</Avatar.Fallback>
|
||||||
</Avatar.Root>
|
</Avatar.Root>
|
||||||
</Sheet.Trigger>
|
</DropdownMenu.Trigger>
|
||||||
<Sheet.Content side="right">
|
<DropdownMenu.Content>
|
||||||
<Sheet.Header>
|
<DropdownMenu.Group>
|
||||||
<Sheet.Title>Menu</Sheet.Title>
|
<DropdownMenu.Label>My Account</DropdownMenu.Label>
|
||||||
</Sheet.Header>
|
<DropdownMenu.Separator />
|
||||||
<div class="menu">
|
<DropdownMenu.Item>
|
||||||
<Sheet.Close asChild let:builder>
|
<User class="mr-2 h-4 w-4" />
|
||||||
<div class="item">
|
<Button variant="link" class="text-secondary-foreground" href="/profile">Profile</Button>
|
||||||
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/profile">View Profile</Button>
|
<DropdownMenu.Shortcut>⇧⌘P</DropdownMenu.Shortcut>
|
||||||
</div>
|
</DropdownMenu.Item>
|
||||||
</Sheet.Close>
|
<DropdownMenu.Item>
|
||||||
<Sheet.Close asChild let:builder>
|
<ListChecks class="mr-2 h-4 w-4" />
|
||||||
<div class="item">
|
<Button variant="link" class="text-secondary-foreground" href="/collection">Collection</Button>
|
||||||
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/collection">Your Collection</Button>
|
<DropdownMenu.Shortcut>⇧⌘C</DropdownMenu.Shortcut>
|
||||||
</div>
|
</DropdownMenu.Item>
|
||||||
</Sheet.Close>
|
<DropdownMenu.Item>
|
||||||
<Sheet.Close asChild let:builder>
|
<ListTodo class="mr-2 h-4 w-4" />
|
||||||
<div class="item">
|
<Button variant="link" class="text-secondary-foreground" href="/wishlist">Wishlist</Button>
|
||||||
<Button builders={[builder]} variant="link" class="text-secondary-foreground" href="/wishlist">Your Wishlist</Button>
|
<DropdownMenu.Shortcut>⇧⌘W</DropdownMenu.Shortcut>
|
||||||
</div>
|
</DropdownMenu.Item>
|
||||||
</Sheet.Close>
|
<DropdownMenu.Item>
|
||||||
<div class="separator" />
|
|
||||||
<div class="item">
|
|
||||||
<form
|
<form
|
||||||
use:enhance
|
use:enhance
|
||||||
action="/logout"
|
action="/logout"
|
||||||
method="POST"
|
method="POST"
|
||||||
>
|
>
|
||||||
<Sheet.Close asChild let:builder>
|
<Button type="submit">
|
||||||
<Button builders={[builder]} type="submit">
|
<LogOut class="mr-2 h-4 w-4"/>
|
||||||
<LogOut class="mr-2 h-4 w-4"/>
|
Sign out
|
||||||
Sign out
|
</Button>
|
||||||
</Button>
|
|
||||||
</Sheet.Close>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
<DropdownMenu.Shortcut>⇧⌘Q</DropdownMenu.Shortcut>
|
||||||
</div>
|
</DropdownMenu.Item>
|
||||||
<Sheet.Footer>
|
</DropdownMenu.Group>
|
||||||
<Sheet.Close asChild let:builder>
|
</DropdownMenu.Content>
|
||||||
<Button builders={[builder]} type="button">Close</Button>
|
</DropdownMenu.Root>
|
||||||
</Sheet.Close>
|
|
||||||
</Sheet.Footer>
|
|
||||||
</Sheet.Content>
|
|
||||||
</Sheet.Root>
|
|
||||||
{/if}
|
{/if}
|
||||||
{#if !user}
|
{#if !user}
|
||||||
<a href="/login">
|
<a href="/login">
|
||||||
|
|
@ -103,10 +94,6 @@
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
|
||||||
/* margin: 0.2rem 0; */
|
|
||||||
}
|
|
||||||
|
|
||||||
.corner {
|
.corner {
|
||||||
width: 3em;
|
width: 3em;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Check } from "lucide-svelte";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
||||||
|
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let checked: $$Props["checked"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.CheckboxItem
|
||||||
|
bind:checked
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerdown
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<DropdownMenuPrimitive.CheckboxIndicator>
|
||||||
|
<Check class="h-4 w-4" />
|
||||||
|
</DropdownMenuPrimitive.CheckboxIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.CheckboxItem>
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.ContentProps;
|
||||||
|
type $$Events = DropdownMenuPrimitive.ContentEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn(
|
||||||
|
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:keydown
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.Content>
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.ItemProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
type $$Events = DropdownMenuPrimitive.ItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Item
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerdown
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.Item>
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.LabelProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Label
|
||||||
|
class={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.Label>
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.RadioGroupProps;
|
||||||
|
|
||||||
|
export let value: $$Props["value"] = undefined;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.RadioGroup {...$$restProps} bind:value>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.RadioGroup>
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { Circle } from "lucide-svelte";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
||||||
|
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let value: $$Props["value"];
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.RadioItem
|
||||||
|
class={cn(
|
||||||
|
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{value}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerdown
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||||
|
<DropdownMenuPrimitive.RadioIndicator>
|
||||||
|
<Circle class="h-2 w-2 fill-current" />
|
||||||
|
</DropdownMenuPrimitive.RadioIndicator>
|
||||||
|
</span>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.RadioItem>
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.SeparatorProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.Separator
|
||||||
|
class={cn("-mx-1 my-1 h-px bg-muted", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
/>
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
|
||||||
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span
|
||||||
|
class={cn("ml-auto text-xs tracking-widest opacity-60", className)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</span>
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.SubContentProps;
|
||||||
|
type $$Events = DropdownMenuPrimitive.SubContentEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
x: -10,
|
||||||
|
y: 0
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.SubContent
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
class={cn(
|
||||||
|
"z-50 min-w-[8rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-lg focus:outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:keydown
|
||||||
|
on:focusout
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</DropdownMenuPrimitive.SubContent>
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import { cn } from "$lib/utils";
|
||||||
|
import { ChevronRight } from "lucide-svelte";
|
||||||
|
|
||||||
|
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
||||||
|
inset?: boolean;
|
||||||
|
};
|
||||||
|
type $$Events = DropdownMenuPrimitive.SubTriggerEvents;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let inset: $$Props["inset"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
|
class={cn(
|
||||||
|
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[highlighted]:bg-accent data-[state=open]:bg-accent",
|
||||||
|
inset && "pl-8",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
|
on:focusin
|
||||||
|
on:focusout
|
||||||
|
on:pointerleave
|
||||||
|
on:pointermove
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
<ChevronRight class="ml-auto h-4 w-4" />
|
||||||
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
48
src/lib/components/ui/dropdown-menu/index.ts
Normal file
48
src/lib/components/ui/dropdown-menu/index.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
|
import Item from "./dropdown-menu-item.svelte";
|
||||||
|
import Label from "./dropdown-menu-label.svelte";
|
||||||
|
import Content from "./dropdown-menu-content.svelte";
|
||||||
|
import Shortcut from "./dropdown-menu-shortcut.svelte";
|
||||||
|
import RadioItem from "./dropdown-menu-radio-item.svelte";
|
||||||
|
import Separator from "./dropdown-menu-separator.svelte";
|
||||||
|
import RadioGroup from "./dropdown-menu-radio-group.svelte";
|
||||||
|
import SubContent from "./dropdown-menu-sub-content.svelte";
|
||||||
|
import SubTrigger from "./dropdown-menu-sub-trigger.svelte";
|
||||||
|
import CheckboxItem from "./dropdown-menu-checkbox-item.svelte";
|
||||||
|
|
||||||
|
const Sub = DropdownMenuPrimitive.Sub;
|
||||||
|
const Root = DropdownMenuPrimitive.Root;
|
||||||
|
const Trigger = DropdownMenuPrimitive.Trigger;
|
||||||
|
const Group = DropdownMenuPrimitive.Group;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Sub,
|
||||||
|
Root,
|
||||||
|
Item,
|
||||||
|
Label,
|
||||||
|
Group,
|
||||||
|
Trigger,
|
||||||
|
Content,
|
||||||
|
Shortcut,
|
||||||
|
Separator,
|
||||||
|
RadioItem,
|
||||||
|
SubContent,
|
||||||
|
SubTrigger,
|
||||||
|
RadioGroup,
|
||||||
|
CheckboxItem,
|
||||||
|
//
|
||||||
|
Root as DropdownMenu,
|
||||||
|
Sub as DropdownMenuSub,
|
||||||
|
Item as DropdownMenuItem,
|
||||||
|
Label as DropdownMenuLabel,
|
||||||
|
Group as DropdownMenuGroup,
|
||||||
|
Content as DropdownMenuContent,
|
||||||
|
Trigger as DropdownMenuTrigger,
|
||||||
|
Shortcut as DropdownMenuShortcut,
|
||||||
|
RadioItem as DropdownMenuRadioItem,
|
||||||
|
Separator as DropdownMenuSeparator,
|
||||||
|
RadioGroup as DropdownMenuRadioGroup,
|
||||||
|
SubContent as DropdownMenuSubContent,
|
||||||
|
SubTrigger as DropdownMenuSubTrigger,
|
||||||
|
CheckboxItem as DropdownMenuCheckboxItem
|
||||||
|
};
|
||||||
|
|
@ -1,6 +1,47 @@
|
||||||
import { type ClassValue, clsx } from "clsx";
|
import { type ClassValue, clsx } from 'clsx';
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
import { cubicOut } from 'svelte/easing';
|
||||||
|
import type { TransitionConfig } from 'svelte/transition';
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
type FlyAndScaleParams = {
|
||||||
|
y?: number;
|
||||||
|
x?: number;
|
||||||
|
start?: number;
|
||||||
|
duration?: number;
|
||||||
|
};
|
||||||
|
export const flyAndScale = (
|
||||||
|
node: Element,
|
||||||
|
params: FlyAndScaleParams = { y: -8, x: 0, start: 0.95, duration: 150 }
|
||||||
|
): TransitionConfig => {
|
||||||
|
const style = getComputedStyle(node);
|
||||||
|
const transform = style.transform === 'none' ? '' : style.transform;
|
||||||
|
const scaleConversion = (valueA: number, scaleA: [number, number], scaleB: [number, number]) => {
|
||||||
|
const [minA, maxA] = scaleA;
|
||||||
|
const [minB, maxB] = scaleB;
|
||||||
|
const percentage = (valueA - minA) / (maxA - minA);
|
||||||
|
const valueB = percentage * (maxB - minB) + minB;
|
||||||
|
return valueB;
|
||||||
|
};
|
||||||
|
const styleToString = (style: Record<string, number | string | undefined>): string => {
|
||||||
|
return Object.keys(style).reduce((str, key) => {
|
||||||
|
if (style[key] === undefined) return str;
|
||||||
|
return str + key + ':' + style[key] + ';';
|
||||||
|
}, '');
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
duration: params.duration ?? 200,
|
||||||
|
delay: 0,
|
||||||
|
css: (t) => {
|
||||||
|
const y = scaleConversion(t, [0, 1], [params.y ?? 5, 0]);
|
||||||
|
const x = scaleConversion(t, [0, 1], [params.x ?? 0, 0]);
|
||||||
|
const scale = scaleConversion(t, [0, 1], [params.start ?? 0.95, 1]);
|
||||||
|
return styleToString({
|
||||||
|
transform: transform + 'translate3d(' + x + 'px, ' + y + 'px, 0) scale(' + scale + ')',
|
||||||
|
opacity: t
|
||||||
|
});
|
||||||
|
},
|
||||||
|
easing: cubicOut
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -4,159 +4,20 @@
|
||||||
import Header from '$lib/components/header/index.svelte';
|
import Header from '$lib/components/header/index.svelte';
|
||||||
import Footer from '$lib/components/footer.svelte';
|
import Footer from '$lib/components/footer.svelte';
|
||||||
|
|
||||||
// $: {
|
|
||||||
// if ($navigating) {
|
|
||||||
// debounce(() => {
|
|
||||||
// boredState.update((n) => ({ ...n, loading: true }));
|
|
||||||
// }, 250);
|
|
||||||
// }
|
|
||||||
// if (!$navigating) {
|
|
||||||
// boredState.update((n) => ({ ...n, loading: false }));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $: isOpen = $boredState?.dialog?.isOpen;
|
|
||||||
|
|
||||||
// if (browser) {
|
|
||||||
// const collator = new Intl.Collator('en');
|
|
||||||
|
|
||||||
// let collectionEmpty = $collectionStore.length === 0 || false;
|
|
||||||
// let wishlistEmpty = $wishlistStore.length === 0 || false;
|
|
||||||
// if (wishlistEmpty && localStorage?.wishlist && localStorage?.wishlist?.length !== 0) {
|
|
||||||
// const wishlist: SavedGameType[] = JSON.parse(localStorage.wishlist);
|
|
||||||
// if (wishlist?.length !== 0) {
|
|
||||||
// wishlist.sort((a, b) => collator.compare(a.name, b.name));
|
|
||||||
// for (const item of wishlist) {
|
|
||||||
// if (!item?.searchTerms) {
|
|
||||||
// item.searchTerms = `${item?.name?.toLowerCase()}`;
|
|
||||||
// }
|
|
||||||
// if (!item?.includeInRandom) {
|
|
||||||
// item.includeInRandom = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// wishlistStore.addAll(wishlist);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (collectionEmpty && localStorage?.collection && localStorage?.collection?.length !== 0) {
|
|
||||||
// const collection: SavedGameType[] = JSON.parse(localStorage.collection);
|
|
||||||
// if (collection?.length !== 0) {
|
|
||||||
// collection.sort((a, b) => collator.compare(a.name, b.name));
|
|
||||||
// for (const item of collection) {
|
|
||||||
// if (!item?.searchTerms) {
|
|
||||||
// item.searchTerms = `${item?.name?.toLowerCase()}`;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// collectionStore.addAll(collection);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const dev = process.env.NODE_ENV !== 'production';
|
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
// $: ({ user } = data);
|
|
||||||
|
|
||||||
// const flash = getFlash(page, {
|
|
||||||
// clearAfterMs: 6000
|
|
||||||
// });
|
|
||||||
// let flashType;
|
|
||||||
// let flashMessage;
|
|
||||||
// $: flashType = $flash?.type;
|
|
||||||
// $: flashMessage = $flash?.message;
|
|
||||||
|
|
||||||
// if ($flash && flashType && flashMessage) {
|
|
||||||
// switch (flashType) {
|
|
||||||
// case 'success':
|
|
||||||
// toast.success(flashMessage);
|
|
||||||
// break;
|
|
||||||
// case 'error':
|
|
||||||
// toast.error(flashMessage);
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// toast.error(flashMessage);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// onMount(() => {
|
|
||||||
// // set the theme to the user's active theme
|
|
||||||
// $theme = user?.theme || 'system';
|
|
||||||
// document.querySelector('html')?.setAttribute('data-theme', $theme);
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
// });
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- {#if !dev}
|
<Header user={data.user} />
|
||||||
<Analytics />
|
|
||||||
{/if} -->
|
|
||||||
|
|
||||||
<!-- <div class="wrapper"> -->
|
<main>
|
||||||
<Header user={data.user} />
|
<Transition url={data.url} transition={{ type: 'page' }}>
|
||||||
|
<slot />
|
||||||
|
</Transition>
|
||||||
|
</main>
|
||||||
|
|
||||||
<main>
|
<Footer />
|
||||||
<Transition url={data.url} transition={{ type: 'page' }}>
|
|
||||||
<slot />
|
|
||||||
</Transition>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<Footer />
|
|
||||||
<!-- </div> -->
|
|
||||||
|
|
||||||
<!-- <Toaster /> -->
|
|
||||||
|
|
||||||
<!-- {#if $boredState?.loading}
|
|
||||||
<Portal>
|
|
||||||
<div class="loading">
|
|
||||||
<Loading></Loading>
|
|
||||||
<h3>Loading...</h3>
|
|
||||||
</div>
|
|
||||||
<div class="background"></div>
|
|
||||||
</Portal>
|
|
||||||
{/if}
|
|
||||||
{#if isOpen}
|
|
||||||
<div class="container">
|
|
||||||
<svelte:component this={$boredState?.dialog?.content}></svelte:component>
|
|
||||||
</div>
|
|
||||||
{/if} -->
|
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
/* .flash {
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
place-items: center;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 2px;
|
|
||||||
} */
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
position: fixed;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
z-index: 101;
|
|
||||||
display: grid;
|
|
||||||
place-items: center;
|
|
||||||
gap: 1rem;
|
|
||||||
|
|
||||||
& h3 {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.background {
|
.background {
|
||||||
background: black;
|
background: black;
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
// import Random from '$lib/components/random/index.svelte';
|
// import Random from '$lib/components/random/index.svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let formData;
|
|
||||||
console.log('formData', formData);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<h1>Search Boardgames!</h1>
|
<h1>Search Boardgames!</h1>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
import { Input } from '$components/ui/input';
|
import { Input } from '$components/ui/input';
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
import * as Alert from "$components/ui/alert";
|
import * as Alert from "$components/ui/alert";
|
||||||
|
import { boredState } from '$lib/stores/boredState.js';
|
||||||
|
import Portal from '$lib/Portal.svelte';
|
||||||
|
import Loading from '$components/loading.svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
const { form, errors, enhance, delayed } = superForm(data.form, {
|
const { form, errors, enhance, delayed } = superForm(data.form, {
|
||||||
|
|
@ -26,7 +29,7 @@
|
||||||
taintedMessage: null,
|
taintedMessage: null,
|
||||||
validators: signInSchema,
|
validators: signInSchema,
|
||||||
validationMethod: 'oninput',
|
validationMethod: 'oninput',
|
||||||
delayMs: 0,
|
delayMs: 250,
|
||||||
});
|
});
|
||||||
|
|
||||||
const flash = flashModule.getFlash(page);
|
const flash = flashModule.getFlash(page);
|
||||||
|
|
@ -76,9 +79,35 @@
|
||||||
</a>.
|
</a>.
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
|
{#if $delayed}
|
||||||
|
<Portal>
|
||||||
|
<!-- <Transition transition={{ type: 'fade', duration: 0 }}> -->
|
||||||
|
<div class="loading">
|
||||||
|
<Loading />
|
||||||
|
<h3>Loading...</h3>
|
||||||
|
</div>
|
||||||
|
<!-- </Transition> -->
|
||||||
|
<div class="background" />
|
||||||
|
</Portal>
|
||||||
|
{/if}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
.loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 101;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
& h3 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
.login {
|
.login {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
import debounce from 'just-debounce-it';
|
import debounce from 'just-debounce-it';
|
||||||
import 'iconify-icon';
|
import 'iconify-icon';
|
||||||
import Analytics from '$lib/components/analytics.svelte';
|
import Analytics from '$lib/components/analytics.svelte';
|
||||||
|
import Portal from "$lib/Portal.svelte";
|
||||||
|
import Loading from "$components/loading.svelte";
|
||||||
import { boredState } from '$lib/stores/boredState';
|
import { boredState } from '$lib/stores/boredState';
|
||||||
import { theme } from '$state/theme';
|
import { theme } from '$state/theme';
|
||||||
|
|
||||||
|
|
@ -48,6 +50,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$: isOpen = $boredState?.dialog?.isOpen;
|
$: isOpen = $boredState?.dialog?.isOpen;
|
||||||
|
$: loading = $boredState?.loading;
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// set the theme to the user's active theme
|
// set the theme to the user's active theme
|
||||||
|
|
@ -82,9 +85,34 @@
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- {#if loading}
|
||||||
|
<Portal>
|
||||||
|
<div class="loading">
|
||||||
|
<Loading />
|
||||||
|
<h3>Loading...</h3>
|
||||||
|
</div>
|
||||||
|
<div class="background" />
|
||||||
|
</Portal>
|
||||||
|
{/if} -->
|
||||||
|
|
||||||
<Toaster />
|
<Toaster />
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
.loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 101;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
& h3 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.layout {
|
.layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue