Updating shadcn files (Uses bits-ui), moving text search to just search page.

This commit is contained in:
Bradley Shellnut 2023-11-06 16:36:51 -08:00
parent 79fde8beb8
commit 229d84df40
27 changed files with 353 additions and 214 deletions

3
src/app.d.ts vendored
View file

@ -2,7 +2,7 @@
// for information about these interfaces
// and what to do when importing types
import type { User } from '@prisma/client';
import type { PrismaClient, User } from '@prisma/client';
type User = Omit<User, 'created_at' | 'updated_at'>;
@ -15,6 +15,7 @@ declare global {
interface Locals {
auth: import('lucia').AuthRequest;
user: Lucia.UserAttributes;
prisma: PrismaClient;
startTimer: number;
error: string;
errorId: string;

View file

View file

@ -1,74 +1,18 @@
<script lang="ts">
import { tick } from 'svelte';
import { fade, fly } from 'svelte/transition';
import { superForm } from 'sveltekit-superforms/client';
import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
import type { SuperValidated } from 'sveltekit-superforms/index';
import { boredState } from '$lib/stores/boredState';
import AdvancedSearch from '$lib/components/search/advancedSearch/index.svelte';
import { xl, md, sm } from '$lib/stores/mediaQueryStore';
import { gameStore } from '$lib/stores/gameSearchStore';
import Pagination from '$lib/components/pagination/index.svelte';
import Game from '$lib/components/game/index.svelte';
import { type GameType, type SavedGameType } from '$lib/types';
import type { SuperValidated } from 'sveltekit-superforms';
import type { SearchSchema } from '$lib/zodValidation';
import { Label } from '$components/ui/label';
import { Input } from '$components/ui/input';
import { Button } from '$components/ui/button';
import { Label } from '$lib/components/ui/label';
import { Input } from '$lib/components/ui/input';
import { Button } from '$lib/components/ui/button';
export let data;
console.log("text search data", data);
export let showButton: boolean = false;
export let advancedSearch: boolean = false;
const { games, totalCount } = data?.searchData;
const { form, errors, enhance, constraints, message }: SuperValidated<SearchSchema> = superForm(data.form);
let gameToRemove: GameType | SavedGameType;
let numberOfGameSkeleton = 1;
let submitButton: HTMLElement;
let pageSize = +form?.limit || 10;
let totalItems = +form?.searchData?.totalCount || 0;
let offset = +form?.skip || 0;
let page = Math.floor(offset / pageSize) + 1 || 1;
let submitting = $boredState?.loading;
let name = form?.name || '';
let disclosureOpen = $errors.length > 0 || false;
$: showPagination = totalCount > pageSize;
if ($xl) {
numberOfGameSkeleton = 8;
} else if ($md) {
numberOfGameSkeleton = 3;
} else if ($sm) {
numberOfGameSkeleton = 2;
} else {
numberOfGameSkeleton = 1;
}
async function handleNextPageEvent(event: CustomEvent) {
if (+event?.detail?.page === page + 1) {
page += 1;
}
await tick();
submitButton.click();
}
async function handlePreviousPageEvent(event: CustomEvent) {
if (+event?.detail?.page === page - 1) {
page -= 1;
}
await tick();
submitButton.click();
}
async function handlePerPageEvent(event: CustomEvent) {
page = 1;
pageSize = event.detail.pageSize;
await tick();
submitButton.click();
}
const { form, errors }: SuperValidated<SearchSchema> = superForm(data.form);
const dev = process.env.NODE_ENV !== 'production';
@ -77,13 +21,13 @@
</script>
{#if dev}
<SuperDebug data={$form} />
<SuperDebug collapsible data={$form} />
{/if}
<search>
<form id="search-form" action="/search" method="GET">
<div class="search">
<fieldset class="text-search" aria-busy={submitting} disabled={submitting}>
<fieldset class="text-search">
<Label for="label">Search</Label>
<Input type="text" id="q" class={$errors.q && "outline outline-destructive"} name="q" placeholder="Search board games" data-invalid={$errors.q} bind:value={$form.q} />
{#if $errors.q}
@ -92,34 +36,6 @@
<input id="skip" type="hidden" name="skip" bind:value={$form.skip} />
<input id="limit" type="hidden" name="limit" bind:value={$form.limit} />
</fieldset>
<!-- {#if advancedSearch} -->
<!-- <Disclosure> -->
<!-- <DisclosureButton
class="disclosure-button"
on:click={() => (disclosureOpen = !disclosureOpen)}
> -->
<!-- <span>Advanced Search?</span> -->
<!-- <ChevronRightIcon
class="icon disclosure-icon"
style={disclosureOpen
? 'transform: rotate(90deg); transition: transform 0.5s ease;'
: 'transform: rotate(0deg); transition: transform 0.5s ease;'}
/> -->
<!-- </DisclosureButton> -->
<!-- {#if disclosureOpen}
<div transition:fade|global> -->
<!-- Using `static`, `DisclosurePanel` is always rendered,
and ignores the `open` state -->
<!-- <DisclosurePanel static> -->
<!-- {#if disclosureOpen}
<AdvancedSearch {form} {errors} {constraints} />
{/if} -->
<!-- </DisclosurePanel> -->
<!-- </div> -->
<!-- {/if} -->
<!-- </Disclosure> -->
<!-- {/if} -->
</div>
{#if showButton}
<Button type="submit">Submit</Button>
@ -127,32 +43,6 @@
</form>
</search>
<section class="games">
<h1>Games Found:</h1>
<div class="games-list">
{#if totalCount > 0}
{#each games as game (game.id)}
<Game {game} />
{/each}
{:else}
<h2>Sorry no games found!</h2>
{/if}
</div>
{#if showPagination && $gameStore?.length > 0}
<Pagination
{pageSize}
{page}
{totalItems}
forwardText="Next"
backwardText="Prev"
pageSizes={[10, 25, 50, 100]}
on:nextPageEvent={handleNextPageEvent}
on:previousPageEvent={handlePreviousPageEvent}
on:perPageEvent={handlePerPageEvent}
/>
{/if}
</section>
<style lang="postcss">
:global(.disclosure-button) {
display: flex;
@ -160,6 +50,12 @@
place-items: center;
}
#search-form {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
button {
padding: 1rem;
margin: 1.5rem 0;
@ -177,35 +73,4 @@
flex-wrap: wrap;
}
}
.games {
margin: 2rem 0rem;
& h1 {
margin-bottom: 2rem;
}
}
.games-list {
display: grid;
--listColumns: 4;
grid-template-columns: repeat(var(--listColumns), minmax(250px, 1fr));
gap: 2rem;
@media (width >= 1500px) {
--listColumns: 3;
}
@media (1000px < width <= 1500px) {
--listColumns: 3;
}
@media (600px < width <= 1000px) {
--listColumns: 2;
}
@media (width <= 600px) {
--listColumns: 1;
}
}
</style>

View file

@ -1,13 +1,10 @@
<script lang="ts">
import { Button as ButtonPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
import { buttonVariants, type Size, type Variant } from ".";
import { buttonVariants, type Props, type Events } from ".";
type $$Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
};
type $$Events = ButtonPrimitive.Events;
type $$Props = Props;
type $$Events = Events;
let className: $$Props["class"] = undefined;
export let variant: $$Props["variant"] = "default";
@ -19,6 +16,7 @@
<ButtonPrimitive.Root
{builders}
class={cn(buttonVariants({ variant, size, className }))}
type="button"
{...$$restProps}
on:click
on:keydown

View file

@ -1,35 +1,51 @@
import Root from './button.svelte';
import { tv, type VariantProps } from 'tailwind-variants';
import Root from "./button.svelte";
import { tv, type VariantProps } from "tailwind-variants";
import type { Button as ButtonPrimitive } from "bits-ui";
export const buttonVariants = tv({
base: 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
const buttonVariants = tv({
base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline'
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive:
"bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline:
"border border-input bg-background hover:bg-accent hover:text-accent-foreground",
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline"
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 rounded-md px-3',
lg: 'h-11 rounded-md px-8',
icon: 'h-10 w-10'
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10"
}
},
defaultVariants: {
variant: 'default',
size: 'default'
variant: "default",
size: "default"
}
});
export type Variant = VariantProps<typeof buttonVariants>['variant'];
export type Size = VariantProps<typeof buttonVariants>['size'];
type Variant = VariantProps<typeof buttonVariants>["variant"];
type Size = VariantProps<typeof buttonVariants>["size"];
type Props = ButtonPrimitive.Props & {
variant?: Variant;
size?: Size;
};
type Events = ButtonPrimitive.Events;
export {
Root,
type Props,
type Events,
//
Root as Button
Root as Button,
type Props as ButtonProps,
type Events as ButtonEvents,
buttonVariants
};

View file

@ -12,11 +12,11 @@
</script>
<CheckboxPrimitive.Root
bind:checked
class={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
"box-content peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
className
)}
bind:checked
{...$$restProps}
on:click
>
@ -26,9 +26,9 @@
let:isIndeterminate
>
{#if isChecked}
<Check class="h-4 w-4" />
<Check class="h-3.5 w-3.5" />
{:else if isIndeterminate}
<Minus class="h-4 w-4" />
<Minus class="h-3.5 w-3.5" />
{/if}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>

View file

@ -8,6 +8,7 @@
export let onCheckedChange: $$Props["onCheckedChange"] = undefined;
const { name, setValue, attrStore, value } = getFormField();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { name: nameAttr, value: valueAttr, ...rest } = $attrStore;
</script>

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { Form as FormPrimitive } from "formsnap";
import { cn } from "@/utils";
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLSpanElement>;

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { cn } from "@/utils";
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLDivElement>;

View file

@ -1,7 +1,7 @@
<script lang="ts">
import type { Label as LabelPrimitive } from "bits-ui";
import { getFormField } from "formsnap";
import { cn } from "@/utils";
import { cn } from "$lib/utils";
import { Label } from "$lib/components/ui/label";
type $$Props = LabelPrimitive.Props;
@ -13,7 +13,7 @@
</script>
<Label
for={ids.input}
for={$ids.input}
class={cn($errors && "text-destructive", className)}
{...$$restProps}
>

View file

@ -5,7 +5,7 @@
type $$Props = SelectPrimitive.Props;
const { setValue, name, value } = getFormField();
export let onSelectedChange: $$Props["onSelectedChange"];
export let onSelectedChange: $$Props["onSelectedChange"] = undefined;
</script>
<Select.Root

View file

@ -1,6 +1,6 @@
<script lang="ts">
import { Form as FormPrimitive } from "formsnap";
import { cn } from "@/utils";
import { cn } from "$lib/utils";
import type { HTMLAttributes } from "svelte/elements";
type $$Props = HTMLAttributes<HTMLParagraphElement>;

View file

@ -18,6 +18,7 @@ import Button from "./form-button.svelte";
const Root = FormPrimitive.Root;
const Field = FormPrimitive.Field;
const Control = FormPrimitive.Control;
const RadioItem = RadioGroupComp.Item;
const NativeRadio = FormPrimitive.Radio;
const SelectContent = SelectComp.Content;
@ -36,6 +37,7 @@ export type TextareaGetFormField = Omit<
export {
Root,
Field,
Control,
Item,
Input,
Label,
@ -59,6 +61,7 @@ export {
//
Root as Form,
Field as FormField,
Control as FormControl,
Item as FormItem,
Input as FormInput,
Textarea as FormTextarea,

View file

@ -13,7 +13,7 @@
<input
class={cn(
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-foreground file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
bind:value

View file

@ -1,2 +1,15 @@
export { default as RadioGroup } from "./RadioGroup.svelte";
export { default as RadioGroupItem } from "./RadioGroupItem.svelte";
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import Root from "./radio-group.svelte";
import Item from "./radio-group-item.svelte";
const Input = RadioGroupPrimitive.Input;
export {
Root,
Input,
Item,
//
Root as RadioGroup,
Input as RadioGroupInput,
Item as RadioGroupItem
};

View file

@ -0,0 +1,28 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import { Circle } from "lucide-svelte";
import { cn } from "$lib/utils";
type $$Props = RadioGroupPrimitive.ItemProps;
type $$Events = RadioGroupPrimitive.ItemEvents;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"];
export { className as class };
</script>
<RadioGroupPrimitive.Item
{value}
class={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary ring-offset-background focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...$$restProps}
on:click
>
<div class="flex items-center justify-center">
<RadioGroupPrimitive.ItemIndicator>
<Circle class="h-2.5 w-2.5 fill-current text-current" />
</RadioGroupPrimitive.ItemIndicator>
</div>
</RadioGroupPrimitive.Item>

View file

@ -0,0 +1,18 @@
<script lang="ts">
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
import { cn } from "$lib/utils";
type $$Props = RadioGroupPrimitive.Props;
let className: $$Props["class"] = undefined;
export let value: $$Props["value"] = undefined;
export { className as class };
</script>
<RadioGroupPrimitive.Root
bind:value
class={cn("grid gap-2", className)}
{...$$restProps}
>
<slot />
</RadioGroupPrimitive.Root>

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { cn } from "$lib/utils";
import { Select as SelectPrimitive } from "bits-ui";
import { Check } from "lucide-svelte";
import { cn } from "$lib/utils";
type $$Props = SelectPrimitive.ItemProps;
type $$Events = SelectPrimitive.ItemEvents;
@ -18,7 +18,7 @@
{disabled}
{label}
class={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex w-full 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}

View file

@ -4,6 +4,7 @@
@layer base {
:root {
--font-serif: 'Inter', sans-serif;
--background: 0 0% 100%;
--foreground: 20 14.3% 4.1%;
--card: 0 0% 100%;

View file

@ -50,6 +50,14 @@ const Search = z.object({
skip: z.number().min(0).default(0)
});
// minAge: z
// .string()
// .min(1)
// .transform((v) => +v)
// .refine((minAge) => !isNaN(minAge), { message: 'Must be a number' })
// .refine((minAge) => minAge >= 1 && minAge <= 120, { message: 'Must be between 1 and 120' })
// .optional(),
export const search_schema = z
.object({
q: z.string().trim().optional().default(''),

View file

@ -18,18 +18,6 @@ import {
} from '$lib/utils/dbUtils.js';
// import { listGameSchema } from '$lib/config/zod-schemas.js';
/**
* Asynchronous function searchForGames to fetch games from a local and remote repository based on the given parameters.
* @async
* @function searchForGames
* @param {SearchQuery} urlQueryParams - An object that represents the search parameters. It includes properties like name, min_players,
* max_players, min_playtime, max_playtime, min_age, skip, limit which are used to define the search condition for games.
* @param {any} locals - An object that contains data related to the local server environment like user information.
* @param {Function} eventFetch - A function that fetches games from the local API.
* @returns {Object} returns an object with totalCount property which is the total number of games fetched and games property which is
* an array of all the games fetched. If any error occurred during the operation, it returns an object with totalCount as 0 and games as empty array.
* @throws will throw an error if the response received from fetching games operation is not OK (200).
*/
async function searchForGames(
locals: App.Locals,
eventFetch: Function,

View file

@ -1,10 +1,192 @@
<script lang="ts">
import TextSearch from '$lib/components/search/textSearch/index.svelte';
import { dev } from '$app/environment';
import type { SuperValidated } from 'sveltekit-superforms';
import { superForm } from 'sveltekit-superforms/client';
import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
import { createPagination, melt } from '@melt-ui/svelte';
import { ChevronLeft, ChevronRight } from 'lucide-svelte';
import type { SearchSchema } from '$lib/zodValidation';
import Game from '$lib/components/game/index.svelte';
import { Label } from '$lib/components/ui/label';
import { Input } from '$lib/components/ui/input';
import { Button } from '$lib/components/ui/button';
export let data;
console.log("search page data", data);
const { form, errors }: SuperValidated<SearchSchema> = superForm(data.form);
const { games, totalCount } = data?.searchData;
let submitButton: HTMLElement;
let pageSize = +form?.limit || 10;
$: showPagination = totalCount > pageSize;
const {
elements: { root, pageTrigger, prevButton, nextButton },
states: { pages, range }
} = createPagination({
count: totalCount,
perPage: pageSize,
defaultPage: 1,
siblingCount: 1
});
// async function handleNextPageEvent(event: CustomEvent) {
// if (+event?.detail?.page === page + 1) {
// page += 1;
// }
// await tick();
// submitButton.click();
// }
// async function handlePreviousPageEvent(event: CustomEvent) {
// if (+event?.detail?.page === page - 1) {
// page -= 1;
// }
// await tick();
// submitButton.click();
// }
// async function handlePerPageEvent(event: CustomEvent) {
// page = 1;
// pageSize = event.detail.pageSize;
// await tick();
// submitButton.click();
// }
</script>
<div class="game-search">
<TextSearch showButton advancedSearch {data} />
{#if dev}
<SuperDebug collapsible data={$form} />
{/if}
<search>
<form id="search-form" action="/search" method="GET">
<div class="search">
<fieldset class="text-search">
<Label for="label">Search</Label>
<Input type="text" id="q" class={$errors.q && "outline outline-destructive"} name="q" placeholder="Search board games" data-invalid={$errors.q} bind:value={$form.q} />
{#if $errors.q}
<p class="text-sm text-destructive">{$errors.q}</p>
{/if}
<input id="skip" type="hidden" name="skip" bind:value={$form.skip} />
<input id="limit" type="hidden" name="limit" bind:value={$form.limit} />
</fieldset>
</div>
<Button type="submit">Submit</Button>
</form>
</search>
<section class="games">
<h1>Games Found:</h1>
<div class="games-list">
{#if totalCount > 0}
{#each games as game (game.id)}
<Game {game} />
{/each}
{:else}
<h2>Sorry no games found!</h2>
{/if}
</div>
{#if showPagination}
<nav use:melt={$root}>
<p class="text-center">Showing items {$range.start} - {$range.end}</p>
<div class="buttons">
<button use:melt={$prevButton}><ChevronLeft /></button>
{#each $pages as page (page.key)}
{#if page.type === 'ellipsis'}
<span>...</span>
{:else}
<button use:melt={$pageTrigger(page)} on:m-click={() => console.log('test')}>{page.value}</button>
{/if}
{/each}
<button use:melt={$nextButton} on:m-click|preventDefault={() => console.log('test')} on:m-keydown|preventDefault={() => console.log('test')}><ChevronRight /></button>
</div>
</nav>
{/if}
</section>
</div>
<style lang="postcss">
nav {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
}
.text-center {
text-align: center;
}
#search-form {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
button {
display: grid;
place-items: center;
border-radius: 2px;
background-color: rgb(var(--color-white) / 1);
color: rgb(var(--color-magnum-700) / 1);
box-shadow: 0px 1px 2px 0px rgb(var(--color-black) / 0.05);
font-size: 14px;
padding-inline: 0.75rem;
height: 2rem;
}
button:hover {
opacity: 0.75;
}
button:disabled {
cursor: not-allowed;
opacity: 0.5;
}
nav :global(button[data-selected]) {
background-color: rgb(var(--color-magnum-900));
color: rgb(var(--color-white));
}
.buttons {
display: flex;
align-items: center;
gap: 0.5rem;
}
.games {
margin: 2rem 0rem;
& h1 {
margin-bottom: 2rem;
}
}
.games-list {
display: grid;
--listColumns: 4;
grid-template-columns: repeat(var(--listColumns), minmax(250px, 1fr));
gap: 2rem;
@media (width >= 1500px) {
--listColumns: 3;
}
@media (1000px < width <= 1500px) {
--listColumns: 3;
}
@media (600px < width <= 1000px) {
--listColumns: 2;
}
@media (width <= 600px) {
--listColumns: 1;
}
}
</style>

View file

@ -2,7 +2,7 @@
import { page } from '$app/stores';
</script>
<div>
<div class="error">
{#if $page.status === 404}
<h1>The page you requested doesn't exist! 🤷‍♂️</h1>
<h3 class="mt-6"><a href="/">Go Home</a></h3>
@ -16,11 +16,23 @@
{/if}
</div>
<style>
h1 {
margin-top: var(--spacing-64);
font-family: var(--font-sans);
font-size: var(--font-32);
<style style="postcss">
.error {
display: grid;
place-items: center;
text-align: center;
margin-top: 4rem;
}
h1 {
font-size: 1.125rem;
line-height: 1.75rem;
font-weight: 600;
}
h3 {
font-size: 1rem;
line-height: 1.5rem;
font-weight: 600;
}
</style>

View file

@ -7,9 +7,12 @@
import 'iconify-icon';
import { page } from '$app/stores';
import { onNavigate } from "$app/navigation";
import { boredState } from '$lib/stores/boredState';
import Analytics from '$lib/components/analytics.svelte';
import { theme } from '$state/theme';
import PageLoadingIndicator from '$lib/page_loading_indicator.svelte';
import Portal from "$lib/Portal.svelte";
import Loading from "$components/loading.svelte";
const dev = process.env.NODE_ENV !== 'production';
@ -49,7 +52,7 @@
// }
// $: isOpen = $boredState?.dialog?.isOpen;
// $: loading = $boredState?.loading;
$: loading = $boredState?.loading;
onMount(() => {
// set the theme to the user's active theme
@ -97,7 +100,7 @@
<slot />
</div>
<!-- {#if loading}
{#if loading}
<Portal>
<div class="loading">
<Loading />
@ -105,7 +108,7 @@
</div>
<div class="background" />
</Portal>
{/if} -->
{/if}
<Toaster />

View file

@ -44,7 +44,9 @@ export const GET = async ({ url, locals }) => {
name: true,
slug: true,
thumb_url: true
}
},
take: limit,
skip
});
}