mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
228 lines
No EOL
5.5 KiB
Svelte
228 lines
No EOL
5.5 KiB
Svelte
<script lang="ts">
|
|
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, createToolbar, melt } from '@melt-ui/svelte';
|
|
import { ChevronLeft, ChevronRight, LayoutList, LayoutGrid } from 'lucide-svelte';
|
|
import type { SearchSchema } from '$lib/zodValidation';
|
|
import Game from '$components/Game.svelte';
|
|
import { Label } from '$lib/components/ui/label';
|
|
import { Input } from '$lib/components/ui/input';
|
|
import { Button } from '$lib/components/ui/button';
|
|
import { Checkbox } from "$lib/components/ui/checkbox";
|
|
|
|
export let 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: toolbarRoot },
|
|
builders: { createToolbarGroup },
|
|
} = createToolbar();
|
|
const {
|
|
elements: { group: listStyleGroup, item: listStyleItem },
|
|
} = createToolbarGroup();
|
|
|
|
const {
|
|
elements: { root: paginationRoot, pageTrigger, prevButton, nextButton },
|
|
states: { pages, range }
|
|
} = createPagination({
|
|
count: totalCount,
|
|
perPage: pageSize,
|
|
defaultPage: 1,
|
|
siblingCount: 1
|
|
});
|
|
|
|
const gameListStyle: 'grid' | 'list' = 'grid';
|
|
function handleListStyle(event) {
|
|
console.log(event, typeof event);
|
|
}
|
|
</script>
|
|
|
|
<div class="game-search">
|
|
{#if dev}
|
|
<SuperDebug collapsible data={$form} />
|
|
{/if}
|
|
|
|
<search>
|
|
<form id="search-form" action="/search" method="GET">
|
|
<fieldset>
|
|
<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>
|
|
<fieldset class="flex items-center space-x-2">
|
|
<Checkbox id="exact" bind:checked={$form.exact} aria-labelledby="exact-label" />
|
|
<Label
|
|
id="exact-label"
|
|
for="exact"
|
|
class="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
>
|
|
Exact Search
|
|
</Label>
|
|
</fieldset>
|
|
<Button type="submit">Submit</Button>
|
|
</form>
|
|
</search>
|
|
|
|
<section class="games">
|
|
<div>
|
|
<h1>Games Found:</h1>
|
|
<div use:melt={$toolbarRoot}>
|
|
<div use:melt={$listStyleGroup} class="search-toolbar">
|
|
<button class="style-item" aria-label='list' use:melt={$listStyleItem('list')} on:m-click|preventDefault={(e) => handleListStyle(e)}>
|
|
<LayoutList class="square-5" />
|
|
</button>
|
|
<button class="style-item" aria-label='grid' use:melt={$listStyleItem('grid')} on:m-click|preventDefault={(e) => handleListStyle(e)}>
|
|
<LayoutGrid class="square-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<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={$paginationRoot}>
|
|
<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;
|
|
|
|
.list {
|
|
--listColumns: 1;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
.search-toolbar {
|
|
display: flex;
|
|
place-items: center;
|
|
gap: 0.15rem;
|
|
}
|
|
|
|
.style-item {
|
|
padding: 0.1rem;
|
|
border-radius: 0.375rem;
|
|
border: 1px solid black;
|
|
|
|
&:hover {
|
|
opacity: 0.75;
|
|
}
|
|
|
|
&[data-state='on'] {
|
|
background-color: grey;
|
|
}
|
|
}
|
|
</style> |