This commit is contained in:
2024-11-24 22:57:21 +01:00
parent bbf13cf203
commit 72933a46d1
48 changed files with 752 additions and 450 deletions

View File

@@ -18,11 +18,19 @@
-->
<script lang="ts">
import { createBubbler } from 'svelte/legacy';
const bubble = createBubbler();
import "@styles/button.css"
export let type: "primary" | "ghost" | "gray" = "primary";
interface Props {
type?: "primary" | "ghost" | "gray";
children?: import('svelte').Snippet;
}
let { type = "primary", children }: Props = $props();
</script>
<button on:click class="btn" class:btn-gray={type === "gray"} class:btn-text={type === "ghost"}>
<slot />
<button onclick={bubble('click')} class="btn" class:btn-gray={type === "gray"} class:btn-text={type === "ghost"}>
{@render children?.()}
</button>

View File

@@ -18,23 +18,30 @@
-->
<script lang="ts">
import { run, createBubbler, stopPropagation } from 'svelte/legacy';
const bubble = createBubbler();
import {createEventDispatcher, onMount} from "svelte";
export let title: string;
export let open: boolean;
let internalOpen = open;
interface Props {
title: string;
open: boolean;
children?: import('svelte').Snippet;
footer?: import('svelte').Snippet;
}
let {
title,
open = $bindable(),
children,
footer
}: Props = $props();
let internalOpen = $state(open);
const dispatch = createEventDispatcher();
$: if (open && !internalOpen) {
dialog.showModal();
internalOpen = true;
} else if (!open && internalOpen) {
dialog.close();
internalOpen = false;
}
let dialog: HTMLDialogElement;
let dialog: HTMLDialogElement = $state();
onMount(() => {
if (open) {
@@ -48,18 +55,27 @@
internalOpen = false;
dispatch("close");
}
run(() => {
if (open && !internalOpen) {
dialog.showModal();
internalOpen = true;
} else if (!open && internalOpen) {
dialog.close();
internalOpen = false;
}
});
</script>
<dialog bind:this={dialog} on:close={close} on:cancel={close} on:click={() => dialog.close()} aria-hidden="true">
<div on:click|stopPropagation aria-hidden="true">
<dialog bind:this={dialog} onclose={close} oncancel={close} onclick={() => dialog.close()} aria-hidden="true">
<div onclick={stopPropagation(bubble('click'))} aria-hidden="true">
<div class="spaced bordered">
<h1>{title}</h1>
</div>
<div class="spaced main bordered">
<slot />
{@render children?.()}
</div>
<div class="footer spaced" on:click={() => dialog.close()} aria-hidden="true">
<slot name="footer" />
<div class="footer spaced" onclick={() => dialog.close()} aria-hidden="true">
{@render footer?.()}
</div>
</div>
</dialog>

View File

@@ -18,6 +18,8 @@
-->
<script lang="ts">
import { preventDefault } from 'svelte/legacy';
import {
ChevronDoubleLeftOutline,
ChevronDoubleRightOutline,
@@ -25,23 +27,27 @@
ChevronRightOutline,
} from "flowbite-svelte-icons";
export let page: number = 0;
export let maxPage: number;
$: pages = new Array(maxPage).fill(0)
.map((_, i) => i + 1)
//.slice(Math.max(page - 2, 0) - Math.abs(Math.max(page + 3 - maxPage, 0)), Math.min(page + 3, maxPage) + Math.abs(Math.min(page - 2, 0)))
.map(i => ({
name: i.toString(),
active: i === page + 1,
i: i - 1
}));
export let firstUrl: string = "#";
export let lastUrl: string = "#";
export let previousUrl: string = "#";
export let nextUrl: string = "#";
export let pagesUrl: (i: number) => string = () => "#";
interface Props {
page?: number;
maxPage: number;
firstUrl?: string;
lastUrl?: string;
previousUrl?: string;
nextUrl?: string;
pagesUrl?: (i: number) => string;
}
let {
page = $bindable(0),
maxPage,
firstUrl = "#",
lastUrl = "#",
previousUrl = "#",
nextUrl = "#",
pagesUrl = () => "#"
}: Props = $props();
const previous = () => {
page = Math.max(page - 1, 0);
@@ -50,37 +56,45 @@
const next = () => {
page = Math.min(page + 1, maxPage - 1);
};
let pages = $derived(new Array(maxPage).fill(0)
.map((_, i) => i + 1)
//.slice(Math.max(page - 2, 0) - Math.abs(Math.max(page + 3 - maxPage, 0)), Math.min(page + 3, maxPage) + Math.abs(Math.min(page - 2, 0)))
.map(i => ({
name: i.toString(),
active: i === page + 1,
i: i - 1
})));
</script>
<div class="w-full flex justify-center mt-4">
<ul class="inline-flex flex-wrap">
<li>
<a href={firstUrl} on:click|preventDefault={() => page = 0} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-r-none">
<a href={firstUrl} onclick={preventDefault(() => page = 0)} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-r-none">
<span class="sr-only">Next</span>
<ChevronDoubleLeftOutline class="w-3 h-3" />
</a>
</li>
<li>
<a href={previousUrl} on:click|preventDefault={previous} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-none">
<a href={previousUrl} onclick={preventDefault(previous)} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-none">
<span class="sr-only">Previous</span>
<ChevronLeftOutline class="w-3 h-3" />
</a>
</li>
{#each pages as p}
<li>
<a href={pagesUrl(p.i)} on:click|preventDefault={() => page = p.i} class="btn h-8 px-3 text-sm flex items-center !m-0 !rounded-none" class:btn-neutral={!p.active}>
<a href={pagesUrl(p.i)} onclick={preventDefault(() => page = p.i)} class="btn h-8 px-3 text-sm flex items-center !m-0 !rounded-none" class:btn-neutral={!p.active}>
<span>{p.name}</span>
</a>
</li>
{/each}
<li>
<a href={nextUrl} on:click|preventDefault={next} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-none">
<a href={nextUrl} onclick={preventDefault(next)} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-none">
<span class="sr-only">Next</span>
<ChevronRightOutline class="w-3 h-3" />
</a>
</li>
<li>
<a href={lastUrl} on:click|preventDefault={() => page = maxPage - 1} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-l-none">
<a href={lastUrl} onclick={preventDefault(() => page = maxPage - 1)} class="btn btn-neutral h-8 px-3 text-sm flex items-center !m-0 !rounded-l-none">
<span class="sr-only">Next</span>
<ChevronDoubleRightOutline class="w-3 h-3" />
</a>