diff options
Diffstat (limited to 'src/components')
41 files changed, 1912 insertions, 1748 deletions
diff --git a/src/components/404.svelte b/src/components/404.svelte index 08323d40..d831a40a 100644 --- a/src/components/404.svelte +++ b/src/components/404.svelte @@ -1,17 +1,17 @@ <script> - import { Icon } from '$comp'; - import { t } from '$lib/translations'; + import { Icon } from "$comp"; + import { t } from "$lib/translations"; </script> <div class="flex justify-center items-center mt-20"> - <div class="space-y-5 text-center"> - <a href="/"> - <Icon icon="logo" style="mx-auto" /> - </a> + <div class="space-y-5 text-center"> + <a href="/"> + <Icon icon="logo" style="mx-auto" /> + </a> - <Icon icon="question" style="mx-auto w-56" /> + <Icon icon="question" style="mx-auto w-56" /> - <h1 class="font-bold text-5xl">{$t('404.404')}</h1> - <p>{$t('404.pageNotFound')}</p> - </div> + <h1 class="font-bold text-5xl">{$t("404.404")}</h1> + <p>{$t("404.pageNotFound")}</p> + </div> </div> diff --git a/src/components/About.svelte b/src/components/About.svelte index 1dbd8038..6e0cdcb5 100644 --- a/src/components/About.svelte +++ b/src/components/About.svelte @@ -1,7 +1,7 @@ <script> import { onMount } from "svelte"; - let locations; + let locations; onMount(async () => { try { ({ locations } = await fetch("/locations").then((r) => r.json())); @@ -10,70 +10,85 @@ } }); - import { Image, Icon, LocationsMap } from '$comp'; - import { t } from '$lib/translations'; + import { Image, Icon, LocationsMap } from "$comp"; + import { t } from "$lib/translations"; - let team = [ - { - name: 'adam', - socials: [ - { type: 'twitter', url: 'https://twitter.com/adamsoltys', color: 'bg-[#1D9BF0]' }, - { type: 'github', url: 'https://github.com/asoltys', color: 'bg-gray-800' } - ] - }, - { name: 'cole', socials: [] } - ]; + let team = [ + { + name: "adam", + socials: [ + { + type: "twitter", + url: "https://twitter.com/adamsoltys", + color: "bg-[#1D9BF0]", + }, + { + type: "github", + url: "https://github.com/asoltys", + color: "bg-gray-800", + }, + ], + }, + { name: "cole", socials: [] }, + ]; </script> <div class="flex justify-center"> - <div class="container space-y-10"> - <h3 class="text-5xl font-medium text-center"> - {$t('about.team.header')} - </h3> - <div class="space-y-10 2xl:space-y-0 2xl:grid gap-y-10 grid-cols-2"> - {#each team as member} - <div class="flex w-full"> - <div class="md:flex 2xl:items-start md:max-w-2xl mx-auto"> - <div class="w-[220px] mx-auto"> - <Image image={member.name} style="rounded-full mx-auto w-40 h-40 mb-5 object-cover" /> + <div class="container space-y-10"> + <h3 class="text-5xl font-medium text-center"> + {$t("about.team.header")} + </h3> + <div class="space-y-10 2xl:space-y-0 2xl:grid gap-y-10 grid-cols-2"> + {#each team as member} + <div class="flex w-full"> + <div class="md:flex 2xl:items-start md:max-w-2xl mx-auto"> + <div class="w-[220px] mx-auto"> + <Image + image={member.name} + style="rounded-full mx-auto w-40 h-40 mb-5 object-cover" + /> - <div class="space-y-2"> - <span class="text-2xl text-center font-semibold block" - >{$t(`about.team.${member.name}.name`)}</span - > - <span class="text-xl text-center text-secondary block" - >{$t(`about.team.${member.name}.position`)}</span - > - </div> + <div class="space-y-2"> + <span class="text-2xl text-center font-semibold block" + >{$t(`about.team.${member.name}.name`)}</span + > + <span class="text-xl text-center text-secondary block" + >{$t(`about.team.${member.name}.position`)}</span + > + </div> - <div class="mt-2 flex justify-center items-center space-x-5"> - {#each member.socials as social} - <a - href={social.url} - target="_blank" - rel="noreferrer" - class={`rounded-full p-2 ${social.color} hover:opacity-80`} - ><Icon icon={social.type} style="w-6" /></a - > - {/each} - </div> - </div> - <div class="text-secondary text-xl w-full max-w-[450px] mt-5"> - {$t(`about.team.${member.name}.bio`)} - </div> - </div> - </div> - {/each} - </div> - </div> + <div class="mt-2 flex justify-center items-center space-x-5"> + {#each member.socials as social} + <a + href={social.url} + target="_blank" + rel="noreferrer" + class={`rounded-full p-2 ${social.color} hover:opacity-80`} + ><Icon icon={social.type} style="w-6" /></a + > + {/each} + </div> + </div> + <div class="text-secondary text-xl w-full max-w-[450px] mt-5"> + {$t(`about.team.${member.name}.bio`)} + </div> + </div> + </div> + {/each} + </div> + </div> </div> {#if locations?.length} - <div> - <h3 class="text-5xl font-medium mb-5 text-center">{$t('about.locations.header')}</h3> - <p class="text-secondary text-xl w-full md:w-10/12 lg:w-2/3 2xl:w-[800px] mx-auto mb-10"> - {@html $t('about.locations.description')} - </p> - <LocationsMap {locations} /> - </div> + <div> + <h3 class="text-5xl font-medium mb-5 text-center"> + {$t("about.locations.header")} + </h3> + <p + class="text-secondary text-xl w-full md:w-10/12 lg:w-2/3 2xl:w-[800px] mx-auto mb-10" + > + {@html $t("about.locations.description")} + </p> + <LocationsMap {locations} /> + </div> {/if} diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 53b31de4..2f088eec 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -1,149 +1,159 @@ <script> - import OutClick from 'svelte-outclick'; - import { banner, newPayment, colorTheme } from '$lib/store'; - import { goto } from '$app/navigation'; - import { Avatar, Icon } from '$comp'; - import { loading, t } from '$lib/translations'; - import { page } from '$app/stores'; + import OutClick from "svelte-outclick"; + import { banner, newPayment, colorTheme } from "$lib/store"; + import { goto } from "$app/navigation"; + import { Avatar, Icon } from "$comp"; + import { loading, t } from "$lib/translations"; + import { page } from "$app/stores"; - export let data; + export let data; - let { subject, user } = data; - $: update(data); - let update = (data) => ({ subject, user } = data); + let { subject, user } = data; + $: update(data); + let update = (data) => ({ subject, user } = data); - let menuButtons; - $: if (user) - menuButtons = [ - { key: 'nav.settings', icon: 'settings', href: `/${user.username}/settings` }, - { key: 'nav.support', icon: 'support', href: `/support` }, - { key: 'nav.map', icon: 'map', href: `/${user.username}/map` }, - { key: 'nav.merch', icon: 'shop', href: `https://coinosmerch.com` }, - { key: 'nav.signOut', icon: 'logout', href: `/logout` } - ]; + let menuButtons; + $: if (user) + menuButtons = [ + { + key: "nav.settings", + icon: "settings", + href: `/${user.username}/settings`, + }, + { key: "nav.support", icon: "support", href: `/support` }, + { key: "nav.map", icon: "map", href: `/${user.username}/map` }, + { key: "nav.merch", icon: "shop", href: `https://coinosmerch.com` }, + { key: "nav.signOut", icon: "logout", href: `/logout` }, + ]; - let showMenu = false; + let showMenu = false; - $: bg = - $banner?.id && $banner.id === subject.id - ? `url(${$banner.src})` - : subject?.banner - ? `url(/api/public/${subject.banner}.webp)` - : undefined; + $: bg = + $banner?.id && $banner.id === subject.id + ? `url(${$banner.src})` + : subject?.banner + ? `url(/api/public/${subject.banner}.webp)` + : undefined; - $: $page && (showMenu = false); + $: $page && (showMenu = false); </script> {#if !$loading} - <header - class="bg-gradient-to-r {$colorTheme} h-[175px] w-full relative bg-cover mb-20" - style:background-image={bg} - > - <nav class="flex justify-end items-center space-x-4 p-5"> - {#if user} - <a href={`/${user.username}`}> - <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}` - ? 'opacity-100' - : 'opacity-70 hover:opacity-80'}" - ><Icon icon="home" style="mx-auto w-6 md:w-8" /> - </button> - </a> - <a href={`/${user.username}/receive`}> - <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}/receive` - ? 'opacity-100' - : 'opacity-70 hover:opacity-80'}" - ><Icon icon="numpad" style="mx-auto w-6 md:w-8" /> - </button> - </a> - <a href={`/${user.username}/payments`}> - <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}/payments` - ? 'opacity-100' - : 'opacity-70 hover:opacity-80'} relative" - ><Icon icon="clock" style="mx-auto w-6 md:w-8" /> - {#if $newPayment} - <span class="absolute top-0 right-0"> - <span class="flex h-3 w-3"> - <span - class="animate-ping absolute inline-flex h-full w-full rounded-full bg-[#F7931A] opacity-75" - /> - <span class="relative inline-flex rounded-full h-3 w-3 bg-[#F7931A]" /> - </span> - </span> - {/if} - </button> - </a> - <a href={`/send`}> - <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/send` - ? 'opacity-100' - : 'opacity-70 hover:opacity-80'}" - ><Icon icon="send" style="mx-auto w-6 md:w-8" /> - </button> - </a> - <div class="relative"> - <OutClick on:outclick={() => (showMenu = false)}> - <button - class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}` || - $page.url.pathname === `/${user.username}/settings` || - $page.url.pathname === `/support` - ? 'opacity-100' - : `opacity-70 hover:opacity-80 ${showMenu ? 'opacity-80' : ''}`}" - on:click={() => (showMenu = !showMenu)} - ><Icon icon="menu" style="mx-auto w-6 md:w-8" /> - </button> + <header + class="bg-gradient-to-r {$colorTheme} h-[175px] w-full relative bg-cover mb-20" + style:background-image={bg} + > + <nav class="flex justify-end items-center space-x-4 p-5"> + {#if user} + <a href={`/${user.username}`}> + <button + class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/${user.username}` + ? 'opacity-100' + : 'opacity-70 hover:opacity-80'}" + ><Icon icon="home" style="mx-auto w-6 md:w-8" /> + </button> + </a> + <a href={`/${user.username}/receive`}> + <button + class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/${user.username}/receive` + ? 'opacity-100' + : 'opacity-70 hover:opacity-80'}" + ><Icon icon="numpad" style="mx-auto w-6 md:w-8" /> + </button> + </a> + <a href={`/${user.username}/payments`}> + <button + class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/${user.username}/payments` + ? 'opacity-100' + : 'opacity-70 hover:opacity-80'} relative" + ><Icon icon="clock" style="mx-auto w-6 md:w-8" /> + {#if $newPayment} + <span class="absolute top-0 right-0"> + <span class="flex h-3 w-3"> + <span + class="animate-ping absolute inline-flex h-full w-full rounded-full bg-[#F7931A] opacity-75" + /> + <span + class="relative inline-flex rounded-full h-3 w-3 bg-[#F7931A]" + /> + </span> + </span> + {/if} + </button> + </a> + <a href={`/send`}> + <button + class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/send` + ? 'opacity-100' + : 'opacity-70 hover:opacity-80'}" + ><Icon icon="send" style="mx-auto w-6 md:w-8" /> + </button> + </a> + <div class="relative"> + <OutClick on:outclick={() => (showMenu = false)}> + <button + class="bg-white p-2 rounded-full w-12 h-12 md:w-16 md:h-16 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/${user.username}` || + $page.url.pathname === `/${user.username}/settings` || + $page.url.pathname === `/support` + ? 'opacity-100' + : `opacity-70 hover:opacity-80 ${ + showMenu ? 'opacity-80' : '' + }`}" + on:click={() => (showMenu = !showMenu)} + ><Icon icon="menu" style="mx-auto w-6 md:w-8" /> + </button> - <div - class="{showMenu - ? 'block' - : 'hidden'} absolute top-14 right-0 bg-white rounded-3xl p-8 shadow-xl z" - > - <ul class="space-y-5 w-48"> - {#each menuButtons as { href, icon, key }} - <li> - <a {href} data-sveltekit-prefetch="off"> - <button - class="flex justify-center items-center font-semibold hover:opacity-80" - ><Icon {icon} style="mr-2 w-6 md:w-8" /> {$t(key)} - </button> - </a> - </li> - {/each} - </ul> - <hr class="my-4" /> - <a href="/"><img src="/images/logo.svg" alt="Coinos" class="w-32" /></a> - </div> - </OutClick> - </div> - {:else} - <a href={`/login?redirect=${$page.url.pathname}`}> - <button class="bg-white px-5 py-2 rounded-xl font-semibold text-sm" - >{$t('nav.signIn')}</button - > - </a> - {/if} - </nav> - <div - class="absolute md:w-[64px] md:mx-auto lg:left-[164px] left-[calc(50vw-64px)] -bottom-[64px] z-30" - > - <Avatar user={subject} /> - </div> - </header> + <div + class="{showMenu + ? 'block' + : 'hidden'} absolute top-14 right-0 bg-white rounded-3xl p-8 shadow-xl z" + > + <ul class="space-y-5 w-48"> + {#each menuButtons as { href, icon, key }} + <li> + <a {href} data-sveltekit-prefetch="off"> + <button + class="flex justify-center items-center font-semibold hover:opacity-80" + ><Icon {icon} style="mr-2 w-6 md:w-8" /> {$t(key)} + </button> + </a> + </li> + {/each} + </ul> + <hr class="my-4" /> + <a href="/" + ><img src="/images/logo.svg" alt="Coinos" class="w-32" /></a + > + </div> + </OutClick> + </div> + {:else} + <a href={`/login?redirect=${$page.url.pathname}`}> + <button class="bg-white px-5 py-2 rounded-xl font-semibold text-sm" + >{$t("nav.signIn")}</button + > + </a> + {/if} + </nav> + <div + class="absolute md:w-[64px] md:mx-auto lg:left-[164px] left-[calc(50vw-64px)] -bottom-[64px] z-30" + > + <Avatar user={subject} /> + </div> + </header> {/if} <style> - .z { - z-index: 100; - } + .z { + z-index: 100; + } - header { - view-transition-name: header; - } + header { + view-transition-name: header; + } </style> diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte index b258a0e8..3955a42f 100644 --- a/src/components/Avatar.svelte +++ b/src/components/Avatar.svelte @@ -1,29 +1,31 @@ <script> - import { avatar, banner, colorTheme } from '$lib/store'; - import { Icon } from '$comp'; - import { punk } from '$lib/utils'; + import { avatar, banner, colorTheme } from "$lib/store"; + import { Icon } from "$comp"; + import { punk } from "$lib/utils"; - export let user; - export let size = 32; - export let disabled = false; + export let user; + export let size = 32; + export let disabled = false; - $: s = size.toString(); - $: link = user.anon ? `/${user.pubkey}` : `/${user.username}`; + $: s = size.toString(); + $: link = user.anon ? `/${user.pubkey}` : `/${user.username}`; - $: src = - ($avatar?.id && $avatar.id === user.id && $avatar.src) || - '/api/public/' + - (user.profile ? user.profile + '.webp' : 'punks/' + punk(user.pubkey || user.id || 'aa')); + $: src = + ($avatar?.id && $avatar.id === user.id && $avatar.src) || + "/api/public/" + + (user.profile + ? user.profile + ".webp" + : "punks/" + punk(user.pubkey || user.id || "aa")); </script> <a href={link} class:pointer-events-none={disabled}> - <div - class="w-{s} h-{s} rounded-full border-4 border-white overflow-hidden bg-gradient-to-r {$colorTheme} flex justify-center items-center" - > - <img - {src} - class="w-full h-full object-cover object-center overflow-hidden" - alt={user.username} - /> - </div> + <div + class="w-{s} h-{s} rounded-full border-4 border-white overflow-hidden bg-gradient-to-r {$colorTheme} flex justify-center items-center" + > + <img + {src} + class="w-full h-full object-cover object-center overflow-hidden" + alt={user.username} + /> + </div> </a> diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte index 0e4f2ec2..92714f98 100644 --- a/src/components/Balance.svelte +++ b/src/components/Balance.svelte @@ -1,34 +1,34 @@ <script> - import { Pin } from '$comp'; - import { f, s, sat, sats } from '$lib/utils'; - import { animatedRate, pin } from '$lib/store'; - import { t } from '$lib/translations'; + import { Pin } from "$comp"; + import { f, s, sat, sats } from "$lib/utils"; + import { animatedRate, pin } from "$lib/store"; + import { t } from "$lib/translations"; - let show; - export let user; + let show; + export let user; </script> {#if show && user.haspin && $pin?.length !== 6} - <Pin cancel={() => (show = false)} /> + <Pin cancel={() => (show = false)} /> {/if} <div class="space-y-2"> - {#if user.haspin && !$pin} - <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={() => (show = true)}>{$t('user.showBalance')}</button - > - {:else} - <div class="text-5xl font-bold tabular-nums"> - {#if isNaN($animatedRate)} - <div class="text-gray-200">—</div> - {:else} - {f((user.balance * $animatedRate) / sats, user.currency)} - {/if} - </div> + {#if user.haspin && !$pin} + <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={() => (show = true)}>{$t("user.showBalance")}</button + > + {:else} + <div class="text-5xl font-bold tabular-nums"> + {#if isNaN($animatedRate)} + <div class="text-gray-200">—</div> + {:else} + {f((user.balance * $animatedRate) / sats, user.currency)} + {/if} + </div> - <div class="text-secondary text-2xl"> - ⚡️{s(user.balance)} - </div> - {/if} + <div class="text-secondary text-2xl"> + ⚡️{s(user.balance)} + </div> + {/if} </div> diff --git a/src/components/Calendar.svelte b/src/components/Calendar.svelte index 7504f48e..b07c136c 100644 --- a/src/components/Calendar.svelte +++ b/src/components/Calendar.svelte @@ -1,14 +1,14 @@ <svg - xmlns="http://www.w3.org/2000/svg" - class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" + xmlns="http://www.w3.org/2000/svg" + class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" > - <path - stroke-linecap="round" - stroke-linejoin="round" - stroke-width="2" - d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" - /> + <path + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" + /> </svg> diff --git a/src/components/Card.svelte b/src/components/Card.svelte index 44ab635f..864465c0 100644 --- a/src/components/Card.svelte +++ b/src/components/Card.svelte @@ -1,14 +1,14 @@ <svg - xmlns="http://www.w3.org/2000/svg" - class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" + xmlns="http://www.w3.org/2000/svg" + class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" > - <path - stroke-linecap="round" - stroke-linejoin="round" - stroke-width="2" - d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" - /> + <path + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" + /> </svg> diff --git a/src/components/Check.svelte b/src/components/Check.svelte index 4c9f504b..222c4dea 100644 --- a/src/components/Check.svelte +++ b/src/components/Check.svelte @@ -1,11 +1,11 @@ <svg - class="flex-shrink-0 w-5 h-5 text-gray-500 mr-1" - fill="currentColor" - viewBox="0 0 20 20" - xmlns="http://www.w3.org/2000/svg" - ><path - fill-rule="evenodd" - d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" - clip-rule="evenodd" - /></svg + class="flex-shrink-0 w-5 h-5 text-gray-500 mr-1" + fill="currentColor" + viewBox="0 0 20 20" + xmlns="http://www.w3.org/2000/svg" + ><path + fill-rule="evenodd" + d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" + clip-rule="evenodd" + /></svg > diff --git a/src/components/Code.svelte b/src/components/Code.svelte index ffca98a4..6c1048cf 100644 --- a/src/components/Code.svelte +++ b/src/components/Code.svelte @@ -1,27 +1,31 @@ <script> - import { copyNoNewlines as copy } from '$lib/utils'; - import { Icon } from '$comp'; - import samples from '$lib/samples'; - export let sample; + import { copyNoNewlines as copy } from "$lib/utils"; + import { Icon } from "$comp"; + import samples from "$lib/samples"; + export let sample; </script> -<div class="bg-black text-white rounded-lg p-4 flex gap-4 whitespace-pre-wrap font-mono"> - <div class="overflow-x-scroll max-w-full scrollbar-hide"> - <div class="break-all min-w-[800px]">{samples[sample]}</div> - </div> - <button class="ml-auto my-auto invert opacity-90" on:click={() => copy(samples[sample])} - ><Icon icon="copy" style="w-10 max-w-none" /></button - > +<div + class="bg-black text-white rounded-lg p-4 flex gap-4 whitespace-pre-wrap font-mono" +> + <div class="overflow-x-scroll max-w-full scrollbar-hide"> + <div class="break-all min-w-[800px]">{samples[sample]}</div> + </div> + <button + class="ml-auto my-auto invert opacity-90" + on:click={() => copy(samples[sample])} + ><Icon icon="copy" style="w-10 max-w-none" /></button + > </div> <style> - .scrollbar-hide::-webkit-scrollbar { - display: none; - } + .scrollbar-hide::-webkit-scrollbar { + display: none; + } - /* For IE, Edge and Firefox */ - .scrollbar-hide { - -ms-overflow-style: none; /* IE and Edge */ - scrollbar-width: none; /* Firefox */ - } + /* For IE, Edge and Firefox */ + .scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + } </style> diff --git a/src/components/Event.svelte b/src/components/Event.svelte index 68f44589..2312f44e 100644 --- a/src/components/Event.svelte +++ b/src/components/Event.svelte @@ -1,84 +1,87 @@ <script> - import { Avatar, Icon } from '$comp'; - export let event; + import { Avatar, Icon } from "$comp"; + export let event; - let { id, user, seen, content } = event; + let { id, user, seen, content } = event; - let distance = (date) => { - let m = 60; - let h = 60 * m; - let d = 24 * h; + let distance = (date) => { + let m = 60; + let h = 60 * m; + let d = 24 * h; - let diff = Math.round(Date.now() / 1000) - date; - return diff > d - ? Math.round(diff / d) + 'd' - : diff > h - ? Math.round(diff / h) + 'h' - : diff > m - ? Math.round(diff / m) + 'm' - : diff > 2 - ? diff + 's' - : 'now'; - }; + let diff = Math.round(Date.now() / 1000) - date; + return diff > d + ? Math.round(diff / d) + "d" + : diff > h + ? Math.round(diff / h) + "h" + : diff > m + ? Math.round(diff / m) + "m" + : diff > 2 + ? diff + "s" + : "now"; + }; - let w; + let w; </script> <svelte:window bind:innerWidth={w} /> -<div class="flex text-sm lg:text-base text-secondary hover:bg-gray-100 px-4 py-3" :key={id}> - <a href={`/${user.pubkey}`}> - <div class="mb-auto mr-2"> - <div class="md:hidden"> - <Avatar size={12} {user} disabled={true} /> - </div> - <div class="hidden md:block"> - <Avatar size={20} {user} disabled={true} /> - </div> - </div> - </a> +<div + class="flex text-sm lg:text-base text-secondary hover:bg-gray-100 px-4 py-3" + :key={id} +> + <a href={`/${user.pubkey}`}> + <div class="mb-auto mr-2"> + <div class="md:hidden"> + <Avatar size={12} {user} disabled={true} /> + </div> + <div class="hidden md:block"> + <Avatar size={20} {user} disabled={true} /> + </div> + </div> + </a> - <div class="grow" style={`max-width: ${w - 100}px`}> - <div class="w-full flex pb-1 text-black pt-1"> - <div> - {user.display_name || ''} - <span class="text-secondary">@{user.username}</span> - </div> - <div class="text-secondary"> {distance(seen)}</div> - </div> - <div class="break-words text-black"> - {content} - </div> + <div class="grow" style={`max-width: ${w - 100}px`}> + <div class="w-full flex pb-1 text-black pt-1"> + <div> + {user.display_name || ""} + <span class="text-secondary">@{user.username}</span> + </div> + <div class="text-secondary"> {distance(seen)}</div> + </div> + <div class="break-words text-black"> + {content} + </div> - <div class="flex justify-between text-sm text-secondary pt-3"> - <div class="flex group"> - <Icon - icon="party" - style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">444</div> - </div> - <div class="flex group"> - <Icon - icon="support" - style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">1072</div> - </div> - <div class="flex group"> - <Icon - icon="smile" - style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">26</div> - </div> - <div class="flex group"> - <Icon - icon="bolt" - style="mr-1 h-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" - /> - <div class="my-auto group-hover:text-black">4</div> - </div> - </div> - </div> + <div class="flex justify-between text-sm text-secondary pt-3"> + <div class="flex group"> + <Icon + icon="party" + style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" + /> + <div class="my-auto group-hover:text-black">444</div> + </div> + <div class="flex group"> + <Icon + icon="support" + style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" + /> + <div class="my-auto group-hover:text-black">1072</div> + </div> + <div class="flex group"> + <Icon + icon="smile" + style="mr-1 w-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" + /> + <div class="my-auto group-hover:text-black">26</div> + </div> + <div class="flex group"> + <Icon + icon="bolt" + style="mr-1 h-10 my-auto opacity-50 group-hover:opacity-100 group-hover:bg-white rounded-full p-2" + /> + <div class="my-auto group-hover:text-black">4</div> + </div> + </div> + </div> </div> diff --git a/src/components/FaqCard.svelte b/src/components/FaqCard.svelte index 918e03d6..ae1ad077 100644 --- a/src/components/FaqCard.svelte +++ b/src/components/FaqCard.svelte @@ -1,15 +1,15 @@ <script> - import { t } from '$lib/translations'; + 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; + // 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; </script> <div class="mx-auto w-full md:w-2/3 lg:w-[700px] space-y-5"> - <p class="text-2xl font-medium">{$t('faq.' + questionID + '.question')}</p> - <p class="text-secondary text-xl font-medium"> - {$t('faq.' + questionID + '.answer')} - </p> + <p class="text-2xl font-medium">{$t("faq." + questionID + ".question")}</p> + <p class="text-secondary text-xl font-medium"> + {$t("faq." + questionID + ".answer")} + </p> </div> diff --git a/src/components/Feed.svelte b/src/components/Feed.svelte index 7de087a7..0c9c96d1 100644 --- a/src/components/Feed.svelte +++ b/src/components/Feed.svelte @@ -1,72 +1,84 @@ <script> - import { t } from '$lib/translations'; - import { onMount } from 'svelte'; - import { Event } from '$comp'; - import { browser } from '$app/environment'; - import VirtualScroll from 'svelte-virtual-scroll-list'; - import { fail } from '$lib/utils'; - import { sign, send } from '$lib/nostr'; + import { t } from "$lib/translations"; + import { onMount } from "svelte"; + import { Event } from "$comp"; + import { browser } from "$app/environment"; + import VirtualScroll from "svelte-virtual-scroll-list"; + import { fail } from "$lib/utils"; + import { sign, send } from "$lib/nostr"; - export let events; - export let user = undefined; + export let events; + export let user = undefined; - let message; + let message; - let submit = async () => { - try { - let mnemonic, key, seed, entropy, child, privkey; + let submit = async () => { + try { + let mnemonic, key, seed, entropy, child, privkey; - let event = { - pubkey: user.pubkey, - created_at: Math.floor(Date.now() / 1000), - kind: 1, - content: message, - tags: [] - }; + let event = { + pubkey: user.pubkey, + created_at: Math.floor(Date.now() / 1000), + kind: 1, + content: message, + tags: [], + }; - await sign({ event, user }); - await send(event); + await sign({ event, user }); + await send(event); - event.user = user; - event.seen = event.created_at; + event.user = user; + event.seen = event.created_at; - events[event.id] = event; - events = events; - } catch (e) { - console.log(e, e.stack); - fail('Problem posting event'); - } - }; + events[event.id] = event; + events = events; + } catch (e) { + console.log(e, e.stack); + fail("Problem posting event"); + } + }; - $: sorted = Object.values(events) - .filter((ev) => ev?.pubkey && ev?.kind === 1) - .sort((a, b) => b.seen - a.seen); + $: sorted = Object.values(events) + .filter((ev) => ev?.pubkey && ev?.kind === 1) + .sort((a, b) => b.seen - a.seen); </script> {#if user} - <form on:submit|preventDefault={submit} class="flex justify-center gap-4 max-w-2xl mx-auto"> - <div class="grow"> - <input - name="message" - bind:value={message} - placeholder="What's happening?" - class="my-5 mx-auto" - /> - </div> - <button class="rounded-full border py-4 px-5 font-bold hover:opacity-80 w-40 my-5">Post</button> - </form> + <form + on:submit|preventDefault={submit} + class="flex justify-center gap-4 max-w-2xl mx-auto" + > + <div class="grow"> + <input + name="message" + bind:value={message} + placeholder="What's happening?" + class="my-5 mx-auto" + /> + </div> + <button + class="rounded-full border py-4 px-5 font-bold hover:opacity-80 w-40 my-5" + >Post</button + > + </form> {/if} {#if browser} - {#if sorted.length} - <VirtualScroll data={sorted} key="id" let:data pageMode={true} estimateSize={200}> - <a href={`/${data.user.pubkey}/event/${data.id}`}> - <Event event={data} /> - </a> - </VirtualScroll> - {:else} - <div class="flex w-full"> - <div class="mx-auto text-secondary">{$t('user.noNotes')}</div> - </div> - {/if} + {#if sorted.length} + <VirtualScroll + data={sorted} + key="id" + let:data + pageMode={true} + estimateSize={200} + > + <a href={`/${data.user.pubkey}/event/${data.id}`}> + <Event event={data} /> + </a> + </VirtualScroll> + {:else} + <div class="flex w-full"> + <div class="mx-auto text-secondary">{$t("user.noNotes")}</div> + </div> + {/if} {/if} diff --git a/src/components/Footer.svelte b/src/components/Footer.svelte index eda26526..c1ac79cf 100644 --- a/src/components/Footer.svelte +++ b/src/components/Footer.svelte @@ -1,65 +1,74 @@ <script> - import { Icon, LocaleSelector } from '$comp'; - import { t } from '$lib/translations'; + import { Icon, LocaleSelector } from "$comp"; + import { t } from "$lib/translations"; - const followLinks = [ - { url: 'https://twitter.com/coinoswallet', titleID: 'twitter' }, - { url: 'https://t.me/coinoswallet', titleID: 'telegram' }, - { url: 'https://linktr.ee/coinos.io', titleID: 'linktree' } - ]; + const followLinks = [ + { url: "https://twitter.com/coinoswallet", titleID: "twitter" }, + { url: "https://t.me/coinoswallet", titleID: "telegram" }, + { url: "https://linktr.ee/coinos.io", titleID: "linktree" }, + ]; - const companyLinks = [ - { url: '/docs', titleID: 'documentation' }, - { url: '/support', titleID: 'support' } - ]; + const companyLinks = [ + { url: "/docs", titleID: "documentation" }, + { url: "/support", titleID: "support" }, + ]; </script> -<footer class="space-y-10 md:space-y-0 text-xl block md:flex justify-around mb-20"> - <div class="space-y-5"> - <div class="text-center w-full"> - <a href="/"><Icon icon="logo" style="w-48 mx-auto md:mx-0" /></a> - </div> - <div class="flex gap-2 justify-center sm:hidden"> - <div> - <a href="/register"> - <button - class="bg-black text-white border rounded-full px-4 py-2 font-bold hover:opacity-80 text-lg" - > - {$t('nav.startInSeconds')} - </button> - </a> - </div> - </div> - <div class="w-full flex"> - <div class="mx-auto"> - <LocaleSelector - style="p-2 text-center hover:opacity-80 cursor-pointer border rounded-full" - /> - </div> - </div> - </div> +<footer + class="space-y-10 md:space-y-0 text-xl block md:flex justify-around mb-20" +> + <div class="space-y-5"> + <div class="text-center w-full"> + <a href="/"><Icon icon="logo" style="w-48 mx-auto md:mx-0" /></a> + </div> + <div class="flex gap-2 justify-center sm:hidden"> + <div> + <a href="/register"> + <button + class="bg-black text-white border rounded-full px-4 py-2 font-bold hover:opacity-80 text-lg" + > + {$t("nav.startInSeconds")} + </button> + </a> + </div> + </div> + <div class="w-full flex"> + <div class="mx-auto"> + <LocaleSelector + style="p-2 text-center hover:opacity-80 cursor-pointer border rounded-full" + /> + </div> + </div> + </div> - <div class="text-center md:text-left"> - <p class="font-semibold">{$t('footer.followUs')}</p> - <ul class="mt-5 text-secondary space-y-3 font-medium"> - {#each followLinks as link} - <li> - <a href={link.url} target="_blank" rel="noreferrer" class="hover:opacity-80" - >{$t('footer.' + link.titleID)}</a - > - </li> - {/each} - </ul> - </div> + <div class="text-center md:text-left"> + <p class="font-semibold">{$t("footer.followUs")}</p> + <ul class="mt-5 text-secondary space-y-3 font-medium"> + {#each followLinks as link} + <li> + <a + href={link.url} + target="_blank" + rel="noreferrer" + class="hover:opacity-80">{$t("footer." + link.titleID)}</a + > + </li> + {/each} + </ul> + </div> - <div class="text-center md:text-left"> - <p class="font-semibold">{$t('footer.company')}</p> - <ul class="mt-5 text-secondary space-y-3"> - {#each companyLinks as link} - <li><a href={link.url} class="hover:opacity-80">{$t('footer.' + link.titleID)}</a></li> - {/each} - </ul> - </div> + <div class="text-center md:text-left"> + <p class="font-semibold">{$t("footer.company")}</p> + <ul class="mt-5 text-secondary space-y-3"> + {#each companyLinks as link} + <li> + <a href={link.url} class="hover:opacity-80" + >{$t("footer." + link.titleID)}</a + > + </li> + {/each} + </ul> + </div> - <Icon icon="shield" style="mx-auto md:mx-0" /> + <Icon icon="shield" style="mx-auto md:mx-0" /> </footer> diff --git a/src/components/Heart.svelte b/src/components/Heart.svelte index 55b13fa9..9bae6500 100644 --- a/src/components/Heart.svelte +++ b/src/components/Heart.svelte @@ -1,16 +1,16 @@ <svg - width="24" - height="24" - class="mr-1" - viewBox="0 0 24 24" - fill="none" - xmlns="http://www.w3.org/2000/svg" + width="24" + height="24" + class="mr-1" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" > - <path - d="M4.31802 6.31802C2.56066 8.07538 2.56066 10.9246 4.31802 12.682L12.0001 20.364L19.682 12.682C21.4393 10.9246 21.4393 8.07538 19.682 6.31802C17.9246 4.56066 15.0754 4.56066 13.318 6.31802L12.0001 7.63609L10.682 6.31802C8.92462 4.56066 6.07538 4.56066 4.31802 6.31802Z" - stroke="currentColor" - stroke-width="2" - stroke-linecap="round" - stroke-linejoin="round" - /> + <path + d="M4.31802 6.31802C2.56066 8.07538 2.56066 10.9246 4.31802 12.682L12.0001 20.364L19.682 12.682C21.4393 10.9246 21.4393 8.07538 19.682 6.31802C17.9246 4.56066 15.0754 4.56066 13.318 6.31802L12.0001 7.63609L10.682 6.31802C8.92462 4.56066 6.07538 4.56066 4.31802 6.31802Z" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + /> </svg> diff --git a/src/components/HowItWorksCard.svelte b/src/components/HowItWorksCard.svelte index 784c738d..e5e62d05 100644 --- a/src/components/HowItWorksCard.svelte +++ b/src/components/HowItWorksCard.svelte @@ -1,14 +1,14 @@ <script> - import Icon from './Icon.svelte'; - import { t } from '$lib/translations'; - export let image; - export let stepID; + import Icon from "./Icon.svelte"; + import { t } from "$lib/translations"; + export let image; + export let stepID; </script> <div class="space-y-5"> - <Icon icon={image} style="mx-auto w-32 h-32" /> - <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')} - </p> + <Icon icon={image} style="mx-auto w-32 h-32" /> + <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")} + </p> </div> diff --git a/src/components/Icon.svelte b/src/components/Icon.svelte index 4b86cc43..0b47f726 100644 --- a/src/components/Icon.svelte +++ b/src/components/Icon.svelte @@ -1,6 +1,6 @@ <script> - export let icon; - export let style = undefined; + export let icon; + export let style = undefined; </script> <img src="/icons/{icon}.svg" alt={icon} class={style} /> diff --git a/src/components/Image.svelte b/src/components/Image.svelte index dcd9d3ff..4f8b39bb 100644 --- a/src/components/Image.svelte +++ b/src/components/Image.svelte @@ -1,6 +1,6 @@ <script> - export let image; - export let style; + export let image; + export let style; </script> <img src="/images/{image}.webp" alt={image} class={style} /> diff --git a/src/components/Invoice.svelte b/src/components/Invoice.svelte index b0cd58a2..363d260a 100644 --- a/src/components/Invoice.svelte +++ b/src/components/Invoice.svelte @@ -1,32 +1,39 @@ <script> - import { t } from '$lib/translations'; - import { f, sat, sats } from '$lib/utils'; - import { fly } from 'svelte/transition'; - import { Avatar, Icon } from '$comp'; - import { invoice } from '$lib/store'; + import { t } from "$lib/translations"; + import { f, sat, sats } from "$lib/utils"; + import { fly } from "svelte/transition"; + import { Avatar, Icon } from "$comp"; + import { invoice } from "$lib/store"; </script> {#if $invoice} - <div class="fixed bottom-0 border-t w-full p-4 bg-white z-50" in:fly> - <div class="flex flex-wrap md:flex-nowrap max-w-xl mx-auto gap-2"> - <div class="my-auto mx-auto"> - <div class="flex"> - <Avatar user={$invoice.user.username} size={12} /> - <h1 class="my-auto"> - <b>{$invoice.user.username}</b> - {$t('payments.isRequesting')} - <b>{f(($invoice.amount * $invoice.rate) / sats, $invoice.currency)}</b> - {sat($invoice.amount)} - </h1> - </div> - </div> - <div class="mx-auto my-auto flex gap-2"> - <a href={`/${invoice.user.username}/invoice/${$invoice.id}/tip`}> - <button class="rounded-full border py-2 px-4 font-bold hover:opacity-80 w-32"> - {$t('payments.pay')} - </button> - </a> - </div> - </div> - </div> + <div class="fixed bottom-0 border-t w-full p-4 bg-white z-50" in:fly> + <div class="flex flex-wrap md:flex-nowrap max-w-xl mx-auto gap-2"> + <div class="my-auto mx-auto"> + <div class="flex"> + <Avatar user={$invoice.user.username} size={12} /> + <h1 class="my-auto"> + <b>{$invoice.user.username}</b> + {$t("payments.isRequesting")} + <b + >{f( + ($invoice.amount * $invoice.rate) / sats, + $invoice.currency + )}</b + > + {sat($invoice.amount)} + </h1> + </div> + </div> + <div class="mx-auto my-auto flex gap-2"> + <a href={`/${invoice.user.username}/invoice/${$invoice.id}/tip`}> + <button + class="rounded-full border py-2 px-4 font-bold hover:opacity-80 w-32" + > + {$t("payments.pay")} + </button> + </a> + </div> + </div> + </div> {/if} diff --git a/src/components/LandingHeader.svelte b/src/components/LandingHeader.svelte index ed7907c1..556d44a3 100644 --- a/src/components/LandingHeader.svelte +++ b/src/components/LandingHeader.svelte @@ -1,125 +1,133 @@ <script> - import { goto } from '$app/navigation'; - import { scroll } from '$lib/utils'; - import { Icon } from '$comp'; - import { t } from '$lib/translations'; - import { page } from '$app/stores'; + import { goto } from "$app/navigation"; + import { scroll } from "$lib/utils"; + import { Icon } from "$comp"; + import { t } from "$lib/translations"; + import { page } from "$app/stores"; - export let howItWorks; - export let faq; - export let about; - export let user; + export let howItWorks; + export let faq; + export let about; + export let user; - let showMobileMenu = false; - let header; - const mobileMenuButtonClick = (section) => { - showMobileMenu = false; - scroll(section); - }; + let showMobileMenu = false; + let header; + const mobileMenuButtonClick = (section) => { + showMobileMenu = false; + scroll(section); + }; </script> <header - class="w-full lg:w-5/6 py-5 mx-auto fixed md:sticky z-10 top-0 bg-white/90" - bind:this={header} + class="w-full lg:w-5/6 py-5 mx-auto fixed md:sticky z-10 top-0 bg-white/90" + bind:this={header} > - <nav class="block xl:flex flex-wrap justify-between items-center"> - <div class="flex justify-start md:justify-center items-center md:space-x-10"> - <a href="/" on:click={() => scroll(header)}> - <Icon icon="logo" style="hidden md:block mb-5 xl:mb-0" /> - <Icon icon="logo" style="block md:hidden ml-5 w-48" /> - </a> - </div> + <nav class="block xl:flex flex-wrap justify-between items-center"> + <div + class="flex justify-start md:justify-center items-center md:space-x-10" + > + <a href="/" on:click={() => scroll(header)}> + <Icon icon="logo" style="hidden md:block mb-5 xl:mb-0" /> + <Icon icon="logo" style="block md:hidden ml-5 w-48" /> + </a> + </div> - <!-- desktop nav --> - <div class="hidden space-x-10 md:flex flex-wrap justify-center items-center font-bold"> - {#if $page.url.pathname === '/'} - <button class="hover:opacity-80" on:click={() => scroll(howItWorks)} - >{$t('howItWorks.header')}</button - > - <button class="hover:opacity-80" on:click={() => scroll(faq)}>{$t('faq.header')}</button> - <button class="hover:opacity-80" on:click={() => scroll(about)}>{$t('about.header')}</button - > - {/if} - {#if user} - <button - class="border rounded-full px-6 py-2 font-bold" - on:click={() => goto(`/${user.username}`)} - >Home - </button> - <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold" - on:click={() => goto('/logout')} - > - {$t('nav.signOut')} - </button> - {:else} - <button - class="border rounded-full px-6 py-2 font-bold hover:opacity-80" - on:click={() => goto('/register')} - >{$t('nav.startInSeconds')} - </button> - <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold hover:opacity-80" - on:click={() => goto('/login')} - > - {$t('nav.signIn')} - </button> - {/if} - </div> + <!-- desktop nav --> + <div + class="hidden space-x-10 md:flex flex-wrap justify-center items-center font-bold" + > + {#if $page.url.pathname === "/"} + <button class="hover:opacity-80" on:click={() => scroll(howItWorks)} + >{$t("howItWorks.header")}</button + > + <button class="hover:opacity-80" on:click={() => scroll(faq)} + >{$t("faq.header")}</button + > + <button class="hover:opacity-80" on:click={() => scroll(about)} + >{$t("about.header")}</button + > + {/if} + {#if user} + <button + class="border rounded-full px-6 py-2 font-bold" + on:click={() => goto(`/${user.username}`)} + >Home + </button> + <button + class="bg-black text-white border rounded-full px-6 py-2 font-bold" + on:click={() => goto("/logout")} + > + {$t("nav.signOut")} + </button> + {:else} + <button + class="border rounded-full px-6 py-2 font-bold hover:opacity-80" + on:click={() => goto("/register")} + >{$t("nav.startInSeconds")} + </button> + <button + class="bg-black text-white border rounded-full px-6 py-2 font-bold hover:opacity-80" + on:click={() => goto("/login")} + > + {$t("nav.signIn")} + </button> + {/if} + </div> - <!-- mobile nav --> - <button - class="block md:hidden absolute top-[34.5px] right-10 z" - on:click={() => (showMobileMenu = !showMobileMenu)} - ><Icon icon={!showMobileMenu ? 'menu' : 'close'} /> - </button> + <!-- mobile nav --> + <button + class="block md:hidden absolute top-[34.5px] right-10 z" + on:click={() => (showMobileMenu = !showMobileMenu)} + ><Icon icon={!showMobileMenu ? "menu" : "close"} /> + </button> - <div - class="container w-full px-10 md:hidden absolute top-0 {showMobileMenu - ? 'right-0' - : 'right-[-100%]'} transition-all ease-in-out duration-300 h-[100vh] w-full bg-white" - > - <div class="space-y-8 mt-24 font-bold text-xl"> - <button on:click={() => mobileMenuButtonClick(howItWorks)} class="block" - >{$t('howItWorks.header')}</button - > - <button on:click={() => mobileMenuButtonClick(faq)} class="block">{$t('faq.header')}</button - > - <button on:click={() => mobileMenuButtonClick(about)} class="block" - >{$t('about.header')}</button - > - {#if !user} - <button - class="border rounded-full px-6 py-2 font-bold block w-full" - on:click={() => goto('/register')} - >{$t('nav.startInSeconds')} - </button> - <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold block w-full" - on:click={() => goto('/login')} - > - {$t('nav.signIn')} - </button> - {:else} - <button - class="border rounded-full px-6 py-2 font-bold block" - on:click={() => goto(`/${user.username}`)} - >{$t('nav.account')} - </button> - <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold block" - on:click={() => goto('/logout')} - > - {$t('nav.signOut')} - </button> - {/if} - </div> - </div> - </nav> + <div + class="container w-full px-10 md:hidden absolute top-0 {showMobileMenu + ? 'right-0' + : 'right-[-100%]'} transition-all ease-in-out duration-300 h-[100vh] w-full bg-white" + > + <div class="space-y-8 mt-24 font-bold text-xl"> + <button on:click={() => mobileMenuButtonClick(howItWorks)} class="block" + >{$t("howItWorks.header")}</button + > + <button on:click={() => mobileMenuButtonClick(faq)} class="block" + >{$t("faq.header")}</button + > + <button on:click={() => mobileMenuButtonClick(about)} class="block" + >{$t("about.header")}</button + > + {#if !user} + <button + class="border rounded-full px-6 py-2 font-bold block w-full" + on:click={() => goto("/register")} + >{$t("nav.startInSeconds")} + </button> + <button + class="bg-black text-white border rounded-full px-6 py-2 font-bold block w-full" + on:click={() => goto("/login")} + > + {$t("nav.signIn")} + </button> + {:else} + <button + class="border rounded-full px-6 py-2 font-bold block" + on:click={() => goto(`/${user.username}`)} + >{$t("nav.account")} + </button> + <button + class="bg-black text-white border rounded-full px-6 py-2 font-bold block" + on:click={() => goto("/logout")} + > + {$t("nav.signOut")} + </button> + {/if} + </div> + </div> + </nav> </header> <style> - .z { - z-index: 100; - } + .z { + z-index: 100; + } </style> diff --git a/src/components/LandingHero.svelte b/src/components/LandingHero.svelte index 8e1d6476..e03bfdc2 100644 --- a/src/components/LandingHero.svelte +++ b/src/components/LandingHero.svelte @@ -1,37 +1,40 @@ <script> - import { goto } from '$app/navigation'; - import { Icon, Image } from '$comp'; - import { t } from '$lib/translations'; + import { goto } from "$app/navigation"; + import { Icon, Image } from "$comp"; + import { t } from "$lib/translations"; </script> <div class="mt-[96.88px] md:mt-0"> - <div class="space-y-10"> - <h1 - class="text-5xl md:text-6xl lg:text-7xl font-medium text-center w-full md:w-3/4 lg:w-1/2 max-w-7xl mx-auto leading-tight" - > - {$t('landing.header_before_icon')} - <span class="relative"> - {$t('landing.header_with_icon')} - <Icon icon="rays" style="absolute -top-16 left-5 md:left-8 lg:left-14 2xl:left-24" /> - </span> - {$t('landing.header_after_icon')} - </h1> - <h2 - class="text-center text-secondary w-full md:w-3/5 lg:w-2/5 max-w-3xl mx-auto text-xl leading-normal font-medium" - > - {$t('landing.subheader')} - </h2> + <div class="space-y-10"> + <h1 + class="text-5xl md:text-6xl lg:text-7xl font-medium text-center w-full md:w-3/4 lg:w-1/2 max-w-7xl mx-auto leading-tight" + > + {$t("landing.header_before_icon")} + <span class="relative"> + {$t("landing.header_with_icon")} + <Icon + icon="rays" + style="absolute -top-16 left-5 md:left-8 lg:left-14 2xl:left-24" + /> + </span> + {$t("landing.header_after_icon")} + </h1> + <h2 + class="text-center text-secondary w-full md:w-3/5 lg:w-2/5 max-w-3xl mx-auto text-xl leading-normal font-medium" + > + {$t("landing.subheader")} + </h2> - <div class="flex justify-center"> - <a href="/register"> - <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold hover:opacity-80" - > - {$t('nav.startInSeconds')} - </button> - </a> - </div> - </div> + <div class="flex justify-center"> + <a href="/register"> + <button + class="bg-black text-white border rounded-full px-6 py-2 font-bold hover:opacity-80" + > + {$t("nav.startInSeconds")} + </button> + </a> + </div> + </div> - <Image image="hero-image" style="w-full md:w-2/3 max-w-5xl mx-auto mt-20" /> + <Image image="hero-image" style="w-full md:w-2/3 max-w-5xl mx-auto mt-20" /> </div> diff --git a/src/components/LandingInfoCard.svelte b/src/components/LandingInfoCard.svelte index 3d719e0b..fadcb6c0 100644 --- a/src/components/LandingInfoCard.svelte +++ b/src/components/LandingInfoCard.svelte @@ -1,26 +1,32 @@ <script> - import Image from './Image.svelte'; + import Image from "./Image.svelte"; - export let image; - export let title; - export let description = undefined; - export let order = undefined; + export let image; + export let title; + export let description = undefined; + export let order = undefined; </script> <div class="block lg:flex justify-center lg:space-x-20 items-center"> - <Image - {image} - style="w-2/3 md:w-5/12 lg:w-2/5 xl:w-1/3 2xl:w-1/4 max-w-xl mx-auto lg:mx-0 mb-10 lg:mb-0 {order === - 'reverse' && 'order-last'}" - /> - <div class="w-full lg:w-1/2 max-w-3xl space-y-10 mx-auto lg:mx-0"> - <h3 class="text-5xl font-medium text-left w-full mx-auto lg:mx-0 md:w-[500px]">{title}</h3> - <p class="text-secondary text-xl font-medium w-full md:w-[500px] mx-auto lg:mx-0"> - {#if description} - {description} - {:else} - <slot /> - {/if} - </p> - </div> + <Image + {image} + style="w-2/3 md:w-5/12 lg:w-2/5 xl:w-1/3 2xl:w-1/4 max-w-xl mx-auto lg:mx-0 mb-10 lg:mb-0 {order === + 'reverse' && 'order-last'}" + /> + <div class="w-full lg:w-1/2 max-w-3xl space-y-10 mx-auto lg:mx-0"> + <h3 + class="text-5xl font-medium text-left w-full mx-auto lg:mx-0 md:w-[500px]" + > + {title} + </h3> + <p + class="text-secondary text-xl font-medium w-full md:w-[500px] mx-auto lg:mx-0" + > + {#if description} + {description} + {:else} + <slot /> + {/if} + </p> + </div> </div> diff --git a/src/components/Left.svelte b/src/components/Left.svelte index 24ab927f..1e236969 100644 --- a/src/components/Left.svelte +++ b/src/components/Left.svelte @@ -1,16 +1,16 @@ <svg - class="w-5" - width="24" - height="24" - viewBox="0 0 24 24" - fill="none" - xmlns="http://www.w3.org/2000/svg" + class="w-5" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" > - <path - d="M15 19L8 12L15 5" - stroke="currentColor" - stroke-width="2" - stroke-linecap="round" - stroke-linejoin="round" - /> + <path + d="M15 19L8 12L15 5" + stroke="currentColor" + stroke-width="2" + stroke-linecap="round" + stroke-linejoin="round" + /> </svg> diff --git a/src/components/Lnurlp.svelte b/src/components/Lnurlp.svelte index 9918a3f4..427e4c07 100644 --- a/src/components/Lnurlp.svelte +++ b/src/components/Lnurlp.svelte @@ -1,60 +1,60 @@ <script> - import { t } from '$lib/translations'; - import { enhance } from '$app/forms'; - import { Numpad, Spinner } from '$comp'; - import { pin } from '$lib/store'; + import { t } from "$lib/translations"; + import { enhance } from "$app/forms"; + import { Numpad, Spinner } from "$comp"; + import { pin } from "$lib/store"; - export let data, form; - let { currency } = data.user; - let { minSendable, maxSendable, callback, metadata, rates } = data; + export let data, form; + let { currency } = data.user; + let { minSendable, maxSendable, callback, metadata, rates } = data; - $: rate = rates[currency]; + $: rate = rates[currency]; - let amount = Math.round(minSendable / 1000), - loading; - let submit = () => (loading = true); + let amount = Math.round(minSendable / 1000), + loading; + let submit = () => (loading = true); </script> <div class="container px-4 mt-20 max-w-xl mx-auto"> - <div class="text-center mb-8"> - {#each JSON.parse(metadata) as m} - <div> - {#if m[0] === 'text/plain'} - <h1 class="text-3xl md:text-4xl font-semibold mb-2">{m[1]}</h1> - {/if} - {#if m[0].includes('image')} - <img src={`data:image/png;base64,${m[1]}`} alt="Recipient" /> - {/if} - </div> - {/each} - </div> + <div class="text-center mb-8"> + {#each JSON.parse(metadata) as m} + <div> + {#if m[0] === "text/plain"} + <h1 class="text-3xl md:text-4xl font-semibold mb-2">{m[1]}</h1> + {/if} + {#if m[0].includes("image")} + <img src={`data:image/png;base64,${m[1]}`} alt="Recipient" /> + {/if} + </div> + {/each} + </div> - {#if form?.error} - <div class="text-red-600 text-center mb-5"> - {form.error} - </div> - {/if} + {#if form?.error} + <div class="text-red-600 text-center mb-5"> + {form.error} + </div> + {/if} - <Numpad bind:amount bind:rate {currency} /> + <Numpad bind:amount bind:rate {currency} /> - <form action="?/pay" method="POST" use:enhance on:submit={submit}> - <input name="amount" value={amount} type="hidden" /> - <input name="minSendable" value={minSendable} type="hidden" /> - <input name="maxSendable" value={maxSendable} type="hidden" /> - <input name="callback" value={callback} type="hidden" /> - <input name="pin" value={$pin} type="hidden" /> + <form action="?/pay" method="POST" use:enhance on:submit={submit}> + <input name="amount" value={amount} type="hidden" /> + <input name="minSendable" value={minSendable} type="hidden" /> + <input name="maxSendable" value={maxSendable} type="hidden" /> + <input name="callback" value={callback} type="hidden" /> + <input name="pin" value={$pin} type="hidden" /> - <div class="flex w-full"> - <button - type="submit" - class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24" - > - {#if loading} - <Spinner /> - {:else} - {$t('payments.send')} - {/if} - </button> - </div> - </form> + <div class="flex w-full"> + <button + type="submit" + class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24" + > + {#if loading} + <Spinner /> + {:else} + {$t("payments.send")} + {/if} + </button> + </div> + </form> </div> diff --git a/src/components/Lnurlw.svelte b/src/components/Lnurlw.svelte index f780d755..09bbca7f 100644 --- a/src/components/Lnurlw.svelte +++ b/src/components/Lnurlw.svelte @@ -1,56 +1,65 @@ <script> - import { t } from '$lib/translations'; - import { enhance } from '$app/forms'; - import { Numpad, Spinner } from '$comp'; - import { pin } from '$lib/store'; + import { t } from "$lib/translations"; + import { enhance } from "$app/forms"; + import { Numpad, Spinner } from "$comp"; + import { pin } from "$lib/store"; - export let data, form; + export let data, form; - let { currency, username } = data.user; - let { defaultDescription, minWithdrawable, maxWithdrawable, k1, callback, rates } = data; - $: rate = rates[currency]; + let { currency, username } = data.user; + let { + defaultDescription, + minWithdrawable, + maxWithdrawable, + k1, + callback, + rates, + } = data; + $: rate = rates[currency]; - let amount = Math.round(maxWithdrawable / 1000), - loading; + let amount = Math.round(maxWithdrawable / 1000), + loading; - let submit = () => (loading = true); + let submit = () => (loading = true); </script> <div class="container px-4 mt-20 max-w-xl mx-auto"> - <div class="text-center mb-8"> - <div> - <h1 class="text-3xl md:text-4xl font-semibold mb-2">{defaultDescription}</h1> - </div> - </div> + <div class="text-center mb-8"> + <div> + <h1 class="text-3xl md:text-4xl font-semibold mb-2"> + {defaultDescription} + </h1> + </div> + </div> - {#if form?.error} - <div class="text-red-600 text-center mb-5"> - {form.error} - </div> - {/if} + {#if form?.error} + <div class="text-red-600 text-center mb-5"> + {form.error} + </div> + {/if} - <Numpad bind:amount {currency} bind:rate /> + <Numpad bind:amount {currency} bind:rate /> - <form action="?/withdraw" method="POST" use:enhance on:submit={submit}> - <input name="amount" value={amount} type="hidden" /> - <input name="username" value={username} type="hidden" /> - <input name="currency" value={currency} type="hidden" /> - <input name="minWithdrawable" value={minWithdrawable} type="hidden" /> - <input name="maxWithdrawable" value={maxWithdrawable} type="hidden" /> - <input name="callback" value={callback} type="hidden" /> - <input name="k1" value={k1} type="hidden" /> + <form action="?/withdraw" method="POST" use:enhance on:submit={submit}> + <input name="amount" value={amount} type="hidden" /> + <input name="username" value={username} type="hidden" /> + <input name="currency" value={currency} type="hidden" /> + <input name="minWithdrawable" value={minWithdrawable} type="hidden" /> + <input name="maxWithdrawable" value={maxWithdrawable} type="hidden" /> + <input name="callback" value={callback} type="hidden" /> + <input name="k1" value={k1} type="hidden" /> - <div class="flex w-full"> - <button - type="submit" - class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24" - > - {#if loading} - <Spinner /> - {:else} - {$t('payments.redeem')} - {/if} - </button> - </div> - </form> + <div class="flex w-full"> + <button + type="submit" + class="opacity-100 hover:opacity-80'} rounded-2xl border py-3 font-bold mx-auto mt-2 bg-black text-white px-4 w-24" + > + {#if loading} + <Spinner /> + {:else} + {$t("payments.redeem")} + {/if} + </button> + </div> + </form> </div> diff --git a/src/components/LoadingSplash.svelte b/src/components/LoadingSplash.svelte index 2ab4c739..65ee5cd8 100644 --- a/src/components/LoadingSplash.svelte +++ b/src/components/LoadingSplash.svelte @@ -1,7 +1,7 @@ <script> - import { Icon } from '$comp'; + import { Icon } from "$comp"; </script> <div class="flex justify-center items-center"> - <Icon icon="logo" style="mt-[calc(50vh-72px)]" /> + <Icon icon="logo" style="mt-[calc(50vh-72px)]" /> </div> diff --git a/src/components/LocaleSelector.svelte b/src/components/LocaleSelector.svelte index 28e01d07..8ec5def0 100644 --- a/src/components/LocaleSelector.svelte +++ b/src/components/LocaleSelector.svelte @@ -1,18 +1,18 @@ <script> - import { t, locale, locales } from '$lib/translations'; - export let style; + import { t, locale, locales } from "$lib/translations"; + export let style; </script> <select name="language" bind:value={$locale} class={style}> - {#each $locales as locale} - <option value={locale}>{$t(`lang.${locale}`)}</option> - {/each} + {#each $locales as locale} + <option value={locale}>{$t(`lang.${locale}`)}</option> + {/each} </select> <style> - select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - } + select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + } </style> diff --git a/src/components/LocationsMap.svelte b/src/components/LocationsMap.svelte index 0068b95f..cd26d4bd 100644 --- a/src/components/LocationsMap.svelte +++ b/src/components/LocationsMap.svelte @@ -1,276 +1,286 @@ <script> - import { tick, onMount, onDestroy } from 'svelte'; - import { browser } from '$app/environment'; - import { Icon, Popup } from '$comp'; - import { shuffleArray } from '$lib/utils'; + import { tick, onMount, onDestroy } from "svelte"; + import { browser } from "$app/environment"; + import { Icon, Popup } from "$comp"; + import { shuffleArray } from "$lib/utils"; - import 'maplibre-gl/dist/maplibre-gl.css'; + import "maplibre-gl/dist/maplibre-gl.css"; - export let locations; - let map; - let mapContainer, mapWrapper; - let markers = []; + export let locations; + let map; + let mapContainer, mapWrapper; + let markers = []; - let currentIndex = -1; - let timeout; + let currentIndex = -1; + let timeout; - let full = () => { - if (!document.fullscreenElement) { - if (mapWrapper.requestFullscreen) { - mapWrapper.requestFullscreen(); - } else if (mapWrapper.mozRequestFullScreen) { - /* Firefox */ - mapWrapper.mozRequestFullScreen(); - } else if (mapWrapper.webkitRequestFullscreen) { - /* Chrome, Safari & Opera */ - mapWrapper.webkitRequestFullscreen(); - } else if (mapWrapper.msRequestFullscreen) { - /* IE/Edge */ - mapWrapper.msRequestFullscreen(); - } + let full = () => { + if (!document.fullscreenElement) { + if (mapWrapper.requestFullscreen) { + mapWrapper.requestFullscreen(); + } else if (mapWrapper.mozRequestFullScreen) { + /* Firefox */ + mapWrapper.mozRequestFullScreen(); + } else if (mapWrapper.webkitRequestFullscreen) { + /* Chrome, Safari & Opera */ + mapWrapper.webkitRequestFullscreen(); + } else if (mapWrapper.msRequestFullscreen) { + /* IE/Edge */ + mapWrapper.msRequestFullscreen(); + } - map.resize(); - } else { - if (document.exitFullscreen) { - document.exitFullscreen(); - } else if (document.mozCancelFullScreen) { - /* Firefox */ - document.mozCancelFullScreen(); - } else if (document.webkitExitFullscreen) { - /* Chrome, Safari and Opera */ - document.webkitExitFullscreen(); - } else if (document.msExitFullscreen) { - /* IE/Edge */ - document.msExitFullscreen(); - } - } - }; + map.resize(); + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { + /* Firefox */ + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + /* Chrome, Safari and Opera */ + document.webkitExitFullscreen(); + } else if (document.msExitFullscreen) { + /* IE/Edge */ + document.msExitFullscreen(); + } + } + }; - function select(m) { - stopFlying(); - currentIndex = inview.indexOf(m); - flyToMarker(m); - } + function select(m) { + stopFlying(); + currentIndex = inview.indexOf(m); + flyToMarker(m); + } - async function flyToMarker(marker) { - map.flyTo({ - zoom: 12, - center: marker.getLngLat(), - essential: true, - easing: function (t) { - return 1 - Math.pow(1 - t, 3); - }, - duration: 3000 - }); + async function flyToMarker(marker) { + map.flyTo({ + zoom: 12, + center: marker.getLngLat(), + essential: true, + easing: function (t) { + return 1 - Math.pow(1 - t, 3); + }, + duration: 3000, + }); - await new Promise((r) => setTimeout(r, 3000)); - marker.getElement().click(); - await new Promise((r) => setTimeout(r, 1500)); + await new Promise((r) => setTimeout(r, 3000)); + marker.getElement().click(); + await new Promise((r) => setTimeout(r, 1500)); - if (!timeout) return; + if (!timeout) return; - map.flyTo({ - zoom: 10.5, - center: marker.getLngLat(), - essential: true, - easing: function (t) { - return 1 - Math.pow(1 - t, 3); - }, - duration: 1500 - }); - } + map.flyTo({ + zoom: 10.5, + center: marker.getLngLat(), + essential: true, + easing: function (t) { + return 1 - Math.pow(1 - t, 3); + }, + duration: 1500, + }); + } - let toggle = () => { - if (timeout) stopFlying(); - else startFlying(); - }; + let toggle = () => { + if (timeout) stopFlying(); + else startFlying(); + }; - let currentPopup; - function startFlying() { - currentIndex++; + let currentPopup; + function startFlying() { + currentIndex++; - for (let p in popups) popups[p].remove(); - if (currentIndex >= inview.length) currentIndex = 0; - flyToMarker(inview[currentIndex]); + for (let p in popups) popups[p].remove(); + if (currentIndex >= inview.length) currentIndex = 0; + flyToMarker(inview[currentIndex]); - timeout = setTimeout(startFlying, 6000); - } + timeout = setTimeout(startFlying, 6000); + } - function stopFlying() { - if (!timeout) return; - timeout = clearTimeout(timeout); + function stopFlying() { + if (!timeout) return; + timeout = clearTimeout(timeout); - if (currentPopup) { - currentPopup.remove(); - } + if (currentPopup) { + currentPopup.remove(); + } - map.jumpTo({ center: map.getCenter(), zoom: map.getZoom() }); - map.off('moveend'); // Remove moveend listener if set - } + map.jumpTo({ center: map.getCenter(), zoom: map.getZoom() }); + map.off("moveend"); // Remove moveend listener if set + } - let inview = []; + let inview = []; - function updateLabelVisibility() { - inview = []; - if (!map) return; - let zoom = map.getZoom(); - let bounds = map.getBounds(); + function updateLabelVisibility() { + inview = []; + if (!map) return; + let zoom = map.getZoom(); + let bounds = map.getBounds(); - for (let marker of markers) { - let isInView = bounds.contains(marker.getLngLat()); - let { tags } = marker; + for (let marker of markers) { + let isInView = bounds.contains(marker.getLngLat()); + let { tags } = marker; - if (isInView) { - inview.push(marker); - } - } + if (isInView) { + inview.push(marker); + } + } - inview = inview.sort((a, b) => a.tags.name.localeCompare(b.tags.name)); - shuffleArray(inview); - } + inview = inview.sort((a, b) => a.tags.name.localeCompare(b.tags.name)); + shuffleArray(inview); + } - let popups = {}; - let counter = 0; + let popups = {}; + let counter = 0; - onMount(() => { - if (browser) { - import('maplibre-gl').then(({ default: maplibre }) => { - map = new maplibre.Map({ - container: mapContainer, - style: 'https://tiles.stadiamaps.com/styles/stamen_toner.json', - center: [-123.05, 49.26], - zoom: 10.5 - }); + onMount(() => { + if (browser) { + import("maplibre-gl").then(({ default: maplibre }) => { + map = new maplibre.Map({ + container: mapContainer, + style: "https://tiles.stadiamaps.com/styles/stamen_toner.json", + center: [-123.05, 49.26], + zoom: 10.5, + }); - map.on('load', () => { - locations.forEach((location) => { - if (location['deleted_at']) return; + map.on("load", () => { + locations.forEach((location) => { + if (location["deleted_at"]) return; - let { lat, lon, tags } = location['osm_json']; - if (!(lat && lon)) return; + let { lat, lon, tags } = location["osm_json"]; + if (!(lat && lon)) return; - let element = document.createElement('div'); - element.className = 'marker'; + let element = document.createElement("div"); + element.className = "marker"; - let popupContainer = document.createElement('div'); + let popupContainer = document.createElement("div"); - let popup = new Popup({ - target: popupContainer, - props: { tags } - }); + let popup = new Popup({ + target: popupContainer, + props: { tags }, + }); - let marker = new maplibre.Marker({ color: '#F7931A' }) - .setLngLat([lon, lat]) - .setPopup(new maplibre.Popup().setDOMContent(popupContainer)) - .addTo(map); + let marker = new maplibre.Marker({ color: "#F7931A" }) + .setLngLat([lon, lat]) + .setPopup(new maplibre.Popup().setDOMContent(popupContainer)) + .addTo(map); - marker.id = counter++; + marker.id = counter++; - marker.getElement().addEventListener('click', () => { - let p = marker.getPopup(); - popups[marker.id] = p; - p.setDOMContent(popupContainer); - p.on('close', () => { - delete popups[marker.id]; - }); - }); + marker.getElement().addEventListener("click", () => { + let p = marker.getPopup(); + popups[marker.id] = p; + p.setDOMContent(popupContainer); + p.on("close", () => { + delete popups[marker.id]; + }); + }); - marker.tags = tags; + marker.tags = tags; - markers.push(marker); - }); + markers.push(marker); + }); - updateLabelVisibility(); + updateLabelVisibility(); - let observer = new IntersectionObserver( - (entries, observer) => { - entries.forEach((entry) => { - if (entry.isIntersecting) startFlying(); - else stopFlying(); - }); - }, - { threshold: 0.5 } - ); + let observer = new IntersectionObserver( + (entries, observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) startFlying(); + else stopFlying(); + }); + }, + { threshold: 0.5 } + ); - observer.observe(mapContainer); - }); + observer.observe(mapContainer); + }); - map.on('mousedown', stopFlying); - map.on('touchstart', stopFlying); - map.on('wheel', stopFlying); - map.on('dragstart', stopFlying); + map.on("mousedown", stopFlying); + map.on("touchstart", stopFlying); + map.on("wheel", stopFlying); + map.on("dragstart", stopFlying); - let resize = () => map && map.resize(); + let resize = () => map && map.resize(); - document.addEventListener('fullscreenchange', resize, false); - document.addEventListener('webkitfullscreenchange', resize, false); - document.addEventListener('mozfullscreenchange', resize, false); - document.addEventListener('MSFullscreenChange', resize, false); - }); - } - }); + document.addEventListener("fullscreenchange", resize, false); + document.addEventListener("webkitfullscreenchange", resize, false); + document.addEventListener("mozfullscreenchange", resize, false); + document.addEventListener("MSFullscreenChange", resize, false); + }); + } + }); - onDestroy(() => map && map.remove()); + onDestroy(() => map && map.remove()); </script> <div class="container mx-auto p-2 space-y-5"> - <div class="flex w-full h-[60vh]" id="map" bind:this={mapWrapper}> - <div id="map-container" class="mx-auto h-full w-full z-0" bind:this={mapContainer} /> - <div class="relative"> - <div class="flex absolute flex top-2 right-2 gap-2"> - <button class="rounded-full border-2 border-black bg-white w-10 h-10" on:click={toggle}> - {#if timeout} - <Icon icon="pause" style="w-4 m-auto" /> - {:else} - <Icon icon="play" style="w-4 m-auto" /> - {/if} - </button> - <button class="rounded-full border-2 border-black bg-white w-10 h-10" on:click={full}> - <Icon icon="full" style="w-4 m-auto" /> - </button> - </div> - </div> - </div> + <div class="flex w-full h-[60vh]" id="map" bind:this={mapWrapper}> + <div + id="map-container" + class="mx-auto h-full w-full z-0" + bind:this={mapContainer} + /> + <div class="relative"> + <div class="flex absolute flex top-2 right-2 gap-2"> + <button + class="rounded-full border-2 border-black bg-white w-10 h-10" + on:click={toggle} + > + {#if timeout} + <Icon icon="pause" style="w-4 m-auto" /> + {:else} + <Icon icon="play" style="w-4 m-auto" /> + {/if} + </button> + <button + class="rounded-full border-2 border-black bg-white w-10 h-10" + on:click={full} + > + <Icon icon="full" style="w-4 m-auto" /> + </button> + </div> + </div> + </div> - <!-- <div class="hidden lg:grid grid-cols-3 justify-items-center"> --> - <!-- {#each inview as m} --> - <!-- <button --> - <!-- on:click={() => select(m)} --> - <!-- class="text-left" --> - <!-- class:font-bold={m.id === inview[currentIndex]?.id} --> - <!-- id={`marker-${m.id}`}>{m.tags.name}</button --> - <!-- > --> - <!-- {/each} --> - <!-- </div> --> + <!-- <div class="hidden lg:grid grid-cols-3 justify-items-center"> --> + <!-- {#each inview as m} --> + <!-- <button --> + <!-- on:click={() => select(m)} --> + <!-- class="text-left" --> + <!-- class:font-bold={m.id === inview[currentIndex]?.id} --> + <!-- id={`marker-${m.id}`}>{m.tags.name}</button --> + <!-- > --> + <!-- {/each} --> + <!-- </div> --> </div> <style> - #map:fullscreen, - #map-container:fullscreen { - width: 100% !important; - height: 100% !important; - } + #map:fullscreen, + #map-container:fullscreen { + width: 100% !important; + height: 100% !important; + } - :global(.maplibregl-popup-close-button) { - font-size: 24px; - padding: 8px; - } + :global(.maplibregl-popup-close-button) { + font-size: 24px; + padding: 8px; + } - :global(.maplibregl-popup :focus) { - outline: none; - } + :global(.maplibregl-popup :focus) { + outline: none; + } - :global(.maplibregl-ctrl-attrib) { - display: none; - } + :global(.maplibregl-ctrl-attrib) { + display: none; + } - :global(.maplibregl-popup-content) { - padding: 1em 2em; - border-radius: 4px; - font-size: 14px; - color: black; - background-color: white; - overflow: hidden; - width: 280px; - } + :global(.maplibregl-popup-content) { + padding: 1em 2em; + border-radius: 4px; + font-size: 14px; + color: black; + background-color: white; + overflow: hidden; + width: 280px; + } </style> diff --git a/src/components/Lock.svelte b/src/components/Lock.svelte index 11475acf..fce994a2 100644 --- a/src/components/Lock.svelte +++ b/src/components/Lock.svelte @@ -1,14 +1,14 @@ <svg - xmlns="http://www.w3.org/2000/svg" - class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6" - fill="none" - viewBox="0 0 24 24" - stroke="currentColor" + xmlns="http://www.w3.org/2000/svg" + class="absolute bottom-0 left-0 -mb-0.5 transform translate-x-1/2 -translate-y-1/2 text-black peer-placeholder-shown:text-gray-300 h-6 w-6" + fill="none" + viewBox="0 0 24 24" + stroke="currentColor" > - <path - stroke-linecap="round" - stroke-linejoin="round" - stroke-width="2" - d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" - /> + <path + stroke-linecap="round" + stroke-linejoin="round" + stroke-width="2" + d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" + /> </svg> diff --git a/src/components/Numpad.svelte b/src/components/Numpad.svelte index 5ea1418c..6b779085 100644 --- a/src/components/Numpad.svelte +++ b/src/components/Numpad.svelte @@ -1,219 +1,236 @@ <script> - import { Left, Icon } from '$comp'; - import { f, s, post, warning, sat, sats } from '$lib/utils'; - import { t } from '$lib/translations'; + import { Left, Icon } from "$comp"; + import { f, s, post, warning, sat, sats } from "$lib/utils"; + import { t } from "$lib/translations"; - export let amount, - currency, - fiat = !amount, - rate, - submit = undefined; + export let amount, + currency, + fiat = !amount, + rate, + submit = undefined; - export let amountFiat = 0; + export let amountFiat = 0; - let arrow = '<'; + let arrow = "<"; - $: update(amount, amountFiat); - let update = (a, f) => { - if (fiat) { - amount = Math.round(f / (rate / sats)); - } else { - amountFiat = ((a * rate) / sats).toFixed(2); - } - }; + $: update(amount, amountFiat); + let update = (a, f) => { + if (fiat) { + amount = Math.round(f / (rate / sats)); + } else { + amountFiat = ((a * rate) / sats).toFixed(2); + } + }; - let loading = false; + let loading = false; - let symbol = - { - USD: '$', - CAD: '$', - AUD: '$', - NZD: '$', - MXN: '$', - BRL: 'R$', - HKD: '$', - TWD: '$', - JPY: '¥', - CNY: '¥', - GBP: '£', - EUR: '€', - KRW: '₩' - }[currency] || ''; + let symbol = + { + USD: "$", + CAD: "$", + AUD: "$", + NZD: "$", + MXN: "$", + BRL: "R$", + HKD: "$", + TWD: "$", + JPY: "¥", + CNY: "¥", + GBP: "£", + EUR: "€", + KRW: "₩", + }[currency] || ""; - const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<']; + const numPad = ["1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "<"]; - const handleInput = (value) => { - if (fiat) { - if (amountFiat === 0 && value !== '.' && value !== '<' && value !== '0') { - amountFiat = value; - } else if ((amountFiat === 0 || amountFiat === '0') && value === '0') { - return; - } else if (amountFiat === 0 && value === '.') { - amountFiat = '0.'; - } else if (amountFiat !== 0 && amountFiat.includes('.') && value === '.') { - return; - } else if (value === '<') { - if (amountFiat !== 0) { - amountFiat = amountFiat.slice(0, amountFiat.length - 1); - if (amountFiat.length === 0) { - amountFiat = 0; - amount = 0; - } - } - } else if (value !== '.' && value !== '<' && parseInt(amountFiat + value) > rate) { - warning($t('user.receive.lessThan1BTCWarning')); - } else if (amountFiat !== 0 && amountFiat.match(/\.../)) { - return; - } else { - amountFiat = amountFiat + value; - } - } else { - if (value === '.') { - return; - } else if (!amount && value !== '<' && value !== '0') { - amount = parseInt(value); - } else if (value === '<') { - if (amount !== 0) { - amount = Math.floor(amount / 10); - if (amount.length === 0) { - amount = 0; - amountFiat = 0; - } - } - } else if (value !== '<' && parseInt(amount + value) > sats) { - warning($t('user.receive.lessThan1BTCWarning')); - } else { - console.log('CLICK', amount.toString(), value); - amount = parseInt(amount.toString() + value); - console.log('AMOUNT', amount); - } - } - }; + const handleInput = (value) => { + if (fiat) { + if (amountFiat === 0 && value !== "." && value !== "<" && value !== "0") { + amountFiat = value; + } else if ((amountFiat === 0 || amountFiat === "0") && value === "0") { + return; + } else if (amountFiat === 0 && value === ".") { + amountFiat = "0."; + } else if ( + amountFiat !== 0 && + amountFiat.includes(".") && + value === "." + ) { + return; + } else if (value === "<") { + if (amountFiat !== 0) { + amountFiat = amountFiat.slice(0, amountFiat.length - 1); + if (amountFiat.length === 0) { + amountFiat = 0; + amount = 0; + } + } + } else if ( + value !== "." && + value !== "<" && + parseInt(amountFiat + value) > rate + ) { + warning($t("user.receive.lessThan1BTCWarning")); + } else if (amountFiat !== 0 && amountFiat.match(/\.../)) { + return; + } else { + amountFiat = amountFiat + value; + } + } else { + if (value === ".") { + return; + } else if (!amount && value !== "<" && value !== "0") { + amount = parseInt(value); + } else if (value === "<") { + if (amount !== 0) { + amount = Math.floor(amount / 10); + if (amount.length === 0) { + amount = 0; + amountFiat = 0; + } + } + } else if (value !== "<" && parseInt(amount + value) > sats) { + warning($t("user.receive.lessThan1BTCWarning")); + } else { + console.log("CLICK", amount.toString(), value); + amount = parseInt(amount.toString() + value); + console.log("AMOUNT", amount); + } + } + }; - $: html = fiat ? amountFiat : s(amount); + $: html = fiat ? amountFiat : s(amount); - let prev = ''; + let prev = ""; - let input = (e) => { - if (prev === '0' && html !== '0.') { - prev = ''; - html = html.replace('0', ''); - } + let input = (e) => { + if (prev === "0" && html !== "0.") { + prev = ""; + html = html.replace("0", ""); + } - let sel = getSelection(); - let i = sel.focusOffset; + let sel = getSelection(); + let i = sel.focusOffset; - let clean = html - .substr(0, 15) - .replace(/[^0-9.,]+/g, '') - .replace('.', 'F') - .replace(/\./g, '') - .replace('F', '.'); + let clean = html + .substr(0, 15) + .replace(/[^0-9.,]+/g, "") + .replace(".", "F") + .replace(/\./g, "") + .replace("F", "."); - if (fiat) clean = clean.replace(',', ''); - if (clean !== html) { - html = clean; - i = html.length; - } + if (fiat) clean = clean.replace(",", ""); + if (clean !== html) { + html = clean; + i = html.length; + } - if (amount > sats && html.length > prev.length) { - html = prev; - warning($t('user.receive.lessThan1BTCWarning')); - i--; - } + if (amount > sats && html.length > prev.length) { + html = prev; + warning($t("user.receive.lessThan1BTCWarning")); + i--; + } - if (fiat) { - amountFiat = html; - } else { - amount = parseInt(html.replace(/,/g, '')); - } + if (fiat) { + amountFiat = html; + } else { + amount = parseInt(html.replace(/,/g, "")); + } - if (!amount) amount = null; + if (!amount) amount = null; - setTimeout(() => { - if (!fiat) { - let p = prev.split(',')[0].length; - if (html.length > prev.length && p === 3) i++; - if (html.length < prev.length && p === 1 && i > 1) i--; - } + setTimeout(() => { + if (!fiat) { + let p = prev.split(",")[0].length; + if (html.length > prev.length && p === 3) i++; + if (html.length < prev.length && p === 1 && i > 1) i--; + } - let node = e.target.childNodes[0]; - let range = document.createRange(); + let node = e.target.childNodes[0]; + let range = document.createRange(); - if (node) { - range.setStart(node, i); - range.setEnd(node, i); + if (node) { + range.setStart(node, i); + range.setEnd(node, i); - let sel = getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - } + let sel = getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } - prev = html.toString(); - }, 0); - }; + prev = html.toString(); + }, 0); + }; - let focus = (e) => { - let range = document.createRange(); - range.selectNodeContents(e.target); - let sel = getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - }; + let focus = (e) => { + let range = document.createRange(); + range.selectNodeContents(e.target); + let sel = getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + }; - let keydown = (e) => e.key === 'Enter' && (e.preventDefault() || submit.click()); + let keydown = (e) => + e.key === "Enter" && (e.preventDefault() || submit.click()); </script> <div class="flex justify-center items-center mb-3 px-3"> - <div class="space-y-5"> - <div class="text-center"> - <div class="text-5xl md:text-6xl font-semibold tracking-widest flex justify-center"> - <div class="my-auto" class:text-5xl={!fiat}>{fiat ? symbol : '⚡️'}</div> - <div - contenteditable - bind:innerHTML={html} - on:focus={focus} - on:input={input} - on:keydown={keydown} - class="outline-none my-auto" - /> - </div> - <div class="mt-2"> - <span class="text-secondary mr-1">{fiat ? sat(amount) : f(amountFiat, currency)}</span> - <button - type="button" - on:click={() => { - if (fiat) { - amount = parseInt((amountFiat / (rate / sats)).toFixed(0)); - } else { - amountFiat = - (amount * (rate / sats)).toFixed(2) > 0.0 ? (amount * (rate / sats)).toFixed(2) : 0; - } - fiat = !fiat; - }}><Icon icon="swap" style="inline hover:opacity-80" /></button - > - </div> - </div> + <div class="space-y-5"> + <div class="text-center"> + <div + class="text-5xl md:text-6xl font-semibold tracking-widest flex justify-center" + > + <div class="my-auto" class:text-5xl={!fiat}> + {fiat ? symbol : "⚡️"} + </div> + <div + contenteditable + bind:innerHTML={html} + on:focus={focus} + on:input={input} + on:keydown={keydown} + class="outline-none my-auto" + /> + </div> + <div class="mt-2"> + <span class="text-secondary mr-1" + >{fiat ? sat(amount) : f(amountFiat, currency)}</span + > + <button + type="button" + on:click={() => { + if (fiat) { + amount = parseInt((amountFiat / (rate / sats)).toFixed(0)); + } else { + amountFiat = + (amount * (rate / sats)).toFixed(2) > 0.0 + ? (amount * (rate / sats)).toFixed(2) + : 0; + } + fiat = !fiat; + }}><Icon icon="swap" style="inline hover:opacity-80" /></button + > + </div> + </div> - <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto"> - {#each numPad as value} - {#if value === arrow} - <button - type="button" - class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center hover:opacity-80" - on:click={() => handleInput(value)} - > - <Left /> - </button> - {:else} - <button - type="button" - class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" - on:click={() => handleInput(value)}>{value}</button - > - {/if} - {/each} - </div> - </div> + <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto"> + {#each numPad as value} + {#if value === arrow} + <button + type="button" + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center hover:opacity-80" + on:click={() => handleInput(value)} + > + <Left /> + </button> + {:else} + <button + type="button" + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" + on:click={() => handleInput(value)}>{value}</button + > + {/if} + {/each} + </div> + </div> </div> diff --git a/src/components/Password.svelte b/src/components/Password.svelte index a84c0b16..007ce718 100644 --- a/src/components/Password.svelte +++ b/src/components/Password.svelte @@ -1,77 +1,83 @@ <script> - import { Icon } from '$comp'; - import { focus, fail, post } from '$lib/utils'; - import { password as pw, passwordPrompt } from '$lib/store'; + import { Icon } from "$comp"; + import { focus, fail, post } from "$lib/utils"; + import { password as pw, passwordPrompt } from "$lib/store"; - export let user; + export let user; - let password; - let { username } = user; - let revealPassword = false; + let password; + let { username } = user; + let revealPassword = false; - let cancel = () => ($passwordPrompt = false); + let cancel = () => ($passwordPrompt = false); - let submit = async () => { - try { - await post('/password', { password }); - $passwordPrompt = false; - $pw = password; - } catch (e) { - fail('Invalid password, try again'); - } - }; + let submit = async () => { + try { + await post("/password", { password }); + $passwordPrompt = false; + $pw = password; + } catch (e) { + fail("Invalid password, try again"); + } + }; </script> -<div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20"> - <div 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">Please enter your password</h1> - <form on:submit|preventDefault={submit}> - <div class="relative mb-5"> - {#if revealPassword} - <input - name="password" - type="text" - required - class="bg-primary" - bind:value={password} - autocapitalize="none" - use:focus - /> - {:else} - <input - name="password" - type="password" - required - class="bg-primary" - bind:value={password} - autocapitalize="none" - use:focus - /> - {/if} - <button - type="button" - on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-6" - > - <Icon icon={revealPassword ? 'eye' : 'eye-off'} /> - </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} - > - <div class="my-auto">Cancel</div> - </button> - <button - type="submit" - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" - > - <div class="my-auto">Submit</div> - </button> - </div> - </form> - </div> +<div + class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-20" +> + <div + 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"> + Please enter your password + </h1> + <form on:submit|preventDefault={submit}> + <div class="relative mb-5"> + {#if revealPassword} + <input + name="password" + type="text" + required + class="bg-primary" + bind:value={password} + autocapitalize="none" + use:focus + /> + {:else} + <input + name="password" + type="password" + required + class="bg-primary" + bind:value={password} + autocapitalize="none" + use:focus + /> + {/if} + <button + type="button" + on:click={() => (revealPassword = !revealPassword)} + class="absolute right-5 top-6" + > + <Icon icon={revealPassword ? "eye" : "eye-off"} /> + </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} + > + <div class="my-auto">Cancel</div> + </button> + <button + type="submit" + class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" + > + <div class="my-auto">Submit</div> + </button> + </div> + </form> + </div> </div> diff --git a/src/components/Pin.svelte b/src/components/Pin.svelte index 0cff904f..bd51cb0a 100644 --- a/src/components/Pin.svelte +++ b/src/components/Pin.svelte @@ -1,59 +1,63 @@ <script> - import { t } from '$lib/translations'; - import { post, success, fail, focus } from '$lib/utils'; - import { Pinpad } from '$comp'; - import { pin } from '$lib/store'; - import { onMount } from 'svelte'; + import { t } from "$lib/translations"; + import { post, success, fail, focus } from "$lib/utils"; + import { Pinpad } from "$comp"; + 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 persist = true; - export let notify = true; + export let value = ""; + export let title = $t("user.settings.verifyPIN"); + export let cancel = () => (p = ""); + export let persist = true; + export let notify = true; - let p = ''; + let p = ""; - $: update(value); - let update = (value) => (p = value); + $: update(value); + let update = (value) => (p = value); - $: p.toString().length > 5 && (value = p.toString()); + $: p.toString().length > 5 && (value = p.toString()); - let loaded; - onMount(() => setTimeout(() => (loaded = true), 500)); + let loaded; + onMount(() => setTimeout(() => (loaded = true), 500)); - $: loaded && checkPin(p); - let checkPin = async (p) => { - if (p?.length !== 6) return; - let result; - try { - result = await post('/pin', { pin: p }); - } catch (e) { - console.log('Pin check failed', e); - } + $: loaded && checkPin(p); + let checkPin = async (p) => { + if (p?.length !== 6) return; + let result; + try { + result = await post("/pin", { pin: p }); + } catch (e) { + console.log("Pin check failed", e); + } - if (result) { - if (notify) success('Pin confirmed'); - if (persist) $pin = p; - } else { - fail('Invalid pin'); - value = ''; - } - }; + if (result) { + if (notify) success("Pin confirmed"); + if (persist) $pin = p; + } else { + fail("Invalid pin"); + value = ""; + } + }; </script> {#if loaded} - <div class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50"> - <div class="relative top-40 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5"> - <h1 class="text-center text-2xl font-semibold">{title}</h1> - <Pinpad bind:v={p} {cancel} /> - <div class="w-full flex"> - <button - class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" - on:click|preventDefault={cancel} - > - <div class="my-auto">Cancel</div> - </button> - </div> - </div> - </div> + <div + class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-50" + > + <div + class="relative top-40 mx-auto p-5 border w-96 shadow-lg rounded-md bg-white space-y-5" + > + <h1 class="text-center text-2xl font-semibold">{title}</h1> + <Pinpad bind:v={p} {cancel} /> + <div class="w-full flex"> + <button + class="border-2 border-black rounded-xl font-semibold mx-auto py-3 w-40 hover:opacity-80 mx-auto" + on:click|preventDefault={cancel} + > + <div class="my-auto">Cancel</div> + </button> + </div> + </div> + </div> {/if} diff --git a/src/components/Pinpad.svelte b/src/components/Pinpad.svelte index f55dc40d..5db23154 100644 --- a/src/components/Pinpad.svelte +++ b/src/components/Pinpad.svelte @@ -1,80 +1,88 @@ <script> - import { Left, Icon } from '$comp'; - import { focus, post, warning } from '$lib/utils'; - import { t } from '$lib/translations'; + import { Left, Icon } from "$comp"; + import { focus, post, warning } from "$lib/utils"; + import { t } from "$lib/translations"; - export let v; - export let cancel; + export let v; + export let cancel; - let arrow = '<'; - let loading = false; + let arrow = "<"; + let loading = false; - const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'C', '0', '<']; + const numPad = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "C", "0", "<"]; - const handleInput = (n) => { - v = (v || '').toString(); - if (n === 'C') return (v = ''); - if (n === '<') return (v = v.length > 1 ? Math.floor(v / 10) : ''); - if (v.length > 5) n = ''; - if (parseInt(n) >= 0) v += n; - }; + const handleInput = (n) => { + v = (v || "").toString(); + if (n === "C") return (v = ""); + if (n === "<") return (v = v.length > 1 ? Math.floor(v / 10) : ""); + if (v.length > 5) n = ""; + if (parseInt(n) >= 0) v += n; + }; - let validate = (e) => { - let k = e.key || e.code; - if (k === 'Escape') cancel(); - if (e.key.length <= 1 && !(e.metaKey || e.ctrlKey || e.altKey) && !(k >= '0' && k <= '9')) { - if (e.preventDefault) e.preventDefault(); - else e.returnValue = false; - } - }; + let validate = (e) => { + let k = e.key || e.code; + if (k === "Escape") cancel(); + if ( + e.key.length <= 1 && + !(e.metaKey || e.ctrlKey || e.altKey) && + !(k >= "0" && k <= "9") + ) { + if (e.preventDefault) e.preventDefault(); + else e.returnValue = false; + } + }; - let hide = true; + let hide = true; </script> <div class="flex justify-center items-center"> - <div class="space-y-5"> - <div class="text-5xl md:text-6xl font-semibold relative w-[300px]"> - {#if hide} - <input - on:keydown={validate} - use:focus - bind:value={v} - type="password" - class="outline-none border-0 text-center py-0" - pattern="[0-9]+" - /> - {:else} - <input - on:keydown={validate} - bind:value={v} - class="outline-none border-0 text-center py-0" - type="text" - pattern="[0-9]+" - /> - {/if} - <button type="button" on:click={() => (hide = !hide)} class="absolute -right-5 top-5"> - <Icon icon={hide ? 'eye-off' : 'eye'} style="w-8" /> - </button> - </div> + <div class="space-y-5"> + <div class="text-5xl md:text-6xl font-semibold relative w-[300px]"> + {#if hide} + <input + on:keydown={validate} + use:focus + bind:value={v} + type="password" + class="outline-none border-0 text-center py-0" + pattern="[0-9]+" + /> + {:else} + <input + on:keydown={validate} + bind:value={v} + class="outline-none border-0 text-center py-0" + type="text" + pattern="[0-9]+" + /> + {/if} + <button + type="button" + on:click={() => (hide = !hide)} + class="absolute -right-5 top-5" + > + <Icon icon={hide ? "eye-off" : "eye"} style="w-8" /> + </button> + </div> - <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto grayscale"> - {#each numPad as value} - {#if value === arrow} - <button - type="button" - class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center hover:opacity-80" - on:click={() => handleInput(value)} - > - <Left /> - </button> - {:else} - <button - type="button" - class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" - on:click={() => handleInput(value)}>{value}</button - > - {/if} - {/each} - </div> - </div> + <div class="grid grid-cols-3 gap-2 w-[300px] mx-auto grayscale"> + {#each numPad as value} + {#if value === arrow} + <button + type="button" + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center hover:opacity-80" + on:click={() => handleInput(value)} + > + <Left /> + </button> + {:else} + <button + type="button" + class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white hover:opacity-80" + on:click={() => handleInput(value)}>{value}</button + > + {/if} + {/each} + </div> + </div> </div> diff --git a/src/components/Popup.svelte b/src/components/Popup.svelte index 8fe1d160..5d2b9b6a 100644 --- a/src/components/Popup.svelte +++ b/src/components/Popup.svelte @@ -1,38 +1,42 @@ <script> - import { page } from '$app/stores'; - import { Avatar } from '$comp'; - export let tags; + import { page } from "$app/stores"; + import { Avatar } from "$comp"; + export let tags; - let addr = (tags) => { - let { 'addr:housenumber': house, 'addr:street': street, 'addr:city': city } = tags; - if (house) return `${house} ${street}`; - return ''; - }; + let addr = (tags) => { + let { + "addr:housenumber": house, + "addr:street": street, + "addr:city": city, + } = tags; + if (house) return `${house} ${street}`; + return ""; + }; </script> {#if tags} - {#if tags.user} - <a href={`/${tags.user.username}`}> - <div class="space-y-5"> - <div> - <span class="block font-bold">{tags.name}</span> - <span class="block">{addr(tags)}</span> - </div> + {#if tags.user} + <a href={`/${tags.user.username}`}> + <div class="space-y-5"> + <div> + <span class="block font-bold">{tags.name}</span> + <span class="block">{addr(tags)}</span> + </div> - <div> - <div class="flex w-full"> - <div class="mx-auto"> - <Avatar user={tags.user} size={16} /> - </div> - </div> - <div class="break-all text-center"> - {$page.url.host}/{tags.user.username.toLowerCase()} - </div> - </div> - </div> - </a> - {:else} - <span class="block font-bold">{tags.name}</span> - <span class="block">{addr(tags)}</span> - {/if} + <div> + <div class="flex w-full"> + <div class="mx-auto"> + <Avatar user={tags.user} size={16} /> + </div> + </div> + <div class="break-all text-center"> + {$page.url.host}/{tags.user.username.toLowerCase()} + </div> + </div> + </div> + </a> + {:else} + <span class="block font-bold">{tags.name}</span> + <span class="block">{addr(tags)}</span> + {/if} {/if} diff --git a/src/components/Qr.svelte b/src/components/Qr.svelte index c67d134e..8a716b14 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; + import screenfull from "screenfull"; + export let src; + let qr; </script> <div - class="w-80 mx-auto my-5 cursor-pointer" - bind:this={qr} - on:click={() => screenfull.toggle(qr)} - on:keydown={() => screenfull.toggle(qr)} + class="w-80 mx-auto my-5 cursor-pointer" + bind:this={qr} + on:click={() => screenfull.toggle(qr)} + on:keydown={() => screenfull.toggle(qr)} > - <img {src} class="mx-auto" alt="QR Code" /> + <img {src} class="mx-auto" alt="QR Code" /> </div> diff --git a/src/components/Quote.svelte b/src/components/Quote.svelte index 1e099061..8901dae1 100644 --- a/src/components/Quote.svelte +++ b/src/components/Quote.svelte @@ -1,11 +1,11 @@ <svg - aria-hidden="true" - class="w-10 h-10 text-gray-400 dark:text-gray-600" - viewBox="0 0 24 27" - fill="none" - xmlns="http://www.w3.org/2000/svg" - ><path - d="M14.017 18L14.017 10.609C14.017 4.905 17.748 1.039 23 0L23.995 2.151C21.563 3.068 20 5.789 20 8h34V18H14.017ZM0 18V10.609C0 4.905 3.748 1.038 9 0L9.996 2.151C7.563 3.068 6 5.789 6 8H9.983L9.983 18L0 18Z" - fill="currentColor" - /></svg + aria-hidden="true" + class="w-10 h-10 text-gray-400 dark:text-gray-600" + viewBox="0 0 24 27" + fill="none" + xmlns="http://www.w3.org/2000/svg" + ><path + d="M14.017 18L14.017 10.609C14.017 4.905 17.748 1.039 23 0L23.995 2.151C21.563 3.068 20 5.789 20 8h34V18H14.017ZM0 18V10.609C0 4.905 3.748 1.038 9 0L9.996 2.151C7.563 3.068 6 5.789 6 8H9.983L9.983 18L0 18Z" + fill="currentColor" + /></svg > diff --git a/src/components/RegisterOrLogin.svelte b/src/components/RegisterOrLogin.svelte index 57e0eeed..5617fc7b 100644 --- a/src/components/RegisterOrLogin.svelte +++ b/src/components/RegisterOrLogin.svelte @@ -1,179 +1,191 @@ <script> - import { applyAction, deserialize } from '$app/forms'; - import { tick } from 'svelte'; - import { fly } from 'svelte/transition'; - import { enhance } from '$app/forms'; - import { Pin, Icon, Spinner } from '$comp'; - import { focus, fail } from '$lib/utils'; - import { password, loginRedirect } from '$lib/store'; - import { t } from '$lib/translations'; - import { page } from '$app/stores'; - import { generate } from '$lib/nostr'; - import { invalidateAll } from '$app/navigation'; + import { applyAction, deserialize } from "$app/forms"; + import { tick } from "svelte"; + import { fly } from "svelte/transition"; + import { enhance } from "$app/forms"; + import { Pin, Icon, Spinner } from "$comp"; + import { focus, fail } from "$lib/utils"; + import { password, loginRedirect } from "$lib/store"; + import { t } from "$lib/translations"; + import { page } from "$app/stores"; + import { generate } from "$lib/nostr"; + import { invalidateAll } from "$app/navigation"; - export let form; - export let pageID; + export let form; + export let pageID; - let token, formElement; - let code = []; - let redirect; + let token, formElement; + let code = []; + let redirect; - $password = undefined; + $password = undefined; - $: need2fa = form?.message === '2fa'; - let cancel = () => (need2fa = false); - $: if (form?.message === '2fa' && form.token === token) token = ''; + $: need2fa = form?.message === "2fa"; + let cancel = () => (need2fa = false); + $: if (form?.message === "2fa" && form.token === token) token = ""; - let username, email, btn; + let username, email, btn; - $: update(form); - let update = (form) => form && ({ username, password: $password } = form); + $: update(form); + let update = (form) => form && ({ username, password: $password } = form); - $: token && token?.length === 6 && tick().then(() => btn.click()); + $: token && token?.length === 6 && tick().then(() => btn.click()); - let revealPassword = false; + let revealPassword = false; - let action = { - register: '/register', - signIn: '/login' - }[pageID]; + let action = { + register: "/register", + signIn: "/login", + }[pageID]; - let loading; - async function handleSubmit(e) { - loading = true; + let loading; + async function handleSubmit(e) { + loading = true; - let data = new FormData(this); - let user = Object.fromEntries(data); - await generate(user); + let data = new FormData(this); + let user = Object.fromEntries(data); + await generate(user); - for (let k in user) { - data.set(k, user[k]); - } + for (let k in user) { + data.set(k, user[k]); + } - const response = await fetch(action, { - method: 'POST', - body: data - }); + const response = await fetch(action, { + method: "POST", + body: data, + }); - const result = deserialize(await response.text()); + const result = deserialize(await response.text()); - if (result.type === 'success') { - await invalidateAll(); - } + if (result.type === "success") { + await invalidateAll(); + } - applyAction(result); - loading = false; - } + applyAction(result); + loading = false; + } </script> {#if need2fa} - <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> + <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> {/if} <div class="pt-10"> - <div class="w-[243px] mx-auto mb-10"> - <a href="/"> - <Icon icon="logo" /> - </a> - </div> + <div class="w-[243px] mx-auto mb-10"> + <a href="/"> + <Icon icon="logo" /> + </a> + </div> - <div class="flex justify-center items-center"> - <div class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]"> - <h1 class="text-2xl font-bold text-center">{$t('login.' + pageID)}</h1> + <div class="flex justify-center items-center"> + <div + class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]" + > + <h1 class="text-2xl font-bold text-center">{$t("login." + pageID)}</h1> - {#if form?.error} - <div class="text-red-600 text-center" in:fly> - {form.error} - </div> - {/if} + {#if form?.error} + <div class="text-red-600 text-center" in:fly> + {form.error} + </div> + {/if} - <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> - <input - type="hidden" - name="loginRedirect" - value={$loginRedirect || $page.url.searchParams.get('redirect')} - /> - <input type="hidden" name="token" value={token} /> + <form + class="space-y-5" + on:submit|preventDefault={handleSubmit} + method="POST" + > + <input + type="hidden" + name="loginRedirect" + value={$loginRedirect || $page.url.searchParams.get("redirect")} + /> + <input type="hidden" name="token" value={token} /> - <div> - <label for="username" class="font-semibold">{$t('login.username')}</label> - <input - name="username" - type="text" - required - class="bg-primary" - bind:value={username} - use:focus - autocapitalize="none" - /> - </div> + <div> + <label for="username" class="font-semibold" + >{$t("login.username")}</label + > + <input + name="username" + type="text" + required + class="bg-primary" + bind:value={username} + use:focus + autocapitalize="none" + /> + </div> - <div class="relative"> - <label for="password" class="block font-semibold">{$t('login.password')}</label> - {#if revealPassword} - <input - name="password" - type="text" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {:else} - <input - name="password" - type="password" - required - class="bg-primary" - bind:value={$password} - autocapitalize="none" - /> - {/if} - <button - type="button" - on:click={() => (revealPassword = !revealPassword)} - class="absolute right-5 top-10" - > - <Icon icon={revealPassword ? 'eye' : 'eye-off'} /> - </button> - </div> + <div class="relative"> + <label for="password" class="block font-semibold" + >{$t("login.password")}</label + > + {#if revealPassword} + <input + name="password" + type="text" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> + {:else} + <input + name="password" + type="password" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> + {/if} + <button + type="button" + on:click={() => (revealPassword = !revealPassword)} + class="absolute right-5 top-10" + > + <Icon icon={revealPassword ? "eye" : "eye-off"} /> + </button> + </div> - {#if pageID === 'register'} - <p class="text-secondary text-sm"> - {$t('login.passwordRecommendation')} - </p> - {:else} - <!-- TODO --> - <!-- <div class="flex justify-end items-center"> --> - <!-- <a href="/forgot" class="underline underline-offset-4 text-black text-sm" --> - <!-- >{$t('login.forgotUserOrPassword')}</a --> - <!-- > --> - <!-- </div> --> - {/if} + {#if pageID === "register"} + <p class="text-secondary text-sm"> + {$t("login.passwordRecommendation")} + </p> + {:else} + <!-- TODO --> + <!-- <div class="flex justify-end items-center"> --> + <!-- <a href="/forgot" class="underline underline-offset-4 text-black text-sm" --> + <!-- >{$t('login.forgotUserOrPassword')}</a --> + <!-- > --> + <!-- </div> --> + {/if} - <button - type="submit" - class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" - disabled={loading} - bind:this={btn} - > - {#if loading} - <Spinner /> - {:else} - {$t('login.' + pageID)} - {/if} - </button> - </form> + <button + type="submit" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + disabled={loading} + bind:this={btn} + > + {#if loading} + <Spinner /> + {:else} + {$t("login." + pageID)} + {/if} + </button> + </form> - <p class="text-secondary text-center font-medium"> - {pageID === 'register' ? $t('login.haveAccount') : $t('login.noAccount')} - <a - href={pageID === 'register' ? '/login' : '/register'} - class="block md:inline text-black underline underline-offset-4 hover:opacity-80" - > - {pageID === 'register' ? $t('login.signIn') : $t('login.register')} - </a> - </p> - </div> - </div> + <p class="text-secondary text-center font-medium"> + {pageID === "register" + ? $t("login.haveAccount") + : $t("login.noAccount")} + <a + href={pageID === "register" ? "/login" : "/register"} + class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + > + {pageID === "register" ? $t("login.signIn") : $t("login.register")} + </a> + </p> + </div> + </div> </div> diff --git a/src/components/Request.svelte b/src/components/Request.svelte index 44f8516d..f3331954 100644 --- a/src/components/Request.svelte +++ b/src/components/Request.svelte @@ -1,34 +1,36 @@ <script> - import { t } from '$lib/translations'; - import { fly } from 'svelte/transition'; - import { Avatar, Icon } from '$comp'; - import { request, requestRedirect } from '$lib/store'; - import { page } from '$app/stores'; + import { t } from "$lib/translations"; + import { fly } from "svelte/transition"; + import { Avatar, Icon } from "$comp"; + import { request, requestRedirect } from "$lib/store"; + import { page } from "$app/stores"; - export let user; + export let user; - $requestRedirect = $page.url.pathname; + $requestRedirect = $page.url.pathname; </script> {#if $request} - <div class="fixed bottom-0 border-t w-full p-4 bg-white z-50" in:fly> - <div class="flex flex-wrap md:flex-nowrap max-w-xl mx-auto gap-2"> - <div class="my-auto mx-auto"> - <div class="flex"> - <Avatar user={$request.requester} size={12} /> - <h1 class="my-auto"> - <b>{$request.requester.username}</b> - {$t('payments.readyToPay')} - </h1> - </div> - </div> - <div class="mx-auto my-auto flex gap-2"> - <a href={`/${user.username}/receive/${$request.id}`}> - <button class="rounded-full border py-2 px-4 font-bold hover:opacity-80 w-32"> - {$t('payments.invoice')} - </button> - </a> - </div> - </div> - </div> + <div class="fixed bottom-0 border-t w-full p-4 bg-white z-50" in:fly> + <div class="flex flex-wrap md:flex-nowrap max-w-xl mx-auto gap-2"> + <div class="my-auto mx-auto"> + <div class="flex"> + <Avatar user={$request.requester} size={12} /> + <h1 class="my-auto"> + <b>{$request.requester.username}</b> + {$t("payments.readyToPay")} + </h1> + </div> + </div> + <div class="mx-auto my-auto flex gap-2"> + <a href={`/${user.username}/receive/${$request.id}`}> + <button + class="rounded-full border py-2 px-4 font-bold hover:opacity-80 w-32" + > + {$t("payments.invoice")} + </button> + </a> + </div> + </div> + </div> {/if} diff --git a/src/components/Slider.svelte b/src/components/Slider.svelte index 3c94d127..b82b6bf9 100644 --- a/src/components/Slider.svelte +++ b/src/components/Slider.svelte @@ -1,56 +1,56 @@ <script> - export let value, - handle, - min = 0, - max = 100; + export let value, + handle, + min = 0, + max = 100; </script> <input - id="slider" - type="range" - {min} - {max} - bind:value - class="px-0 py-0 my-5" - style="--bgPercent: {((value - min) * 100) / (max - min)}%;" - on:input={handle} + id="slider" + type="range" + {min} + {max} + bind:value + class="px-0 py-0 my-5" + style="--bgPercent: {((value - min) * 100) / (max - min)}%;" + on:input={handle} /> <style> - #slider { - -webkit-appearance: none; - width: 100%; - height: 6px; - border-radius: 5px; - background: linear-gradient( - to right, - black 0%, - black var(--bgPercent), - #f5f7fa var(--bgPercent), - #f5f7fa 100% - ); - outline: none; - } + #slider { + -webkit-appearance: none; + width: 100%; + height: 6px; + border-radius: 5px; + background: linear-gradient( + to right, + black 0%, + black var(--bgPercent), + #f5f7fa var(--bgPercent), + #f5f7fa 100% + ); + outline: none; + } - #slider:active { - background-color: black; - } + #slider:active { + background-color: black; + } - #slider::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 30px; - height: 30px; - border-radius: 50%; - background: black; - cursor: pointer; - } + #slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 30px; + height: 30px; + border-radius: 50%; + background: black; + cursor: pointer; + } - #slider::-moz-range-thumb { - width: 30px; - height: 30px; - border-radius: 50%; - background: black; - cursor: pointer; - } + #slider::-moz-range-thumb { + width: 30px; + height: 30px; + border-radius: 50%; + background: black; + cursor: pointer; + } </style> diff --git a/src/components/Spinner.svelte b/src/components/Spinner.svelte index eccf98ce..e9c3348f 100644 --- a/src/components/Spinner.svelte +++ b/src/components/Spinner.svelte @@ -1,13 +1,20 @@ <svg - class="mx-auto h-6 w-6 animate-spin text-white" - xmlns="http://www.w3.org/2000/svg" - fill="none" - viewBox="0 0 24 24" + class="mx-auto h-6 w-6 animate-spin text-white" + xmlns="http://www.w3.org/2000/svg" + fill="none" + viewBox="0 0 24 24" > - <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" /> - <path - class="opacity-75" - fill="currentColor" - d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" - /> + <circle + class="opacity-25" + cx="12" + cy="12" + r="10" + stroke="currentColor" + stroke-width="4" + /> + <path + class="opacity-75" + fill="currentColor" + d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" + /> </svg> diff --git a/src/components/Toggle.svelte b/src/components/Toggle.svelte index 3516e48b..1e4cf4c4 100644 --- a/src/components/Toggle.svelte +++ b/src/components/Toggle.svelte @@ -1,11 +1,17 @@ <script> - export let id; - export let value; + export let id; + export let value; </script> <label for={id} class="inline-flex relative items-center mr-5 cursor-pointer"> - <input type="checkbox" bind:checked={value} {id} name={id} class="sr-only peer" /> - <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-gray-600" - /> + <input + type="checkbox" + bind:checked={value} + {id} + name={id} + class="sr-only peer" + /> + <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-gray-600" + /> </label> diff --git a/src/components/index.js b/src/components/index.js index 53838581..661ad4fa 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,40 +1,40 @@ -export { default as Popup } from './Popup.svelte'; -export { default as Code } from './Code.svelte'; -export { default as Slider } from './Slider.svelte'; -export { default as Pinpad } from './Pinpad.svelte'; -export { default as Balance } from './Balance.svelte'; -export { default as Lnurlp } from './Lnurlp.svelte'; -export { default as Lnurlw } from './Lnurlw.svelte'; -export { default as Event } from './Event.svelte'; -export { default as Password } from './Password.svelte'; -export { default as Feed } from './Feed.svelte'; -export { default as Invoice } from './Invoice.svelte'; -export { default as Request } from './Request.svelte'; -export { default as Pin } from './Pin.svelte'; -export { default as Card } from './Card.svelte'; -export { default as Lock } from './Lock.svelte'; -export { default as Calendar } from './Calendar.svelte'; -export { default as Avatar } from './Avatar.svelte'; -export { default as Left } from './Left.svelte'; -export { default as Numpad } from './Numpad.svelte'; -export { default as Spinner } from './Spinner.svelte'; -export { default as Check } from './Check.svelte'; -export { default as Heart } from './Heart.svelte'; -export { default as Quote } from './Quote.svelte'; -export { default as LandingHeader } from './LandingHeader.svelte'; -export { default as LandingHero } from './LandingHero.svelte'; -export { default as LandingInfoCard } from './LandingInfoCard.svelte'; -export { default as HowItWorksCard } from './HowItWorksCard.svelte'; -export { default as FaqCard } from './FaqCard.svelte'; -export { default as Icon } from './Icon.svelte'; -export { default as Image } from './Image.svelte'; -export { default as RegisterOrLogin } from './RegisterOrLogin.svelte'; -export { default as AppHeader } from './AppHeader.svelte'; -export { default as LocaleSelector } from './LocaleSelector.svelte'; -export { default as LoadingSplash } from './LoadingSplash.svelte'; -export { default as PageNotFound } from './404.svelte'; -export { default as About } from './About.svelte'; -export { default as Footer } from './Footer.svelte'; -export { default as Toggle } from './Toggle.svelte'; -export { default as LocationsMap } from './LocationsMap.svelte'; -export { default as Qr } from './Qr.svelte'; +export { default as Popup } from "./Popup.svelte"; +export { default as Code } from "./Code.svelte"; +export { default as Slider } from "./Slider.svelte"; +export { default as Pinpad } from "./Pinpad.svelte"; +export { default as Balance } from "./Balance.svelte"; +export { default as Lnurlp } from "./Lnurlp.svelte"; +export { default as Lnurlw } from "./Lnurlw.svelte"; +export { default as Event } from "./Event.svelte"; +export { default as Password } from "./Password.svelte"; +export { default as Feed } from "./Feed.svelte"; +export { default as Invoice } from "./Invoice.svelte"; +export { default as Request } from "./Request.svelte"; +export { default as Pin } from "./Pin.svelte"; +export { default as Card } from "./Card.svelte"; +export { default as Lock } from "./Lock.svelte"; +export { default as Calendar } from "./Calendar.svelte"; +export { default as Avatar } from "./Avatar.svelte"; +export { default as Left } from "./Left.svelte"; +export { default as Numpad } from "./Numpad.svelte"; +export { default as Spinner } from "./Spinner.svelte"; +export { default as Check } from "./Check.svelte"; +export { default as Heart } from "./Heart.svelte"; +export { default as Quote } from "./Quote.svelte"; +export { default as LandingHeader } from "./LandingHeader.svelte"; +export { default as LandingHero } from "./LandingHero.svelte"; +export { default as LandingInfoCard } from "./LandingInfoCard.svelte"; +export { default as HowItWorksCard } from "./HowItWorksCard.svelte"; +export { default as FaqCard } from "./FaqCard.svelte"; +export { default as Icon } from "./Icon.svelte"; +export { default as Image } from "./Image.svelte"; +export { default as RegisterOrLogin } from "./RegisterOrLogin.svelte"; +export { default as AppHeader } from "./AppHeader.svelte"; +export { default as LocaleSelector } from "./LocaleSelector.svelte"; +export { default as LoadingSplash } from "./LoadingSplash.svelte"; +export { default as PageNotFound } from "./404.svelte"; +export { default as About } from "./About.svelte"; +export { default as Footer } from "./Footer.svelte"; +export { default as Toggle } from "./Toggle.svelte"; +export { default as LocationsMap } from "./LocationsMap.svelte"; +export { default as Qr } from "./Qr.svelte"; |
