your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import type { WebsiteData, PronounSet } from '$lib/types';
3 import { Badge, Button, Input, Switch, Label } from '@foxui/core';
4 import Modal from '$lib/components/modal/Modal.svelte';
5
6 let {
7 data = $bindable(),
8 editing = false
9 }: {
10 data: WebsiteData;
11 editing?: boolean;
12 } = $props();
13
14 let modalOpen = $state(false);
15 let editSets: PronounSet[] = $state([]);
16 let editDisplayMode: 'all' | 'firstOnly' = $state('all');
17
18 function openModal() {
19 if (data.pronounsRecord?.value?.sets?.length) {
20 editSets = JSON.parse(JSON.stringify(data.pronounsRecord.value.sets));
21 editDisplayMode = data.pronounsRecord.value.displayMode === 'firstOnly' ? 'firstOnly' : 'all';
22 } else {
23 editSets = [{ forms: [''] }];
24 editDisplayMode = 'all';
25 }
26 modalOpen = true;
27 }
28
29 function save() {
30 const validSets = editSets.filter((set) => set.forms.some((form) => form.length > 0));
31 if (validSets.length > 0) {
32 data.pronounsRecord = {
33 value: {
34 sets: validSets,
35 displayMode: editDisplayMode
36 }
37 };
38 } else {
39 data.pronounsRecord = undefined;
40 }
41 data = { ...data };
42 modalOpen = false;
43 }
44
45 function addSet() {
46 editSets = [...editSets, { forms: [''] }];
47 }
48
49 function removeSet(index: number) {
50 editSets = editSets.filter((_, i) => i !== index);
51 }
52
53 function updateSetInput(index: number, value: string) {
54 editSets[index] = { forms: value.split('/').map((s) => s.trim()) };
55 }
56
57 let allSets = $derived(data.pronounsRecord?.value?.sets ?? []);
58 let sets = $derived(
59 data.pronounsRecord?.value?.displayMode === 'firstOnly' ? allSets.slice(0, 1) : allSets
60 );
61</script>
62
63{#if sets.length}
64 <div class="flex flex-wrap gap-1">
65 {#each sets as set, i (i)}
66 <Badge>{set.forms.join('/')}</Badge>
67 {/each}
68 </div>
69{/if}
70
71{#if editing}
72 <Button size="sm" onclick={openModal}>
73 <svg
74 xmlns="http://www.w3.org/2000/svg"
75 fill="none"
76 viewBox="0 0 24 24"
77 stroke-width="1.5"
78 stroke="currentColor"
79 class="size-3"
80 >
81 <path
82 stroke-linecap="round"
83 stroke-linejoin="round"
84 d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
85 />
86 </svg>
87 {sets.length ? 'edit' : 'add'} pronouns
88 </Button>
89
90 <Modal open={modalOpen} onOpenChange={(v) => (modalOpen = v)} closeButton>
91 <div class="flex flex-col gap-4">
92 <h3 class="text-base-900 dark:text-base-100 text-lg font-semibold">Edit pronouns</h3>
93
94 <div class="flex flex-col gap-2">
95 {#each editSets as set, i (i)}
96 <div class="flex items-center gap-2">
97 <Input
98 value={set.forms.join('/')}
99 oninput={(e) => updateSetInput(i, e.currentTarget.value)}
100 placeholder="e.g. she/her"
101 variant="secondary"
102 sizeVariant="sm"
103 class="grow"
104 />
105 {#if editSets.length > 1}
106 <Button size="iconSm" variant="ghost" onclick={() => removeSet(i)}>×</Button>
107 {/if}
108 </div>
109 {/each}
110 </div>
111
112 {#if editSets.length < 10}
113 <Button
114 size="sm"
115 variant="secondary"
116 onclick={addSet}
117 disabled={!editSets.at(-1)?.forms.some((f) => f.length > 0)}
118 class="w-fit"
119 >
120 + add more pronouns
121 </Button>
122 {/if}
123
124 {#if editSets.length > 1}
125 <div class="flex items-center gap-1.5">
126 <Switch
127 id="pronouns-display-mode"
128 checked={editDisplayMode === 'firstOnly'}
129 onCheckedChange={(checked) => {
130 editDisplayMode = checked ? 'firstOnly' : 'all';
131 }}
132 />
133 <Label for="pronouns-display-mode">show first only</Label>
134 </div>
135 {/if}
136
137 <div class="flex justify-end gap-2">
138 <Button variant="secondary" onclick={() => (modalOpen = false)}>Cancel</Button>
139 <Button onclick={save}>Save</Button>
140 </div>
141 </div>
142 </Modal>
143{/if}