aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2023-12-01 20:04:13 -0800
committerAdam Soltys <[email protected]>2023-12-01 20:04:13 -0800
commit216a600224fde22ce76b367557a02094ec693886 (patch)
treed1189bbaa39db204633523132a7d4767b952717d /src/components
parent7d9bc1f54dfd04172e8d6d43ebc2efd6f407e833 (diff)
downloadcoinos-ui-216a600224fde22ce76b367557a02094ec693886.tar.gz
coinos-ui-216a600224fde22ce76b367557a02094ec693886.zip
prettier
Diffstat (limited to 'src/components')
-rw-r--r--src/components/404.svelte20
-rw-r--r--src/components/About.svelte131
-rw-r--r--src/components/AppHeader.svelte276
-rw-r--r--src/components/Avatar.svelte44
-rw-r--r--src/components/Balance.svelte48
-rw-r--r--src/components/Calendar.svelte22
-rw-r--r--src/components/Card.svelte22
-rw-r--r--src/components/Check.svelte18
-rw-r--r--src/components/Code.svelte42
-rw-r--r--src/components/Event.svelte147
-rw-r--r--src/components/FaqCard.svelte18
-rw-r--r--src/components/Feed.svelte124
-rw-r--r--src/components/Footer.svelte121
-rw-r--r--src/components/Heart.svelte26
-rw-r--r--src/components/HowItWorksCard.svelte18
-rw-r--r--src/components/Icon.svelte4
-rw-r--r--src/components/Image.svelte4
-rw-r--r--src/components/Invoice.svelte61
-rw-r--r--src/components/LandingHeader.svelte230
-rw-r--r--src/components/LandingHero.svelte63
-rw-r--r--src/components/LandingInfoCard.svelte46
-rw-r--r--src/components/Left.svelte26
-rw-r--r--src/components/Lnurlp.svelte96
-rw-r--r--src/components/Lnurlw.svelte95
-rw-r--r--src/components/LoadingSplash.svelte4
-rw-r--r--src/components/LocaleSelector.svelte20
-rw-r--r--src/components/LocationsMap.svelte454
-rw-r--r--src/components/Lock.svelte22
-rw-r--r--src/components/Numpad.svelte395
-rw-r--r--src/components/Password.svelte144
-rw-r--r--src/components/Pin.svelte98
-rw-r--r--src/components/Pinpad.svelte144
-rw-r--r--src/components/Popup.svelte66
-rw-r--r--src/components/Qr.svelte16
-rw-r--r--src/components/Quote.svelte18
-rw-r--r--src/components/RegisterOrLogin.svelte306
-rw-r--r--src/components/Request.svelte56
-rw-r--r--src/components/Slider.svelte90
-rw-r--r--src/components/Spinner.svelte27
-rw-r--r--src/components/Toggle.svelte18
-rw-r--r--src/components/index.js80
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">&mdash;</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">&mdash;</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">&nbsp;{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">&nbsp;{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";