diff --git a/frontend/src/lib/api/default_preferences.ts b/frontend/src/lib/api/default_preferences.ts index ad8a2dc..0d564d2 100644 --- a/frontend/src/lib/api/default_preferences.ts +++ b/frontend/src/lib/api/default_preferences.ts @@ -30,12 +30,19 @@ const defaultPreferences: CustomPreferences = { favourite: false, }, avoid: { - icon: "people", + icon: "hand-thumbs-down", tooltip: "Avoid", size: PreferenceSize.Small, muted: true, favourite: false, }, + missing: { + icon: "question-lg", + tooltip: "Unknown (missing)", + size: PreferenceSize.Normal, + muted: false, + favourite: false, + }, }; export default defaultPreferences; diff --git a/frontend/src/lib/api/entities.ts b/frontend/src/lib/api/entities.ts index b5cac81..ccb3b22 100644 --- a/frontend/src/lib/api/entities.ts +++ b/frontend/src/lib/api/entities.ts @@ -58,13 +58,13 @@ export interface Field { export interface FieldEntry { value: string; - status: WordStatus; + status: string; } export interface Pronoun { pronouns: string; display_text: string | null; - status: WordStatus; + status: string; } export enum WordStatus { diff --git a/frontend/src/lib/components/StatusIcon.svelte b/frontend/src/lib/components/StatusIcon.svelte index b26b03c..be4977c 100644 --- a/frontend/src/lib/components/StatusIcon.svelte +++ b/frontend/src/lib/components/StatusIcon.svelte @@ -13,7 +13,7 @@ let currentPreference: CustomPreference; $: currentPreference = - status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.okay; + status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.missing; let iconElement: HTMLElement; diff --git a/frontend/src/lib/components/StatusLine.svelte b/frontend/src/lib/components/StatusLine.svelte index 77ae5d0..021326c 100644 --- a/frontend/src/lib/components/StatusLine.svelte +++ b/frontend/src/lib/components/StatusLine.svelte @@ -13,7 +13,7 @@ let currentPreference: CustomPreference; $: currentPreference = - status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.okay; + status in mergedPreferences ? mergedPreferences[status] : defaultPreferences.missing; let classes: string; $: classes = setClasses(currentPreference); diff --git a/frontend/src/routes/edit/EditableField.svelte b/frontend/src/routes/edit/EditableField.svelte index 446fe71..66be6c9 100644 --- a/frontend/src/routes/edit/EditableField.svelte +++ b/frontend/src/routes/edit/EditableField.svelte @@ -1,10 +1,11 @@
@@ -58,30 +36,17 @@ - {textFor(status)} + {currentPreference.tooltip} - + - (status = WordStatus.Favourite)} - active={status === WordStatus.Favourite}>Favourite - (status = WordStatus.Okay)} active={status === WordStatus.Okay} - >Okay - (status = WordStatus.Jokingly)} - active={status === WordStatus.Jokingly}>Jokingly - (status = WordStatus.FriendsOnly)} - active={status === WordStatus.FriendsOnly}>Friends only - (status = WordStatus.Avoid)} - active={status === WordStatus.Avoid}>Avoid + {#each preferenceIds as id} + (status = id)} active={status === id}> + + {mergedPreferences[id].tooltip} + + {/each} diff --git a/frontend/src/routes/edit/EditablePronouns.svelte b/frontend/src/routes/edit/EditablePronouns.svelte index b1df161..d1a1548 100644 --- a/frontend/src/routes/edit/EditablePronouns.svelte +++ b/frontend/src/routes/edit/EditablePronouns.svelte @@ -1,5 +1,6 @@
@@ -75,31 +55,17 @@ click={toggleDisplay} /> - {textFor(pronoun.status)} + {currentPreference.tooltip} - + - (pronoun.status = WordStatus.Favourite)} - active={pronoun.status === WordStatus.Favourite}>Favourite - (pronoun.status = WordStatus.Okay)} - active={pronoun.status === WordStatus.Okay}>Okay - (pronoun.status = WordStatus.Jokingly)} - active={pronoun.status === WordStatus.Jokingly}>Jokingly - (pronoun.status = WordStatus.FriendsOnly)} - active={pronoun.status === WordStatus.FriendsOnly}>Friends only - (pronoun.status = WordStatus.Avoid)} - active={pronoun.status === WordStatus.Avoid}>Avoid + {#each preferenceIds as id} + (pronoun.status = id)} active={pronoun.status === id}> + + {mergedPreferences[id].tooltip} + + {/each} diff --git a/frontend/src/routes/edit/FieldEntry.svelte b/frontend/src/routes/edit/FieldEntry.svelte index d03595d..2a9b086 100644 --- a/frontend/src/routes/edit/FieldEntry.svelte +++ b/frontend/src/routes/edit/FieldEntry.svelte @@ -1,5 +1,6 @@
@@ -58,30 +36,17 @@ - {textFor(status)} + {currentPreference.tooltip} - + - (status = WordStatus.Favourite)} - active={status === WordStatus.Favourite}>Favourite - (status = WordStatus.Okay)} active={status === WordStatus.Okay} - >Okay - (status = WordStatus.Jokingly)} - active={status === WordStatus.Jokingly}>Jokingly - (status = WordStatus.FriendsOnly)} - active={status === WordStatus.FriendsOnly}>Friends only - (status = WordStatus.Avoid)} - active={status === WordStatus.Avoid}>Avoid + {#each preferenceIds as id} + (status = id)} active={status === id}> + + {mergedPreferences[id].tooltip} + + {/each} diff --git a/frontend/src/routes/edit/member/[id]/+page.svelte b/frontend/src/routes/edit/member/[id]/+page.svelte index fe3d6f8..f095364 100644 --- a/frontend/src/routes/edit/member/[id]/+page.svelte +++ b/frontend/src/routes/edit/member/[id]/+page.svelte @@ -153,10 +153,9 @@ if (list[0].size > MAX_AVATAR_BYTES) { addToast({ header: "Avatar too large", - body: - `This avatar is too large, please resize it (maximum is ${prettyBytes( - MAX_AVATAR_BYTES, - )}, the file you tried to upload is ${prettyBytes(list[0].size)})`, + body: `This avatar is too large, please resize it (maximum is ${prettyBytes( + MAX_AVATAR_BYTES, + )}, the file you tried to upload is ${prettyBytes(list[0].size)})`, }); return null; } @@ -440,6 +439,7 @@ moveName(index, true)} moveDown={() => moveName(index, false)} remove={() => removeName(index)} @@ -479,6 +479,7 @@ {#each pronouns as _, index} movePronoun(index, true)} moveDown={() => movePronoun(index, false)} remove={() => removePronoun(index)} @@ -520,6 +521,7 @@ {#each fields as _, index} removeField(index)} moveField={(up) => moveField(index, up)} /> diff --git a/frontend/src/routes/edit/profile/+page.svelte b/frontend/src/routes/edit/profile/+page.svelte index 4134de4..a3ef65c 100644 --- a/frontend/src/routes/edit/profile/+page.svelte +++ b/frontend/src/routes/edit/profile/+page.svelte @@ -8,6 +8,8 @@ type FieldEntry, type MeUser, type Pronoun, + PreferenceSize, + type CustomPreferences, } from "$lib/api/entities"; import FallbackImage from "$lib/components/FallbackImage.svelte"; import { userStore } from "$lib/store"; @@ -37,6 +39,7 @@ import { charCount, renderMarkdown } from "$lib/utils"; import MarkdownHelp from "../MarkdownHelp.svelte"; import prettyBytes from "pretty-bytes"; + import CustomPreference from "./CustomPreference.svelte"; const MAX_AVATAR_BYTES = 1_000_000; @@ -52,6 +55,7 @@ let pronouns: Pronoun[] = window.structuredClone(data.user.pronouns); let fields: Field[] = window.structuredClone(data.user.fields); let list_private = data.user.list_private; + let custom_preferences = window.structuredClone(data.user.custom_preferences); let avatar: string | null; let avatar_files: FileList | null; @@ -60,6 +64,9 @@ let newPronouns = ""; let newLink = ""; + let preferenceIds: string[]; + $: preferenceIds = Object.keys(custom_preferences); + let modified = false; $: modified = isModified( @@ -73,6 +80,7 @@ avatar, member_title, list_private, + custom_preferences, ); $: getAvatar(avatar_files).then((b64) => (avatar = b64)); @@ -87,6 +95,7 @@ avatar: string | null, member_title: string, list_private: boolean, + custom_preferences: CustomPreferences, ) => { if (bio !== (user.bio || "")) return true; if (display_name !== (user.display_name || "")) return true; @@ -95,6 +104,7 @@ if (!fieldsEqual(fields, user.fields)) return true; if (!namesEqual(names, user.names)) return true; if (!pronounsEqual(pronouns, user.pronouns)) return true; + if (!customPreferencesEqual(custom_preferences, user.custom_preferences)) return true; if (avatar !== null) return true; if (list_private !== user.list_private) return true; @@ -136,6 +146,21 @@ return arr1.every((_, i) => arr1[i] === arr2[i]); }; + const customPreferencesEqual = (obj1: CustomPreferences, obj2: CustomPreferences) => { + return Object.keys(obj1) + .map((key) => { + if (!(key in obj2)) return false; + return ( + obj1[key].icon === obj2[key].icon && + obj1[key].tooltip === obj2[key].tooltip && + obj1[key].favourite === obj2[key].favourite && + obj1[key].muted === obj2[key].muted && + obj1[key].size === obj2[key].size + ); + }) + .every((entry) => entry); + }; + const getAvatar = async (list: FileList | null) => { if (!list || list.length === 0) return null; if (list[0].size > MAX_AVATAR_BYTES) { @@ -226,6 +251,19 @@ newLink = ""; }; + const addPreference = () => { + const id = crypto.randomUUID(); + + custom_preferences[id] = { + icon: "question", + tooltip: "New preference", + size: PreferenceSize.Normal, + muted: false, + favourite: false, + }; + custom_preferences = custom_preferences; + }; + const removeName = (index: number) => { names.splice(index, 1); names = [...names]; @@ -246,6 +284,11 @@ fields = [...fields]; }; + const removePreference = (id: string) => { + delete custom_preferences[id]; + custom_preferences = custom_preferences; + }; + const updateUser = async () => { const toastId = addToast({ header: "Saving changes", @@ -264,6 +307,7 @@ fields, member_title, list_private, + custom_preferences, }); data.user = resp; @@ -367,6 +411,7 @@ moveName(index, true)} moveDown={() => moveName(index, false)} remove={() => removeName(index)} @@ -447,6 +492,7 @@ {#each fields as _, index} removeField(index)} moveField={(up) => moveField(index, up)} /> @@ -478,7 +524,7 @@
- +
@@ -510,5 +556,18 @@

+
+

+ Preferences +

+ {#each preferenceIds as id} + removePreference(id)} + /> + {/each} +
diff --git a/frontend/src/routes/edit/profile/CustomPreference.svelte b/frontend/src/routes/edit/profile/CustomPreference.svelte new file mode 100644 index 0000000..84e49a0 --- /dev/null +++ b/frontend/src/routes/edit/profile/CustomPreference.svelte @@ -0,0 +1,86 @@ + + + + + Change icon + + + + +

+ +

+ + {#each filteredIcons as icon} + (preference.icon = icon)} + > {icon} + {:else} +

Start typing to filter

+ {/each} +
+
+ + Change text size + + + + + + (preference.size = PreferenceSize.Large)}>Large + (preference.size = PreferenceSize.Normal)}>Medium + (preference.size = PreferenceSize.Small)}>Small + + + + + +