diff options
| author | Adam Soltys <[email protected]> | 2025-05-03 08:43:35 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2025-05-03 08:43:35 -0700 |
| commit | 5d4c882cc48bbee005ba65f082ad7bd771070b3d (patch) | |
| tree | 54822d1f2cbc4c3672ab67b2eb2585e6af88e6cb /src/routes/(app)/settings/profile | |
| parent | 9d66feae5483141be0689d834b6d45906d6be84a (diff) | |
| download | coinos-ui-5d4c882cc48bbee005ba65f082ad7bd771070b3d.tar.gz coinos-ui-5d4c882cc48bbee005ba65f082ad7bd771070b3d.zip | |
settings re-org
Diffstat (limited to 'src/routes/(app)/settings/profile')
| -rw-r--r-- | src/routes/(app)/settings/profile/+page.server.ts | 5 | ||||
| -rw-r--r-- | src/routes/(app)/settings/profile/+page.svelte | 169 |
2 files changed, 174 insertions, 0 deletions
diff --git a/src/routes/(app)/settings/profile/+page.server.ts b/src/routes/(app)/settings/profile/+page.server.ts new file mode 100644 index 00000000..4145935e --- /dev/null +++ b/src/routes/(app)/settings/profile/+page.server.ts @@ -0,0 +1,5 @@ +import updateUser from "$lib/settings"; + +export const actions = { + default: updateUser, +}; diff --git a/src/routes/(app)/settings/profile/+page.svelte b/src/routes/(app)/settings/profile/+page.svelte new file mode 100644 index 00000000..bee50d39 --- /dev/null +++ b/src/routes/(app)/settings/profile/+page.svelte @@ -0,0 +1,169 @@ +<script> + import { tick } from "svelte"; + import { avatar, banner as bannerStore } from "$lib/store"; + import { t } from "$lib/translations"; + import { page } from "$app/stores"; + + let { data } = $props(); + let { user } = $derived(data); + let { id } = user; + let { about, banner, picture, display, username } = + $state(user); + + let avatarFile, + avatarInput = $state(), + bannerFile, + bannerInput = $state(); + + let selectAvatar = () => avatarInput.click(); + let selectBanner = () => bannerInput.click(); + + let percent; + let progress = async (event) => { + percent = Math.round((event.loaded / event.total) * 100); + }; + + let tooLarge = $state({}); + + 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 === "picture") { + $avatar = { id, file, type, progress }; + } else if (type === "banner") { + $bannerStore = { id, file, type, progress }; + } + + var reader = new FileReader(); + reader.onload = async (e) => { + if (type === "picture") { + $avatar.src = e.target.result; + } else if (type === "banner") { + $bannerStore.src = e.target.result; + } + }; + + reader.readAsDataURL(file); + }; + + let url = $derived(`${$page.url.host}/${username}`); + let full = $derived(`${$page.url.protocol}//${url}`); + let addr = $derived(`${username}@${$page.url.host}`); +</script> + +<div> + <label for="username" class="font-bold mb-1 block" + >{$t("user.settings.username")}</label + > + <div class="flex mb-2"> + <input type="text" name="username" bind:value={username} /> + </div> +</div> + +<div> + <label for="display" class="font-bold mb-1 block" + >{$t("user.settings.displayName")}</label + > + <input type="text" name="display" bind:value={display} /> +</div> + +<div class="space-y-2"> + <span class="font-bold">{$t("user.settings.profileImage")}</span> + + <div class="flex"> + {#if $avatar || picture} + <div + class="relative rounded-full overflow-hidden text-center w-20 h-20 my-auto hover:opacity-80 cursor-pointer" + onclick={selectAvatar} + onkeydown={selectAvatar} + > + <img + src={$avatar?.src || picture} + class="absolute w-full h-full object-cover object-center visible overflow-hidden" + alt={username} + /> + </div> + {:else} + <div + class="rounded-full border-4 border-base-100 p-4 bg-base-200 w-24 h-24 my-auto hover:opacity-80 cursor-pointer" + onclick={selectAvatar} + onkeydown={selectAvatar} + ></div> + {/if} + <div class="ml-2 p-2"> + <!-- found missing translation --> + <button + type="button" + class="btn" + onclick={selectAvatar} + onkeydown={selectAvatar}>{$t("user.settings.select")}</button + > + <input + type="file" + class="hidden" + bind:this={avatarInput} + onchange={(e) => handleFile(e, "picture")} + /> + </div> + </div> + + {#if tooLarge["avatar"]} + <div class="text-red-600">Max file size 10MB</div> + {/if} +</div> + +<div class="space-y-2"> + <div class="flex justify-between items-center"> + <span class="font-bold">{$t("user.settings.bannerImage")}</span> + </div> + + {#if $bannerStore || banner} + <img + src={$bannerStore ? $bannerStore.src : banner} + class="w-full object-cover object-center visible overflow-hidden h-48 mb-4 hover:opacity-80" + onclick={selectBanner} + onkeydown={selectBanner} + alt="Banner" + /> + {:else} + <div + class="bg-base-200 w-full h-48 mb-4 cursor-pointer hover:opacity-80" + onclick={selectBanner} + onkeydown={selectBanner} + alt="Banner" + ></div> + {/if} + + <button + type="button" + class="btn !w-auto" + onclick={selectBanner} + onkeydown={selectBanner}>{$t("user.settings.select")}</button + > + <input + type="file" + class="hidden" + bind:this={bannerInput} + onchange={(e) => handleFile(e, "banner")} + /> + + {#if tooLarge["banner"]} + <div class="text-red-600">Max file size 10MB</div> + {/if} +</div> + +<div> + <label for="about" class="font-bold mb-1 block" + >{$t("user.settings.about")}</label + > + <textarea + type="text" + name="about" + bind:value={about} + placeholder={$t("user.settings.aboutPlaceholder")} + ></textarea> +</div> |
