diff options
| author | Adam Soltys <[email protected]> | 2024-09-04 18:59:30 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2024-09-04 19:32:52 -0700 |
| commit | e2996ef8d1d3628731e340481d01a5ef07e2abd1 (patch) | |
| tree | f5c171f23afeb63166db73f3cf8db30515ad54fa /src/components | |
| parent | accddd02f0b77a697edfee1d3f9beaeecbad9458 (diff) | |
| download | coinos-ui-e2996ef8d1d3628731e340481d01a5ef07e2abd1.tar.gz coinos-ui-e2996ef8d1d3628731e340481d01a5ef07e2abd1.zip | |
wip
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/About.svelte | 5 | ||||
| -rw-r--r-- | src/components/Account.svelte | 53 | ||||
| -rw-r--r-- | src/components/Balance.svelte | 6 | ||||
| -rw-r--r-- | src/components/Items.svelte | 209 |
4 files changed, 268 insertions, 5 deletions
diff --git a/src/components/About.svelte b/src/components/About.svelte index 1e60db72..01ff4c7c 100644 --- a/src/components/About.svelte +++ b/src/components/About.svelte @@ -91,14 +91,15 @@ {@html $t("about.locations.description")} </p> <!-- <LocationsMap {locations} /> --> + <a href="/map"> <div class="relative"> <img src="/map.png" class="mx-auto" /> <button - class="bg-black text-white border rounded-full px-6 py-2 font-bold hover:opacity-80 absolute left-1/2 top-1/2 text-2xl" + class="bg-black text-white border border-4 rounded-full px-6 py-2 font-bold hover:bg-secondary absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 text-2xl" > - View map + {$t("about.locations.viewMap")} </button> </div> </a> diff --git a/src/components/Account.svelte b/src/components/Account.svelte new file mode 100644 index 00000000..5286c4d3 --- /dev/null +++ b/src/components/Account.svelte @@ -0,0 +1,53 @@ +<script> + import Icon from "$comp/Icon.svelte"; + import Balance from "$comp/Balance.svelte"; + import { t } from "$lib/translations"; + + export let user, rate, account; + let { balance, setup, type } = account; +</script> + +<div class="border rounded-xl shadow p-4 space-y-5"> + <div class="flex justify-center lg:justify-start"> + <Balance {balance} {user} {rate} /> + <div class="ml-auto text-secondary">{type}</div> + </div> + + <div class="flex flex-wrap gap-3 justify-center w-full text-xl"> + {#if setup} + <a href={`/send`} class="contents grow"> + <button + type="button" + class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-primary grow" + > + <div class="mx-auto flex gap-2"> + <Icon icon="send" style="w-8" /> + <div class="my-auto">{$t("user.dashboard.send")}</div> + </div> + </button> + </a> + + <a href={`/${user.username}/receive`} class="contents"> + <button + class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-primary grow" + > + <div class="mx-auto flex gap-2"> + <Icon icon="receive" style="w-8" /> + <div class="my-auto">{$t("user.dashboard.receive")}</div> + </div> + </button> + </a> + {:else} + <a href={`/${user.username}/account/setup`} class="contents"> + <button + class="rounded-2xl border py-5 px-6 font-bold hover:opacity-80 flex bg-primary grow" + > + <div class="mx-auto flex gap-2"> + <Icon icon="settings" style="w-8" /> + <div class="my-auto">{$t("user.dashboard.setup")}</div> + </div> + </button> + </a> + {/if} + </div> +</div> diff --git a/src/components/Balance.svelte b/src/components/Balance.svelte index 4d5ac6bd..51c56555 100644 --- a/src/components/Balance.svelte +++ b/src/components/Balance.svelte @@ -6,7 +6,7 @@ import { t } from "$lib/translations"; let show; - export let user, rate; + export let user, rate, balance; </script> {#if show && user.haspin && $pin?.length !== 6} @@ -27,12 +27,12 @@ {#if isNaN(rate)} <div class="text-gray-200">—</div> {:else} - {f((user.balance * rate) / sats, user.currency)} + {f((balance * rate) / sats, user.currency)} {/if} </div> <div class="text-secondary text-2xl"> - ⚡️{s(user.balance)} + ⚡️{s(balance)} </div> {/if} </div> diff --git a/src/components/Items.svelte b/src/components/Items.svelte new file mode 100644 index 00000000..f449215c --- /dev/null +++ b/src/components/Items.svelte @@ -0,0 +1,209 @@ +<script> + import { btc, f, sat, post } from "$lib/utils"; + import { browser } from "$app/environment"; + import { goto, invalidate } from "$app/navigation"; + import { fade } from "svelte/transition"; + import { cubicIn } from "svelte/easing"; + import { flip } from "svelte/animate"; + import { + dndzone, + SHADOW_ITEM_MARKER_PROPERTY_NAME, + SOURCES, + TRIGGERS, + } from "svelte-dnd-action"; + import DeleteItem from "$comp/DeleteItem.svelte"; + import Icon from "$comp/Icon.svelte"; + + export let subject, user, items, total, rate, currency; + + let flipDurationMs = 200; + let dropTargetStyle = {}; + + let dragDisabled = + subject?.id !== user?.id || (browser && window.innerWidth < 768); + + let deleting; + let del = (item) => { + deleting = item; + }; + + function handleConsider(e) { + const { + items: newItems, + info: { source, trigger }, + } = e.detail; + items = newItems; + if (source === SOURCES.KEYBOARD && trigger === TRIGGERS.DRAG_STOPPED) + reset(); + } + + async function handleFinalize(e) { + const { + items: newItems, + info: { source }, + } = e.detail; + items = newItems; + if (source === SOURCES.POINTER) reset(); + + if (subject?.id === user?.id) { + await post("/api/items/sort", { items }); + invalidate("app:items"); + } + } + + function startDrag(e) { + e.preventDefault(); + dragDisabled = false; + } + + function handleKeyDown(e) { + if ((e.key === "Enter" || e.key === " ") && dragDisabled) + dragDisabled = false; + } + + $: if (total > 0 && browser) { + let payButton = document.querySelector("#payButton"); + if (payButton) payButton.addEventListener("click", checkout); + } + + let checkout = async () => { + let invoice = { + type: "lightning", + amount: btc(total, rate), + currency, + items: items.filter((i) => i.quantity > 0), + prompt: subject.prompt, + memoPrompt: subject.memoPrompt, + rate, + }; + + let { id } = await post(`/${subject.username}/invoice`, { + invoice, + user: { username: subject.username }, + }); + + if (invoice.memoPrompt) { + return goto(`/${subject.username}/invoice/${id}/memo`); + } + goto(`/${subject.username}/invoice/${id}`); + }; + + let reset = () => + (dragDisabled = + user?.username !== subject?.username || window.innerWidth < 768); +</script> + +<svelte:window on:resize={reset} /> + +{#if deleting} + <DeleteItem bind:item={deleting} /> +{/if} + +{#if items.length} + <h2 class="text-2xl font-bold">Select items</h2> +{/if} +<div + class="grid sm:grid-cols-2 gap-4 pb-20" + use:dndzone={{ items, flipDurationMs, dropTargetStyle, dragDisabled }} + on:consider={handleConsider} + on:finalize={handleFinalize} +> + {#each items as i (i.id)} + <button + type="button" + class="w-full text-center cursor-pointer hover:opacity-80 mb-auto" + on:click={() => i.quantity++} + > + <div class="relative w-full h-64 overflow-hidden rounded-xl"> + {#if i[SHADOW_ITEM_MARKER_PROPERTY_NAME]} + <div + in:fade={{ duration: 200, easing: cubicIn }} + class="custom-shadow-item" + /> + {:else if i.image} + <img + src={`/api/public/${i.image}.webp`} + alt={i.name} + class="mx-auto object-cover h-full w-full" + /> + {:else} + <div + class="bg-gradient-to-r from-primary to-gradient mb-4 cursor-pointer hover:opacity-80 w-full h-full" + alt="Banner" + /> + {/if} + {#if user?.username === subject.username} + <div class="flex gap-2 justify-center absolute top-2 right-2"> + <button type="button" on:click|stopPropagation={() => {}}> + <a href={`/${user.username}/items/${i.id}`}> + <button + class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" + > + <Icon icon="edit" style="w-8 mx-auto invert" /> + </button> + </a> + </button> + <button + class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" + on:click|stopPropagation={() => del(i)} + > + <Icon icon="trash" style="w-8 mx-auto invert" /> + </button> + <button + type="button" + on:click|stopPropagation={() => {}} + class="sm:hidden" + on:mousedown={startDrag} + on:touchstart={startDrag} + on:keydown={handleKeyDown} + > + <a href={`/${user.username}/items/${i.id}`}> + <button + class="bg-black rounded-full w-12 h-12 bg-opacity-40 hover:bg-opacity-100" + > + <Icon icon="move" style="w-8 mx-auto invert" /> + </button> + </a> + </button> + </div> + {/if} + </div> + <div class="bg-white rounded-xl py-2"> + <div class="flex text-left gap-2"> + <div class="overflow-hidden space-y-1"> + <div class="text-2xl break-words">{i.name}</div> + <div class="flex gap-2"> + <div class="font-semibold text-lg"> + {f(i.price, currency)} + </div> + <div class="text-secondary my-auto"> + {sat(btc(i.price, rate))} + </div> + </div> + </div> + <div class="flex gap-1 ml-auto mb-auto justify-around tabular-nums"> + {#if i.quantity} + <button + type="button" + on:click|stopPropagation={() => i.quantity > 0 && i.quantity--} + > + <Icon icon="minus" style="w-10 min-w-10" /> + </button> + {/if} + <div class="text-2xl my-auto text-center"> + {#if i.quantity}{i.quantity}{:else}—{/if} + </div> + {#if i.quantity} + <button + type="button" + on:click|stopPropagation={() => i.quantity++} + > + <Icon icon="plus" style="w-10 min-w-10" /> + </button> + {/if} + </div> + </div> + </div> + </button> + {/each} +</div> |
