diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/components/Avatar.svelte | 5 | ||||
| -rw-r--r-- | src/components/Feed.svelte | 49 | ||||
| -rw-r--r-- | src/components/index.js | 1 | ||||
| -rw-r--r-- | src/lib/runners.js | 79 | ||||
| -rw-r--r-- | src/lib/utils.js | 3 | ||||
| -rw-r--r-- | src/locales/en.json | 3 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/+layout.server.js | 1 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/+page.server.js | 15 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/+page.svelte | 105 | ||||
| -rw-r--r-- | src/routes/(app)/feed/+page.svelte | 42 |
10 files changed, 124 insertions, 179 deletions
diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte index cfbec54f..7ee774bf 100644 --- a/src/components/Avatar.svelte +++ b/src/components/Avatar.svelte @@ -5,12 +5,13 @@ export let user; export let size = 32; export let disabled = false; - export let src; + export let src = undefined; $: s = size.toString(); + $: link = user ? `/${user.username}` : '/'; </script> -<a href={`/${user ? user.username : ''}`} class:pointer-events-none={disabled}> +<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" > diff --git a/src/components/Feed.svelte b/src/components/Feed.svelte new file mode 100644 index 00000000..973afa19 --- /dev/null +++ b/src/components/Feed.svelte @@ -0,0 +1,49 @@ +<script> + import { Avatar } from '$comp'; + import { browser } from '$app/environment'; + import VirtualScroll from 'svelte-virtual-scroll-list'; + import { runner } from '$lib/utils'; + export let events; + + let distance = (d) => { + let diff = Math.round(Date.now() / 1000) - d; + return diff > 3600 + ? Math.round(diff / 3600) + 'd' + : diff > 60 + ? Math.round(diff / 60) + 'm' + : diff > 2 + ? diff + 's' + : 'now'; + }; + + let w; +</script> + +<svelte:window bind:innerWidth={w} /> + +{#if browser} + <VirtualScroll data={events} key="id" let:data pageMode={true} estimateSize={200}> + <div class="flex border-b py-4 text-sm lg:text-lg text-secondary" :key={data.id}> + <a href={`/${data.pubkey}`}> + <div class="mb-auto mr-2"> + <div class="md:hidden"> + <Avatar size={12} src={`/api/public/runners/${runner(data.pubkey)}`} disabled={true} /> + </div> + <div class="hidden md:block"> + <Avatar size={20} src={`/api/public/runners/${runner(data.pubkey)}`} disabled={true} /> + </div> + </div> + </a> + + <div class="grow" style={`max-width: ${w - 100}px`}> + <div class="w-full flex pb-1 text-black"> + <div>{data.pubkey.substr(0, 6)}</div> + <div class="text-secondary"> {distance(data.seen)}</div> + </div> + <div class="break-words"> + {data.content} + </div> + </div> + </div> + </VirtualScroll> +{/if} diff --git a/src/components/index.js b/src/components/index.js index 07b169bb..90bc1e7e 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,3 +1,4 @@ +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'; diff --git a/src/lib/runners.js b/src/lib/runners.js deleted file mode 100644 index 363594d2..00000000 --- a/src/lib/runners.js +++ /dev/null @@ -1,79 +0,0 @@ -export default [ - 'Qma97iPUioF6VcpjYhFiSFHqsGkAVgTMqbQ1GVehM2pp4C.webp', - 'QmagBTQuuUk1M1NLynLNyQkYC7DsUiiFSAU1evW37SRSwx.webp', - 'QmbeKTXKLVj93h3YWj982fk1enGKQnhK8AtBYmPn4wY7dZ.webp', - 'QmbK8cqgzG5hrWaiUpUbzdgVyE794FBwtom2b7iAgiXQSH.webp', - 'QmbWXGrxDE9y651Vv9MgrogKto7u3Ybyh4WMULronJwNnr.webp', - 'QmbxFA62kwH5oXUbjvF2Gd2F5GGB3QPBzgW6RBUSw8pZzh.webp', - 'Qmc7PyW1wQFnj21A87xcuicwipCvaH8A77o9jaY9zgmana.webp', - 'QmcicA4dudWA373vnchnSVGe38UiyB6dqxqoEsyX3KrJzQ.webp', - 'QmcSy2SDhKYkNLonwEKVab3bR24AHAbMwDwQ16e4trmjpX.webp', - 'Qmd8afMsK5FZsDmuARphzCP3mpDa57f8FzMF9bHPSywwXB.webp', - 'QmdjPgJyjj3Pm1LTixswHUMFfgmG3uFxvjNC36qWVENmZ5.webp', - 'Qme1VjBDnswkW8kk88aoFxaRTNRLRdbkz7YqWKWZby1jE3.webp', - 'Qme9dxEfyn8pzt1g6PZZphUoFWnYjg2LMfF5drb2K2iLNF.webp', - 'QmeddNU7LGkfmzXzvepChaVxRJvZGAG8vvthLChDC2tEYj.webp', - 'QmedXmb6nLU7pYbyRknyZ1SvdZwKPjjpm2zVRtYpy7otXx.webp', - 'QmefpdjwVZUJvLzGKxKoygtmXN6GHr8nr4o4jNpzdwCXEu.webp', - 'QmehU24Epg96y4ZUabrW6qj4eLQH9QBV6k4c9aRM8xy2AT.webp', - 'QmeioKyTRUYkQqJUuxrwffmv16WwpA1cVDVFmsZzY3NNaW.webp', - 'QmeMawqD5VBcpxodUbhFFSNRxPEGoFKS7jhTbFCayNvNBn.webp', - 'QmeMvib26HHuZeib7Wp4juU5WioyDRTuSu4WDCmjkTXQx1.webp', - 'QmeW63YBirM8snAhRoDhWHQEv6QKNRFg66wZpphb9bPXrH.webp', - 'QmfBT4ZfpyjZGKfQfpEeHXCio8AemckucF8maKWvgNmeJt.webp', - 'QmfFk5p2m67Nnw4dy5bt3DK3XEYxscACJDAEAFi1CdvSmk.webp', - 'QmfMsRyPxGrWiQhyS3UQqUVbMZWn5VASkwtRYypqMLX9te.webp', - 'QmfNKusvYqWVyG5Zz3N51ujU9qhYH1F6sbDxz55pYfj3Xr.webp', - 'QmfXzwHuSG1VscFDArZumVALCAisdHqHuetxwY51Pda1NU.webp', - 'QmNatn6kdBZtNbSXcP6v4B9dgjqiubTbWRKYBSM1zQGgyS.webp', - 'QmNWrLehxdsRozLCgcmuGMFPn5Ns1VqQmJuGnGUujaQtmd.webp', - 'QmNxyEoaFMoAWtWbFMF3MyWtUDWMAYxGRGYzyy5LtyP9K3.webp', - 'QmPfgfagqM9R9tWWYBSEhaZr1NP1XZYtBXkUYorCMBZwjK.webp', - 'QmPkLz8DG83AN9jtSq5ECxpkZnhsugW2wmDMBDUbj3Y739.webp', - 'QmPNZ6aVvENjB9g3ujaqxTMjQ9NhYZpZk9A6VgC5YLJDHA.webp', - 'QmQ37PgXP5rNU1udKjiy4VmzjwjgBgfNzwSVENdCZvvjuF.webp', - 'QmQfEcHQXxpEw5NVvsxC69MHPqQ77cNgW9Gk4KyYbD6qAB.webp', - 'QmQGSZV3nJudGuEZTGAtoj2xaQ9shButYNG9YJRN9hydCT.webp', - 'QmQGwJXCtNjc84uMLtyNjoGjqu1mtbiMcydVuSMWCrJYg3.webp', - 'QmQNBhQuvor1RigscMF5nUk9LHz4pGJwXpFE3WAGQFi31H.webp', - 'QmQutjFQni2fwVBLJWJZJxdjiy6HRGaJY878ZZYBVP2gwD.webp', - 'QmQwCerH77D2xmvKKRtAQkxwJ4rGFqKXPd5q8QqY6DyxWw.webp', - 'QmRdcJmvem9gdYpNcsXhsZpZ5CShrce22QCDVV7bP3mAWa.webp', - 'QmRgz9FE5awn4B59tgNfPeWPNMBchAChxNQxxGSXphjzUr.webp', - 'QmRLFwrM89hW9UYbwsFMAohcAruMZQhzTHrgNQr6GGFdwa.webp', - 'QmRsNUKTzAkamrs336zoWGRyR1vK9tA237MLPMV7uN8yPK.webp', - 'QmRXxrfQ4PjDCpR5ABpMVpv9HrkoaCAqTewMbz14tCQhSD.webp', - 'QmSg5eyj1hYRTf9Y5XP9iErHeN55RkvgNF9NdKkiv1qSaw.webp', - 'QmSkRtY1FoQCgHhc5o6QNwufBHCv5sS9ZTHcQ2U3qbj5RX.webp', - 'QmSroPbEoFMGWrfqe55jpgHoiuDaiGj4FLqrxi7cjZz2nZ.webp', - 'QmSYJj61VGBSaNGGen7nmwdmxtAEHj3nAev5hzy7sKQvxR.webp', - 'QmTByAPptSDbHZsJRd52RgCcxhpXFdq4ppFTnSZ7U6ytpi.webp', - 'QmUCNzXjPpR4ZCTJTvMpphYktEsvQ8GLQQiTKd1s7QGiGY.webp', - 'QmUmbAD837VXSaswskCcgdqQ4UuMPC35bQHJCr7GovPmaZ.webp', - 'QmUnTpgH1WmzHYhtMtsLggPrNKkvwDfWaGzQzfpghveVCY.webp', - 'QmUNZkQPLUwz8cvmUtdC5PTmas7bxhGctB6HucPeC9MjSU.webp', - 'QmUqgre9anYKfmdSwH5N7S6ueoci8Q58TcfPaLGpumLKs1.webp', - 'QmV3w7aXh6NGiB8YH3Jbo5cNy8o6t8u2KRgaSUVds2jhu1.webp', - 'QmVMf9MY7t29gmuVpusuHX5WGQSm4xyZ7sb3Cc1nJq3WTr.webp', - 'QmVpVAijTi6NaVfn2rmYoQ6idu82UB8sXGADpyfHrNvSZu.webp', - 'QmW1UPkwVgU8QCWiEPyoJoBqzTm1jRPuC8LyW158x4pnAA.webp', - 'QmW8z18VErUt8LvT6r28piJzKvZTbiAHD9GG5nTLd4KYCE.webp', - 'QmWaJhEtvFh114pBxfEkX9giS7usg49tK4dsWgHvwPeVzu.webp', - 'QmWiJAyFRrTSwVAMB3hhD1cKZGz8HTt844u3ibcRqQPTje.webp', - 'QmWMFkLBYREzfcbuznpYXtgR6LEyxFDgNsnHRn4bELszem.webp', - 'QmWU9QJU8p6hUzanPakPF5QaZtSf5CF5vCHHkwNyYJNGAN.webp', - 'QmWYgYnUYw6pYzaQ9j8DYsTydYtJNZ3L6FRZQzW4bWnP7E.webp', - 'QmXBm6r15Lj1g8eABA8CqytV829kxANtYj3mqvWPmx5jSi.webp', - 'QmXCAUh3MpDFZ3u3MnWcosBzKv8vfaxMsKvqm7AGbdwdei.webp', - 'QmXip2hTHZcuxAyg82gQsiSddZmHXY7d557RC1UURMtrer.webp', - 'QmXVrUBK4YDGfqpK9fED2Tk6ghzjbjsDo7Ss77QrntoDFq.webp', - 'QmYp51YmcALY2v31pa55sviwawkopQ3VC1kbA57LKsjE8w.webp', - 'QmYzPXHdRqALFic8hBEc8NcdB6UJM5Xw3qMuCvWFAMJdb1.webp', - 'QmZgPvTiuiVAymjNpfVNVFkbc7z6r2Nk2sdEtFQJ79wH3o.webp', - 'QmZgQideTeAq8tm58Yg5dSy1HMDg9r5ULv82GzyNYWackh.webp', - 'QmZHgKSucFxJjhsVVYh6iqAKdFw66KPFiTHsSsbXWL4cJW.webp', - 'QmZPe1aMGyJK76T5hqknVv9N8JyGkjsgDBbTKjdKrNTKrS.webp', - 'QmZrUF8DcagN8AGawoz8vGKcBxKdfaeaFgsd7A52zRzuH5.webp', - 'QmZuwrCX6xqibVY5WDRAjcx3tDHsRX1KdWZuncHjrH4hkS.webp', - 'QmZXNZpEXTMwkpgx5kJ8VQhFeV3ksn6JsiZhX3sACVD3rX.webp' -]; diff --git a/src/lib/utils.js b/src/lib/utils.js index bd428160..02c318b6 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -8,6 +8,9 @@ export function scroll(section) { } const base = browser ? '' : PUBLIC_COINOS_URL; +export const runner = (k) => { + return Math.round((parseInt(k[0], 16) - 1) / 15 * 7) + 1 + '.webp'; +}; export const g = (url, fetch, headers) => fetch(base + url, { headers }) diff --git a/src/locales/en.json b/src/locales/en.json index 33b7c5cf..d455f107 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -277,6 +277,7 @@ "from": "from", "redeem": "Redeem", "redeemed": "Redeemed", - "redeemedBy": "Redeemed by" + "redeemedBy": "Redeemed by", + "sendMessage": "Message" } } diff --git a/src/routes/(app)/[username]/+layout.server.js b/src/routes/(app)/[username]/+layout.server.js index a352fe45..035536aa 100644 --- a/src/routes/(app)/[username]/+layout.server.js +++ b/src/routes/(app)/[username]/+layout.server.js @@ -5,6 +5,7 @@ export let load = async ({ params: { username } }) => { try { return { subject: await get(`/users/${username}`) }; } catch (e) { + if (username.length === 64) return { subject: { username }} throw error(500, 'Unable to retrieve user account data'); } }; diff --git a/src/routes/(app)/[username]/+page.server.js b/src/routes/(app)/[username]/+page.server.js index 1d07a1db..25835d8a 100644 --- a/src/routes/(app)/[username]/+page.server.js +++ b/src/routes/(app)/[username]/+page.server.js @@ -1,7 +1,18 @@ +import { get } from '$lib/utils'; import Qr from 'qrcode-base64'; export async function load({ params, url }) { - let text = `${encodeURI(params.username)}@${url.hostname}`; + let { username } = params; + let text = `${encodeURI(username)}@${url.hostname}`; let src = Qr.drawImg(text, { size: 300 }); - return { src, text }; + let events = []; + console.log("EV", events) + + try { + events = await get(`/${username}/events`); + } catch (e) { + console.log(e); + } + + return { events, src, text }; } diff --git a/src/routes/(app)/[username]/+page.svelte b/src/routes/(app)/[username]/+page.svelte index 42e3dd3a..e8cd2d10 100644 --- a/src/routes/(app)/[username]/+page.svelte +++ b/src/routes/(app)/[username]/+page.svelte @@ -1,83 +1,78 @@ <script> - import { browser } from '$app/environment'; - import { onMount } from 'svelte'; - import { Icon, PageNotFound } from '$comp'; - import { copy } from '$lib/utils'; + import { Feed, Icon, PageNotFound } from '$comp'; import { t } from '$lib/translations'; export let data; - let { user, subject, src, text } = data; + let { events, user, subject, src, text } = data; let followed = false; + + let { username: n } = subject; + $: username = n.length > 60 ? n.substr(0, 6) : n; </script> -<div class="container mx-auto w-full px-4 mb-4 flex flex-wrap"> - <div class="w-[240px] pt-20 space-y-5 lg:absolute left-20 mx-auto"> - <h1 class="text-3xl font-bold text-center mx-auto lg:text-left">{subject.username}</h1> +<div class="container mx-auto w-full px-4 mb-4 flex flex-wrap md:flex-nowrap"> + <div class="hidden lg:block w-[240px] md:mr-10" /> + <div class="w-[240px] lg:absolute pt-20 space-y-5 left-20 mx-auto md:mr-10"> + <h1 class="text-3xl font-bold text-center mx-auto lg:text-left">{username}</h1> <div class="text-secondary mx-auto text-center lg:text-left lg:mx-0"> {subject.address && subject.address !== 'null' ? subject.address : ''} </div> <div class="flex flex-wrap gap-2 w-full"> - <div class="w-full flex"> - <a href={`/${subject.username}/receive`} class="mx-auto"> - <button class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60"> - <div class="mx-auto flex"> - <div style="mr-1">⚡️</div> - <div>{$t('user.lightning')} {$t('user.invoice')}</div> - </div> - </button> - </a> - </div> - - <div class="w-full flex"> - <a href={`/${subject.username}/receive/bitcoin`} class="mx-auto"> - <button class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60"> - <div class="mx-auto flex"> - <img src="/images/bitcoin.svg" class="w-5 my-auto mr-1" /> - <div>{$t('user.bitcoin')} {$t('user.invoice')}</div> - </div> - </button> - </a> - </div> + {#if subject.username.length < 60} + <div class="w-full flex"> + <a href={`/${subject.username}/receive`} class="mx-auto"> + <button class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60"> + <div class="mx-auto flex"> + <div style="mr-1">⚡️</div> + <div>{$t('user.lightning')} {$t('user.invoice')}</div> + </div> + </button> + </a> + </div> - {#if user?.username !== subject.username} <div class="w-full flex"> - <a href={`/${subject.username}/request`} class="mx-auto"> + <a href={`/${subject.username}/receive/bitcoin`} class="mx-auto"> <button class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60"> <div class="mx-auto flex"> - <Icon icon="support" style="mr-1" /> - <div>{$t('transactions.requestAnInvoice')}</div> + <img src="/images/bitcoin.svg" class="w-5 my-auto mr-1" /> + <div>{$t('user.bitcoin')} {$t('user.invoice')}</div> </div> </button> </a> </div> + + {#if user?.username !== subject.username} + <div class="w-full flex"> + <a href={`/${subject.username}/request`} class="mx-auto"> + <button class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60"> + <div class="mx-auto flex"> + <Icon icon="support" style="mr-1" /> + <div>{$t('transactions.requestAnInvoice')}</div> + </div> + </button> + </a> + </div> + {/if} + {:else} + <div class="w-full flex"> + <a href={`/${subject.username}/request`} class="mx-auto"> + <button class="rounded-full border py-3 px-6 font-bold hover:opacity-80 flex w-60"> + <div class="mx-auto flex"> + <Icon icon="support" style="mr-1" /> + <div>{$t('transactions.sendMessage')}</div> + </div> + </button> + </a> + </div> {/if} </div> </div> - <div class="w-full flex"> - <div class="space-y-5 mt-5 lg:pt-20 mx-auto max-w-lg"> - <div class="border-2 rounded-[20%] w-[380px] py-6 mx-auto"> - <img {src} class="mx-auto" on:click={() => copy(text)} alt="Lightning address" /> - </div> - - <div class="bg-primary font-semibold rounded-3xl text-sm p-3 flex"> - <div class="my-auto font-semibold text-lg w-full text-center">{text}</div> - <button class="ml-auto hover:opacity-80" on:click={() => copy(text)}> - <Icon icon="copy" /> - </button> - </div> - - {#if user?.username === subject.username} - <p class="text-secondary mb-1"> - {$t('user.this')} - <a href="https://lightningaddress.com" class="underline" target="_blank" rel="noreferrer" - >{$t('user.lightningAddress')}</a - > - {$t('user.likeAnEmail')} - </p> - {/if} + <div class="w-full flex md:pt-12 lg:pt-0"> + <div class="mx-auto space-y-5 mt-5 lg:max-w-lg xl:max-w-2xl"> + <Feed {events} /> </div> </div> </div> diff --git a/src/routes/(app)/feed/+page.svelte b/src/routes/(app)/feed/+page.svelte index 3269e0d2..2bbadc64 100644 --- a/src/routes/(app)/feed/+page.svelte +++ b/src/routes/(app)/feed/+page.svelte @@ -1,15 +1,9 @@ <script> - import { fade } from 'svelte/transition'; - import { Avatar, Icon } from '$comp'; - import { t } from '$lib/translations'; + import { Feed } from '$comp'; import { events } from '$lib/store'; - import VirtualScroll from 'svelte-virtual-scroll-list'; - import { browser } from '$app/environment'; - import runners from '$lib/runners'; export let data; let { user } = data; - let runner = () => runners[Math.floor(Math.random() * runners.length)]; $: length = $events?.q?.length; $: sorted = Object.values($events) @@ -17,44 +11,12 @@ .sort((a, b) => b.seen - a.seen); let w; - - let distance = (d) => { - let diff = Math.round(Date.now() / 1000) - d; - return diff > 3600 - ? Math.round(diff / 3600) + 'd' - : diff > 60 - ? Math.round(diff / 60) + 'm' - : diff > 2 ? diff + 's' : 'now'; - }; </script> <svelte:window bind:innerWidth={w} /> <div class="mb-20"> <div class="container w-full mx-auto text-lg px-4 md:max-w-2xl space-y-5"> - {#if browser} - <VirtualScroll data={sorted} key="id" let:data pageMode={true} estimateSize={200}> - <div class="flex border-b py-4 text-sm text-secondary" :key={data.id} use:fade> - <div class="mb-auto mr-2"> - <div class="md:hidden"> - <Avatar size={12} src={`/api/public/runners/${runner()}`} /> - </div> - <div class="hidden md:block"> - <Avatar size={20} src={`/api/public/runners/${runner()}`} /> - </div> - </div> - - <div class="grow" style={`max-width: ${w - 100}px`}> - <div class="w-full flex pb-1 text-black"> - <div>{data.pubkey.substr(0, 6)}</div> - <div class="text-secondary"> {distance(data.seen)}</div> - </div> - <div class="break-words"> - {data.content} - </div> - </div> - </div> - </VirtualScroll> - {/if} + <Feed events={sorted} /> </div> </div> |
