aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(app)/settings/profile
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2025-05-03 08:43:35 -0700
committerAdam Soltys <[email protected]>2025-05-03 08:43:35 -0700
commit5d4c882cc48bbee005ba65f082ad7bd771070b3d (patch)
tree54822d1f2cbc4c3672ab67b2eb2585e6af88e6cb /src/routes/(app)/settings/profile
parent9d66feae5483141be0689d834b6d45906d6be84a (diff)
downloadcoinos-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.ts5
-rw-r--r--src/routes/(app)/settings/profile/+page.svelte169
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>