diff options
Diffstat (limited to 'src')
108 files changed, 1314 insertions, 939 deletions
diff --git a/src/components/About.svelte b/src/components/About.svelte index 01ff4c7c..5f87e99a 100644 --- a/src/components/About.svelte +++ b/src/components/About.svelte @@ -24,7 +24,7 @@ { name: "cole", socials: [] }, ]; - let locations; + let locations = $state(); onMount(async () => { try { ({ locations } = await fetch("/locations").then((r) => r.json())); diff --git a/src/components/Account.svelte b/src/components/Account.svelte index 38c8c418..c378b9a3 100644 --- a/src/components/Account.svelte +++ b/src/components/Account.svelte @@ -1,14 +1,19 @@ <script> + import { run } from 'svelte/legacy'; + import { goto } from "$app/navigation"; import Icon from "$comp/Icon.svelte"; import Balance from "$comp/Balance.svelte"; import { t } from "$lib/translations"; - export let user, rate, account, last; - let { name, seed, balance, id } = account; - $: type = seed ? "Savings" : "Cash"; + let { + user, + rate, + account, + last + } = $props(); + let { name, seed, balance, id } = $state(account); - $: refresh(account); let refresh = (a) => ({ seed, balance, id } = a); let setAccount = () => (document.cookie = `aid=${id}; path=/; max-age=86400`); @@ -16,38 +21,42 @@ setAccount(); goto("/payments"); }; + let type = $derived(seed ? "Savings" : "Cash"); + run(() => { + refresh(account); + }); </script> <div class="block space-y-2 border-primary py-4 cursor-pointer" class:border-b-8={!last} - on:click={go} + onclick={go} > <div class="flex"> <Balance {balance} {user} {rate} /> - <a href={`/payments`} class="contents" on:click={setAccount}> + <a href={`/payments`} class="contents" onclick={setAccount}> <button class="ml-auto flex gap-1 mb-auto pb-4 pl-4"> - <iconify-icon icon="ph:clock-bold" width="32" /> + <iconify-icon icon="ph:clock-bold" width="32"></iconify-icon> </button> </a> <a href={`/account/${id}`} class="contents"> <button class="flex gap-1 mb-auto pb-4 pl-4"> - <iconify-icon icon="ph:gear-bold" width="32" /> + <iconify-icon icon="ph:gear-bold" width="32"></iconify-icon> </button> </a> </div> <div class="flex justify-center w-full text-xl gap-2"> - <a href={`/invoice`} class="contents" on:click={setAccount}> + <a href={`/invoice`} class="contents" onclick={setAccount}> <button class="btn !w-auto flex-grow"> - <iconify-icon icon="ph:hand-coins-bold" width="32" flip="horizontal" /> + <iconify-icon icon="ph:hand-coins-bold" width="32" flip="horizontal"></iconify-icon> <div class="my-auto">{$t("user.dashboard.receive")}</div> </button> </a> - <a href={`/send`} class="contents grow" on:click={setAccount}> + <a href={`/send`} class="contents grow" onclick={setAccount}> <button type="button" class="btn !w-auto flex-grow"> - <iconify-icon icon="ph:paper-plane-right-bold" width="32" /> + <iconify-icon icon="ph:paper-plane-right-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.dashboard.send")}</div> </button> </a> diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 5a922792..fef2f0f4 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { banner, theme, newPayment } from "$lib/store"; import { goto } from "$app/navigation"; import Avatar from "$comp/Avatar.svelte"; @@ -6,19 +8,21 @@ import { loading, t } from "$lib/translations"; import { page } from "$app/stores"; - export let user, subject; + let { user, subject = $bindable() } = $props(); - let w; - $: if (!subject) subject = user; + let w = $state(); + run(() => { + if (!subject) subject = user; + }); - $: bg = - $banner?.id && $banner.id === subject.id + let bg = + $derived($banner?.id && $banner.id === subject.id ? `url(${$banner.src})` : subject?.banner ? subject.banner.includes(":") ? `url(${subject.banner})` : `url(/api/public/${subject.banner}.webp)` - : undefined; + : undefined); const links = [ { @@ -40,10 +44,10 @@ }, ]; - $: opacity = (href) => + let opacity = $derived((href) => $page.url.pathname === href ? "opacity-100" - : "opacity-90 hover:opacity-none"; + : "opacity-90 hover:opacity-none"); </script> <svelte:window bind:innerWidth={w} /> @@ -58,7 +62,7 @@ {#each links as { href, icon, flip }} <a {href} data-sveltekit-preload-code="eager"> <button class="btn-menu {opacity(href)}"> - <iconify-icon {icon} width={w > 640 ? 32 : 24} {flip} /> + <iconify-icon {icon} width={w > 640 ? 32 : 24} {flip}></iconify-icon> </button> </a> {/each} diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte index a088c4ee..3007c3e7 100644 --- a/src/components/Avatar.svelte +++ b/src/components/Avatar.svelte @@ -1,20 +1,29 @@ -<script> +<script lang="ts"> + import { run } from 'svelte/legacy'; + import { avatar, banner } from "$lib/store"; import Icon from "$comp/Icon.svelte"; import { punk } from "$lib/utils"; - export let user; - export let size = 32; - export let disabled = false; + interface Props { + user: any; + size?: number; + disabled?: boolean; + } + + let { user, size = 32, disabled = false }: Props = $props(); - $: s = size.toString(); - $: link = user?.anon ? `/${user.pubkey}` : `/${user.username}`; + let s = $derived(size.toString()); + let link = $derived(user?.anon ? `/${user.pubkey}` : `/${user.username}`); let base = "/api/public"; - $: profile = user?.profile ? `${base}/${user.profile}.webp` : user?.picture; - $: fallback = `${base}/punks/` + punk(user.pubkey || user.id || "aa"); - $: tmp = $avatar?.id && $avatar.id === user.id && $avatar.src; - $: src = tmp || profile || fallback; + let profile = $derived(user?.profile ? `${base}/${user.profile}.webp` : user?.picture); + let fallback = $derived(`${base}/punks/` + punk(user.pubkey || user.id || "aa")); + let tmp = $derived($avatar?.id && $avatar.id === user.id && $avatar.src); + let src; + run(() => { + src = tmp || profile || fallback; + }); let handle = () => (src = fallback); </script> @@ -27,7 +36,7 @@ {src} class="w-full h-full object-cover object-center overflow-hidden" alt={user.username} - on:error={handle} + onerror={handle} /> </div> </a> diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte index 0cc27068..91463f7e 100644 --- a/src/components/Balance.svelte +++ b/src/components/Balance.svelte @@ -1,12 +1,14 @@ <script> + import { preventDefault } from 'svelte/legacy'; + import Icon from "$comp/Icon.svelte"; import Pin from "$comp/Pin.svelte"; import { f, s, sat, sats } from "$lib/utils"; import { pin } from "$lib/store"; import { t } from "$lib/translations"; - let show; - export let user, rate, balance; + let show = $state(); + let { user, rate, balance } = $props(); </script> {#if show && user.haspin && $pin?.length !== 6} @@ -16,7 +18,7 @@ <div> {#if user.haspin && !$pin} <button - on:click|preventDefault={() => (show = true)} + onclick={preventDefault(() => (show = true))} class="flex gap-2 text-xl" > <Icon icon="eye-off" style="w-8 my-auto" /> diff --git a/src/components/Code.svelte b/src/components/Code.svelte index 7ec046a6..00ef38a8 100644 --- a/src/components/Code.svelte +++ b/src/components/Code.svelte @@ -2,7 +2,7 @@ import { copyNoNewlines as copy } from "$lib/utils"; import Icon from "$comp/Icon.svelte"; import samples from "$lib/samples"; - export let sample; + let { sample } = $props(); </script> <div @@ -13,7 +13,7 @@ </div> <button class="ml-auto my-auto invert opacity-90" - on:click={() => copy(samples[sample])} + onclick={() => copy(samples[sample])} ><Icon icon="copy" style="w-10 max-w-none" /></button > </div> diff --git a/src/components/DarkToggle.svelte b/src/components/DarkToggle.svelte index 5ddc80a1..be1fe858 100644 --- a/src/components/DarkToggle.svelte +++ b/src/components/DarkToggle.svelte @@ -9,12 +9,12 @@ <button class="flex justify-center items-center hover:opacity-80 gap-2 font-bold" - on:click={dark} + onclick={dark} > <iconify-icon icon={$theme === "dark" ? "ph:sun-bold" : "ph:moon-stars-bold"} width="30" - /> +></iconify-icon> {$t(`nav.${$theme === "dark" ? "light" : "dark"}`)} </button> diff --git a/src/components/DeleteItem.svelte b/src/components/DeleteItem.svelte index 8f7f97ca..d45f09e6 100644 --- a/src/components/DeleteItem.svelte +++ b/src/components/DeleteItem.svelte @@ -1,9 +1,11 @@ <script> + import { preventDefault } from 'svelte/legacy'; + import Icon from "$comp/Icon.svelte"; import { fail, post } from "$lib/utils"; import { invalidate } from "$app/navigation"; - export let item; + let { item = $bindable() } = $props(); let cancel = () => (item = null); @@ -25,13 +27,13 @@ class="relative top-1/3 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5" > <h1 class="text-center text-2xl font-semibold">Delete item</h1> - <form on:submit|preventDefault={submit}> + <form onsubmit={preventDefault(submit)}> <div class="w-full flex"> <button type="button" class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" - on:click={cancel} - on:keydown={cancel} + onclick={cancel} + onkeydown={cancel} > <div class="my-auto">No</div> </button> diff --git a/src/components/Event.svelte b/src/components/Event.svelte index 640b9e68..78fdd230 100644 --- a/src/components/Event.svelte +++ b/src/components/Event.svelte @@ -1,7 +1,7 @@ <script> import Avatar from "$comp/Avatar.svelte"; import Icon from "$comp/Icon.svelte"; - export let event; + let { event } = $props(); let { id, user, seen, content } = event; @@ -22,7 +22,7 @@ : "now"; }; - let w; + let w = $state(); </script> <svelte:window bind:innerWidth={w} /> diff --git a/src/components/FaqCard.svelte b/src/components/FaqCard.svelte index ae1ad077..a2d13bc8 100644 --- a/src/components/FaqCard.svelte +++ b/src/components/FaqCard.svelte @@ -1,10 +1,15 @@ -<script> +<script lang="ts"> import { t } from "$lib/translations"; // this ID will be used to get the strings from the locale // question is at faq.[questionID].question - // answer is at faq.[questionID].answer - export let questionID; + + interface Props { + // answer is at faq.[questionID].answer + questionID: any; + } + + let { questionID }: Props = $props(); </script> <div class="mx-auto w-full md:w-2/3 lg:w-[700px] space-y-5"> diff --git a/src/components/Feed.svelte b/src/components/Feed.svelte index 5dc2b21a..593c2289 100644 --- a/src/components/Feed.svelte +++ b/src/components/Feed.svelte @@ -1,4 +1,6 @@ <script> + import { preventDefault } from 'svelte/legacy'; + import { t } from "$lib/translations"; import { onMount } from "svelte"; import Event from "$comp/Event.svelte"; @@ -7,10 +9,9 @@ import { fail } from "$lib/utils"; import { sign, send } from "$lib/nostr"; - export let events; - export let user = undefined; + let { events = $bindable(), user = undefined } = $props(); - let message; + let message = $state(); let submit = async () => { try { @@ -38,14 +39,14 @@ } }; - $: sorted = Object.values(events) + let sorted = $derived(Object.values(events) .filter((ev) => ev?.pubkey && ev?.kind === 1) - .sort((a, b) => b.seen - a.seen); + .sort((a, b) => b.seen - a.seen)); </script> {#if user} <form - on:submit|preventDefault={submit} + onsubmit={preventDefault(submit)} class="flex justify-center gap-4 max-w-2xl mx-auto" > <div class="grow"> @@ -68,14 +69,16 @@ <VirtualScroll data={sorted} key="id" - let:data + pageMode={true} estimateSize={200} > - <a href={`/${data.user.pubkey}/event/${data.id}`}> - <Event event={data} /> - </a> - </VirtualScroll> + {#snippet children({ data })} + <a href={`/${data.user.pubkey}/event/${data.id}`}> + <Event event={data} /> + </a> + {/snippet} + </VirtualScroll> {:else} <div class="flex w-full"> <div class="mx-auto text-secondary">{$t("user.noNotes")}</div> diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte index 1fac31e9..3af5f6a3 100644 --- a/src/components/Footer.svelte +++ b/src/components/Footer.svelte @@ -24,7 +24,7 @@ <div class="space-y-5"> <div class="text-center w-full"> <a href="/"> - <iconify-icon icon="coinos:logo" width="224" /> + <iconify-icon icon="coinos:logo" width="224"></iconify-icon> </a> </div> <div class="flex gap-2 justify-center sm:hidden"> @@ -73,5 +73,5 @@ </ul> </div> - <iconify-icon icon="coinos:shield" class="flex justify-center" width="96" /> + <iconify-icon icon="coinos:shield" class="flex justify-center" width="96"></iconify-icon> </footer> diff --git a/src/components/HowItWorksCard.svelte b/src/components/HowItWorksCard.svelte index a8fe63fd..2b8967ae 100644 --- a/src/components/HowItWorksCard.svelte +++ b/src/components/HowItWorksCard.svelte @@ -1,12 +1,11 @@ <script> import Icon from "./Icon.svelte"; import { t } from "$lib/translations"; - export let image; - export let stepID; + let { image, stepID } = $props(); </script> <div class="space-y-5"> - <iconify-icon icon={image} class="mx-auto" width="128" /> + <iconify-icon icon={image} class="mx-auto" width="128"></iconify-icon> <p class="text-2xl font-medium">{$t("howItWorks." + stepID + ".header")}</p> <p class="text-secondary text-xl font-medium w-full md:w-2/3 mx-auto"> {$t("howItWorks." + stepID + ".description")} diff --git a/src/components/Icon.svelte b/src/components/Icon.svelte index 0b47f726..6d55bf94 100644 --- a/src/components/Icon.svelte +++ b/src/components/Icon.svelte @@ -1,6 +1,5 @@ <script> - export let icon; - export let style = undefined; + let { icon, style = undefined } = $props(); </script> <img src="/icons/{icon}.svg" alt={icon} class={style} /> diff --git a/src/components/Image.svelte b/src/components/Image.svelte index 4f8b39bb..4bc90571 100644 --- a/src/components/Image.svelte +++ b/src/components/Image.svelte @@ -1,6 +1,5 @@ <script> - export let image; - export let style; + let { image, style } = $props(); </script> <img src="/images/{image}.webp" alt={image} class={style} /> diff --git a/src/components/InvoiceActions.svelte b/src/components/InvoiceActions.svelte index 7f1607e0..0b5dca55 100644 --- a/src/components/InvoiceActions.svelte +++ b/src/components/InvoiceActions.svelte @@ -1,33 +1,35 @@ <script> - export let user, + let { + user, invoice, copy, t, link, type, types, - showQr, + showQr = $bindable(), txt, - toggleAmount; + toggleAmount + } = $props(); </script> <div class="text-secondary space-y-2 text-xl pt-2"> - <button type="button" class="btn" on:click={() => copy(txt)}> - <iconify-icon icon="ph:copy-bold" width="32" /> + <button type="button" class="btn" onclick={() => copy(txt)}> + <iconify-icon icon="ph:copy-bold" width="32"></iconify-icon> <div class="my-auto"> {t("payments.copy")} </div> </button> {#if user?.id === invoice?.user?.id} - <button class="btn" on:click={toggleAmount}> - <iconify-icon icon="ph:pencil-simple-bold" width="32" /> + <button class="btn" onclick={toggleAmount}> + <iconify-icon icon="ph:pencil-simple-bold" width="32"></iconify-icon> <div class="my-auto">{t("payments.setAmount")}</div> </button> {:else} <a href={link} class="block"> <button class="btn"> - <iconify-icon icon="ph:wallet-bold" width="32" /> + <iconify-icon icon="ph:wallet-bold" width="32"></iconify-icon> <div class="my-auto">{t("payments.openLink")}</div> </button> </a> @@ -35,11 +37,11 @@ {#if txt.startsWith("ln")} <div class="w-full flex justify-center gap-2 flex-wrap"> - <button class="btn" on:click={() => (showQr = !showQr)}> + <button class="btn" onclick={() => (showQr = !showQr)}> {#if showQr} - <iconify-icon icon="ph:text-align-center-bold" width="32" /> + <iconify-icon icon="ph:text-align-center-bold" width="32"></iconify-icon> {:else} - <iconify-icon icon="ph:qr-code-bold" width="32" /> + <iconify-icon icon="ph:qr-code-bold" width="32"></iconify-icon> {/if} <div class="my-auto"> {showQr ? t("payments.showText") : t("payments.showQr")} diff --git a/src/components/InvoiceData.svelte b/src/components/InvoiceData.svelte index 7723eb56..da1ea5d9 100644 --- a/src/components/InvoiceData.svelte +++ b/src/components/InvoiceData.svelte @@ -1,16 +1,18 @@ <script> import { btc, f, sat, s, sats } from "$lib/utils"; - export let showQr, + let { + showQr, src, link, - qr, + qr = $bindable(), txt, invoice, amount, amountFiat, currency, tip, - rate; + rate + } = $props(); </script> {#if showQr} diff --git a/src/components/InvoiceTypes.svelte b/src/components/InvoiceTypes.svelte index 354f0a49..cdd01aac 100644 --- a/src/components/InvoiceTypes.svelte +++ b/src/components/InvoiceTypes.svelte @@ -1,5 +1,12 @@ <script> - export let aid, user, type, types, t, setType; + let { + aid, + user, + type, + types, + t, + setType + } = $props(); </script> {#if aid === user?.id} @@ -8,7 +15,7 @@ class="btn flex-nowrap" class:bg-base-300={type === types.bitcoin} class:text-secondary={type === types.bitcoin} - on:click={() => setType(types.bitcoin)} + onclick={() => setType(types.bitcoin)} > <img src="/images/bitcoin.svg" class="w-8" alt="Bitcoin" /> <div class="my-auto text-lg">Bitcoin</div> @@ -18,7 +25,7 @@ class="btn flex-nowrap" class:bg-base-300={type === types.liquid} class:text-secondary={type === types.liquid} - on:click={() => setType(types.liquid)} + onclick={() => setType(types.liquid)} > <img src="/images/liquid.svg" class="w-8" alt="Liquid" /> <div class="my-auto text-lg">Liquid</div> @@ -28,7 +35,7 @@ class="btn flex-nowrap" class:bg-base-300={type === types.lightning} class:text-secondary={type === types.lightning} - on:click={() => setType(types.lightning)} + onclick={() => setType(types.lightning)} > <div class="bg-base-100 rounded-full w-8 h-8 text-center flex"> <div class="m-auto">⚡️</div> diff --git a/src/components/ItemForm.svelte b/src/components/ItemForm.svelte index 7e0f58d8..d3ea88c0 100644 --- a/src/components/ItemForm.svelte +++ b/src/components/ItemForm.svelte @@ -1,15 +1,16 @@ <script> + import { preventDefault } from 'svelte/legacy'; + import { t } from "$lib/translations"; import { upload } from "$lib/upload"; import { fail } from "$lib/utils"; import { applyAction, deserialize } from "$app/forms"; import Spinner from "$comp/Spinner.svelte"; - export let item; - export let user; + let { item = $bindable(), user } = $props(); - let fileInput, formElement, file, submitting, progress; + let fileInput = $state(), formElement = $state(), file, submitting = $state(), progress; let select = () => fileInput.click(); - let src; + let src = $state(); let tooLarge = {}; let handleFile = async ({ target }, type) => { @@ -67,7 +68,7 @@ <form method="POST" class="space-y-5" - on:submit|preventDefault={handleSubmit} + onsubmit={preventDefault(handleSubmit)} bind:this={formElement} > <input type="hidden" name="id" bind:value={item.id} /> @@ -104,24 +105,24 @@ {src} alt={item.name} class="object-cover w-full h-full" - on:click={select} - on:keydown={select} + onclick={select} + onkeydown={select} /> {:else if item.image} <img src={`/api/public/${item.image}.webp`} alt={item.name} class="object-cover w-full h-full" - on:click={select} - on:keydown={select} + onclick={select} + onkeydown={select} /> {:else} <div class="bg-gradient-to-r from-primary to-gradient mb-4 cursor-pointer hover:opacity-80 w-full h-full" - on:click={select} - on:keydown={select} + onclick={select} + onkeydown={select} alt="Banner" - /> +></div> {/if} </div> </div> @@ -130,7 +131,7 @@ type="file" class="hidden" bind:this={fileInput} - on:change={(e) => handleFile(e, "item")} + onchange={(e) => handleFile(e, "item")} /> </div> diff --git a/src/components/Items.svelte b/src/components/Items.svelte index db5dedc1..a7b4fe1a 100644 --- a/src/components/Items.svelte +++ b/src/components/Items.svelte @@ -1,4 +1,6 @@ <script> + import { run, stopPropagation } from 'svelte/legacy'; + import { t } from "$lib/translations"; import { btc, f, sat, post } from "$lib/utils"; import { browser } from "$app/environment"; @@ -15,15 +17,22 @@ import DeleteItem from "$comp/DeleteItem.svelte"; import Icon from "$comp/Icon.svelte"; - export let subject, user, items, rate, currency, total; + let { + subject, + user, + items = $bindable(), + rate, + currency, + total + } = $props(); let flipDurationMs = 200; let dropTargetStyle = {}; let dragDisabled = - subject?.id !== user?.id || (browser && window.innerWidth < 768); + $state(subject?.id !== user?.id || (browser && window.innerWidth < 768)); - let deleting; + let deleting = $state(); let del = (item) => { deleting = item; }; @@ -62,10 +71,6 @@ dragDisabled = false; } - $: if (total > 0 && browser) { - let payButton = document.querySelector("#payButton"); - if (payButton) payButton.addEventListener("click", checkout); - } let checkout = async () => { let invoice = { @@ -92,9 +97,15 @@ let reset = () => (dragDisabled = user?.username !== subject?.username || window.innerWidth < 768); + run(() => { + if (total > 0 && browser) { + let payButton = document.querySelector("#payButton"); + if (payButton) payButton.addEventListener("click", checkout); + } + }); </script> -<svelte:window on:resize={reset} /> +<svelte:window onresize={reset} /> {#if deleting} <DeleteItem bind:item={deleting} /> @@ -106,21 +117,21 @@ <div class="grid sm:grid-cols-2 gap-4 pb-20" use:dndzone={{ items, flipDurationMs, dropTargetStyle, dragDisabled }} - on:consider={handleConsider} - on:finalize={handleFinalize} + onconsider={handleConsider} + onfinalize={handleFinalize} > {#each items as i (i.id)} <button type="button" class="w-full text-center cursor-pointer hover:opacity-80 mb-auto" - on:click={() => i.quantity++} + onclick={() => i.quantity++} > <div class="relative w-full h-64 overflow-hidden rounded-xl"> {#if i[SHADOW_ITEM_MARKER_PROPERTY_NAME]} <div in:fade={{ duration: 200, easing: cubicIn }} class="custom-shadow-item" - /> +></div> {:else if i.image} <img src={`/api/public/${i.image}.webp`} @@ -131,7 +142,7 @@ <div class="bg-gradient-to-r from-primary to-gradient mb-4 cursor-pointer hover:opacity-80 w-full h-full" alt="Banner" - /> +></div> {/if} {#if user?.username === subject.username} <div class="flex gap-2 justify-center absolute top-2 right-2"> @@ -144,16 +155,16 @@ </a> <button class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" - on:click|stopPropagation={() => del(i)} + onclick={stopPropagation(() => del(i))} > <Icon icon="trash" style="w-8 mx-auto invert" /> </button> <div - on:click|stopPropagation={() => {}} + onclick={stopPropagation(() => {})} class="sm:hidden" - on:mousedown={startDrag} - on:touchstart={startDrag} - on:keydown={handleKeyDown} + onmousedown={startDrag} + ontouchstart={startDrag} + onkeydown={handleKeyDown} > <a href={`/items/${i.id}`}> <button @@ -183,7 +194,7 @@ {#if i.quantity} <button type="button" - on:click|stopPropagation={() => i.quantity > 0 && i.quantity--} + onclick={stopPropagation(() => i.quantity > 0 && i.quantity--)} > <Icon icon="minus" style="w-10 min-w-10" /> </button> @@ -194,7 +205,7 @@ {#if i.quantity} <button type="button" - on:click|stopPropagation={() => i.quantity++} + onclick={stopPropagation(() => i.quantity++)} > <Icon icon="plus" style="w-10 min-w-10" /> </button> @@ -213,7 +224,7 @@ {#if total > 0} <button class="rounded-2xl py-5 px-6 font-bold hover:bg-neutral-700 flex bg-black text-white mx-auto" - on:click={checkout} + onclick={checkout} > <div class="mx-auto flex"> <div class="my-auto text-2xl"> diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte index 7a4c5d18..c20c80a0 100644 --- a/src/components/LandingHeader.svelte +++ b/src/components/LandingHeader.svelte @@ -7,13 +7,15 @@ import DarkToggle from "$comp/DarkToggle.svelte"; import LocaleSelector from "$comp/LocaleSelector.svelte"; - export let howItWorks; - export let faq; - export let about; - export let user; + let { + howItWorks, + faq, + about, + user + } = $props(); - let showMobileMenu = false; - let header; + let showMobileMenu = $state(false); + let header = $state(); const mobileMenuButtonClick = (section) => { showMobileMenu = false; scroll(section); @@ -26,45 +28,45 @@ > <nav class="block lg:flex justify-between items-center"> <div class="flex justify-start lg:justify-center items-center lg:space-x-5"> - <a href="/" on:click={() => scroll(header)}> - <iconify-icon icon="coinos:logo" width="224" /> + <a href="/" onclick={() => scroll(header)}> + <iconify-icon icon="coinos:logo" width="224"></iconify-icon> </a> </div> <!-- desktop nav --> <div class="hidden space-x-5 lg:flex justify-center items-center font-bold"> {#if $page.url.pathname === "/"} - <button class="hover:opacity-80" on:click={() => scroll(howItWorks)} + <button class="hover:opacity-80" onclick={() => scroll(howItWorks)} >{$t("howItWorks.header")}</button > - <button class="hover:opacity-80" on:click={() => scroll(faq)} + <button class="hover:opacity-80" onclick={() => scroll(faq)} >{$t("faq.header")}</button > - <button class="hover:opacity-80" on:click={() => scroll(about)} + <button class="hover:opacity-80" onclick={() => scroll(about)} >{$t("about.header")}</button > {/if} {#if user} <button class="btn !w-auto !rounded-full" - on:click={() => goto(`/${user.username}`)} + onclick={() => goto(`/${user.username}`)} >Home </button> <button class="btn !w-auto !rounded-full" - on:click={() => goto("/logout")} + onclick={() => goto("/logout")} > {$t("nav.signOut")} </button> {:else} <button class="btn btn-accent !w-auto !rounded-full" - on:click={() => goto("/register")} + onclick={() => goto("/register")} >{$t("nav.register")} </button> <button class="btn !w-auto !rounded-full" - on:click={() => goto("/login")} + onclick={() => goto("/login")} > {$t("nav.signIn")} </button> @@ -73,12 +75,12 @@ <button class="block lg:hidden absolute top-[34.5px] right-10 z" - on:click={() => (showMobileMenu = !showMobileMenu)} + onclick={() => (showMobileMenu = !showMobileMenu)} > <iconify-icon icon={!showMobileMenu ? "ph:list-bold" : "ph:x-bold"} width="32" - /> +></iconify-icon> </button> <div @@ -89,31 +91,31 @@ <div class="space-y-5 mt-24 font-bold text-xl"> <LocaleSelector /> <DarkToggle /> - <button on:click={() => mobileMenuButtonClick(howItWorks)} class="block" + <button onclick={() => mobileMenuButtonClick(howItWorks)} class="block" >{$t("howItWorks.header")}</button > - <button on:click={() => mobileMenuButtonClick(faq)} class="block" + <button onclick={() => mobileMenuButtonClick(faq)} class="block" >{$t("faq.header")}</button > - <button on:click={() => mobileMenuButtonClick(about)} class="block" + <button onclick={() => mobileMenuButtonClick(about)} class="block" >{$t("about.header")}</button > {#if !user} - <button class="btn btn-accent" on:click={() => goto("/register")} + <button class="btn btn-accent" onclick={() => goto("/register")} >{$t("nav.register")} </button> - <button class="btn" on:click={() => goto("/login")}> + <button class="btn" onclick={() => goto("/login")}> {$t("nav.signIn")} </button> {:else} <button class="border rounded-full px-6 py-2 font-bold block" - on:click={() => goto(`/${user.username}`)} + onclick={() => goto(`/${user.username}`)} >{$t("nav.account")} </button> <button class="bg-primary text-white border rounded-full px-6 py-2 font-bold block" - on:click={() => goto("/logout")} + onclick={() => goto("/logout")} > {$t("nav.signOut")} </button> diff --git a/src/components/LandingHero.svelte b/src/components/LandingHero.svelte index 8d47283e..d3f71390 100644 --- a/src/components/LandingHero.svelte +++ b/src/components/LandingHero.svelte @@ -17,7 +17,7 @@ <iconify-icon icon="coinos:rays" class="absolute -top-16 left-5 md:left-8 lg:left-14 2xl:left-24" - /> +></iconify-icon> </span> {$t("landing.header_after_icon")} </h1> diff --git a/src/components/LandingInfoCard.svelte b/src/components/LandingInfoCard.svelte index fadcb6c0..63951e86 100644 --- a/src/components/LandingInfoCard.svelte +++ b/src/components/LandingInfoCard.svelte @@ -1,10 +1,13 @@ <script> import Image from "./Image.svelte"; - export let image; - export let title; - export let description = undefined; - export let order = undefined; + let { + image, + title, + description = undefined, + order = undefined, + children + } = $props(); </script> <div class="block lg:flex justify-center lg:space-x-20 items-center"> @@ -25,7 +28,7 @@ {#if description} {description} {:else} - <slot /> + {@render children?.()} {/if} </p> </div> diff --git a/src/components/Lnurlp.svelte b/src/components/Lnurlp.svelte index 0268e363..74be0571 100644 --- a/src/components/Lnurlp.svelte +++ b/src/components/Lnurlp.svelte @@ -1,19 +1,29 @@ <script> + import { run } from 'svelte/legacy'; + import { t } from "$lib/translations"; import { enhance } from "$app/forms"; import Numpad from "$comp/Numpad.svelte"; import Spinner from "$comp/Spinner.svelte"; import { pin } from "$lib/store"; - export let data, form, send, comment; + let { + data, + form, + send = $bindable(), + comment = $bindable() + } = $props(); let { currency } = data.user; let { minSendable, maxSendable, commentAllowed, callback, metadata, rates } = data; - $: rate = rates[currency]; + let rate; + run(() => { + rate = rates[currency]; + }); - let amount = Math.round(minSendable / 1000), - loading; + let amount = $state(Math.round(minSendable / 1000)), + loading = $state(); let submit = () => (loading = true); </script> @@ -39,7 +49,7 @@ <Numpad bind:amount bind:rate {currency} bind:submit={send} /> - <form action="?/pay" method="POST" use:enhance on:submit={submit}> + <form action="?/pay" method="POST" use:enhance onsubmit={submit}> <input name="amount" value={amount} type="hidden" /> <input name="minSendable" value={minSendable} type="hidden" /> <input name="maxSendable" value={maxSendable} type="hidden" /> @@ -53,7 +63,7 @@ class="w-full p-4 border rounded-xl h-32 text-xl" bind:value={comment} autocapitalize="none" - /> +></textarea> {/if} <div class="flex w-full"> diff --git a/src/components/Lnurlw.svelte b/src/components/Lnurlw.svelte index d0fbf3b4..50aa1488 100644 --- a/src/components/Lnurlw.svelte +++ b/src/components/Lnurlw.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { sats, f, s } from "$lib/utils"; import { t } from "$lib/translations"; import { enhance } from "$app/forms"; @@ -6,7 +8,7 @@ import Spinner from "$comp/Spinner.svelte"; import { pin } from "$lib/store"; - export let data, form; + let { data, form } = $props(); let { currency, username } = data.user; let { @@ -17,13 +19,16 @@ callback, rates, } = data; - $: rate = rates[currency]; + let rate; + run(() => { + rate = rates[currency]; + }); - let amount = Math.round(minWithdrawable / 1000), - loading; + let amount = $state(Math.round(minWithdrawable / 1000)), + loading = $state(); let submit = () => (loading = true); - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); + let amountFiat = $derived(parseFloat(((amount * rate) / sats).toFixed(2))); </script> <div class="container px-4 mt-20 max-w-xl mx-auto"> @@ -56,7 +61,7 @@ <Numpad bind:amount {currency} bind:rate /> {/if} - <form action="?/withdraw" method="POST" use:enhance on:submit={submit}> + <form action="?/withdraw" method="POST" use:enhance onsubmit={submit}> <input name="amount" value={amount} type="hidden" /> <input name="username" value={username} type="hidden" /> <input name="currency" value={currency} type="hidden" /> diff --git a/src/components/LocaleSelector.svelte b/src/components/LocaleSelector.svelte index d837a534..cb057dbd 100644 --- a/src/components/LocaleSelector.svelte +++ b/src/components/LocaleSelector.svelte @@ -1,8 +1,13 @@ <script> + import { run } from 'svelte/legacy'; + import { t, locale, locales } from "$lib/translations"; - export let style; + let { style } = $props(); - $: l = $locale; + let l; + run(() => { + l = $locale; + }); const handleChange = ({ currentTarget }) => { const { value } = currentTarget; @@ -11,7 +16,7 @@ }; </script> -<select name="language" bind:value={l} on:change={handleChange}> +<select name="language" bind:value={l} onchange={handleChange}> {#each $locales as locale} <option value={locale}>{$t(`lang.${locale}`)}</option> {/each} diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte index c01d8b75..b04b8e98 100644 --- a/src/components/LocationsMap.svelte +++ b/src/components/LocationsMap.svelte @@ -1,5 +1,5 @@ <script> - import { tick, onMount, onDestroy } from "svelte"; + import { tick, onMount, onDestroy, mount } from "svelte"; import { browser } from "$app/environment"; import Icon from "$comp/Icon.svelte"; import Popup from "$comp/Popup.svelte"; @@ -7,15 +7,15 @@ import "maplibre-gl/dist/maplibre-gl.css"; - export let locations; + let { locations } = $props(); let map; - let mapContainer, mapWrapper; + let mapContainer = $state(), mapWrapper = $state(); let markers = []; - let search; + let search = $state(); let clearSearch = (e) => (search = ""); let currentIndex = -1; - let timeout; + let timeout = $state(); let full = () => { if (!document.fullscreenElement) { @@ -49,11 +49,6 @@ } }; - $: list = search - ? markers.filter((m) => - m.tags.name.toLowerCase().includes(search.toLowerCase()), - ) - : inview; let scroll = () => { const el = document.querySelector(".selected"); @@ -65,7 +60,7 @@ }); }; - let selected; + let selected = $state(); function select(m) { selected = m; stopFlying(); @@ -109,7 +104,7 @@ }; let toggleList = () => (showList = !showList); - let showList; + let showList = $state(); let currentPopup; function startFlying() { @@ -155,7 +150,7 @@ map.off("moveend"); } - let inview = []; + let inview = $state([]); let updateLabelVisibility = debounce(() => { inview = []; @@ -201,10 +196,10 @@ let popupContainer = document.createElement("div"); - new Popup({ - target: popupContainer, - props: { tags }, - }); + mount(Popup, { + target: popupContainer, + props: { tags }, + }); let marker = new maplibre.Marker({ color: "#F7931A", scale: 0.65 }) .setLngLat([lon, lat]) @@ -252,6 +247,11 @@ }); onDestroy(() => map && map.remove()); + let list = $derived(search + ? markers.filter((m) => + m.tags.name.toLowerCase().includes(search.toLowerCase()), + ) + : inview); </script> <div class="w-screen h-dvh flex" id="map" bind:this={mapWrapper}> @@ -259,11 +259,11 @@ id="map-container" class="mx-auto h-full w-full z-0" bind:this={mapContainer} - /> +></div> <div class="absolute flex top-2 left-2 gap-2"> <button class="rounded-full border-2 border-black bg-base-100 w-10 h-10" - on:click={back} + onclick={back} > <Icon icon="arrow-left" style="w-4 m-auto" /> </button> @@ -277,7 +277,7 @@ <input bind:value={search} class="w-full" /> <div class="flex gap-1 absolute right-6 top-3"> {#if search} - <button on:click={clearSearch}> + <button onclick={clearSearch}> <Icon icon="close" style="w-8" /> </button> {:else} @@ -288,7 +288,7 @@ {#each list as marker, i} <button - on:click={() => select(marker)} + onclick={() => select(marker)} class:font-bold={selected === marker} class:selected={selected === marker} class="block whitespace-nowrap text-ellipsis text-left w-full overflow-hidden" @@ -301,13 +301,13 @@ <div class="absolute flex top-2 right-2 gap-2"> <button class="rounded-full border-2 border-black bg-white w-10 h-10" - on:click={toggleList} + onclick={toggleList} > <Icon icon="list" style="w-4 m-auto" /> </button> <button class="rounded-full border-2 border-black bg-white w-10 h-10" - on:click={toggle} + onclick={toggle} > {#if timeout} <Icon icon="pause" style="w-4 m-auto" /> diff --git a/src/components/Menu.svelte b/src/components/Menu.svelte index 3ce6d9ce..de21bbbc 100644 --- a/src/components/Menu.svelte +++ b/src/components/Menu.svelte @@ -1,26 +1,35 @@ <script> + import { run } from 'svelte/legacy'; + import { theme } from "$lib/store"; import DarkToggle from "$comp/DarkToggle.svelte"; import OutClick from "svelte-outclick"; - export let t, user, w, opacity; + let { + t, + user, + w, + opacity + } = $props(); let dark = () => ($theme = $theme === "dark" ? "light" : "dark"); - let showMenu = false; + let showMenu = $state(false); - let menuButtons; - $: if (user) - menuButtons = [ - { key: "nav.settings", icon: "ph:gear-bold", href: `/settings` }, - { key: "nav.support", icon: "ph:lifebuoy-bold", href: `/support` }, - { key: "nav.map", icon: "ph:map-trifold-bold", href: `/map` }, - { - key: "nav.merch", - icon: "ph:storefront-bold", - href: `https://coinosmerch.com`, - }, - { key: "nav.dark", icon: "ph:moon-stars-bold", href: `/dark` }, - { key: "nav.signOut", icon: "ph:sign-out-bold", href: `/logout` }, - ]; + let menuButtons = $state(); + run(() => { + if (user) + menuButtons = [ + { key: "nav.settings", icon: "ph:gear-bold", href: `/settings` }, + { key: "nav.support", icon: "ph:lifebuoy-bold", href: `/support` }, + { key: "nav.map", icon: "ph:map-trifold-bold", href: `/map` }, + { + key: "nav.merch", + icon: "ph:storefront-bold", + href: `https://coinosmerch.com`, + }, + { key: "nav.dark", icon: "ph:moon-stars-bold", href: `/dark` }, + { key: "nav.signOut", icon: "ph:sign-out-bold", href: `/logout` }, + ]; + }); let hideMenu = () => (showMenu = false); let toggleMenu = () => (showMenu = !showMenu); @@ -28,8 +37,8 @@ <div> <OutClick on:outclick={hideMenu}> - <button class="btn-menu {opacity('/support')}" on:click={toggleMenu} - ><iconify-icon icon="ph:list-bold" width={w > 640 ? 32 : 24} /> + <button class="btn-menu {opacity('/support')}" onclick={toggleMenu} + ><iconify-icon icon="ph:list-bold" width={w > 640 ? 32 : 24}></iconify-icon> </button> <div @@ -47,12 +56,12 @@ {href} data-sveltekit-preload-code="eager" data-sveltekit-preload-data="false" - on:click={hideMenu} + onclick={hideMenu} > <button class="flex justify-center items-center font-semibold hover:opacity-80 gap-2" > - <iconify-icon {icon} width="32" /> + <iconify-icon {icon} width="32"></iconify-icon> {t(key)} </button> </a> @@ -61,7 +70,7 @@ {/each} </ul> <hr class="my-4" /> - <a href="/?stay=true"><iconify-icon icon="coinos:logo" width="160" /></a> + <a href="/?stay=true"><iconify-icon icon="coinos:logo" width="160"></iconify-icon></a> </div> </OutClick> </div> diff --git a/src/components/Mnemonic.svelte b/src/components/Mnemonic.svelte index 41e81d9a..93035230 100644 --- a/src/components/Mnemonic.svelte +++ b/src/components/Mnemonic.svelte @@ -1,5 +1,5 @@ <script> - export let mnemonic; + let { mnemonic } = $props(); </script> <div class="flex w-full border p-4 rounded-2xl h-full"> diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte index 07d1ef4c..03c7c48f 100644 --- a/src/components/Numpad.svelte +++ b/src/components/Numpad.svelte @@ -1,21 +1,33 @@ -<script> +<script lang="ts"> + import { run, preventDefault, stopPropagation } from "svelte/legacy"; + import Left from "$comp/Left.svelte"; import Icon from "$comp/Icon.svelte"; import { f, s, focus, warning, sat, sats } from "$lib/utils"; import { t } from "$lib/translations"; - export let amount, - currency, - element, - fiat = !amount, - rate, - submit = undefined; + interface Props { + amount: any; + currency: any; + element: any; + fiat?: any; + rate: any; + submit?: any; + amountFiat?: number; + } - export let amountFiat = 0; + let { + amount = $bindable(), + currency, + element = $bindable(), + fiat = $bindable(!amount), + rate = $bindable(), + submit = undefined, + amountFiat = $bindable(0), + }: Props = $props(); let arrow = "<"; - $: update(amount, amountFiat); let update = (a, f) => { if (fiat) { amount = Math.round(f / (rate / sats)); @@ -102,8 +114,6 @@ } }; - $: html = fiat ? amountFiat : s(amount); - let prev = ""; let input = (e) => { @@ -193,6 +203,13 @@ } fiat = !fiat; }; + run(() => { + update(amount, amountFiat); + }); + let html; + run(() => { + html = fiat ? amountFiat : s(amount); + }); </script> <div class="flex justify-center items-center"> @@ -208,17 +225,17 @@ use:focus contenteditable bind:innerHTML={html} - on:focus={select} - on:blur={blur} - on:input={input} - on:keydown={keydown} + onfocus={select} + onblur={blur} + oninput={input} + onkeydown={keydown} class="outline-none my-auto" bind:this={element} - /> + ></div> </div> <div class="flex items-center justify-center text-2xl cursor-pointer" - on:click|preventDefault|stopPropagation={swap} + onclick={stopPropagation(preventDefault(swap))} > {fiat ? "⚡️" + s(amount) : f(amountFiat, currency)} </div> @@ -230,7 +247,7 @@ <button type="button" class="btn" - on:click|preventDefault|stopPropagation={() => handleInput(value)} + onclick={stopPropagation(preventDefault(() => handleInput(value)))} > <Left /> </button> @@ -238,7 +255,7 @@ <button type="button" class="btn" - on:click|preventDefault|stopPropagation={() => handleInput(value)} + onclick={stopPropagation(preventDefault(() => handleInput(value)))} >{value}</button > {/if} diff --git a/src/components/Password.svelte b/src/components/Password.svelte index cb57eec5..ac2a9a44 100644 --- a/src/components/Password.svelte +++ b/src/components/Password.svelte @@ -1,13 +1,15 @@ <script> + import { preventDefault } from 'svelte/legacy'; + import Icon from "$comp/Icon.svelte"; import { focus, fail, post } from "$lib/utils"; import { password as pw, passwordPrompt } from "$lib/store"; - export let user; + let { user } = $props(); - let password; + let password = $state(); let { username } = user; - let revealPassword = false; + let revealPassword = $state(false); let cancel = () => ($passwordPrompt = false); @@ -31,7 +33,7 @@ <h1 class="text-center text-2xl font-semibold"> Please enter your password </h1> - <form on:submit|preventDefault={submit}> + <form onsubmit={preventDefault(submit)}> <div class="relative mb-5"> {#if revealPassword} <input @@ -54,21 +56,21 @@ {/if} <button type="button" - on:click={() => (revealPassword = !revealPassword)} + onclick={() => (revealPassword = !revealPassword)} class="absolute right-5 top-6" > <iconify-icon icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"} width="32" - /> +></iconify-icon> </button> </div> <div class="w-full flex"> <button type="button" class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" - on:click={cancel} - on:keydown={cancel} + onclick={cancel} + onkeydown={cancel} > <div class="my-auto">Cancel</div> </button> diff --git a/src/components/Pin.svelte b/src/components/Pin.svelte index fb17c612..da53577e 100644 --- a/src/components/Pin.svelte +++ b/src/components/Pin.svelte @@ -1,28 +1,36 @@ -<script> +<script lang="ts"> + import { run, createBubbler, preventDefault } from "svelte/legacy"; + + const bubble = createBubbler(); import { t } from "$lib/translations"; import { post, success, fail, focus, setCookie } from "$lib/utils"; import Pinpad from "$comp/Pinpad.svelte"; import { pin } from "$lib/store"; import { onMount } from "svelte"; - export let value = ""; - export let title = $t("user.settings.verifyPIN"); - export let cancel = () => (p = ""); - export let notify = true; + interface Props { + value?: string; + title?: any; + cancel?: any; + notify?: boolean; + } - let p = ""; + let { + value = $bindable(""), + title = $t("user.settings.verifyPIN"), + cancel = () => (p = ""), + notify = true, + }: Props = $props(); - $: update(value); - let update = (value) => (p = value); + let p = $state(""); - $: p.toString().length > 5 && (value = p.toString()); + let update = (value) => (p = value); - let loaded; + let loaded = $state(); onMount(() => setTimeout(() => (loaded = true), 500)); - let locktime = 30 * 60; + let locktime = $state(30 * 60); - $: loaded && checkPin(p); let checkPin = async (p) => { if (p?.length !== 6) return; let result; @@ -41,12 +49,21 @@ value = ""; } }; + run(() => { + p.toString().length > 5 && (value = p.toString()); + }); + run(() => { + update(value); + }); + run(() => { + loaded && checkPin(p); + }); </script> {#if loaded} <div class="fixed bg-base-100 bg-opacity-90 inset-0 h-full w-full z-50 cursor-default" - on:click|preventDefault + onclick={preventDefault(bubble("click"))} > <div class="mx-auto p-5 border shadow-lg rounded-md bg-base-100 space-y-5 max-w-lg" @@ -58,10 +75,7 @@ <label for="locktime" class="font-bold" >{$t("user.settings.rememberFor")}</label > - <select - name="locktime" - bind:value={locktime} - > + <select name="locktime" bind:value={locktime}> <option value={30}>30 {$t("user.settings.seconds")}</option> <option value={5 * 60}>5 {$t("user.settings.minutes")}</option> <option value={10 * 60}>10 {$t("user.settings.minutes")}</option> @@ -72,7 +86,7 @@ </div> <div class="w-full flex"> - <button class="btn" on:click|preventDefault={cancel}> + <button class="btn" onclick={preventDefault(cancel)}> <div class="my-auto">Cancel</div> </button> </div> diff --git a/src/components/Pinpad.svelte b/src/components/Pinpad.svelte index d61dd2a0..93f31d08 100644 --- a/src/components/Pinpad.svelte +++ b/src/components/Pinpad.svelte @@ -1,11 +1,12 @@ <script> + import { preventDefault, stopPropagation } from 'svelte/legacy'; + import Left from "$comp/Left.svelte"; import Icon from "$comp/Icon.svelte"; import { focus, post, warning } from "$lib/utils"; import { t } from "$lib/translations"; - export let v; - export let cancel; + let { v = $bindable(), cancel } = $props(); let arrow = "<"; let loading = false; @@ -33,7 +34,7 @@ } }; - let hide = true; + let hide = $state(true); </script> <label @@ -41,7 +42,7 @@ > {#if hide} <input - on:keydown={validate} + onkeydown={validate} use:focus bind:value={v} type="password" @@ -50,7 +51,7 @@ /> {:else} <input - on:keydown={validate} + onkeydown={validate} use:focus bind:value={v} class="clean text-center !text-5xl !w-96 block" @@ -61,9 +62,9 @@ <iconify-icon icon={hide ? "ph:eye-slash-bold" : "ph:eye-bold"} width="32" - on:click|stopPropagation|preventDefault={() => (hide = !hide)} + onclick={stopPropagation(preventDefault(() => (hide = !hide)))} class="cursor-pointer" - /> +></iconify-icon> </label> <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto grayscale"> @@ -72,7 +73,7 @@ <button type="button" class="btn" - on:click|stopPropagation|preventDefault={() => handleInput(value)} + onclick={stopPropagation(preventDefault(() => handleInput(value)))} > <Left /> </button> @@ -80,7 +81,7 @@ <button type="button" class="btn" - on:click|stopPropagation|preventDefault={() => handleInput(value)} + onclick={stopPropagation(preventDefault(() => handleInput(value)))} >{value}</button > {/if} diff --git a/src/components/Popup.svelte b/src/components/Popup.svelte index df96215f..661b2bed 100644 --- a/src/components/Popup.svelte +++ b/src/components/Popup.svelte @@ -1,7 +1,7 @@ <script> import { page } from "$app/stores"; import Avatar from "$comp/Avatar.svelte"; - export let tags; + let { tags } = $props(); let addr = (tags) => { let { diff --git a/src/components/Qr.svelte b/src/components/Qr.svelte index e98497c4..c8d33e23 100644 --- a/src/components/Qr.svelte +++ b/src/components/Qr.svelte @@ -1,14 +1,14 @@ <script> import screenfull from "screenfull"; - export let src; - let qr; + let { src } = $props(); + let qr = $state(); </script> <div class="w-80 mx-auto cursor-pointer" bind:this={qr} - on:click={() => screenfull.toggle(qr)} - on:keydown={() => screenfull.toggle(qr)} + onclick={() => screenfull.toggle(qr)} + onkeydown={() => screenfull.toggle(qr)} > <img {src} class="mx-auto" alt="QR Code" /> </div> diff --git a/src/components/SetAmount.svelte b/src/components/SetAmount.svelte index 506762da..332c2eca 100644 --- a/src/components/SetAmount.svelte +++ b/src/components/SetAmount.svelte @@ -1,17 +1,21 @@ <script> + import { preventDefault, stopPropagation } from "svelte/legacy"; + import Numpad from "$comp/Numpad.svelte"; import Toggle from "$comp/Toggle.svelte"; - export let currency, - rate, - fiat, - submit, + let { + currency = $bindable(), + fiat = $bindable(), + rate = $bindable(), + submit = $bindable(), settingAmount, setAmount, - newAmount, + newAmount = $bindable(), toggleAmount, t, - amountPrompt; + amountPrompt = $bindable(), + } = $props(); </script> {#if settingAmount} @@ -21,19 +25,13 @@ <div class="relative mx-auto p-12 max-w-xl shadow-lg rounded-md bg-base-100 space-y-5" > - <form on:submit|preventDefault={setAmount} class="space-y-5"> - <Numpad - bind:amount={newAmount} - bind:currency - bind:rate - bind:fiat - bind:submit - /> + <form onsubmit={preventDefault(setAmount)} class="space-y-5"> + <Numpad bind:amount={newAmount} bind:fiat {currency} {rate} {submit} /> <div class="w-full flex flex-wrap gap-2"> <button bind:this={submit} type="submit" - on:click|preventDefault|stopPropagation={setAmount} + onclick={stopPropagation(preventDefault(setAmount))} class="btn btn-accent" > <div class="my-auto">{t("payments.ok")}</div> @@ -41,8 +39,8 @@ <button type="button" class="btn" - on:click|preventDefault|stopPropagation={toggleAmount} - on:keydown|preventDefault|stopPropagation={toggleAmount} + onclick={stopPropagation(preventDefault(toggleAmount))} + onkeydown={stopPropagation(preventDefault(toggleAmount))} > <div class="my-auto">{t("payments.cancel")}</div> </button> diff --git a/src/components/Slider.svelte b/src/components/Slider.svelte index b82b6bf9..137c28b4 100644 --- a/src/components/Slider.svelte +++ b/src/components/Slider.svelte @@ -1,8 +1,17 @@ -<script> - export let value, +<script lang="ts"> + interface Props { + value: any; + handle: any; + min?: number; + max?: number; + } + + let { + value = $bindable(), handle, min = 0, - max = 100; + max = 100 + }: Props = $props(); </script> <input @@ -13,7 +22,7 @@ bind:value class="px-0 py-0 my-5" style="--bgPercent: {((value - min) * 100) / (max - min)}%;" - on:input={handle} + oninput={handle} /> <style> diff --git a/src/components/Toggle.svelte b/src/components/Toggle.svelte index 2f92837d..0bc319ab 100644 --- a/src/components/Toggle.svelte +++ b/src/components/Toggle.svelte @@ -1,6 +1,5 @@ <script> - export let id; - export let value; + let { id, value = $bindable() } = $props(); </script> <label for={id} class="inline-flex relative items-center mr-5 cursor-pointer"> @@ -13,5 +12,5 @@ /> <div class="w-11 h-6 bg-gray-200 rounded-full peer dark:bg-gray-700 peer-focus:ring-4 peer-focus:ring-gray-300 dark:peer-focus:ring-gray-800 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-green-500" - /> +></div> </label> diff --git a/src/components/WalletPass.svelte b/src/components/WalletPass.svelte index 75c94f34..57cf69c3 100644 --- a/src/components/WalletPass.svelte +++ b/src/components/WalletPass.svelte @@ -1,9 +1,11 @@ <script> + import { preventDefault } from 'svelte/legacy'; + import { focus } from "$lib/utils"; import { t } from "$lib/translations"; import Icon from "$comp/Icon.svelte"; - export let cancel, password, submit; - let revealPassword; + let { cancel, password = $bindable(), submit } = $props(); + let revealPassword = $state(); </script> <div @@ -15,7 +17,7 @@ <h1 class="text-center text-2xl font-semibold"> {$t("payments.enterWalletPass")} </h1> - <form on:submit|preventDefault={submit}> + <form onsubmit={preventDefault(submit)}> <div class="relative mb-5"> {#if revealPassword} <input @@ -38,7 +40,7 @@ {/if} <button type="button" - on:click={() => (revealPassword = !revealPassword)} + onclick={() => (revealPassword = !revealPassword)} class="absolute right-5 top-1/2" > <Icon icon={revealPassword ? "eye" : "eye-off"} /> @@ -48,8 +50,8 @@ <button type="button" class="border rounded-2xl font-semibold mx-auto py-5 px-6 hover:opacity-80 mx-auto grow" - on:click={cancel} - on:keydown={cancel} + onclick={cancel} + onkeydown={cancel} > <div class="my-auto">Cancel</div> </button> diff --git a/src/routes/(app)/+error.svelte b/src/routes/(app)/+error.svelte index 6ce7979c..b950608b 100644 --- a/src/routes/(app)/+error.svelte +++ b/src/routes/(app)/+error.svelte @@ -3,7 +3,7 @@ import Icon from "$comp/Icon.svelte"; import { page } from "$app/stores"; - export let data; + let { data } = $props(); let { user } = data; let link = user ? `/${user.username}` : "/"; diff --git a/src/routes/(app)/+layout.svelte b/src/routes/(app)/+layout.svelte index 095e597d..c09fc309 100644 --- a/src/routes/(app)/+layout.svelte +++ b/src/routes/(app)/+layout.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { SvelteToast } from "@zerodevx/svelte-toast"; import { onDestroy, onMount } from "svelte"; import { close, connect, send } from "$lib/socket"; @@ -22,12 +24,10 @@ import { t, locale, loading } from "$lib/translations"; import { goto, afterNavigate, preloadData } from "$app/navigation"; - export let data; + let { data, children } = $props(); - let { generate, rate, user, subject, token, rates, theme } = data; - $: theme = $themeStore; + let { generate, rate, user, subject, token, rates, theme } = $state(data); - $: update(data); let update = (data) => { ({ rate, user, subject, token, rates, theme } = data); }; @@ -67,7 +67,6 @@ } }); - $: browser && connect(token); let lost, checkTimer, @@ -93,6 +92,15 @@ clearTimeout(expireTimer); } }); + run(() => { + theme = $themeStore; + }); + run(() => { + update(data); + }); + run(() => { + browser && connect(token); + }); </script> {#if browser && user && $passwordPrompt} @@ -119,7 +127,7 @@ <main class="pb-20 min-h-dvh" data-theme={theme}> <AppHeader {user} {subject} /> {#if !$loading} - <slot /> + {@render children?.()} {/if} </main> diff --git a/src/routes/(app)/[username]/(profile)/+layout.svelte b/src/routes/(app)/[username]/(profile)/+layout.svelte index 03cad4ff..65911eee 100644 --- a/src/routes/(app)/[username]/(profile)/+layout.svelte +++ b/src/routes/(app)/[username]/(profile)/+layout.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { invalidate } from "$app/navigation"; import { browser } from "$app/environment"; import { hexToUint8Array } from "uint8array-extras"; @@ -8,7 +10,7 @@ import { bech32m } from "@scure/base"; import { page } from "$app/stores"; - export let data; + let { data, children } = $props(); let { encode, toWords } = bech32m; @@ -22,10 +24,9 @@ follows, followers, followList, - } = data; - let { currency, npub, username: n, display } = subject; + } = $state(data); + let { currency, npub, username: n, display } = $state(subject); - $: refresh(data); let refresh = (data) => { ({ events, @@ -41,15 +42,8 @@ ({ currency, npub, username: n, display } = subject); }; - $: stripped = n.replace(/\s/g, ""); - $: username = n.length > 60 ? n.substr(0, 6) : display || stripped; - $: lnaddr = subject?.anon - ? subject.lud16 || undefined - : `${stripped}@${$page.url.host}`; - $: profile = `${$page.url.host}/${subject.anon ? npub : stripped}`; - let list = []; - $: followList.then((l) => (list = l)); + let list = $state([]); let follow = async () => { list = [...list, subject.pubkey]; let tags = await get( @@ -95,15 +89,14 @@ } }; - $: following = list.some((t) => t.includes(subject.pubkey)); - let showBio; + let showBio = $state(); let toggleBio = () => (showBio = !showBio); - let showDetails; + let showDetails = $state(); let toggleDetails = () => (showDetails = !showDetails); - let password; + let password = $state(); let reset = async () => { try { @@ -113,28 +106,41 @@ fail(e.message); } }; + run(() => { + refresh(data); + }); + let stripped = $derived(n.replace(/\s/g, "")); + let username = $derived(n.length > 60 ? n.substr(0, 6) : display || stripped); + let lnaddr = $derived(subject?.anon + ? subject.lud16 || undefined + : `${stripped}@${$page.url.host}`); + let profile = $derived(`${$page.url.host}/${subject.anon ? npub : stripped}`); + run(() => { + followList.then((l) => (list = l)); + }); + let following = $derived(list.some((t) => t.includes(subject.pubkey))); </script> <div class="container mx-auto w-full px-4 flex flex-wrap lg:flex-nowrap"> - <div class="hidden lg:block lg:w-[280px] xl:w-[360px]" /> + <div class="hidden lg:block lg:w-[280px] xl:w-[360px]"></div> <div class="w-full lg:w-[280px] xl:w-[360px] lg:absolute space-y-2 left-20 mx-auto" > <button type="button" - on:click={toggleDetails} + onclick={toggleDetails} class="flex text-3xl font-bold text-center mx-auto justify-center gap-2" > <div class="my-auto break-words">{display || username}</div> - <iconify-icon icon="ph:qr-code-bold" width="32" /> + <iconify-icon icon="ph:qr-code-bold" width="32"></iconify-icon> </button> {#if subject.address || subject.about} <div class="text-secondary mx-auto text-center lg:mx-0 break-words space-y-1" class:line-clamp-2={!showBio} - on:click={toggleBio} - on:keydown={toggleBio} + onclick={toggleBio} + onkeydown={toggleBio} > <div> {subject.address || subject.about} @@ -177,11 +183,11 @@ {lnaddr} </div> <div class="flex mb-auto gap-1"> - <button class="my-auto" on:click={() => copy(lnaddr)} - ><iconify-icon icon="ph:copy-bold" width="32" /></button + <button class="my-auto" onclick={() => copy(lnaddr)} + ><iconify-icon icon="ph:copy-bold" width="32"></iconify-icon></button > <a href={`/qr/${encodeURIComponent(lnaddr)}`} class="my-auto"> - <iconify-icon icon="ph:qr-code-bold" width="32" /> + <iconify-icon icon="ph:qr-code-bold" width="32"></iconify-icon> </a> </div> </div> @@ -194,8 +200,8 @@ {profile} </div> <div class="flex mb-auto gap-1"> - <button class="my-auto" on:click={() => copy(profile)} - ><iconify-icon icon="ph:copy-bold" width="32" /></button + <button class="my-auto" onclick={() => copy(profile)} + ><iconify-icon icon="ph:copy-bold" width="32"></iconify-icon></button > <a href={`/qr/${encodeURIComponent( @@ -203,7 +209,7 @@ )}`} class="my-auto" > - <iconify-icon icon="ph:qr-code-bold" width="32" /> + <iconify-icon icon="ph:qr-code-bold" width="32"></iconify-icon> </a> </div> </div> @@ -215,11 +221,11 @@ {npub} </div> <div class="flex my-auto gap-1"> - <button class="my-auto" on:click={() => copy(npub)} - ><iconify-icon icon="ph:copy-bold" width="32" /></button + <button class="my-auto" onclick={() => copy(npub)} + ><iconify-icon icon="ph:copy-bold" width="32"></iconify-icon></button > <a href={`/qr/${encodeURIComponent(npub)}`} class="my-auto"> - <iconify-icon icon="ph:qr-code-bold" width="32" /> + <iconify-icon icon="ph:qr-code-bold" width="32"></iconify-icon> </a> </div> </div> @@ -230,13 +236,13 @@ <div class="flex flex-wrap gap-2 w-full text-lg"> {#if user && user.username !== subject.username && subject.pubkey} {#if following} - <button class="btn" on:click={unfollow}> - <iconify-icon icon="ph:user-bold" width="32" /> + <button class="btn" onclick={unfollow}> + <iconify-icon icon="ph:user-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.unfollow")}</div> </button> {:else} - <button class="btn" on:click={follow}> - <iconify-icon icon="ph:user-bold" width="32" /> + <button class="btn" onclick={follow}> + <iconify-icon icon="ph:user-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.follow")}</div> </button> {/if} @@ -256,14 +262,14 @@ <!-- {/if} --> {#if user?.admin && user.username !== subject.username} - <form class="w-full flex" on:submit|preventDefault={reset}> + <form class="w-full flex" onsubmit={preventDefault(reset)}> <input placeholder="Password reset" bind:value={password} /> <button type="submit" class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex w-60" > <div class="mx-auto flex"> - <iconify-icon icon="ph:clock" width="32" /> + <iconify-icon icon="ph:clock" width="32"></iconify-icon> </div> </button> </form> @@ -275,7 +281,7 @@ <div class="mx-auto space-y-5 lg:max-w-xl xl:max-w-2xl lg:pl-10 mt-5 lg:mt-0" > - <slot /> + {@render children?.()} </div> </div> </div> diff --git a/src/routes/(app)/[username]/(profile)/+page.svelte b/src/routes/(app)/[username]/(profile)/+page.svelte index d14f2f58..e956aab7 100644 --- a/src/routes/(app)/[username]/(profile)/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { btc, f, sat } from "$lib/utils"; import Icon from "$comp/Icon.svelte"; import Account from "$comp/Account.svelte"; @@ -8,20 +10,22 @@ import { installPrompt } from "$lib/store"; import { afterNavigate, preloadData } from "$app/navigation"; - export let data; + let { data } = $props(); afterNavigate(() => { preloadData(`/${user.username}/receive`); preloadData("/send"); }); - let { accounts, subject, user, items, rates } = data; - $: ({ currency } = subject); - $: rate = rates[currency]; - $: total = items.reduce((a, b) => a + b.price * b.quantity, 0); + let { accounts, subject, user, items, rates } = $state(data); + let { currency } = $derived(subject); + let rate = $derived(rates[currency]); + let total = $derived(items.reduce((a, b) => a + b.price * b.quantity, 0)); let refresh = (d) => ({ accounts, items, subject, user, rates } = d); - $: refresh(data); + run(() => { + refresh(data); + }); let install = async () => { if (!$installPrompt) return; @@ -42,14 +46,14 @@ <a href={`/account/savings`} class="contents"> <button class="btn btn-lg w-full rounded-2xl whitespace-nowrap"> - <iconify-icon icon="ph:plus-circle-bold" width="32" /> + <iconify-icon icon="ph:plus-circle-bold" width="32"></iconify-icon> {$t("accounts.addAccount")} </button> </a> {#if $installPrompt} - <button class="btn btn-accent lg:hidden" on:click={install}> - <iconify-icon icon="ph:floppy-disk-bold" width="32" /> + <button class="btn btn-accent lg:hidden" onclick={install}> + <iconify-icon icon="ph:floppy-disk-bold" width="32"></iconify-icon> {$t("user.install")} </button> {/if} @@ -64,7 +68,7 @@ {#if total > 0} <button class="rounded-2xl py-5 px-6 font-bold hover:bg-neutral-700 flex bg-black text-white mx-auto" - on:click={checkout} + onclick={checkout} > <div class="mx-auto flex"> <div class="my-auto text-2xl"> diff --git a/src/routes/(app)/[username]/(profile)/event/[id]/+page.svelte b/src/routes/(app)/[username]/(profile)/event/[id]/+page.svelte index 74ce1067..9244d392 100644 --- a/src/routes/(app)/[username]/(profile)/event/[id]/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/event/[id]/+page.svelte @@ -1,6 +1,6 @@ <script> import Event from "$comp/Event.svelte"; - export let data; + let { data } = $props(); let { event } = data; </script> diff --git a/src/routes/(app)/[username]/(profile)/followers/+page.svelte b/src/routes/(app)/[username]/(profile)/followers/+page.svelte index c0080990..b7ad4948 100644 --- a/src/routes/(app)/[username]/(profile)/followers/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/followers/+page.svelte @@ -4,7 +4,7 @@ import { browser } from "$app/environment"; import VirtualScroll from "svelte-virtual-scroll-list"; - export let data; + let { data } = $props(); let { followers } = data; </script> @@ -17,34 +17,36 @@ <div>Loading followers...</div> {:then followers} {#if followers.length} - <VirtualScroll data={followers} key="pubkey" let:data pageMode={true}> - <a - href={`/${data.pubkey}`} - data-sveltekit-preload-data="tap" - rel="nofollow" - > - <div - class="flex border-b last:border-b-0 py-4 text-2xl text-secondary" - :key={data.pubkey} + <VirtualScroll data={followers} key="pubkey" pageMode={true}> + {#snippet children({ data })} + <a + href={`/${data.pubkey}`} + data-sveltekit-preload-data="tap" + rel="nofollow" > - <div class="mb-auto mr-2"> - <div class="md:hidden"> - <Avatar size={12} user={data} disabled={true} /> + <div + class="flex border-b last:border-b-0 py-4 text-2xl text-secondary" + :key={data.pubkey} + > + <div class="mb-auto mr-2"> + <div class="md:hidden"> + <Avatar size={12} user={data} disabled={true} /> + </div> + <div class="hidden md:block"> + <Avatar size={20} user={data} disabled={true} /> + </div> </div> - <div class="hidden md:block"> - <Avatar size={20} user={data} disabled={true} /> - </div> - </div> - <div class="w-full flex pb-1 text-black my-auto"> - <div> - <div>{data.display_name || ""}</div> - <div class="text-secondary text-lg">@{data.name}</div> + <div class="w-full flex pb-1 text-black my-auto"> + <div> + <div>{data.display_name || ""}</div> + <div class="text-secondary text-lg">@{data.name}</div> + </div> </div> </div> - </div> - </a> - </VirtualScroll> + </a> + {/snippet} + </VirtualScroll> {:else} <div>No followers</div> {/if} diff --git a/src/routes/(app)/[username]/(profile)/follows/+page.svelte b/src/routes/(app)/[username]/(profile)/follows/+page.svelte index 9b2f70d1..ad416500 100644 --- a/src/routes/(app)/[username]/(profile)/follows/+page.svelte +++ b/src/routes/(app)/[username]/(profile)/follows/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { onMount } from "svelte"; import { t } from "$lib/translations"; import Avatar from "$comp/Avatar.svelte"; @@ -6,10 +8,12 @@ import VirtualScroll from "svelte-virtual-scroll-list"; import { invalidate } from "$app/navigation"; - export let data; - let { follows } = data; - $: refresh(data); + let { data } = $props(); + let { follows } = $state(data); let refresh = (data) => ({ follows } = data); + run(() => { + refresh(data); + }); </script> <div class="px-3 md:px-0 w-full md:w-[400px] mx-auto"> @@ -22,31 +26,33 @@ {:then follows} {#if follows.length} {#if browser} - <VirtualScroll data={follows} key="pubkey" let:data pageMode={true}> - <a - href={`/${data.pubkey}`} - data-sveltekit-preload-data="tap" - rel="nofollow" - > - <div class="flex py-4 text-lg text-secondary" :key={data.pubkey}> - <div class="mb-auto mr-2"> - <div class="md:hidden"> - <Avatar size={12} user={data} disabled={true} /> - </div> - <div class="hidden md:block"> - <Avatar size={20} user={data} disabled={true} /> + <VirtualScroll data={follows} key="pubkey" pageMode={true}> + {#snippet children({ data })} + <a + href={`/${data.pubkey}`} + data-sveltekit-preload-data="tap" + rel="nofollow" + > + <div class="flex py-4 text-lg text-secondary" :key={data.pubkey}> + <div class="mb-auto mr-2"> + <div class="md:hidden"> + <Avatar size={12} user={data} disabled={true} /> + </div> + <div class="hidden md:block"> + <Avatar size={20} user={data} disabled={true} /> + </div> </div> - </div> - <div class="w-full flex pb-1 text-black my-auto"> - <div> - <div>{data.display_name || ""}</div> - <div class="text-secondary text-base">@{data.name}</div> + <div class="w-full flex pb-1 text-black my-auto"> + <div> + <div>{data.display_name || ""}</div> + <div class="text-secondary text-base">@{data.name}</div> + </div> </div> </div> - </div> - </a> - </VirtualScroll> + </a> + {/snippet} + </VirtualScroll> {/if} {:else} <div>No follows</div> diff --git a/src/routes/(app)/[username]/+layout.svelte b/src/routes/(app)/[username]/+layout.svelte index ce152831..e3ad7259 100644 --- a/src/routes/(app)/[username]/+layout.svelte +++ b/src/routes/(app)/[username]/+layout.svelte @@ -1,9 +1,9 @@ <script> - export let data; + let { data, children, fixed } = $props(); </script> <div class="content"> - <slot /> + {@render children?.()} </div> -<slot name="fixed" /> +{@render fixed?.()} diff --git a/src/routes/(app)/[username]/receive/+page.svelte b/src/routes/(app)/[username]/receive/+page.svelte index e9e5ca43..9a696929 100644 --- a/src/routes/(app)/[username]/receive/+page.svelte +++ b/src/routes/(app)/[username]/receive/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { send } from "$lib/socket"; import { btc, post, copy, f, get, types, sat, s, sats } from "$lib/utils"; import { tick, onMount, onDestroy } from "svelte"; @@ -12,12 +14,11 @@ import { t } from "$lib/translations"; import { goto, invalidate } from "$app/navigation"; - export let data; + let { data } = $props(); let showOptions; - let { id, rates, subject, user, src, text } = data; - $: refresh(data); + let { id, rates, subject, user, src, text } = $state(data); let refresh = (data) => { ({ id, rates, subject, user, src, text } = data); }; @@ -29,19 +30,15 @@ let qr; - $: link = [types.bitcoin, types.liquid].includes(type) - ? text - : `lightning:${text}`; - $: txt = [types.bitcoin, types.liquid].includes(type) ? hash : text; let aid = subject.id; - let invoice = { + let invoice = $state({ aid, type: types.lightning, items: [], user: subject, - }; - let amount, amountFiat, tip; + }); + let amount = $state(), amountFiat, tip; let setType = async (type) => { invoice.type = type; @@ -75,10 +72,16 @@ }; let newAmount; - let settingAmount; + let settingAmount = $state(); let toggleAmount = () => (settingAmount = !settingAmount); - let fiat; let submit; + run(() => { + refresh(data); + }); + let link = $derived([types.bitcoin, types.liquid].includes(type) + ? text + : `lightning:${text}`); + let txt = $derived([types.bitcoin, types.liquid].includes(type) ? hash : text); </script> <div class="invoice container mx-auto max-w-xl px-4 space-y-2"> @@ -115,7 +118,6 @@ <SetAmount {currency} {rate} - {fiat} {submit} {settingAmount} {setAmount} diff --git a/src/routes/(app)/account/[id]/+page.svelte b/src/routes/(app)/account/[id]/+page.svelte index be7d6112..29add530 100644 --- a/src/routes/(app)/account/[id]/+page.svelte +++ b/src/routes/(app)/account/[id]/+page.svelte @@ -14,19 +14,19 @@ PUBLIC_COINOS_RELAY as relay, } from "$env/static/public"; - export let data; + let { data } = $props(); let { account, user } = data; let { id, name, seed } = account; - let mnemonic, password; - let passwordPrompt; - let cancel = () => (passwordPrompt = false); + let mnemonic = $state(), password = $state(); + let passwordPrompt = $state(); + let cancel = $state(() => (passwordPrompt = false)); let toggle = () => (passwordPrompt = !passwordPrompt); - let submit = async () => { + let submit = $state(async () => { toggle(); let entropy = await decrypt(seed, password); mnemonic = entropyToMnemonic(entropy, wordlist); - }; + }); let del = async () => { try { @@ -37,7 +37,7 @@ } }; - let nwc; + let nwc = $state(); let revealNwc = () => (nwc = `nostr+walletconnect://${pk}?relay=${encodeURIComponent( relay, @@ -53,17 +53,17 @@ {#if mnemonic} <Mnemonic {mnemonic} /> - <button on:click={() => copy(mnemonic)} type="button" class="btn"> - <iconify-icon icon="ph:copy-bold" width="32" /> + <button onclick={() => copy(mnemonic)} type="button" class="btn"> + <iconify-icon icon="ph:copy-bold" width="32"></iconify-icon> <div class="my-auto">{$t("accounts.copy")}</div></button > {:else if seed} <button - on:click={toggle} + onclick={toggle} type="button" class="flex gap-2 rounded-2xl border py-5 mx-auto px-6 w-full justify-center" > - <iconify-icon icon="ph:eye-bold" width="32" /> + <iconify-icon icon="ph:eye-bold" width="32"></iconify-icon> <div class="my-auto">{$t("accounts.revealMnemonic")}</div></button > {:else if nwc} @@ -71,26 +71,26 @@ {nwc} </div> <button - on:click={() => copy(nwc)} + onclick={() => copy(nwc)} type="button" class="flex gap-2 rounded-2xl border py-5 mx-auto px-6 w-full justify-center" > - <iconify-icon icon="ph:copy-bold" width="32" /> + <iconify-icon icon="ph:copy-bold" width="32"></iconify-icon> <div class="my-auto">{$t("accounts.copy")}</div></button > <a href={`/qr/${encodeURIComponent(nwc)}`} class="my-auto block"> <button - on:click={() => copy(nwc)} + onclick={() => copy(nwc)} type="button" class="flex gap-2 rounded-2xl border py-5 mx-auto px-6 w-full justify-center" > - <iconify-icon icon="ph:qr-code-bold" width="32" /> + <iconify-icon icon="ph:qr-code-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.receive.showQR")}</div></button > </a> {:else} <button - on:click={revealNwc} + onclick={revealNwc} type="button" class="flex gap-2 rounded-2xl border py-5 mx-auto px-6 w-full justify-center" > @@ -101,7 +101,7 @@ {#if seed} <button - on:click={del} + onclick={del} type="button" class="flex gap-2 rounded-2xl border py-5 mx-auto px-6 w-full justify-center" > @@ -111,7 +111,7 @@ {/if} </div> - <div /> + <div></div> </form> </div> </div> diff --git a/src/routes/(app)/account/import/+page.svelte b/src/routes/(app)/account/import/+page.svelte index a1d6549b..b94cc839 100644 --- a/src/routes/(app)/account/import/+page.svelte +++ b/src/routes/(app)/account/import/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { goto } from "$app/navigation"; import { mnemonic } from "$lib/store"; import { fail, focus, versions } from "$lib/utils"; @@ -8,7 +10,7 @@ import { validateMnemonic } from "@scure/bip39"; import { wordlist } from "@scure/bip39/wordlists/english"; - let el, pasted, text; + let el = $state(), pasted = $state(), text = $state(); let paste = async () => { text = await navigator.clipboard.readText(); @@ -26,14 +28,16 @@ } }; - $: if (browser && pasted && text) form.submit() && (pasted = false); + run(() => { + if (browser && pasted && text) form.submit() && (pasted = false); + }); </script> <div class="space-y-5"> <h1 class="text-center text-3xl font-semibold">{$t("accounts.import")}</h1> <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-2"> - <form on:submit|preventDefault={submit} class="space-y-2"> + <form onsubmit={preventDefault(submit)} class="space-y-2"> <textarea use:focus name="text" @@ -41,7 +45,7 @@ class="w-full p-4 border rounded-xl h-48 text-xl" bind:value={text} autocapitalize="none" - /> +></textarea> <button bind:this={el} type="submit" diff --git a/src/routes/(app)/account/pass/+page.svelte b/src/routes/(app)/account/pass/+page.svelte index 5becf337..62ef9b8e 100644 --- a/src/routes/(app)/account/pass/+page.svelte +++ b/src/routes/(app)/account/pass/+page.svelte @@ -1,4 +1,6 @@ <script lang="ts"> + import { preventDefault } from 'svelte/legacy'; + import { tick, onMount } from "svelte"; import { t } from "$lib/translations"; import { mnemonic } from "$lib/store"; @@ -15,12 +17,12 @@ import { goto } from "$app/navigation"; import { HDKey } from "@scure/bip32"; - export let data; + let { data } = $props(); let { user } = data; - let submitting; + let submitting = $state(); - let confirm, password, revealPassword, revealConfirm; + let confirm = $state(), password = $state(), revealPassword = $state(), revealConfirm = $state(); let type = "bitcoin"; let name = $t("accounts.savings"); @@ -70,7 +72,7 @@ </div> <form - on:submit|preventDefault={submit} + onsubmit={preventDefault(submit)} class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5" > <p class="text-secondary mb-1"> @@ -100,7 +102,7 @@ <button tabindex="-1" type="button" - on:click={() => (revealPassword = !revealPassword)} + onclick={() => (revealPassword = !revealPassword)} class="absolute right-5 -translate-y-1/2 top-1/2" > <Icon icon={revealPassword ? "eye" : "eye-off"} /> @@ -129,7 +131,7 @@ <button type="button" tabindex="-1" - on:click={() => (revealConfirm = !revealConfirm)} + onclick={() => (revealConfirm = !revealConfirm)} class="absolute right-5 -translate-y-1/2 top-1/2" > <Icon icon={revealConfirm ? "eye" : "eye-off"} /> diff --git a/src/routes/(app)/account/savings/+page.svelte b/src/routes/(app)/account/savings/+page.svelte index 2461bd20..d0474636 100644 --- a/src/routes/(app)/account/savings/+page.svelte +++ b/src/routes/(app)/account/savings/+page.svelte @@ -13,7 +13,7 @@ <a href="/account/seed" class="block"> <div class="card card-side shadow shadow-base-400 p-8 hover:bg-base-200"> <figure class="w-20"> - <iconify-icon icon="ph:file-plus-bold" width="64" /> + <iconify-icon icon="ph:file-plus-bold" width="64"></iconify-icon> </figure> <div> <div class="text-xl">{$t("accounts.create")}</div> @@ -24,7 +24,7 @@ <a href="/account/import" class="block"> <div class="card card-side shadow p-8 hover:bg-base-200"> <figure class="w-20"> - <iconify-icon icon="ph:folder-open-bold" width="64" /> + <iconify-icon icon="ph:folder-open-bold" width="64"></iconify-icon> </figure> <div> <div class="text-xl">{$t("accounts.import")}</div> diff --git a/src/routes/(app)/account/seed/+page.svelte b/src/routes/(app)/account/seed/+page.svelte index 5d828369..b3e7d57c 100644 --- a/src/routes/(app)/account/seed/+page.svelte +++ b/src/routes/(app)/account/seed/+page.svelte @@ -9,7 +9,7 @@ import { generateMnemonic } from "@scure/bip39"; import { wordlist } from "@scure/bip39/wordlists/english"; - export let data; + let { data } = $props(); let { user } = data; onMount(async () => { @@ -36,7 +36,7 @@ <button type="button" class="flex gap-2 text-center break-all rounded-2xl hover:opacity-80 py-3 px-4 w-full mx-auto justify-center border whitespace-nowrap mb-2" - on:click={generate} + onclick={generate} > <Icon icon="random" style="w-8 my-auto" /> <div class="my-auto">{$t("accounts.regenerate")}</div> @@ -45,7 +45,7 @@ <button type="button" class="flex gap-2 text-center break-all rounded-2xl hover:opacity-80 py-3 px-4 w-full mx-auto justify-center border whitespace-nowrap mb-2" - on:click={() => copy($mnemonic)} + onclick={() => copy($mnemonic)} > <Icon icon="copy" style="w-8 my-auto" /> <div class="my-auto"> diff --git a/src/routes/(app)/admin/+layout.svelte b/src/routes/(app)/admin/+layout.svelte index 54905ab0..39cfe5ed 100644 --- a/src/routes/(app)/admin/+layout.svelte +++ b/src/routes/(app)/admin/+layout.svelte @@ -1,10 +1,10 @@ <script> import LandingHeader from "$comp/LandingHeader.svelte"; - export let data; + let { data, children } = $props(); let { user } = data; </script> <LandingHeader {user} /> <main class="container px-10 md:px-40 mx-auto min-h-[600px] pb-20"> - <slot /> + {@render children?.()} </main> diff --git a/src/routes/(app)/admin/+page.svelte b/src/routes/(app)/admin/+page.svelte index 214bf5b3..ccaa8794 100644 --- a/src/routes/(app)/admin/+page.svelte +++ b/src/routes/(app)/admin/+page.svelte @@ -1,9 +1,9 @@ <script> import { post } from "$lib/utils"; - export let data; + let { data } = $props(); let reset = (username) => post(`/reset`, { password }); let { users } = data; - let password; + let password = $state(); </script> {#each users as { balance, username, expected }} @@ -15,7 +15,7 @@ <div> <button class="text-sm md:text-lg rounded-full border py-2 px-4 hover:opacity-80 min-w-[72px] bg-black text-white" - on:click={() => reset(username)}>Reset</button + onclick={() => reset(username)}>Reset</button > </div> </div> diff --git a/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte b/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte index f9c80329..d0d06046 100644 --- a/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte +++ b/src/routes/(app)/ecash/[id]/[...version]/+layout.svelte @@ -3,7 +3,7 @@ import { t } from "$lib/translations"; import Icon from "$comp/Icon.svelte"; - export let data; + let { data, children } = $props(); let { id, rates, user, token, total, spent, external, mint } = data; let currency = user?.currency || "USD"; @@ -11,8 +11,8 @@ let amount = total - spent; - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); - $: spentFiat = parseFloat(((spent * rate) / sats).toFixed(2)); + let amountFiat = $derived(parseFloat(((amount * rate) / sats).toFixed(2))); + let spentFiat = $derived(parseFloat(((spent * rate) / sats).toFixed(2))); </script> <div class="container px-4 max-w-lg mx-auto space-y-5 mt-20"> @@ -52,5 +52,5 @@ </div> {/if} - <slot /> + {@render children?.()} </div> diff --git a/src/routes/(app)/ecash/[id]/[...version]/+page.svelte b/src/routes/(app)/ecash/[id]/[...version]/+page.svelte index b350b124..47126c78 100644 --- a/src/routes/(app)/ecash/[id]/[...version]/+page.svelte +++ b/src/routes/(app)/ecash/[id]/[...version]/+page.svelte @@ -4,11 +4,10 @@ import { t } from "$lib/translations"; import { page } from "$app/stores"; - export let data; - export let form; + let { data, form } = $props(); let link = $page.url.href; - let { id, total, version, token, external, spent } = data; + let { id, total, version, token, external, spent } = $state(data); </script> {#if form?.error} @@ -20,8 +19,8 @@ {/if} <div class="flex flex-wrap gap-2 text-xl"> - <button type="button" class="btn" on:click={() => copy(link)}> - <iconify-icon icon="ph:link-bold" width="32" /> + <button type="button" class="btn" onclick={() => copy(link)}> + <iconify-icon icon="ph:link-bold" width="32"></iconify-icon> <div class="my-auto">{$t("payments.shareLink")}</div> </button> @@ -33,7 +32,7 @@ icon="ph:hand-coins-bold" width="32" flip="horizontal" - /> +></iconify-icon> <div class="my-auto">{$t("payments.swap")}</div> </button> </a> @@ -45,7 +44,7 @@ icon="ph:hand-coins-bold" width="32" flip="horizontal" - /> +></iconify-icon> <div class="my-auto">{$t("payments.redeem")}</div> </button> </form> @@ -54,7 +53,7 @@ <button class="btn break-all !h-auto py-5 font-normal leading-normal" - on:click={() => copy(token)} + onclick={() => copy(token)} > {token} </button> @@ -62,14 +61,14 @@ {#if version === 4} <a data-sveltekit-reload href={`/ecash/${id}/3`} class="contents"> <button type="button" class="btn"> - <iconify-icon icon="ph:gear-bold" width="32" /> + <iconify-icon icon="ph:gear-bold" width="32"></iconify-icon> <div class="my-auto">{$t("payments.legacyVersion")}</div> </button> </a> {:else} <a data-sveltekit-reload href={`/ecash/${id}`} class="contents"> <button type="button" class="btn"> - <iconify-icon icon="ph:gear-bold" width="32" /> + <iconify-icon icon="ph:gear-bold" width="32"></iconify-icon> <div class="my-auto">{$t("payments.newVersion")}</div> </button> </a> diff --git a/src/routes/(app)/ecash/[id]/[...version]/swap/+page.svelte b/src/routes/(app)/ecash/[id]/[...version]/swap/+page.svelte index ee22cea2..c434c9b4 100644 --- a/src/routes/(app)/ecash/[id]/[...version]/swap/+page.svelte +++ b/src/routes/(app)/ecash/[id]/[...version]/swap/+page.svelte @@ -1,5 +1,5 @@ <script> - export let data; + let { data } = $props(); </script> <div class="text-center"> diff --git a/src/routes/(app)/forgot/+page.svelte b/src/routes/(app)/forgot/+page.svelte index 378262cc..eb981734 100644 --- a/src/routes/(app)/forgot/+page.svelte +++ b/src/routes/(app)/forgot/+page.svelte @@ -6,8 +6,8 @@ import Spinner from "$comp/Spinner.svelte"; import { fly } from "svelte/transition"; - export let form; - let email; + let { form } = $props(); + let email = $state(); let loading; </script> diff --git a/src/routes/(app)/fund/[id]/+page.svelte b/src/routes/(app)/fund/[id]/+page.svelte index b81e2917..0931075a 100644 --- a/src/routes/(app)/fund/[id]/+page.svelte +++ b/src/routes/(app)/fund/[id]/+page.svelte @@ -9,7 +9,7 @@ import { types, copy, f, s, sat, sats } from "$lib/utils"; import { loginRedirect } from "$lib/store"; - export let data; + let { data } = $props(); let { amount, src, payments, rates, user } = data; let { id } = $page.params; @@ -19,10 +19,10 @@ let currency = user ? user.currency : "CAD"; let rate = rates[currency]; - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); + let amountFiat = $derived(parseFloat(((amount * rate) / sats).toFixed(2))); $loginRedirect = $page.url.pathname; - let show; + let show = $state(); let toggle = () => (show = !show); </script> @@ -83,14 +83,14 @@ <div class="flex gap-2" data-sveltekit-prefetch="off"> <button class="rounded-full border py-3 px-2 font-bold hover:opacity-80 flex gap-1 w-full justify-center" - on:click={toggle} + onclick={toggle} > <Icon icon="qr" style="invert" /> {show ? $t("payments.hide") : $t("payments.show")} QR </button> <button class="rounded-full border py-3 px-2 font-bold hover:opacity-80 flex gap-1 w-full justify-center" - on:click={() => copy($page.url.host + $page.url.pathname)} + onclick={() => copy($page.url.host + $page.url.pathname)} > <Icon icon="copy" style="w-6" /> {$t("payments.copyLink")} diff --git a/src/routes/(app)/fund/[id]/sweep/+page.svelte b/src/routes/(app)/fund/[id]/sweep/+page.svelte index 927c59d3..a34a8610 100644 --- a/src/routes/(app)/fund/[id]/sweep/+page.svelte +++ b/src/routes/(app)/fund/[id]/sweep/+page.svelte @@ -4,11 +4,11 @@ import Icon from "$comp/Icon.svelte"; import { t } from "$lib/translations"; - export let data; + let { data } = $props(); let { amount, id, user, rates } = data; let { currency } = user; - $: rate = rates[currency]; + let rate = $derived(rates[currency]); </script> <div class="container px-4 max-w-xl mx-auto mt-10 space-y-5 text-center"> @@ -33,7 +33,7 @@ </div> <a href={`/payments`}> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> + <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div> </a> <div class="flex justify-center"> diff --git a/src/routes/(app)/fund/[id]/withdraw/+page.svelte b/src/routes/(app)/fund/[id]/withdraw/+page.svelte index 0ad3c2cf..89654d23 100644 --- a/src/routes/(app)/fund/[id]/withdraw/+page.svelte +++ b/src/routes/(app)/fund/[id]/withdraw/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { t } from "$lib/translations"; import { enhance } from "$app/forms"; import Icon from "$comp/Icon.svelte"; @@ -8,25 +10,29 @@ import { back } from "$lib/utils"; import { pin } from "$lib/store"; - export let data; - export let form; + let { data, form } = $props(); let { rates } = data; - let { amount, id } = $page.params; - let { currency } = data.user; - let loading; + let { amount, id } = $state($page.params); + let { currency } = $state(data.user); + let loading = $state(); let submit = () => (loading = true); - $: update(form); let update = () => { if (form?.message.includes("pin")) $pin = undefined; loading = false; }; - $: rate = rates[currency]; + run(() => { + update(form); + }); + let rate; + run(() => { + rate = rates[currency]; + }); </script> -<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}> +<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" onclick={back}> <Icon icon="arrow-left" style="w-10" /> </button> @@ -39,7 +45,7 @@ <div class="container px-4 mt-20 max-w-xl mx-auto"> <Numpad bind:amount bind:currency bind:rate /> - <form method="POST" use:enhance on:submit={submit}> + <form method="POST" use:enhance onsubmit={submit}> <input name="id" value={id} type="hidden" /> <input name="amount" value={amount} type="hidden" /> <input name="pin" value={$pin} type="hidden" /> diff --git a/src/routes/(app)/generate/+page.svelte b/src/routes/(app)/generate/+page.svelte index 49d75dc6..72ca2485 100644 --- a/src/routes/(app)/generate/+page.svelte +++ b/src/routes/(app)/generate/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { fail, post, wait } from "$lib/utils"; import { onMount } from "svelte"; import { goto, invalidate } from "$app/navigation"; @@ -8,10 +10,10 @@ import { generate } from "$lib/nostr"; import { browser } from "$app/environment"; - export let data; - let { user } = data; + let { data } = $props(); + let { user } = $state(data); - let loaded; + let loaded = $state(); let gen = async () => { if (!browser) return; @@ -43,7 +45,9 @@ onMount(() => browser && setTimeout(() => (loaded = true) && gen(), 50)); - $: $pin?.length === 6 && gen(user); + run(() => { + $pin?.length === 6 && gen(user); + }); </script> {#if loaded && user?.haspin && $pin?.length !== 6} diff --git a/src/routes/(app)/invoice/[id]/[email protected] b/src/routes/(app)/invoice/[id]/[email protected] index 62c05db1..05fd603f 100644 --- a/src/routes/(app)/invoice/[id]/[email protected] +++ b/src/routes/(app)/invoice/[id]/[email protected] @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { SvelteToast } from "@zerodevx/svelte-toast"; import { onDestroy, onMount } from "svelte"; import { close, connect, send } from "$lib/socket"; @@ -22,16 +24,14 @@ import { t, locale, loading } from "$lib/translations"; import { goto, onNavigate } from "$app/navigation"; - export let data; + let { data, children } = $props(); - let { generate, rate, user, subject, token, rates, theme } = data; + let { generate, rate, user, subject, token, rates, theme } = $state(data); - $: update(data); let update = (data) => { ({ rate, user, subject, token, rates, theme } = data); }; - $: theme = $themeStore; $themeStore = theme; onMount(async () => { @@ -58,7 +58,6 @@ } }); - $: browser && connect(token); let lost, checkTimer, @@ -84,6 +83,15 @@ clearTimeout(expireTimer); } }); + run(() => { + update(data); + }); + run(() => { + theme = $themeStore; + }); + run(() => { + browser && connect(token); + }); </script> {#if browser && user && $passwordPrompt} @@ -110,7 +118,7 @@ <main class="min-h-dvh" data-theme={theme}> <AppHeader {user} {subject} /> {#if !$loading} - <slot /> + {@render children?.()} {/if} </main> diff --git a/src/routes/(app)/invoice/[id]/+page.svelte b/src/routes/(app)/invoice/[id]/+page.svelte index ae208779..fef43e4d 100644 --- a/src/routes/(app)/invoice/[id]/+page.svelte +++ b/src/routes/(app)/invoice/[id]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from "svelte/legacy"; + import { enhance } from "$app/forms"; import { send } from "$lib/socket"; import { btc, post, copy, f, get, types, sat, s, sats } from "$lib/utils"; @@ -13,7 +15,7 @@ import { t } from "$lib/translations"; import { goto, invalidate } from "$app/navigation"; - export let data; + let { data } = $props(); let showOptions; @@ -24,8 +26,7 @@ let readingerror = (e) => console.log("nfc error", e); - $: refresh(data); - let { invoice, id, subject, user, src } = data; + let { invoice, id, subject, user, src } = $state(data); let { aid, amount, @@ -35,9 +36,9 @@ text, tip, user: { username, currency }, - } = invoice; + } = $state(invoice); - let qr; + let qr = $state(); let tipPercent = 0; let refresh = async (data) => { @@ -64,9 +65,6 @@ tipPercent = (tip / amount) * 100; }; - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); - $: tipAmount = ((tip * rate) / sats).toFixed(2); - let subbed = {}; onMount(async () => { @@ -81,11 +79,6 @@ } }); - $: link = [types.bitcoin, types.liquid].includes(type) - ? text - : `lightning:${text}`; - $: txt = [types.bitcoin, types.liquid].includes(type) ? hash : text; - let setType = async (type) => { invoice.type = type; ({ id } = await post(`/invoice`, { @@ -96,7 +89,7 @@ goto(`./${id}?options=true`, { invalidateAll: true, noScroll: true }); }; - let setAmount = async () => { + let setAmount = $state(async () => { if (typeof $amountPrompt === "undefined") $amountPrompt = true; settingAmount = false; amount = newAmount; @@ -112,39 +105,57 @@ else url += "?options=true"; goto(url, { invalidateAll: true, noScroll: true }); - }; + }); - let newAmount; - let settingAmount; - let toggleAmount = () => (settingAmount = !settingAmount); - let fiat; - let submit; + let newAmount = $state(); + let settingAmount = $state(); + let toggleAmount = $state(() => (settingAmount = !settingAmount)); + let fiat = $state(true); + let submit = $state(); + run(() => { + refresh(data); + }); + let amountFiat; + run(() => { + amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); + }); + let tipAmount = $derived(((tip * rate) / sats).toFixed(2)); + let link; + run(() => { + link = [types.bitcoin, types.liquid].includes(type) + ? text + : `lightning:${text}`; + }); + let txt; + run(() => { + txt = [types.bitcoin, types.liquid].includes(type) ? hash : text; + }); </script> <div class="invoice container mx-auto max-w-xl px-4 space-y-2"> <InvoiceData - bind:src - bind:link - bind:qr - bind:txt - bind:invoice - bind:amount - bind:amountFiat - bind:currency - bind:tip - bind:rate - bind:showQr={$showQr} + {src} + {link} + {qr} + {txt} + {invoice} + {amount} + {amountFiat} + {currency} + {tip} + {rate} + showQr={$showQr} /> <InvoiceActions - bind:toggleAmount - bind:user - bind:invoice + {toggleAmount} + {user} + {invoice} {copy} - bind:link - bind:type + {link} + {type} {types} - bind:txt + {txt} t={$t} bind:showQr={$showQr} /> @@ -153,14 +164,14 @@ </div> <SetAmount - bind:currency - bind:rate - bind:fiat - bind:submit - bind:settingAmount - bind:setAmount bind:newAmount - bind:toggleAmount + bind:fiat + {currency} + {rate} + {submit} + {settingAmount} + {setAmount} + {toggleAmount} amountPrompt={$amountPrompt} t={$t} /> diff --git a/src/routes/(app)/invoice/[id]/memo/+page.svelte b/src/routes/(app)/invoice/[id]/memo/+page.svelte index 4d23ff19..02f4a5d9 100644 --- a/src/routes/(app)/invoice/[id]/memo/+page.svelte +++ b/src/routes/(app)/invoice/[id]/memo/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { onMount } from "svelte"; import { browser } from "$app/environment"; import { invoice as inv, request } from "$lib/store"; @@ -17,11 +19,10 @@ import { enhance } from "$app/forms"; let submitting; - let submit; + let submit = $state(); - export let data; - $: refresh(data); - let { invoice, id, user, rates } = data; + let { data } = $props(); + let { invoice, id, user, rates } = $state(data); let { amount, hash, @@ -34,7 +35,7 @@ text, tip, user: { username, currency }, - } = invoice; + } = $state(invoice); invoice.memo = user?.username; @@ -55,6 +56,9 @@ user: { username }, } = invoice); }; + run(() => { + refresh(data); + }); </script> <form diff --git a/src/routes/(app)/invoice/[id]/paid/+page.svelte b/src/routes/(app)/invoice/[id]/paid/+page.svelte index b3b6e71a..1bbba082 100644 --- a/src/routes/(app)/invoice/[id]/paid/+page.svelte +++ b/src/routes/(app)/invoice/[id]/paid/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { scale } from "svelte/transition"; import Icon from "$comp/Icon.svelte"; import { toast } from "@zerodevx/svelte-toast"; @@ -6,15 +8,17 @@ import { t } from "$lib/translations"; import { fiat, f, s, sat, sats } from "$lib/utils"; - export let data; - let amount, currency, rate, received, pending, tip, user, id; - $: update(data); + let { data } = $props(); + let amount, currency = $state(), rate = $state(), received = $state(), pending = $state(), tip = $state(), user = $state(), id; let update = (data) => { ({ amount, currency, rate, received, pending, tip, user, id } = data.invoice); }; toast.pop(0); + run(() => { + update(data); + }); </script> <div class="container px-4 text-center mx-auto"> @@ -77,7 +81,7 @@ </div> <a href={`/${user.username}`}> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> + <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div> </a> <div class="flex justify-center"> diff --git a/src/routes/(app)/invoice/[id]/tip/+page.svelte b/src/routes/(app)/invoice/[id]/tip/+page.svelte index ff3da46e..53f0eb4b 100644 --- a/src/routes/(app)/invoice/[id]/tip/+page.svelte +++ b/src/routes/(app)/invoice/[id]/tip/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { onMount } from "svelte"; import { browser } from "$app/environment"; import { invoice as inv, request } from "$lib/store"; @@ -11,10 +13,10 @@ import { tick } from "svelte"; const tipAmounts = ["No", "10%", "15%", "20%"]; - let showCustomAmount; + let showCustomAmount = $state(); - let customInput; - let customTipAmount; + let customInput = $state(); + let customTipAmount = $state(); let apply = async () => { if (customTipAmount > 0) { @@ -40,7 +42,7 @@ tipPercent = e.target.value; }; - let submitting; + let submitting = $state(); const handleTipButtonClick = async (amount) => { submitting = true; if (amount === "No") { @@ -53,11 +55,10 @@ submit.click(); }; - let submit; + let submit = $state(); - export let data; - $: refresh(data); - let { invoice, id, user, rates } = data; + let { data } = $props(); + let { invoice, id, user, rates } = $state(data); let { aid, amount, @@ -70,10 +71,10 @@ text, tip, user: { username, currency }, - } = invoice; + } = $state(invoice); let qr; - let tipPercent = 0; + let tipPercent = $state(0); let fullscreen; @@ -97,18 +98,27 @@ tipPercent = (tip / amount) * 100; }; - $: currency = user?.currency || invoice.currency; - $: rate = invoice.rate * (rates[currency] / rates[invoice.currency]); - $: tip = Math.round((amount / 100) * tipPercent); - $: amountFiat = parseFloat(((amount * rate) / sats).toFixed(2)); - $: tipAmount = ((tip * rate) / sats).toFixed(2); - $: invoiceAmountFiatFormatted = f(amountFiat, currency); onMount(() => ($request = undefined)); + run(() => { + refresh(data); + }); + run(() => { + currency = user?.currency || invoice.currency; + }); + run(() => { + rate = invoice.rate * (rates[currency] / rates[invoice.currency]); + }); + run(() => { + tip = Math.round((amount / 100) * tipPercent); + }); + let amountFiat = $derived(parseFloat(((amount * rate) / sats).toFixed(2))); + let tipAmount = $derived(((tip * rate) / sats).toFixed(2)); + let invoiceAmountFiatFormatted = $derived(f(amountFiat, currency)); </script> <div class="container px-4 max-w-lg text-center mx-auto"> @@ -154,10 +164,10 @@ <div class="space-y-2"> {#if tip} - <button type="button" class="btn" on:click={() => submit.click()} + <button type="button" class="btn" onclick={() => submit.click()} >Next</button > - <button type="button" class="btn" on:click={() => (tipPercent = 0)} + <button type="button" class="btn" onclick={() => (tipPercent = 0)} >Reset</button > {:else} @@ -168,14 +178,14 @@ type="button" class="btn" class:active={active(amount, tipPercent)} - on:click={() => handleTipButtonClick(amount)}>{amount}</button + onclick={() => handleTipButtonClick(amount)}>{amount}</button > {:else} <button type="button" class="btn" class:active={active(amount, tipPercent)} - on:click={() => handleTipButtonClick(amount)}>{amount}</button + onclick={() => handleTipButtonClick(amount)}>{amount}</button > {/if} {/each} @@ -186,21 +196,21 @@ <button type="button" class="btn" - on:click={() => (showCustomAmount = true)}>Custom</button + onclick={() => (showCustomAmount = true)}>Custom</button > </div> {/if} - <button type="submit" bind:this={submit} /> + <button type="submit" bind:this={submit}></button> </form> {#if showCustomAmount} - <form on:submit|preventDefault={apply} class="space-y-2"> + <form onsubmit={preventDefault(apply)} class="space-y-2"> <input bind:this={customInput} type="number" step="0.01" - on:input={(e) => handleCustomTipAmount(e)} + oninput={(e) => handleCustomTipAmount(e)} placeholder={$t("payments.amount")} use:focus /> diff --git a/src/routes/(app)/items/[id]/+page.svelte b/src/routes/(app)/items/[id]/+page.svelte index 65720350..9629f311 100644 --- a/src/routes/(app)/items/[id]/+page.svelte +++ b/src/routes/(app)/items/[id]/+page.svelte @@ -1,12 +1,15 @@ <script> + import { run } from 'svelte/legacy'; + import { t } from "$lib/translations"; import ItemForm from "$comp/ItemForm.svelte"; import { fail } from "$lib/utils"; - export let data; - export let form; + let { data, form } = $props(); - $: form?.message && fail(form.message); + run(() => { + form?.message && fail(form.message); + }); let { item, user } = data; </script> diff --git a/src/routes/(app)/items/create/+page.svelte b/src/routes/(app)/items/create/+page.svelte index b82889c9..b756e73e 100644 --- a/src/routes/(app)/items/create/+page.svelte +++ b/src/routes/(app)/items/create/+page.svelte @@ -1,12 +1,15 @@ <script> + import { run } from 'svelte/legacy'; + import { t } from "$lib/translations"; import ItemForm from "$comp/ItemForm.svelte"; import { fail } from "$lib/utils"; - export let data; - export let form; + let { data, form } = $props(); - $: form?.message && fail(form.message); + run(() => { + form?.message && fail(form.message); + }); let { user } = data; let item = {}; </script> diff --git a/src/routes/(app)/ln/[lnurl]/+page.svelte b/src/routes/(app)/ln/[lnurl]/+page.svelte index 236a2a25..386df9d2 100644 --- a/src/routes/(app)/ln/[lnurl]/+page.svelte +++ b/src/routes/(app)/ln/[lnurl]/+page.svelte @@ -1,7 +1,7 @@ <script> import Lnurlp from "$comp/Lnurlp.svelte"; import Lnurlw from "$comp/Lnurlw.svelte"; - export let data; + let { data } = $props(); let { tag } = data; </script> diff --git a/src/routes/(app)/ln/withdrawal/sent/+page.svelte b/src/routes/(app)/ln/withdrawal/sent/+page.svelte index 143a92f4..e06e3c2c 100644 --- a/src/routes/(app)/ln/withdrawal/sent/+page.svelte +++ b/src/routes/(app)/ln/withdrawal/sent/+page.svelte @@ -4,7 +4,7 @@ import { toast } from "@zerodevx/svelte-toast"; import { t } from "$lib/translations"; - export let data; + let { data } = $props(); let { user } = data; toast.pop(0); </script> @@ -20,7 +20,7 @@ </div> <a href={`/payments`}> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> + <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div> </a> <div class="flex justify-center"> diff --git a/src/routes/(app)/messages/+page.svelte b/src/routes/(app)/messages/+page.svelte index 61464770..269a5de3 100644 --- a/src/routes/(app)/messages/+page.svelte +++ b/src/routes/(app)/messages/+page.svelte @@ -1,20 +1,21 @@ <script> + import { run } from 'svelte/legacy'; + import { t } from "$lib/translations"; import Avatar from "$comp/Avatar.svelte"; import { event as e, password } from "$lib/store"; import { browser } from "$app/environment"; import { decrypt } from "$lib/nostr"; - export let data; + let { data } = $props(); let { messages, notes, invoices, sent, received, subject, user, rates } = - data; - $: refresh(data); + $state(data); let refresh = (d) => ({ messages, notes, invoices, sent, received, subject, user, rates } = d); let keys = new Set(); - let latest = []; + let latest = $state([]); let ready; e.subscribe(async (event) => { @@ -35,7 +36,6 @@ } }); - $: initialize($password); let initialize = async (p) => { let i = 0; ready = false; @@ -61,6 +61,12 @@ latest = latest; ready = true; }; + run(() => { + refresh(data); + }); + run(() => { + initialize($password); + }); </script> <div class="container w-full mx-auto text-lg px-4 max-w-xl space-y-5"> diff --git a/src/routes/(app)/messages/[recipient]/+page.svelte b/src/routes/(app)/messages/[recipient]/+page.svelte index 9b9f6f47..bc1a6383 100644 --- a/src/routes/(app)/messages/[recipient]/+page.svelte +++ b/src/routes/(app)/messages/[recipient]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { cubicInOut } from "svelte/easing"; import { browser } from "$app/environment"; import { t } from "$lib/translations"; @@ -13,7 +15,7 @@ import { tick, onMount } from "svelte"; import { getEventHash } from "nostr-tools"; - export let data; + let { data } = $props(); function fadeScale( node, @@ -36,10 +38,9 @@ }; } - let { messages, recipient, user } = data; - let input, pane; + let { messages, recipient, user } = $state(data); + let input, pane = $state(); - $: initialize($password); let initialize = async (p) => { await Promise.all( messages.map( @@ -61,7 +62,7 @@ } }); - let sent, submitting, message; + let sent, submitting, message = $state(); let submit = async () => { submitting = true; @@ -109,6 +110,9 @@ submit(); } }; + run(() => { + initialize($password); + }); </script> <div class="container max-w-xl mx-auto px-4 space-y-5"> @@ -116,7 +120,7 @@ type="button" class="hover:opacity-80" data-sveltekit-preload-data="false" - on:click={back} + onclick={back} > <Icon icon="arrow-left" style="w-10" /> </button> @@ -162,7 +166,7 @@ <form method="POST" class="w-full border rounded-xl outline-none gap-4 flex p-0 pr-2" - on:submit|preventDefault={submit} + onsubmit={preventDefault(submit)} > <input type="hidden" name="requester_id" value={user.id} /> <input type="hidden" name="recipient" value={recipient.username} /> @@ -172,8 +176,8 @@ contenteditable class="grow break-all py-4 outline-none mt-0 pl-4" bind:innerHTML={message} - on:keydown={keydown} - /> + onkeydown={keydown} +></div> <button type="submit" class="my-auto shrink-0"> <Icon icon="send" style="w-8" /> </button> diff --git a/src/routes/(app)/pay/[username]/[...amount]/+page.svelte b/src/routes/(app)/pay/[username]/[...amount]/+page.svelte index bf2e877e..4fbd0b64 100644 --- a/src/routes/(app)/pay/[username]/[...amount]/+page.svelte +++ b/src/routes/(app)/pay/[username]/[...amount]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from "svelte/legacy"; + import { t } from "$lib/translations"; import { goto } from "$app/navigation"; import { pin } from "$lib/store"; @@ -10,22 +12,19 @@ import { page } from "$app/stores"; import { f, fail, post, s, sat, sats } from "$lib/utils"; - export let data; - export let form; + let { data, form } = $props(); - let { subject, rate, rates, user } = data; + let { subject, rate, rates, user } = $state(data); let currency = subject?.currency || "USD"; - let next; + let next = $state(); - let amount = form?.amount || data.amount; - let a, - af, - fiat = !amount, - hash, + let amount = $state(form?.amount || data.amount); + let a = $state(), + af = $state(0), + fiat = $state(!amount), + hash = $state(), amountFiat = 0; - $: r = rate || rates[subject?.currency]; - let setAmount = async () => { amount = a; amountFiat = parseFloat(af).toFixed(2); @@ -49,14 +48,20 @@ goto(`/send/invoice/${id}`); }; - let loading; + let loading = $state(); let submit = () => (loading = true); - $: update(form); let update = () => { if (form?.message?.includes("pin")) $pin = undefined; loading = false; }; + let r; + run(() => { + r = rate || rates[subject?.currency]; + }); + run(() => { + update(form); + }); </script> {#if form?.message} @@ -72,10 +77,10 @@ {currency} bind:fiat bind:rate={r} - bind:submit={next} + submit={next} /> - <form method="POST" use:enhance on:submit={submit}> + <form method="POST" use:enhance onsubmit={submit}> <input name="amount" value={amount} type="hidden" /> <input name="username" value={subject.username} type="hidden" /> <input name="pin" value={$pin} type="hidden" /> @@ -98,8 +103,8 @@ type="button" bind:this={next} class="btn btn-accent" - on:click={setAmount} - on:keydown={setAmount} + onclick={setAmount} + onkeydown={setAmount} > {$t("payments.next")}</button > diff --git a/src/routes/(app)/payment/[id]/+page.svelte b/src/routes/(app)/payment/[id]/+page.svelte index 150c2bc4..fd5ea95f 100644 --- a/src/routes/(app)/payment/[id]/+page.svelte +++ b/src/routes/(app)/payment/[id]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { browser } from "$app/environment"; import { onMount, tick } from "svelte"; import { t, loading } from "$lib/translations"; @@ -19,11 +21,10 @@ import { PUBLIC_EXPLORER, PUBLIC_LIQUID_EXPLORER } from "$env/static/public"; import locales from "$lib/locales"; - export let data; - let { user, payment: p } = data; + let { data } = $props(); + let { user, payment: p } = $state(data); let locale = locales[user.language]; - $: refresh(data); let refresh = (d) => { ({ user, payment: p } = d); ({ @@ -65,7 +66,7 @@ ourfee, fee, currency, - } = p; + } = $state(p); let a = Math.abs(amount); let expl = { @@ -86,11 +87,11 @@ } }; - let txid, vout; + let txid = $state(), vout = $state(); if (amount > 0) [txid, vout] = ref.split(":"); else txid = hash; - let direction = ""; + let direction = $state(""); onMount(() => { direction = amount > 0 ? $t("payments.from") : $t("payments.to"); @@ -98,6 +99,9 @@ direction = direction[0].toUpperCase() + direction.substr(1, direction.length); }); + run(() => { + refresh(data); + }); </script> <div class="container mx-auto max-w-lg px-4 space-y-8 break-all text-2xl"> @@ -222,7 +226,7 @@ </div> <button class="flex font-bold hover:opacity-80 mb-auto my-auto" - on:click={() => copy(txid)} + onclick={() => copy(txid)} > <Icon icon="copy" style="ml-2 w-12 my-auto" /> </button> @@ -237,7 +241,7 @@ <div>{path}</div> <button class="flex font-bold hover:opacity-80 mb-auto my-auto" - on:click={() => copy(path)} + onclick={() => copy(path)} > <Icon icon="copy" style="ml-2 w-12 my-auto" /> </button> diff --git a/src/routes/(app)/payment/[id]/plain/+page.svelte b/src/routes/(app)/payment/[id]/plain/+page.svelte index c63a9d7f..7d5c09aa 100644 --- a/src/routes/(app)/payment/[id]/plain/+page.svelte +++ b/src/routes/(app)/payment/[id]/plain/+page.svelte @@ -19,7 +19,7 @@ import { format } from "date-fns"; import { PUBLIC_EXPLORER as expl } from "$env/static/public"; - export let data; + let { data } = $props(); let { user, payment: p } = data; let { username } = user; @@ -84,5 +84,5 @@ </div> <a href={`/payment/${id}`}> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> + <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div> </a> diff --git a/src/routes/(app)/payments/[...page]/+page.svelte b/src/routes/(app)/payments/[...page]/+page.svelte index ba2e4992..2735491c 100644 --- a/src/routes/(app)/payments/[...page]/+page.svelte +++ b/src/routes/(app)/payments/[...page]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import Avatar from "$comp/Avatar.svelte"; import { onMount } from "svelte"; import { format } from "date-fns"; @@ -9,9 +11,9 @@ import { differenceInDays, getUnixTime, sub } from "date-fns"; import { goto, invalidate } from "$app/navigation"; import locales from "$lib/locales"; - export let data; + let { data } = $props(); - let { start, end, user, rates, payments } = data; + let { start, end, user, rates, payments } = $state(data); let locale = locales[user.language]; let change = ({ target: { value } }) => goto(value); @@ -21,7 +23,7 @@ return `/p/${p.id}`; }; - $: presets = [ + let presets = $derived([ { title: $t("payments.day"), start: sub(new Date(), { days: 1 }), @@ -42,27 +44,33 @@ start: sub(new Date(), { years: 5 }), end: null, }, - ]; + ]); - $: selection = start + let selection = $derived(start ? presets.findIndex( (p) => Math.abs(differenceInDays(new Date(start * 1000), p.start)) < 1, ) - : 0; + : 0); - let p, - incoming, - outgoing, - pages = []; - $: data && - ({ page: p, pages, start, end, incoming, outgoing, payments } = data); + let p = $state(), + incoming = $state(), + outgoing = $state(), + pages = $state([]); + run(() => { + data && + ({ page: p, pages, start, end, incoming, outgoing, payments } = data); + }); - $: $page && ($newPayment = false); - $: $newPayment && invalidate(`/users/${user.username}`); + run(() => { + $page && ($newPayment = false); + }); + run(() => { + $newPayment && invalidate(`/users/${user.username}`); + }); - $: path = $page.params.page + let path = $derived($page.params.page ? $page.url.pathname.substring(0, $page.url.pathname.lastIndexOf("/")) - : $page.url.pathname; + : $page.url.pathname); let csv = async () => { let url = `/payments`; @@ -128,7 +136,7 @@ } }; - $: showPage = (i) => { + let showPage = $derived((i) => { const currentPage = parseInt(p); const maxVisiblePages = 12; @@ -146,13 +154,13 @@ } return i >= start && i <= end; - }; + }); - $: isEllipsis = (i) => { + let isEllipsis = $derived((i) => { return ( (i === 1 && !showPage(i)) || (i === pages.length - 2 && !showPage(i)) ); - }; + }); </script> <div class="space-y-5"> @@ -241,7 +249,7 @@ {:else if p.type === types.ecash} <img src="/images/cash.png" class="w-12" /> {:else if p.type === types.reconcile} - <iconify-icon icon="ph:scales-bold" width="32" /> + <iconify-icon icon="ph:scales-bold" width="32"></iconify-icon> {:else if p.type === types.bitcoin} <div class="my-auto"> <img @@ -288,7 +296,7 @@ <div class="grid grid-cols-3 w-full text-center text-lg"> {#each Object.keys(incoming) as c} - <span class="text-base text-secondary text-left" /> + <span class="text-base text-secondary text-left"></span> <!-- <span class="text-base text-secondary" --> <!-- >{$t("payments.subtotal")}</span --> <!-- > --> @@ -323,8 +331,8 @@ </div> <div class="flex justify-center"> - <button class="btn !w-auto" on:click={csv}> - <iconify-icon icon="ph:floppy-disk-bold" width="32" /> + <button class="btn !w-auto" onclick={csv}> + <iconify-icon icon="ph:floppy-disk-bold" width="32"></iconify-icon> <div class="my-auto">{$t("payments.export")}</div> </button> </div> diff --git a/src/routes/(app)/qr/[text]/+page.svelte b/src/routes/(app)/qr/[text]/+page.svelte index e1aae854..02a5b718 100644 --- a/src/routes/(app)/qr/[text]/+page.svelte +++ b/src/routes/(app)/qr/[text]/+page.svelte @@ -2,7 +2,7 @@ import Icon from "$comp/Icon.svelte"; import Qr from "$comp/Qr.svelte"; import { back, copy } from "$lib/utils"; - export let data; + let { data } = $props(); let { src, text } = data; </script> @@ -12,9 +12,9 @@ <button type="button" class="btn break-all !h-auto flex-nowrap p-4 font-normal leading-normal" - on:click={() => copy(text)} + onclick={() => copy(text)} > - <iconify-icon icon="ph:copy-bold" width="32" /> + <iconify-icon icon="ph:copy-bold" width="32"></iconify-icon> <div class="my-auto">{text}</div> </button> </div> diff --git a/src/routes/(app)/qr/create/+page.svelte b/src/routes/(app)/qr/create/+page.svelte index fd99a54b..74316ba9 100644 --- a/src/routes/(app)/qr/create/+page.svelte +++ b/src/routes/(app)/qr/create/+page.svelte @@ -1,9 +1,11 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { goto } from "$app/navigation"; import { browser } from "$app/environment"; import { t } from "$lib/translations"; import Icon from "$comp/Icon.svelte"; - let el, text, pasted; + let el = $state(), text = $state(), pasted = $state(); let keypress = (e) => e.key === "Enter" ? e.preventDefault() || el.click() : (pasted = false); @@ -15,7 +17,9 @@ let submit = () => goto(`/qr/${encodeURIComponent(text)}`); - $: if (browser && pasted && text) el.click() && (pasted = false); + run(() => { + if (browser && pasted && text) el.click() && (pasted = false); + }); </script> <div class="container px-4 max-w-lg mx-auto space-y-5 mt-20"> @@ -23,25 +27,25 @@ Create QR </h1> - <form on:submit|preventDefault={submit} class="space-y-2 text-xl"> + <form onsubmit={preventDefault(submit)} class="space-y-2 text-xl"> <div class="mb-2"> <textarea use:focus name="text" placeholder="Enter some text or a URL to put in a QR" - on:keypress={keypress} + onkeypress={keypress} class="w-full p-4 border rounded-xl h-32 text-xl" bind:value={text} - on:paste={() => (pasted = true)} + onpaste={() => (pasted = true)} autocapitalize="none" - /> +></textarea> </div> <div class="flex gap-2"> <button type="button" class="flex border rounded-2xl px-6 py-5 font-bold hover:opacity-80 w-full bg-primary justify-center gap-2" - on:click={paste} + onclick={paste} > <Icon icon="paste" style="w-8 my-auto" /> <div class="my-auto">{$t("user.send.paste")}</div> diff --git a/src/routes/(app)/receive/[...token]/+page.svelte b/src/routes/(app)/receive/[...token]/+page.svelte index 575c8269..3c081fdc 100644 --- a/src/routes/(app)/receive/[...token]/+page.svelte +++ b/src/routes/(app)/receive/[...token]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { page } from "$app/stores"; import { fly } from "svelte/transition"; import { enhance } from "$app/forms"; @@ -9,13 +11,12 @@ import Spinner from "$comp/Spinner.svelte"; import { back, fail, focus } from "$lib/utils"; - export let data; - export let form; + let { data = $bindable(), form } = $props(); let { token } = data; data.subject = data.user; - let el, text, pasted, w; + let el = $state(), text = $state(), pasted = $state(), w = $state(); let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click()); @@ -23,7 +24,9 @@ text = await navigator.clipboard.readText(); }; - $: if (browser && pasted && text) el.click() && (pasted = false); + run(() => { + if (browser && pasted && text) el.click() && (pasted = false); + }); </script> <svelte:window bind:innerWidth={w} /> @@ -49,24 +52,24 @@ use:focus name="text" placeholder={$t("payments.voucherText")} - on:keypress={keypress} + onkeypress={keypress} class="w-full p-4 border rounded-xl h-32 text-xl" bind:value={text} - on:paste={() => (pasted = true)} + onpaste={() => (pasted = true)} autocapitalize="none" - /> +></textarea> </div> <div class="flex gap-2"> <a href="/scan" class="contents"> <button type="button" class="btn !w-auto flex-grow"> - <iconify-icon icon="ph:camera-bold" width="32" /> + <iconify-icon icon="ph:camera-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.send.scan")}</div> </button> </a> - <button type="button" class="btn !w-auto flex-grow" on:click={paste}> - <iconify-icon icon="ph:clipboard-text-bold" width="32" /> + <button type="button" class="btn !w-auto flex-grow" onclick={paste}> + <iconify-icon icon="ph:clipboard-text-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.send.paste")}</div> </button> </div> diff --git a/src/routes/(app)/reset/[code]/+page.svelte b/src/routes/(app)/reset/[code]/+page.svelte index d93e8bdf..144c73a9 100644 --- a/src/routes/(app)/reset/[code]/+page.svelte +++ b/src/routes/(app)/reset/[code]/+page.svelte @@ -5,10 +5,10 @@ import { fly } from "svelte/transition"; import { password } from "$lib/store"; - export let form; + let { form } = $props(); let email; let loading; - let revealPassword; + let revealPassword = $state(); </script> <div class="pt-10"> @@ -56,7 +56,7 @@ {/if} <button type="button" - on:click={() => (revealPassword = !revealPassword)} + onclick={() => (revealPassword = !revealPassword)} class="absolute right-5 top-10" > <Icon icon={revealPassword ? "eye" : "eye-off"} /> diff --git a/src/routes/(app)/scan/[email protected] b/src/routes/(app)/scan/[email protected] index 2dc061a8..14b35465 100644 --- a/src/routes/(app)/scan/[email protected] +++ b/src/routes/(app)/scan/[email protected] @@ -1,3 +1,11 @@ +<script lang="ts"> + interface Props { + children?: import('svelte').Snippet; + } + + let { children }: Props = $props(); +</script> + <main class="min-h-dvh"> - <slot /> + {@render children?.()} </main> diff --git a/src/routes/(app)/scan/+page.svelte b/src/routes/(app)/scan/+page.svelte index 1acc9b13..edff522e 100644 --- a/src/routes/(app)/scan/+page.svelte +++ b/src/routes/(app)/scan/+page.svelte @@ -6,7 +6,7 @@ import { back } from "$lib/utils"; import { goto } from "$app/navigation"; - let scanner, vid, resizing; + let scanner, vid = $state(), resizing; let resize = () => { if (resizing) clearTimeout(resizing); @@ -31,19 +31,19 @@ onDestroy(() => scanner?.stop()); </script> -<svelte:window on:resize={resize} /> +<svelte:window onresize={resize} /> <div class="flex w-full mb-4 p-4"> <div class="mx-auto rounded-3xl"> <video bind:this={vid} class="border-4 rounded-3xl border-black max-h-[calc(100vh*0.7)]" - /> +></video> </div> </div> <div class="flex justify-center"> - <button class="btn !w-auto" on:click={back}>Cancel</button> + <button class="btn !w-auto" onclick={back}>Cancel</button> </div> <style> diff --git a/src/routes/(app)/send/+layout.svelte b/src/routes/(app)/send/+layout.svelte index 9e14fa39..5c6d8f11 100644 --- a/src/routes/(app)/send/+layout.svelte +++ b/src/routes/(app)/send/+layout.svelte @@ -3,7 +3,7 @@ import Pin from "$comp/Pin.svelte"; import { pin } from "$lib/store"; - export let data; + let { data, children } = $props(); let { user } = data; let cancel = () => goto(`/${user.username}`); @@ -13,4 +13,4 @@ <Pin bind:value={$pin} {cancel} /> {/if} -<slot /> +{@render children?.()} diff --git a/src/routes/(app)/send/[...text]/+page.svelte b/src/routes/(app)/send/[...text]/+page.svelte index 2dd4a723..7ec76bc9 100644 --- a/src/routes/(app)/send/[...text]/+page.svelte +++ b/src/routes/(app)/send/[...text]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { page } from "$app/stores"; import { fly } from "svelte/transition"; import { enhance } from "$app/forms"; @@ -10,13 +12,12 @@ import Spinner from "$comp/Spinner.svelte"; import { back, fail, focus } from "$lib/utils"; - export let data; - export let form; + let { data = $bindable(), form } = $props(); data.subject = data.user; let { contacts } = data; - let el, text, pasted, w; + let el = $state(), text = $state(), pasted = $state(), w = $state(); let keypress = (e) => e.key === "Enter" ? e.preventDefault() || el.click() : (pasted = false); @@ -27,7 +28,9 @@ pasted = true; }; - $: if (browser && pasted && text) el.click() && (pasted = false); + run(() => { + if (browser && pasted && text) el.click() && (pasted = false); + }); </script> <svelte:window bind:innerWidth={w} /> @@ -52,29 +55,29 @@ use:focus name="text" placeholder={$t("user.send.placeholder")} - on:keypress={keypress} + onkeypress={keypress} class="w-full p-4 border rounded-xl h-32 text-xl" bind:value={text} - on:paste={() => (pasted = true)} + onpaste={() => (pasted = true)} autocapitalize="none" - /> +></textarea> <div class="flex gap-2"> <a href="/scan" class="contents"> <button type="button" class="btn !w-auto flex-grow"> - <iconify-icon icon="ph:camera-bold" width="32" /> + <iconify-icon icon="ph:camera-bold" width="32"></iconify-icon> {$t("user.send.scan")} </button> </a> - <button type="button" class="btn !w-auto flex-grow" on:click={paste}> - <iconify-icon icon="ph:clipboard-text-bold" width="32" /> + <button type="button" class="btn !w-auto flex-grow" onclick={paste}> + <iconify-icon icon="ph:clipboard-text-bold" width="32"></iconify-icon> {$t("user.send.paste")} </button> </div> <button bind:this={el} type="submit" class="btn btn-accent"> - <iconify-icon icon="ph:paper-plane-right-bold" width="32" /> + <iconify-icon icon="ph:paper-plane-right-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.send.next")}</div> </button> diff --git a/src/routes/(app)/send/bitcoin/[address]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/+page.svelte index 20fed58a..c271543c 100644 --- a/src/routes/(app)/send/bitcoin/[address]/+page.svelte +++ b/src/routes/(app)/send/bitcoin/[address]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { t } from "$lib/translations"; import Icon from "$comp/Icon.svelte"; import Numpad from "$comp/Numpad.svelte"; @@ -6,22 +8,24 @@ import { rate } from "$lib/store"; import { fail, s } from "$lib/utils"; - export let data; + let { data } = $props(); let { balance, rates, user } = data; let { address } = $page.params; let { currency, username } = user; - let amount = 0; - let submit, fiat; + let amount = $state(0); + let submit = $state(), fiat = $state(); - $: update(data); let update = () => ($rate = data.rates[currency]); let setMax = () => { fiat = false; amount = balance; }; + run(() => { + update(data); + }); </script> <div class="container px-4 max-w-xl mx-auto space-y-5 text-center"> @@ -35,8 +39,8 @@ <button type="button" class="btn !w-auto grow" - on:click|preventDefault={setMax} - on:keydown={setMax}>Max ⚡️{s(balance)}</button + onclick={preventDefault(setMax)} + onkeydown={setMax}>Max ⚡️{s(balance)}</button > <form action={`/send/bitcoin/${address}/${amount}`} class="contents"> diff --git a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte index 15080493..20128d2b 100644 --- a/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte +++ b/src/routes/(app)/send/bitcoin/[address]/[amount]/[...feeRate]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { tick } from "svelte"; import { t } from "$lib/translations"; import { enhance } from "$app/forms"; @@ -28,14 +30,13 @@ import { entropyToMnemonic, mnemonicToSeed } from "@scure/bip39"; import { wordlist } from "@scure/bip39/wordlists/english"; - export let data; - export let form; + let { data, form } = $props(); let { encode, decode } = hexUtil; - let passwordPrompt; - let password; - let cancel = () => (passwordPrompt = false); - let signed; + let passwordPrompt = $state(); + let password = $state(); + let cancel = $state(() => (passwordPrompt = false)); + let signed = $state(); let togglePassword = () => (passwordPrompt = !passwordPrompt); let handler = ({ cancel }) => { @@ -90,9 +91,8 @@ rates, hex, inputs, - } = data; + } = $state(data); - $: reload(data); let reload = () => { ({ amount, address, message, fee, fees, feeRate, ourfee, rates, hex } = data); @@ -103,7 +103,7 @@ }; let { balance, currency } = data.user; - let submitting, submit, showSettings; + let submitting = $state(), submit = $state(), showSettings; let feeNames = { fastestFee: $t("payments.fastest"), @@ -113,7 +113,6 @@ let toggleSettings = () => (showSettings = !showSettings); - $: update(form); let update = () => { submitting = false; if (form?.message?.includes("pin")) $pin = undefined; @@ -121,6 +120,12 @@ let setFee = () => goto(`/send/bitcoin/${address}/${amount}/${feeRate}`); let goBack = () => goto(`/send/bitcoin/${address}`); + run(() => { + reload(data); + }); + run(() => { + update(form); + }); </script> <div @@ -148,7 +153,7 @@ <div class="flex flex-wrap gap-4 justify-center"> <select bind:value={feeRate} - on:change={setFee} + onchange={setFee} class="border text-lg bg-white p-4 rounded-2xl text-center my-auto" > {#each Object.keys(feeNames) as feeName} diff --git a/src/routes/(app)/send/ecash/+page.svelte b/src/routes/(app)/send/ecash/+page.svelte index 3a708f80..88239c1a 100644 --- a/src/routes/(app)/send/ecash/+page.svelte +++ b/src/routes/(app)/send/ecash/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { enhance, applyAction } from "$app/forms"; import { t } from "$lib/translations"; import Icon from "$comp/Icon.svelte"; @@ -9,15 +11,14 @@ import { fail, s } from "$lib/utils"; import handler from "$lib/handler"; - export let data; + let { data } = $props(); let { rates, user } = data; let { balance, currency, username } = user; - let amount = 0; - let submit, fiat; + let amount = $state(0); + let submit = $state(), fiat = $state(); - $: update(data); let update = () => ($rate = data.rates[currency]); let setMax = () => { @@ -25,8 +26,11 @@ amount = balance; }; - let submitting; + let submitting = $state(); let toggle = () => (submitting = !submitting); + run(() => { + update(data); + }); </script> <div class="container px-4 max-w-xl mx-auto space-y-5 text-center"> @@ -47,9 +51,9 @@ <button type="button" class="btn !w-auto grow" - on:click|preventDefault={setMax} + onclick={preventDefault(setMax)} disabled={submitting} - on:keydown={setMax}>Max ⚡️{s(balance)}</button + onkeydown={setMax}>Max ⚡️{s(balance)}</button > <button diff --git a/src/routes/(app)/send/fund/[name]/[...amount]/+page.svelte b/src/routes/(app)/send/fund/[name]/[...amount]/+page.svelte index b6a4aa0c..d1c3b204 100644 --- a/src/routes/(app)/send/fund/[name]/[...amount]/+page.svelte +++ b/src/routes/(app)/send/fund/[name]/[...amount]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { t } from "$lib/translations"; import { enhance } from "$app/forms"; import Icon from "$comp/Icon.svelte"; @@ -8,25 +10,29 @@ import { back } from "$lib/utils"; import { pin } from "$lib/store"; - export let data; - export let form; + let { data, form } = $props(); - let { amount, name } = $page.params; + let { amount, name } = $state($page.params); let { rates } = data; let { currency } = data.user; - let loading; + let loading = $state(); - $: rate = rates[currency]; let submit = () => (loading = true); - $: update(form); let update = () => { if (form?.message?.includes("pin")) $pin = undefined; loading = false; }; + let rate; + run(() => { + rate = rates[currency]; + }); + run(() => { + update(form); + }); </script> -<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" on:click={back}> +<button class="ml-5 md:ml-20 mt-5 md:mt-10 hover:opacity-80" onclick={back}> <Icon icon="arrow-left" style="w-10" /> </button> @@ -39,7 +45,7 @@ <div class="container px-4 mt-20 max-w-xl mx-auto"> <Numpad bind:amount {currency} bind:rate /> - <form method="POST" use:enhance on:submit={submit}> + <form method="POST" use:enhance onsubmit={submit}> <input name="name" value={name} type="hidden" /> <input name="amount" value={amount} type="hidden" /> <input name="pin" value={$pin} type="hidden" /> diff --git a/src/routes/(app)/send/invoice/[id]/+page.svelte b/src/routes/(app)/send/invoice/[id]/+page.svelte index 5a9729a2..9f3a008b 100644 --- a/src/routes/(app)/send/invoice/[id]/+page.svelte +++ b/src/routes/(app)/send/invoice/[id]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import handler from "$lib/handler"; import { onDestroy, onMount } from "svelte"; import { t } from "$lib/translations"; @@ -21,34 +23,31 @@ sats, focus, } from "$lib/utils"; - export let data; - export let form; + let { data, form } = $props(); - let { invoice, rates, user } = data; - let { address, hash, payreq, user: recipient, tip } = invoice; - let { currency } = user; + let { invoice, rates, user } = $state(data); + let { address, hash, payreq, user: recipient, tip } = $state(invoice); + let { currency } = $state(user); - $: reload(data); let reload = (data) => { ({ invoice, rates, user } = data); ({ address, hash, payreq, user: recipient, tip } = invoice); ({ currency } = user); }; - $: rate = invoice.rate * (rates[user.currency] / rates[invoice.currency]); - let amount = form?.amount || invoice.amount; - let a, - af, + let amount = $state(form?.amount || invoice.amount); + let a = $state(), + af = $state(), amountFiat = amount * (rate / sats), - fiat = !amount; + fiat = $state(!amount); let setAmount = () => { amount = a; amountFiat = af; }; - let submit, submitting; + let submit = $state(), submitting = $state(); let toggle = () => (submitting = !submitting); let external = async () => { @@ -67,7 +66,6 @@ }); }; - $: update(form); let update = () => { if (form?.message?.includes("pin")) $pin = undefined; submitting = false; @@ -91,6 +89,16 @@ // } // } // }); + run(() => { + reload(data); + }); + let rate; + run(() => { + rate = invoice.rate * (rates[user.currency] / rates[invoice.currency]); + }); + run(() => { + update(form); + }); </script> {#if form?.message} @@ -192,13 +200,13 @@ bind:this={submit} type="button" class="btn !w-auto" - on:click={setAmount} + onclick={setAmount} > {$t("payments.next")} </button> {/if} </div> - <button type="button" class="btn" on:click={external} + <button type="button" class="btn" onclick={external} >{$t("payments.moreOptions")}</button > </form> diff --git a/src/routes/(app)/send/lightning/[payreq]/+page.svelte b/src/routes/(app)/send/lightning/[payreq]/+page.svelte index 659b0e51..6b9fe4e2 100644 --- a/src/routes/(app)/send/lightning/[payreq]/+page.svelte +++ b/src/routes/(app)/send/lightning/[payreq]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from "svelte/legacy"; + import { t } from "$lib/translations"; import { enhance } from "$app/forms"; import Icon from "$comp/Icon.svelte"; @@ -8,8 +10,7 @@ import { back, fiat, f, s, focus } from "$lib/utils"; import { rate, pin } from "$lib/store"; - export let data; - export let form; + let { data, form } = $props(); let { payreq } = $page.params; let { @@ -17,10 +18,9 @@ ourfee, rates, user: { currency }, - } = data; - let a; + } = $state(data); + let a = $state(); - $: reload(data); let reload = (data) => { ({ alias, @@ -31,13 +31,10 @@ if (!$rate) $rate = rates[currency]; }; - $: amount = form?.amount || data.amount; - $: maxfee = Math.max(5, Math.round(amount * 0.005)); - let showMax; + let showMax = $state(); - let loading; + let loading = $state(); let submit = () => (loading = true); - $: update(form); let update = () => { if (form?.message?.includes("pin")) $pin = undefined; loading = false; @@ -45,6 +42,17 @@ let show; let toggle = () => (show = !show); + run(() => { + reload(data); + }); + let amount = $derived(form?.amount || data.amount); + let maxfee; + run(() => { + maxfee = Math.max(5, Math.round(amount * 0.005)); + }); + run(() => { + update(form); + }); </script> <div class="container px-4 max-w-xl mx-auto text-center space-y-2"> @@ -89,7 +97,7 @@ <form method="POST" use:enhance - on:submit={submit} + onsubmit={submit} action="?/send" class="space-y-2" > @@ -135,7 +143,7 @@ </button> {#if !(form?.message || showMax)} - <button type="button" class="btn" on:click={() => (showMax = !showMax)} + <button type="button" class="btn" onclick={() => (showMax = !showMax)} >Advanced settings</button > <input name="maxfee" type="hidden" bind:value={maxfee} /> diff --git a/src/routes/(app)/sent/[id]/+page.svelte b/src/routes/(app)/sent/[id]/+page.svelte index b4f6ab68..615638c7 100644 --- a/src/routes/(app)/sent/[id]/+page.svelte +++ b/src/routes/(app)/sent/[id]/+page.svelte @@ -5,8 +5,8 @@ import { toast } from "@zerodevx/svelte-toast"; import { t } from "$lib/translations"; - export let data; - let { amount, rate, tip, user } = data; + let { data } = $props(); + let { amount, rate, tip, user } = $state(data); let { currency, username } = user; amount = Math.abs(amount); @@ -38,7 +38,7 @@ </div> <a href={`/${username}`} use:focus> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> + <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div> </a> <div class="flex justify-center"> diff --git a/src/routes/(app)/settings/[...tab]/+page.svelte b/src/routes/(app)/settings/[...tab]/+page.svelte index d2da3722..5b9e048d 100644 --- a/src/routes/(app)/settings/[...tab]/+page.svelte +++ b/src/routes/(app)/settings/[...tab]/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { browser } from "$app/environment"; import { onMount, tick } from "svelte"; import { fly } from "svelte/transition"; @@ -22,24 +24,20 @@ import { PUBLIC_COINOS_URL } from "$env/static/public"; - export let data; - export let form; + let { data, form } = $props(); - let submit; - let formElement; + let submit = $state(); + let formElement = $state(); - let { user, token, rates, tab, cookies, subscriptions } = data; + let { user, token, rates, tab, cookies, subscriptions } = $state(data); let prev; - $: update(data); let update = () => { ({ user, token, rates, tab, subscriptions } = data); prev = { ...user }; }; - $: form?.user && ({ user } = form); - $: form?.success && throttledSuccess(); let justUpdated; let throttledSuccess = () => { @@ -50,12 +48,7 @@ } }; - $: form?.message && fail(form.message); - $: if (form?.message?.startsWith("Pin")) { - fail("Wrong pin, try again"); - $pin = ""; - } let tabs = [ { name: "account", key: "ACCOUNT", comp: Account }, @@ -64,13 +57,10 @@ { name: "shopify", key: "SHOPIFY", comp: Shopify }, ]; - $: ({ comp } = tabs.find((t) => t.name === tab)); let { address, id, username } = user; - let submitting; + let submitting = $state(); - $: if (!$loading && $page.url.searchParams.get("verified")) - success($t("user.settings.verified")); async function handleSubmit() { try { @@ -191,6 +181,31 @@ submitting = false; } + run(() => { + update(data); + }); + run(() => { + form?.user && ({ user } = form); + }); + run(() => { + form?.success && throttledSuccess(); + }); + run(() => { + form?.message && fail(form.message); + }); + run(() => { + if (form?.message?.startsWith("Pin")) { + fail("Wrong pin, try again"); + $pin = ""; + } + }); + let { comp } = $derived(tabs.find((t) => t.name === tab)); + run(() => { + if (!$loading && $page.url.searchParams.get("verified")) + success($t("user.settings.verified")); + }); + + const SvelteComponent = $derived(comp); </script> {#if user.haspin && $pin?.length !== 6} @@ -200,7 +215,7 @@ <form method="POST" class="mb-[154px] settings" - on:submit|preventDefault={handleSubmit} + onsubmit={preventDefault(handleSubmit)} bind:this={formElement} > <input type="hidden" name="pin" value={$pin} /> @@ -229,7 +244,7 @@ </div> </div> - <svelte:component this={comp} {user} {rates} {submit} {subscriptions} /> + <SvelteComponent {user} {rates} {submit} {subscriptions} /> </div> <div diff --git a/src/routes/(app)/settings/[...tab]/_account.svelte b/src/routes/(app)/settings/[...tab]/_account.svelte index 8537322e..54249265 100644 --- a/src/routes/(app)/settings/[...tab]/_account.svelte +++ b/src/routes/(app)/settings/[...tab]/_account.svelte @@ -4,11 +4,11 @@ import { t } from "$lib/translations"; import { page } from "$app/stores"; - export let user, rates, submit; + let { user = $bindable(), rates, submit } = $props(); let { id } = user; - let avatarFile, avatarInput, bannerFile, bannerInput; + let avatarFile, avatarInput = $state(), bannerFile, bannerInput = $state(); let selectAvatar = () => avatarInput.click(); let selectBanner = () => bannerInput.click(); @@ -18,7 +18,7 @@ percent = Math.round((event.loaded / event.total) * 100); }; - let tooLarge = {}; + let tooLarge = $state({}); let handleFile = async ({ target }, type) => { tooLarge[type] = false; @@ -47,9 +47,9 @@ if (!user.display) user.display = user.username; - $: url = `${$page.url.host}/${user.username}`; - $: full = `${$page.url.protocol}//${url}`; - $: addr = `${user.username}@${$page.url.host}`; + let url = $derived(`${$page.url.host}/${user.username}`); + let full = $derived(`${$page.url.protocol}//${url}`); + let addr = $derived(`${user.username}@${$page.url.host}`); </script> <div> @@ -83,13 +83,13 @@ icon="ph:check-bold" class="text-success ml-auto" width="32" - /> +></iconify-icon> {:else if user.email} <iconify-icon icon="ph:clock-bold" class="text-warning ml-auto" width="32" - /> +></iconify-icon> {/if} </label> </div> @@ -101,8 +101,8 @@ {#if $avatar || user.profile} <div class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer" - on:click={selectAvatar} - on:keydown={selectAvatar} + onclick={selectAvatar} + onkeydown={selectAvatar} > <img src={$avatar?.src || `/api/public/${user.profile}.webp`} @@ -113,11 +113,11 @@ {:else} <div class="rounded-full border-4 border-white p-4 bg-gradient-to-r from-primary to-gradient w-24 my-auto hover:opacity-80 cursor-pointer" - on:click={selectAvatar} - on:keydown={selectAvatar} + onclick={selectAvatar} + onkeydown={selectAvatar} > <Icon icon="logo-symbol-white" style="mx-auto" /> - <iconify-icon icon="ph:floppy-disk-bold" width="32" /> + <iconify-icon icon="ph:floppy-disk-bold" width="32"></iconify-icon> </div> {/if} <div class="ml-2 p-2"> @@ -125,14 +125,14 @@ <button type="button" class="btn" - on:click={selectAvatar} - on:keydown={selectAvatar}>{$t("user.settings.select")}</button + onclick={selectAvatar} + onkeydown={selectAvatar}>{$t("user.settings.select")}</button > <input type="file" class="hidden" bind:this={avatarInput} - on:change={(e) => handleFile(e, "profile")} + onchange={(e) => handleFile(e, "profile")} /> </div> </div> @@ -151,30 +151,30 @@ <img src={$banner ? $banner.src : `/api/public/${user.banner}.webp`} class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80" - on:click={selectBanner} - on:keydown={selectBanner} + onclick={selectBanner} + onkeydown={selectBanner} alt="Banner" /> {:else} <div class="bg-gradient-to-r from-primary to-gradient w-full h-48 mb-4 cursor-pointer hover:opacity-80" - on:click={selectBanner} - on:keydown={selectBanner} + onclick={selectBanner} + onkeydown={selectBanner} alt="Banner" - /> +></div> {/if} <button type="button" class="btn !w-auto" - on:click={selectBanner} - on:keydown={selectBanner}>{$t("user.settings.select")}</button + onclick={selectBanner} + onkeydown={selectBanner}>{$t("user.settings.select")}</button > <input type="file" class="hidden" bind:this={bannerInput} - on:change={(e) => handleFile(e, "banner")} + onchange={(e) => handleFile(e, "banner")} /> {#if tooLarge["banner"]} @@ -191,5 +191,5 @@ name="address" bind:value={user.address} placeholder={$t("user.settings.aboutPlaceholder")} - /> +></textarea> </div> diff --git a/src/routes/(app)/settings/[...tab]/_pos.svelte b/src/routes/(app)/settings/[...tab]/_pos.svelte index f4a01c09..3f68eebc 100644 --- a/src/routes/(app)/settings/[...tab]/_pos.svelte +++ b/src/routes/(app)/settings/[...tab]/_pos.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { onMount, tick } from "svelte"; import { browser } from "$app/environment"; import Numpad from "$comp/Numpad.svelte"; @@ -9,16 +11,20 @@ import { page } from "$app/stores"; import { PUBLIC_VAPID_PUBKEY } from "$env/static/public"; - export let user, rates, submit, subscriptions; + let { + user = $bindable(), + rates, + submit, + subscriptions + } = $props(); - let { currency } = user; - let rate = rates[currency]; + let { currency } = $state(user); + let rate = $state(rates[currency]); let fiats = Object.keys(rates).sort((a, b) => a.localeCompare(b)); - $: user.language = $locale; let keypress = (e) => e.key === "Enter" && (e.preventDefault() || el.click()); - let editingReserve, editingThreshold, doneReserve, doneThreshold; + let editingReserve = $state(), editingThreshold = $state(), doneReserve = $state(), doneThreshold; let doneEditing = () => { editingReserve = false; editingThreshold = false; @@ -38,9 +44,9 @@ if (!user.threshold) user.threshold = 1000000; if (!user.reserve) user.reserve = 100000; - let reserveEl, thresholdEl; + let reserveEl = $state(), thresholdEl = $state(); - let push, pm, subscription; + let push = $state(), pm, subscription; onMount(async () => { if (!browser) return; @@ -60,8 +66,7 @@ } }); - let permission; - $: updateNotifications(push); + let permission = $state(); let updateNotifications = async (push) => { if (!browser || !pm) return (push = false); @@ -80,6 +85,12 @@ await post("/subscription", { subscription }); } }; + run(() => { + user.language = $locale; + }); + run(() => { + updateNotifications(push); + }); </script> <div> @@ -154,17 +165,17 @@ <textarea name="destination" placeholder={$t("user.settings.destinationPlaceholder")} - on:keypress={keypress} + onkeypress={keypress} class="w-full p-4 border rounded-xl h-48" bind:value={user.destination} - /> +></textarea> </div> <div> <label for="display" class="font-bold mb-1 block" >{$t("user.settings.threshold")}</label > - <button type="button" class="flex w-full" on:click={editThreshold}> + <button type="button" class="flex w-full" onclick={editThreshold}> <div class="p-4 border rounded-2xl rounded-r-none border-r-0 bg-base-200"> ⚡️ </div> @@ -184,7 +195,7 @@ <label for="display" class="font-bold mb-1 block" >{$t("user.settings.reserve")}</label > - <button type="button" class="flex w-full" on:click={editReserve}> + <button type="button" class="flex w-full" onclick={editReserve}> <div class="p-4 border rounded-2xl rounded-r-none border-r-0 bg-base-200"> ⚡️ </div> @@ -220,7 +231,7 @@ <button bind:this={doneReserve} type="button" - on:click={doneEditing} + onclick={doneEditing} class="btn">Ok</button > </div> @@ -247,7 +258,7 @@ <button bind:this={doneReserve} type="button" - on:click={doneEditing} + onclick={doneEditing} class="btn">Ok</button > </div> diff --git a/src/routes/(app)/settings/[...tab]/_security.svelte b/src/routes/(app)/settings/[...tab]/_security.svelte index d67bda37..8bb8a3fa 100644 --- a/src/routes/(app)/settings/[...tab]/_security.svelte +++ b/src/routes/(app)/settings/[...tab]/_security.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { getMnemonic, getNsec } from "$lib/nostr"; import { tick } from "svelte"; import { t } from "$lib/translations"; @@ -10,26 +12,26 @@ import { invalidate } from "$app/navigation"; import { page } from "$app/stores"; - export let user, rates, submit; + let { user = $bindable(), rates, submit } = $props(); - let confirming2fa, - disabling2fa, - importing, + let confirming2fa = $state(), + disabling2fa = $state(), + importing = $state(), locked, mnemonic, - newNsec, - nsec, + newNsec = $state(), + nsec = $state(), old, - otp, - password, - pin, - revealPassword, + otp = $state(), + password = $state(), + pin = $state(), + revealPassword = $state(), revealSeed, - revealNsec, - token = "", - setting2fa, - settingPin, - verify; + revealNsec = $state(), + token = $state(""), + setting2fa = $state(), + settingPin = $state(), + verify = $state(); let toggleImporting = () => { revealNsec = false; @@ -56,8 +58,6 @@ } }; - $: verifying = pin?.length > 5; - $: verify && checkPin(pin); let checkPin = async () => { old = $current; @@ -88,7 +88,7 @@ return true; }; - let disablingPin = false; + let disablingPin = $state(false); let togglePin = async () => { if (user.haspin) { @@ -129,7 +129,6 @@ disabling2fa = false; }; - $: enable2fa(token); let enable2fa = async (twoFa) => { try { if (setting2fa && token.length === 6) { @@ -143,7 +142,6 @@ } }; - $: disable2fa(token); let disable2fa = async () => { try { if (disabling2fa && token.length === 6) { @@ -157,6 +155,19 @@ fail("Failed to disable 2FA, try again"); } }; + let verifying; + run(() => { + verifying = pin?.length > 5; + }); + run(() => { + verify && checkPin(pin); + }); + run(() => { + enable2fa(token); + }); + run(() => { + disable2fa(token); + }); </script> <input type="hidden" name="newpin" value={disablingPin ? "delete" : pin} /> @@ -173,14 +184,14 @@ {/if} <button type="button" - on:click={togglePassword} - on:keydown={togglePassword} + onclick={togglePassword} + onkeydown={togglePassword} class="absolute right-5 top-11" > <iconify-icon icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"} width="32" - /> +></iconify-icon> </button> </div> @@ -203,12 +214,12 @@ notify={false} /> {:else} - <button type="button" class="btn" on:click={togglePin} + <button type="button" class="btn" onclick={togglePin} > <iconify-icon icon={user.haspin ? "ph:lock-key-open-bold" : "ph:lock-key-bold"} width="32" - /> +></iconify-icon> {user.haspin ? $t("user.settings.disablePIN") : $t("user.settings.enablePIN")}</button @@ -232,18 +243,18 @@ <b>{otp.secret}</b> </div> - <button type="button" class="btn" on:click={startConfirming2fa}> - <iconify-icon icon="ph:numpad-bold" width="32" /> + <button type="button" class="btn" onclick={startConfirming2fa}> + <iconify-icon icon="ph:numpad-bold" width="32"></iconify-icon> <div class="my-auto">Confirm</div> </button> {:else if user.twofa} - <button type="button" class="btn" on:click={startDisabling2fa}> - <iconify-icon icon="ph:device-mobile-bold" width="32" /> + <button type="button" class="btn" onclick={startDisabling2fa}> + <iconify-icon icon="ph:device-mobile-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.settings.twofaDisable")}</div> </button> {:else} - <button type="button" class="btn" on:click={startEnabling2fa}> - <iconify-icon icon="ph:device-mobile-bold" width="32" /> + <button type="button" class="btn" onclick={startEnabling2fa}> + <iconify-icon icon="ph:device-mobile-bold" width="32"></iconify-icon> <div class="my-auto">{$t("user.settings.twofaSetup")}</div> </button> {/if} @@ -269,12 +280,12 @@ </p> <div class="flex gap-2"> - <button type="button" class="btn !w-auto flex-grow" on:click={toggleNsec}> + <button type="button" class="btn !w-auto flex-grow" onclick={toggleNsec}> {#if revealNsec} - <iconify-icon icon="ph:eye-slash-bold" width="32" /> + <iconify-icon icon="ph:eye-slash-bold" width="32"></iconify-icon> {$t("user.settings.hideNsec")} {:else} - <iconify-icon icon="ph:warning-bold" width="32" /> + <iconify-icon icon="ph:warning-bold" width="32"></iconify-icon> {$t("user.settings.revealNsec")} {/if} </button> @@ -282,9 +293,9 @@ <button type="button" class="btn !w-auto flex-grow" - on:click={toggleImporting} + onclick={toggleImporting} > - <iconify-icon icon="ph:floppy-disk-bold" width="32" /> + <iconify-icon icon="ph:floppy-disk-bold" width="32"></iconify-icon> {$t("user.settings.import")} </button> </div> @@ -298,8 +309,8 @@ {nsec} </div> - <button type="button" class="btn" on:click={() => copy(nsec)}> - <iconify-icon icon="ph:copy-bold" width="32" /> + <button type="button" class="btn" onclick={() => copy(nsec)}> + <iconify-icon icon="ph:copy-bold" width="32"></iconify-icon> Copy </button> {/if} diff --git a/src/routes/(app)/settings/[...tab]/_shopify.svelte b/src/routes/(app)/settings/[...tab]/_shopify.svelte index 48fe7718..cc746c49 100644 --- a/src/routes/(app)/settings/[...tab]/_shopify.svelte +++ b/src/routes/(app)/settings/[...tab]/_shopify.svelte @@ -3,22 +3,22 @@ import Icon from "$comp/Icon.svelte"; import { page } from "$app/stores"; - export let user; - $: paymentsUrl = - user.shopifyStore && + let { user = $bindable() } = $props(); + let paymentsUrl = + $derived(user.shopifyStore && "https://admin.shopify.com/store/" + user.shopifyStore + - "/settings/payments"; - $: checkoutUrl = - user.shopifyStore && + "/settings/payments"); + let checkoutUrl = + $derived(user.shopifyStore && "https://admin.shopify.com/store/" + user.shopifyStore + - "/settings/checkout"; - $: appsUrl = - user.shopifyStore && + "/settings/checkout"); + let appsUrl = + $derived(user.shopifyStore && "https://admin.shopify.com/store/" + user.shopifyStore + - "/settings/apps/development"; + "/settings/apps/development"); let script = `<script src="${$page.url.protocol}//${$page.url.host}/${user.username}/shopify.js"><\/script>`; </script> diff --git a/src/routes/(app)/verify/[code]/+page.svelte b/src/routes/(app)/verify/[code]/+page.svelte index de5212e5..1fe5d898 100644 --- a/src/routes/(app)/verify/[code]/+page.svelte +++ b/src/routes/(app)/verify/[code]/+page.svelte @@ -3,7 +3,7 @@ import Icon from "$comp/Icon.svelte"; import { t } from "$lib/translations"; - export let data; + let { data } = $props(); let { user, error } = data; </script> @@ -27,7 +27,7 @@ </div> <a href={`/${user.username}`}> - <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50" /> + <div class="opacity-0 w-screen h-screen fixed top-0 left-0 z-50"></div> </a> <div class="flex justify-center"> diff --git a/src/routes/(static)/+layout.svelte b/src/routes/(static)/+layout.svelte index c9bdc091..44310c97 100644 --- a/src/routes/(static)/+layout.svelte +++ b/src/routes/(static)/+layout.svelte @@ -1,13 +1,17 @@ <script> + import { run } from 'svelte/legacy'; + import { SvelteToast } from "@zerodevx/svelte-toast"; import Footer from "$comp/Footer.svelte"; import LandingHeader from "$comp/LandingHeader.svelte"; import { theme as themeStore } from "$lib/store"; - export let data; - let { theme } = data; - $: ({ user } = data); - $: theme = $themeStore; + let { data, children } = $props(); + let { theme } = $state(data); + let { user } = $derived(data); + run(() => { + theme = $themeStore; + }); </script> <SvelteToast options={{ reversed: true, intro: { y: 192 } }} /> @@ -16,6 +20,6 @@ class="container flex px-4 md:px-40 mx-auto min-h-[600px]" data-theme={theme} > - <slot /> + {@render children?.()} </main> <Footer /> diff --git a/src/routes/(static)/docs/+page.svelte b/src/routes/(static)/docs/+page.svelte index f83ba8c0..9f724484 100644 --- a/src/routes/(static)/docs/+page.svelte +++ b/src/routes/(static)/docs/+page.svelte @@ -5,7 +5,7 @@ import Code from "$comp/Code.svelte"; import Icon from "$comp/Icon.svelte"; - export let data; + let { data } = $props(); let { user, token } = data; @@ -40,7 +40,7 @@ <h2 class="text-2xl">API Base URL</h2> <div class="bg-primary text-primary-content rounded-lg p-4 flex gap-4"> <div>{api}</div> - <button class="ml-auto my-auto invert opacity-90" on:click={() => copy(api)} + <button class="ml-auto my-auto invert opacity-90" onclick={() => copy(api)} ><Icon icon="copy" style="w-10 max-w-none" /></button > </div> @@ -61,7 +61,7 @@ <div class="w-full break-all">{tokenSample}</div> <button class="ml-auto my-auto invert opacity-90" - on:click={() => copy(tokenSample)} + onclick={() => copy(tokenSample)} ><Icon icon="copy" style="w-10 max-w-none" /></button > </div> diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte index f51a24eb..d50e0cdc 100644 --- a/src/routes/(static)/login/+page.svelte +++ b/src/routes/(static)/login/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import { onMount } from "svelte"; import { applyAction, deserialize } from "$app/forms"; import { tick } from "svelte"; @@ -23,28 +25,24 @@ if (lang) document.cookie = `lang=${lang} ;`; }); - export let form; + let { form } = $props(); - let token, formElement; + let token = $state(), formElement; let code = []; let redirect; $password = undefined; - $: need2fa = form?.message === "2fa"; let cancel = () => (need2fa = false); - $: if (form?.message === "2fa" && form.token === token) token = ""; - let username, email, btn; + let username = $state(), email, btn = $state(); - $: update(form); let update = (form) => form && ({ username, password: $password } = form); - $: token && token?.length === 6 && tick().then(() => btn.click()); - let revealPassword = false; + let revealPassword = $state(false); - let loading; + let loading = $state(); async function handleSubmit(e) { loading = true; @@ -69,6 +67,19 @@ applyAction(result); loading = false; } + let need2fa; + run(() => { + need2fa = form?.message === "2fa"; + }); + run(() => { + if (form?.message === "2fa" && form.token === token) token = ""; + }); + run(() => { + update(form); + }); + run(() => { + token && token?.length === 6 && tick().then(() => btn.click()); + }); </script> {#if need2fa} @@ -86,7 +97,7 @@ </div> {/if} - <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> + <form class="space-y-5" onsubmit={preventDefault(handleSubmit)} method="POST"> <input type="hidden" name="loginRedirect" @@ -131,10 +142,10 @@ {/if} <iconify-icon class="cursor-pointer ml-auto" - on:click={() => (revealPassword = !revealPassword)} + onclick={() => (revealPassword = !revealPassword)} icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"} width="32" - /> +></iconify-icon> </label> <div class="flex justify-end items-center"> diff --git a/src/routes/(static)/register/+page.svelte b/src/routes/(static)/register/+page.svelte index fe9a4aa2..c179552c 100644 --- a/src/routes/(static)/register/+page.svelte +++ b/src/routes/(static)/register/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run, preventDefault } from 'svelte/legacy'; + import punks from "$lib/punks"; import { upload } from "$lib/upload"; import { afterNavigate, invalidateAll } from "$app/navigation"; @@ -23,12 +25,10 @@ animals, } from "unique-names-generator"; - export let form; - export let data; + let { form = $bindable(), data } = $props(); - $: data && ($avatar = undefined); - let username; - let { index } = data; + let username = $state(); + let { index } = $state(data); let cleared; let clear = () => { @@ -64,24 +64,20 @@ } }); - let token, formElement; + let token = $state(), formElement; let code = []; let redirect; - $: need2fa = form?.message === "2fa"; let cancel = () => (need2fa = false); - $: if (form?.message === "2fa" && form.token === token) token = ""; - let email, btn; + let email, btn = $state(); - $: update(form); let update = (form) => form && ({ username, password: $password } = form); - $: token && token?.length === 6 && tick().then(() => btn.click()); - let revealPassword; + let revealPassword = $state(); - let loading; + let loading = $state(); async function handleSubmit(e) { loading = true; @@ -127,8 +123,7 @@ loading = false; } - let avatarInput; - $: src = `/api/public/${punks[index]}.webp`; + let avatarInput = $state(); let decr = () => (index = index <= 0 ? 63 : index - 1); let incr = () => (index = index >= 63 ? 0 : index + 1); let selectAvatar = () => avatarInput.click(); @@ -149,6 +144,26 @@ reader.readAsDataURL(file); }; + run(() => { + data && ($avatar = undefined); + }); + let need2fa; + run(() => { + need2fa = form?.message === "2fa"; + }); + run(() => { + if (form?.message === "2fa" && form.token === token) token = ""; + }); + run(() => { + update(form); + }); + run(() => { + token && token?.length === 6 && tick().then(() => btn.click()); + }); + let src; + run(() => { + src = `/api/public/${punks[index]}.webp`; + }); </script> {#if need2fa} @@ -163,17 +178,17 @@ type="file" class="hidden" bind:this={avatarInput} - on:change={(e) => handleFile(e, "profile")} + onchange={(e) => handleFile(e, "profile")} /> <div class="relative"> <button class="absolute w-8 h-12 left-12 bg-base-100 rounded top-12" - on:click={decr} + onclick={decr} > - <iconify-icon icon="ph:caret-left-bold" width="32" /> + <iconify-icon icon="ph:caret-left-bold" width="32"></iconify-icon> </button> - <div class="block relative w-32 mx-auto" on:click={selectAvatar}> + <div class="block relative w-32 mx-auto" onclick={selectAvatar}> <button class="w-32 h-32 rounded-full border-4 border-white overflow-hidden flex mx-auto relative" > @@ -186,14 +201,14 @@ <button class="absolute bg-base-100 rounded-full p-2 mx-auto right-0 bottom-0 z-10 w-12" > - <iconify-icon icon="ph:upload-simple-bold" width="24" /> + <iconify-icon icon="ph:upload-simple-bold" width="24"></iconify-icon> </button> </div> <button class="absolute w-8 h-12 right-12 bg-base-100 rounded top-12" - on:click={incr} + onclick={incr} > - <iconify-icon icon="ph:caret-right-bold" width="32" /> + <iconify-icon icon="ph:caret-right-bold" width="32"></iconify-icon> </button> </div> @@ -203,7 +218,7 @@ </div> {/if} - <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> + <form class="space-y-5" onsubmit={preventDefault(handleSubmit)} method="POST"> <input type="hidden" name="loginRedirect" @@ -222,17 +237,17 @@ type="text" required bind:value={username} - on:focus={clear} + onfocus={clear} autocapitalize="none" placeholder={$t("login.username")} /> <iconify-icon class="cursor-pointer" tabindex="-1" - on:click={refresh} + onclick={refresh} icon="ph:dice-three-bold" width="32" - /> +></iconify-icon> </label> <label @@ -257,17 +272,17 @@ required bind:value={$password} autocapitalize="none" - on:focus={clear} + onfocus={clear} placeholder={$t("login.password")} /> {/if} <iconify-icon tabindex="-1" class="cursor-pointer" - on:click={() => (revealPassword = !revealPassword)} + onclick={() => (revealPassword = !revealPassword)} icon={revealPassword ? "ph:eye-bold" : "ph:eye-slash-bold"} width="32" - /> +></iconify-icon> </label> <button type="submit" class="btn" disabled={loading} bind:this={btn}> diff --git a/src/routes/(static)/support/+page.svelte b/src/routes/(static)/support/+page.svelte index 062f552b..b47c5c1a 100644 --- a/src/routes/(static)/support/+page.svelte +++ b/src/routes/(static)/support/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { browser } from "$app/environment"; import { onDestroy } from "svelte"; import { fail, success, post } from "$lib/utils"; @@ -6,16 +8,18 @@ import Icon from "$comp/Icon.svelte"; import { t } from "$lib/translations"; - export let data; + let { data = $bindable() } = $props(); let { user } = data; - $: if (user) { - data.subject = { ...user }; - } + run(() => { + if (user) { + data.subject = { ...user }; + } + }); - let email; - let message; - let sent; + let email = $state(); + let message = $state(); + let sent = $state(); let recaptchaSiteKey = "6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM"; let submit = (e) => { @@ -80,7 +84,7 @@ > and we'll do our best to get back to you in a timely manner. </p> - <form on:submit={submit}> + <form onsubmit={submit}> <div class="mb-4"> <label for="account" class="font-semibold" >{$t("user.support.accountName")}</label @@ -110,7 +114,7 @@ name="message" bind:value={message} required - /> +></textarea> </div> <button diff --git a/src/routes/+error.svelte b/src/routes/+error.svelte index faa7d738..c9e65806 100644 --- a/src/routes/+error.svelte +++ b/src/routes/+error.svelte @@ -2,7 +2,7 @@ import Icon from "$comp/Icon.svelte"; import { page } from "$app/stores"; - export let data; + let { data } = $props(); let { user } = data; let link = user ? `/${user.username}` : "/"; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index e5aeb206..a2dc3bff 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import { browser } from "$app/environment"; import { PUBLIC_DOMAIN } from "$env/static/public"; import "../app.css"; @@ -6,15 +8,17 @@ import { onMount } from "svelte"; import { installPrompt, theme as themeStore } from "$lib/store"; - export let data; - let { pathname, theme } = data; + let { data, children } = $props(); + let { pathname, theme } = $state(data); $themeStore = theme; let host = PUBLIC_DOMAIN.includes("localhost") ? `http://${PUBLIC_DOMAIN}` : `https://${PUBLIC_DOMAIN}`; - $: theme = $themeStore + run(() => { + theme = $themeStore + }); onMount(() => { if (!browser) return; @@ -48,7 +52,7 @@ {#if !$loading} <main data-theme={theme}> - <slot /> + {@render children?.()} </main> {/if} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a04d669e..480ea1c4 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,4 +1,6 @@ <script> + import { run } from 'svelte/legacy'; + import LandingHeader from "$comp/LandingHeader.svelte"; import LandingHero from "$comp/LandingHero.svelte"; import LandingInfoCard from "$comp/LandingInfoCard.svelte"; @@ -11,14 +13,16 @@ import { locale, t } from "$lib/translations"; import { onDestroy, onMount, tick } from "svelte"; - export let data; - let { faqs, locations, user } = data; + let { data } = $props(); + let { faqs, locations, user } = $state(data); let update = (data) => ({ faqs, locations, user } = data); - $: update(data); + run(() => { + update(data); + }); - let howItWorks; - let faq; - let about; + let howItWorks = $state(); + let faq = $state(); + let about = $state(); const howItWorksSteps = [ { image: "coinos:hand", stepID: "step1" }, @@ -26,7 +30,7 @@ { image: "coinos:smile", stepID: "step3" }, ]; - let loaded; + let loaded = $state(); let observer; @@ -66,8 +70,8 @@ title={$t("landing.info3.title")} description={$t("landing.info3.description")} /> - <div bind:this={howItWorks} /> - <div id="about" /> + <div bind:this={howItWorks}></div> + <div id="about"></div> </div> <div> @@ -79,7 +83,7 @@ <HowItWorksCard image={step.image} stepID={step.stepID} /> {/each} </div> - <div bind:this={faq} /> + <div bind:this={faq}></div> </div> <div> @@ -91,7 +95,7 @@ <FaqCard questionID={f} /> {/each} </div> - <div bind:this={about} /> + <div bind:this={about}></div> </div> <About /> diff --git a/src/routes/map/+page.svelte b/src/routes/map/+page.svelte index 2addca54..3e0fae5a 100644 --- a/src/routes/map/+page.svelte +++ b/src/routes/map/+page.svelte @@ -1,7 +1,7 @@ <script> import Icon from "$comp/Icon.svelte"; import LocationsMap from "$comp/LocationsMap.svelte"; - export let data; + let { data } = $props(); let { locations } = data; </script> |
