diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/AppHeader.svelte | 50 | ||||
| -rw-r--r-- | src/components/Avatar.svelte | 4 | ||||
| -rw-r--r-- | src/locales/en.json | 3 | ||||
| -rw-r--r-- | src/routes/[username]/transactions/[...page]/+page.server.js | 18 | ||||
| -rw-r--r-- | src/routes/[username]/transactions/[...page]/+page.svelte | 71 | ||||
| -rw-r--r-- | src/routes/send/[...text]/+page.svelte | 25 | ||||
| -rw-r--r-- | src/routes/send/user/[username]/[...amount]/+page.svelte | 11 |
7 files changed, 122 insertions, 60 deletions
diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 302a9c7a..fb57f27a 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -13,23 +13,14 @@ let update = (data) => ({ subject, user } = data); const menuButtons = [ - { stringID: 'nav.dashboard', icon: 'dash', goto: 'dashboard' }, - { stringID: 'nav.settings', icon: 'settings', goto: 'settings' }, - { stringID: 'nav.support', icon: 'support', goto: 'support' }, - { stringID: 'nav.signOut', icon: 'logout', goto: 'logout' } + { key: 'nav.profile', icon: 'profile', href: `/${user.username}` }, + { key: 'nav.settings', icon: 'settings', href: `/${user.username}/settings` }, + { key: 'nav.support', icon: 'support', href: `/${user.username}/support` }, + { key: 'nav.signOut', icon: 'logout', href: `/${user.username}/logout` } ]; let showMenu = false; - const handleMenuItemClick = (item) => { - if (item === 'logout') { - goto('/logout'); - } else { - showMenu = false; - goto(`/${user.username + '/' + item}`); - } - }; - $: bg = $tempProfileFiles && $tempProfileFiles.banner ? `url(${$tempProfileFiles.banner})` @@ -44,6 +35,15 @@ > <nav class="flex justify-end items-center space-x-4 p-5"> {#if user} + <a href={`/${user.username}/dashboard`}> + <button + class="bg-white p-2 rounded-full w-12 h-12 drop-shadow-xl border border-black/10 {$page + .url.pathname === `/${user.username}/dashboard` + ? 'opacity-100' + : 'opacity-70 hover:opacity-80'}" + ><Icon icon="home" style="mx-auto w-6" /> + </button> + </a> <a href={`/${user.username}/receive`}> <button class="bg-white p-2 rounded-full w-12 h-12 drop-shadow-xl border border-black/10 {$page @@ -72,20 +72,11 @@ {/if} </button> </a> - <a href={`/${user.username}`}> - <button - class="bg-white p-2 rounded-full w-12 h-12 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}` - ? 'opacity-100' - : 'opacity-70 hover:opacity-80'}" - ><Icon icon="profile" style="mx-auto" /> - </button> - </a> <div class="relative"> <OutClick on:outclick={() => (showMenu = false)}> <button class="bg-white p-2 rounded-full w-12 h-12 drop-shadow-xl border border-black/10 {$page - .url.pathname === `/${user.username}/dashboard` || + .url.pathname === `/${user.username}` || $page.url.pathname === `/${user.username}/settings` || $page.url.pathname === `/${user.username}/support` ? 'opacity-100' @@ -100,13 +91,14 @@ : 'hidden'} absolute top-14 right-0 bg-white rounded-3xl p-8 shadow-xl z" > <ul class="space-y-5 w-32"> - {#each menuButtons as button} + {#each menuButtons as { href, icon, key }} <li> - <button - class="flex justify-center items-center font-semibold text-sm hover:opacity-80" - on:click={() => handleMenuItemClick(button.goto)} - ><Icon icon={button.icon} style="mr-1" /> {$t(button.stringID)} - </button> + <a {href}> + <button + class="flex justify-center items-center font-semibold text-sm hover:opacity-80" + ><Icon {icon} style="mr-1" /> {$t(key)} + </button> + </a> </li> {/each} </ul> diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte index c7339bf5..092af740 100644 --- a/src/components/Avatar.svelte +++ b/src/components/Avatar.svelte @@ -3,11 +3,13 @@ import { Icon } from '$comp'; export let user; + export let size = 32; + $: s = size.toString(); </script> <a href={`/${user.username}`}> <div - class="rounded-full border-4 border-white overflow-hidden w-32 h-32 bg-gradient-to-r {$colorTheme} flex justify-center items-center" + class="w-{s} h-{s} rounded-full border-4 border-white overflow-hidden bg-gradient-to-r {$colorTheme} flex justify-center items-center" > {#if user?.profile} <img diff --git a/src/locales/en.json b/src/locales/en.json index b5aef47a..8e71e3a8 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -144,6 +144,7 @@ "failed": "Login failed" }, "nav": { + "profile": "Profile", "startInSeconds": "Start in Seconds", "account": "Account", "signIn": "Sign In", @@ -221,7 +222,7 @@ "send": "Send" }, "transactions": { - "header": "Transaction History", + "header": "Transactions", "AMOUNT": "AMOUNT", "TYPE": "TYPE", "TIME": "TIME", diff --git a/src/routes/[username]/transactions/[...page]/+page.server.js b/src/routes/[username]/transactions/[...page]/+page.server.js index faa8a1ab..caa2e155 100644 --- a/src/routes/[username]/transactions/[...page]/+page.server.js +++ b/src/routes/[username]/transactions/[...page]/+page.server.js @@ -3,12 +3,24 @@ import { get, auth } from '$lib/utils'; let offset = 25; export async function load({ cookies, params, request }) { - let page = parseInt(params.page || 1); - let transactions = await get('/payments', auth(cookies)); + let parts = params.page.split('/'); + + let start, end, page; + if (parts.length === 1) [page] = parts; + if (parts.length === 2) [start, page] = parts; + if (parts.length === 3) [start, end, page] = parts; + if (!parseInt(page)) page = 1; + + let url = '/payments'; + if (start && end) url += `?start=${start}&end=${end}`; + else if (start) url += `?start=${start}`; + else if (end) url += `?end=${end}`; + + let transactions = await get(url, auth(cookies)); let total = transactions.length; let pages = new Array(Math.ceil(total / offset)); let i = (page - 1) * offset; transactions = transactions.slice(i, i + offset); - return { total, transactions, page, pages }; + return { total, transactions, page, pages, start, end }; } diff --git a/src/routes/[username]/transactions/[...page]/+page.svelte b/src/routes/[username]/transactions/[...page]/+page.svelte index b957caf8..cf809445 100644 --- a/src/routes/[username]/transactions/[...page]/+page.svelte +++ b/src/routes/[username]/transactions/[...page]/+page.svelte @@ -1,23 +1,61 @@ <script> + import { Icon } from '$comp'; import { onMount } from 'svelte'; import { formatDistance, parseISO } from 'date-fns'; import { newPayment } from '$lib/store'; import { t } from '$lib/translations'; import { f, s, sats } from '$lib/utils'; import { page } from '$app/stores'; + import { differenceInDays, getUnixTime, sub } from 'date-fns'; export let data; - let { user } = data; + let { start, end, user } = data; + + let presets = [ + { title: 'Today', start: sub(new Date(), { days: 1 }), end: null }, + { title: '7 days', start: sub(new Date(), { days: 7 }), end: null }, + { title: 'Last month', start: sub(new Date(), { months: 1 }), end: null }, + { title: 'All', start: null, end: null } + ]; + + $: selection = start + ? presets.findIndex((p) => Math.abs(differenceInDays(new Date(start * 1000), p.start)) < 1) + : presets.length - 1; let p, total, transactions = [], pages = []; - $: data && ({ page: p, pages, total, transactions } = data); + $: data && ({ page: p, pages, start, end, total, transactions } = data); $: $page && ($newPayment = false); $: $newPayment && invalidate(`/users/${user.username}`); + + let csv = () => { + const keys = ['hash', 'updatedAt', 'rate', 'currency', 'amount', 'fee', 'tip']; + const csv = + keys.map((k) => `"${k}"`).join(',') + + '\n' + + transactions.map((r) => keys.map((k) => `"${r[k]}"`).join(',')).join('\n'); + + const filename = 'transactions.csv'; + let blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }); + if (navigator.msSaveBlob) { + navigator.msSaveBlob(blob, filename); + } else { + let link = document.createElement('a'); + if (link.download !== undefined) { + let url = URL.createObjectURL(blob); + link.setAttribute('href', url); + link.setAttribute('download', filename); + link.style.visibility = 'hidden'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + } + }; </script> <div class="mt-24 mb-20"> @@ -26,13 +64,32 @@ </h1> <div class="container w-full mx-auto md:text-lg px-10 lg:px-72"> - <div class="flex flex-wrap justify-end mb-8"> + <div class="flex text-md text-secondary flex-wrap mb-4"> + <div class="flex flex-wrap gap-2"> + {#each presets as { start, end, title }, i} + <a + class:active={selection === i} + href={`/${user.username}/transactions/${start ? getUnixTime(start) + '/' : ''}1`} + > + <button class="rounded-full border py-2 px-5 hover:opacity-80 mb-2"> + <div class="my-auto">{title}</div> + </button> + </a> + {/each} + </div> + <button class="ml-auto rounded-xl border py-2 px-5 hover:opacity-80 mb-2 flex" on:click={csv}> + <Icon icon="save" style="opacity-50 mr-2" /> + <div class="my-auto">Export</div> + </button> + </div> + + <div class="flex flex-wrap justify-center mb-8"> {#if pages.length > 1} {#each pages as _, i} <a class="mr-1 last:mr-0" href={`/${user.username}/transactions/${i + 1}`} - class:active={p === i + 1} + class:active={parseInt(p) === i + 1} > <div class="border py-2 rounded-full border-2 w-12 h-12 hover:opacity-80 text-center"> {i + 1} @@ -44,7 +101,7 @@ <div class="text-secondary grid grid-cols-3 mb-5"> <h2>{$t('user.transactions.AMOUNT')}</h2> - <h2 class="text-center">{$t('user.transactions.TYPE')}</h2> + <h2 class="text-center" /> <h2 class="text-right">{$t('user.transactions.TIME')}</h2> </div> @@ -85,7 +142,7 @@ </div> <style> - .active div { - @apply bg-gray-100; + .active * { + @apply bg-black text-white border-black; } </style> diff --git a/src/routes/send/[...text]/+page.svelte b/src/routes/send/[...text]/+page.svelte index fe949617..1311422e 100644 --- a/src/routes/send/[...text]/+page.svelte +++ b/src/routes/send/[...text]/+page.svelte @@ -10,8 +10,8 @@ export let form; let el; - let placeholder = 'Address, Invoice or Username'; - let text = placeholder; + let placeholder = 'Paste a bitcoin address, lightning invoice or coinos username'; + let text; let focus = () => text === placeholder && (text = ''); let keypress = (e) => e.key === 'Enter' && (e.preventDefault() || el.click()); @@ -25,7 +25,11 @@ <Icon icon="arrow-left" style="w-10" /> </button> -<form method="POST" class="container px-4 mt-20 max-w-xl mx-auto" use:enhance> +<h1 class="px-3 md:px-0 text-center text-3xl md:text-4xl font-semibold mb-8"> + Send bitcoin or lightning +</h1> + +<form method="POST" class="container px-4 max-w-xl mx-auto" use:enhance> {#if form?.error} <div class="text-red-600 text-center" in:fly> {form.error} @@ -35,17 +39,12 @@ <label for="invoice" class="font-bold mb-1 block">To</label> <input type="hidden" name="text" bind:value={text} /> - <div - class="expandable-textarea" - class:text-gray-400={text === placeholder} - role="textbox" - contenteditable - bind:textContent={text} - on:focus={focus} + <textarea + {placeholder} on:keypress={keypress} - > - {text} - </div> + class="w-full p-4 border rounded-xl h-48" + bind:value={text} + /> </div> <div class="flex justify-end"> diff --git a/src/routes/send/user/[username]/[...amount]/+page.svelte b/src/routes/send/user/[username]/[...amount]/+page.svelte index 6f4cb313..89cec12f 100644 --- a/src/routes/send/user/[username]/[...amount]/+page.svelte +++ b/src/routes/send/user/[username]/[...amount]/+page.svelte @@ -50,11 +50,10 @@ </div> {/if} -<div class="container px-4 mt-20 max-w-xl mx-auto"> +<div class="container px-4 mt-20 max-w-xl mx-auto space-y-8"> {#if amount} - <div class="text-center mb-8"> - <h1 class="text-xl md:text-2xl text-secondary mb-2">Send</h1> - <p class="text-6xl break-words mb-4"> + <div class="text-center mb-8 space-y-5"> + <p class="text-5xl break-words"> {fiat ? f(amountFiat, currency) : s(amount)} {#if !fiat} <span class="text-xl md:text-2xl text-secondary">sats</span> @@ -64,8 +63,8 @@ <h1 class="text-xl md:text-2xl text-secondary mb-2">to</h1> <div class="flex p-1 gap-2 justify-center"> - <Avatar user={recipient} /> - <p class="text-6xl break-words my-auto">{recipient.username}</p> + <Avatar user={recipient} size={'20'} /> + <p class="text-4xl break-words my-auto">{recipient.username}</p> </div> </div> {:else} |
