This repository has no description
1{{ define "onboarding/profile" }}
2 {{ $profile := .EditBio.Profile }}
3 <h1 class="text-2xl font-semibold dark:text-white">Welcome!</h1>
4 <p class="text-base text-gray-500 dark:text-gray-400 mt-1">Let's get your profile ready. All fields are optional.</p>
5
6 <div class="flex flex-col md:flex-row gap-6 mt-6">
7 <div class="shrink-0 flex md:block justify-center">
8 <form hx-post="/profile/avatar" hx-encoding="multipart/form-data" hx-swap="none" class="group">
9 <input type="hidden" name="inline" value="true">
10 <label class="p-0 size-40 rounded-full border border-gray-300 dark:border-gray-700
11 flex flex-col items-center justify-center gap-1 cursor-pointer overflow-hidden
12 text-gray-500 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-800">
13 <img id="onb-avatar" src="{{ profileAvatarUrl $profile "" }}"
14 class="w-full h-full object-cover rounded-full group-[.htmx-request]:hidden {{ if not $profile.Avatar }}hidden{{ end }}">
15 <div id="onb-avatar-placeholder" class="flex flex-col items-center justify-center gap-1 group-[.htmx-request]:hidden {{ if $profile.Avatar }}hidden{{ end }}">
16 {{ i "camera" "size-6" }}
17 <span class="text-sm">Upload picture</span>
18 </div>
19 {{ i "loader-circle" "size-6 animate-spin hidden group-[.htmx-request]:inline" }}
20 <span class="text-sm hidden group-[.htmx-request]:inline">Uploading picture...</span>
21 <input type="file" name="avatar" accept="image/png,image/jpeg" class="hidden"
22 onchange="onbPreviewAvatar(this)">
23 </label>
24 <p id="avatar-error" class="text-red-500 dark:text-red-400 text-sm mt-1 text-center"></p>
25 </form>
26 </div>
27
28 <form hx-post="/welcome/profile" hx-swap="none" id="onb-profile-form" class="flex flex-col gap-4 flex-1">
29 <div class="flex flex-col gap-1">
30 <label for="onb-bio" class="font-medium">
31 Bio
32 </label>
33 <input type="text" id="onb-bio" name="description" placeholder="Tell us about yourself"
34 value="{{ $profile.Description }}" oninput="onbProfileChanged()">
35 </div>
36
37 <div class="flex flex-col gap-1">
38 <label for="onb-pronouns" class="font-medium">
39 Pronouns
40 </label>
41 <input type="text" id="onb-pronouns" name="pronouns" placeholder="they/them"
42 value="{{ $profile.Pronouns }}" oninput="onbProfileChanged()">
43 </div>
44
45 <div class="flex flex-col gap-1">
46 <label for="onb-website" class="font-medium">
47 Website
48 </label>
49 <input type="text" id="onb-website" name="link0" placeholder="example.com"
50 value="{{ index $profile.Links 0 }}" oninput="onbProfileChanged()">
51 </div>
52
53 <p id="update-profile" class="error"></p>
54
55 <div class="flex justify-end mt-2">
56 <button id="onb-next" type="submit" class="btn-flat w-fit flex items-center gap-2 text-sm">
57 Next {{ i "arrow-right" "size-4" }}
58 </button>
59 </div>
60 </form>
61 </div>
62
63 <script>
64 function onbProfileChanged() {
65 const f = document.getElementById('onb-profile-form');
66 const filled = ['description', 'pronouns', 'link0']
67 .some(n => f.elements[n] && f.elements[n].value.trim() !== '');
68 document.getElementById('onb-next').className =
69 (filled ? 'btn-create-flat' : 'btn-flat') + ' w-fit flex items-center gap-2 text-sm';
70 }
71 onbProfileChanged();
72
73 function onbPreviewAvatar(input) {
74 const file = input.files && input.files[0];
75 if (file) {
76 const img = document.getElementById('onb-avatar');
77 img.src = URL.createObjectURL(file);
78 img.classList.remove('hidden');
79 document.getElementById('onb-avatar-placeholder').classList.add('hidden');
80 }
81 input.form.requestSubmit();
82 }
83 </script>
84{{ end }}