diff options
| -rw-r--r-- | src/components/AppHeader.svelte | 4 | ||||
| -rw-r--r-- | src/components/Avatar.svelte | 6 | ||||
| -rw-r--r-- | src/lib/store.js | 4 | ||||
| -rw-r--r-- | src/lib/upload.js | 1 | ||||
| -rw-r--r-- | src/lib/utils.js | 2 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/+layout.server.js | 3 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/settings/[...tab]/+page.svelte | 26 | ||||
| -rw-r--r-- | src/routes/(app)/[username]/settings/[...tab]/_account.svelte | 103 | ||||
| -rw-r--r-- | svelte.config.js | 3 |
9 files changed, 65 insertions, 87 deletions
diff --git a/src/components/AppHeader.svelte b/src/components/AppHeader.svelte index 59537ffa..8d64e713 100644 --- a/src/components/AppHeader.svelte +++ b/src/components/AppHeader.svelte @@ -1,6 +1,6 @@ <script> import OutClick from 'svelte-outclick'; - import { newPayment, colorTheme } from '$lib/store'; + import { banner, newPayment, colorTheme } from '$lib/store'; import { goto } from '$app/navigation'; import { Avatar, Icon } from '$comp'; import { t } from '$lib/translations'; @@ -23,7 +23,7 @@ let showMenu = false; - $: bg = subject?.banner ? `url(/api/public/${subject.id}-banner.webp)` : undefined; + $: bg = $banner?.id === subject.id ? `url(${$banner.src})` : subject?.banner ? `url(/api/public/${subject.id}-banner.webp)` : undefined; $: $page && (showMenu = false); </script> diff --git a/src/components/Avatar.svelte b/src/components/Avatar.svelte index 09161e01..43331c19 100644 --- a/src/components/Avatar.svelte +++ b/src/components/Avatar.svelte @@ -1,5 +1,5 @@ <script> - import { colorTheme } from '$lib/store'; + import { avatar, banner, colorTheme } from '$lib/store'; import { Icon } from '$comp'; import { punk } from '$lib/utils'; @@ -10,9 +10,9 @@ $: s = size.toString(); $: link = user.anon ? `/${user.pubkey}` : `/${user.username}`; - $: src = + $: src = ($avatar?.id === user.id && $avatar.src) || '/api/public/' + - (user?.profile ? user.id + '-profile.webp' : 'punks/' + punk(user?.pubkey || user?.id || 'aa')); + (user.profile ? user.id + '-profile.webp' : 'punks/' + punk(user.pubkey || user.id || 'aa')); </script> <a href={link} class:pointer-events-none={disabled}> diff --git a/src/lib/store.js b/src/lib/store.js index 5d83a74c..d38eb411 100644 --- a/src/lib/store.js +++ b/src/lib/store.js @@ -32,8 +32,8 @@ const persistLocal = (key, defaultValue) => { return s; }; -export const avatarUpload = writable(); -export const bannerUpload = writable(); +export const avatar = writable(); +export const banner = writable(); export const colorTheme = writable('from-primary to-gradient'); export const events = writable({}); export const invoice = writable(); diff --git a/src/lib/upload.js b/src/lib/upload.js index 099e2f30..899dbb0c 100644 --- a/src/lib/upload.js +++ b/src/lib/upload.js @@ -1,4 +1,5 @@ export const upload = async (file, type, progress, token) => { + console.log("TYPE", type) let url = `/api/upload/${type}`; let formData = new FormData(); formData.append('file', file); diff --git a/src/lib/utils.js b/src/lib/utils.js index bb6b34fa..e4b1194f 100644 --- a/src/lib/utils.js +++ b/src/lib/utils.js @@ -171,7 +171,7 @@ export const sat = (s) => { export const sats = 100000000; export const back = () => browser && history.go(-1); -export const focus = (el) => setTimeout(() => el.focus()); +export const focus = (el) => setTimeout(() => el.focus(), 1); export const sleep = (n) => new Promise((r) => setTimeout(r, n)); export const wait = async (f, n = 100, s = 300) => { diff --git a/src/routes/(app)/[username]/+layout.server.js b/src/routes/(app)/[username]/+layout.server.js index d1b203d7..8279698a 100644 --- a/src/routes/(app)/[username]/+layout.server.js +++ b/src/routes/(app)/[username]/+layout.server.js @@ -5,7 +5,8 @@ export let load = async ({ depends, params: { username } }) => { depends('app:user'); try { - return { subject: await get(`/users/${username}`) }; + let subject = await get(`/users/${username}`) + return { subject }; } catch (e) { console.log(e); throw error(500, 'Unable to retrieve user account data'); diff --git a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte index 94ca2223..e1555248 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/+page.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/+page.svelte @@ -6,7 +6,7 @@ import { Icon, Spinner, Pin } from '$comp'; import { t } from '$lib/translations'; import { failure, post, success } from '$lib/utils'; - import { avatarUpload, bannerUpload, password, pin } from '$lib/store'; + import { avatar, banner, password, pin } from '$lib/store'; import { upload } from '$lib/upload'; import { page } from '$app/stores'; import { sign, send, reEncryptEntropy } from '$lib/nostr'; @@ -46,7 +46,7 @@ $: ({ comp } = tabs.find((t) => t.name === tab)); - let { address, username } = user; + let { address, id, username } = user; let loading; async function handleSubmit() { @@ -58,17 +58,14 @@ data.set('cipher', await reEncryptEntropy(user, data.get('password'))); } - try { - if ($avatarUpload) { - await upload($avatarUpload.file, $avatarUpload.type, $avatarUpload.progress, token); - } + if ($avatar) { + await upload($avatar.file, $avatar.type, $avatar.progress, token); + await fetch(`/api/public/${id}-profile.webp`, {cache: 'reload', mode: 'no-cors'}) + } - if ($bannerUpload) { - await upload($bannerUpload.file, $bannerUpload.type, $bannerUpload.progress, token); - } - } catch (e) { - console.log(e); - failure('Something went wrong'); + if ($banner) { + await upload($banner.file, $banner.type, $banner.progress, token); + await fetch(`/api/public/${id}-banner.webp`, {cache: 'reload', mode: 'no-cors'}) } let event = { @@ -99,11 +96,12 @@ } applyAction(result); - loading = false; } catch (e) { console.log(e); - failure('Problem submitting form'); + failure('Something went wrong'); } + + loading = false; } let loaded; diff --git a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte index 93b5442d..9b5af6d3 100644 --- a/src/routes/(app)/[username]/settings/[...tab]/_account.svelte +++ b/src/routes/(app)/[username]/settings/[...tab]/_account.svelte @@ -1,18 +1,14 @@ <script> import { tick } from 'svelte'; - import { colorTheme, avatarUpload, bannerUpload } from '$lib/store'; + import { colorTheme, avatar, banner } from '$lib/store'; import { Icon } from '$comp'; import { t } from '$lib/translations'; - import { upload } from '$lib/upload'; - export let user; + export let rates, user, submit; + let { id } = user; let selectedTheme = 1; - let profileFile; - let select = (type) => files[type].el.click(); - - $: profile = files.profile.src; - $: banner = files.banner.src; + let avatarFile, avatarInput, bannerFile, bannerInput; let colorThemes = [ { theme: 1, color1: 'from-[#F5F7FA]', color2: 'to-[#C3CFE2]' }, @@ -28,6 +24,9 @@ $colorTheme = colors.color1 + ' ' + colors.color2; }; + let selectAvatar = () => avatarInput.click(); + let selectBanner = () => bannerInput.click(); + let percent; let progress = async (event) => { percent = Math.round((event.loaded / event.total) * 100); @@ -35,23 +34,29 @@ let tooLarge = {}; - let files = { profile: {}, banner: {} }; let handleFile = async ({ target }, type) => { tooLarge[type] = false; let file = target.files[0]; + if (!file) return; + if (file.size > 10000000) return (tooLarge[type] = true); + + if(type === 'profile') { + $avatar = { id, file, type, progress }; + } else if (type === 'banner') { + $banner = { id, file, type, progress }; + } + var reader = new FileReader(); reader.onload = async (e) => { - files[type].src = e.target.result; + if (type === 'profile') { + $avatar.src = e.target.result; + } else if (type === 'banner') { + $banner.src = e.target.result; + } }; - reader.readAsDataURL(file); - files[type].filename = file.name; - if (type === 'profile') { - $avatarUpload = { file, type, progress }; - } else if (type === 'banner') { - $bannerUpload = { file, type, progress }; - } + reader.readAsDataURL(file); }; if (!user.display) user.display = user.username; @@ -78,26 +83,14 @@ <span class="font-bold">{$t('user.settings.profileImage')}</span> <div class="flex"> - {#if profile} - <div - class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer" - on:click={() => select('profile')} - on:keydown={() => select('profile')} - > - <img - src={profile} - class="absolute w-full h-full object-cover object-center visible overflow-hidden" - alt={user.username} - /> - </div> - {:else if user.profile} + {#if $avatar || user.profile} <div class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer" - on:click={() => select('profile')} - on:keydown={() => select('profile')} + on:click={selectAvatar} + on:keydown={selectAvatar} > <img - src={`/api/public/${user.id}-profile.webp`} + src={$avatar?.src || `/api/public/${user.id}-profile.webp`} class="absolute w-full h-full object-cover object-center visible overflow-hidden" alt={user.username} /> @@ -105,8 +98,8 @@ {:else} <div class="rounded-full border-4 border-white p-4 bg-gradient-to-r {$colorTheme} w-24 my-auto hover:opacity-80 cursor-pointer" - on:click={() => select('profile')} - on:keydown={() => select('profile')} + on:click={selectAvatar} + on:keydown={selectAvatar} > <Icon icon="logo-symbol-white" style="mx-auto" /> </div> @@ -116,22 +109,19 @@ <button type="button" class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80" - on:click={() => select('profile')} - on:keydown={() => select('profile')}>{$t('user.settings.select')}</button + on:click={selectAvatar} + on:keydown={selectAvatar}>{$t('user.settings.select')}</button > <input type="file" class="hidden" - bind:this={files.profile.el} + bind:this={avatarInput} on:change={(e) => handleFile(e, 'profile')} /> - {#if files.profile.filename} - <div class="mt-2 text-sm">{files.profile.filename}</div> - {/if} </div> </div> - {#if tooLarge['profile']} + {#if tooLarge['avatar']} <div class="text-red-600">Max file size 10MB</div> {/if} </div> @@ -141,27 +131,19 @@ <span class="font-bold">{$t('user.settings.bannerImage')}</span> </div> - {#if banner} - <img - src={banner} - class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80" - on:click={() => select('banner')} - on:keydown={() => select('banner')} - alt="Banner" - /> - {:else if user.banner} + {#if $banner || user.banner} <img - src={`/api/public/${user.id}-banner.webp`} + src={$banner ? $banner.src : `/api/public/${user.id}-banner.webp`} class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80" - on:click={() => select('banner')} - on:keydown={() => select('banner')} + on:click={selectBanner} + on:keydown={selectBanner} alt="Banner" /> {:else} <div class="bg-gradient-to-r {$colorTheme} w-full h-48 mb-4 cursor-pointer hover:opacity-80" - on:click={() => select('banner')} - on:keydown={() => select('banner')} + on:click={selectBanner} + on:keydown={selectBanner} alt="Banner" /> {/if} @@ -169,18 +151,15 @@ <button type="button" class="border rounded-2xl font-bold w-24 text-center px-0 py-2 hover:opacity-80" - on:click={() => select('banner')} - on:keydown={() => select('banner')}>{$t('user.settings.select')}</button + on:click={selectBanner} + on:keydown={selectBanner}>{$t('user.settings.select')}</button > <input type="file" class="hidden" - bind:this={files.banner.el} + bind:this={bannerInput} on:change={(e) => handleFile(e, 'banner')} /> - {#if files.banner.filename} - <div class="mt-2 text-sm">{files.banner.filename}</div> - {/if} {#if tooLarge['banner']} <div class="text-red-600">Max file size 10MB</div> diff --git a/svelte.config.js b/svelte.config.js index ab0e9219..85618815 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -1,7 +1,6 @@ import adapter from '@sveltejs/adapter-node'; import preprocess from 'svelte-preprocess'; -/** @type {import('@sveltejs/kit').Config} */ const config = { preprocess: [ preprocess({ @@ -15,7 +14,7 @@ const config = { } }, onwarn: (warning, handler) => { - if (warning.code.includes("caption") || warning.filename.includes("Toast")) return; + if (warning.code.includes('caption') || warning.filename.includes('Toast')) return; handler(warning); } }; |
