From 59496a8cd8e6abed31feaed3572bc73619a71f81 Mon Sep 17 00:00:00 2001 From: sam Date: Mon, 25 Nov 2024 23:07:17 +0100 Subject: [PATCH] feat(frontend): edit names/pronouns --- Foxnouns.Backend/Utils/ValidationUtils.cs | 4 +- .../src/lib/components/Error.svelte | 2 +- .../src/lib/components/IconButton.svelte | 20 ++++ .../lib/components/editor/FieldEditor.svelte | 56 ++++++++++ .../components/editor/FieldEntryEditor.svelte | 65 ++++++++++++ .../editor/PronounEntryEditor.svelte | 100 ++++++++++++++++++ .../components/editor/PronounsEditor.svelte | 65 ++++++++++++ .../src/lib/defaultPronouns/en.ts | 16 +++ .../src/lib/defaultPronouns/index.ts | 7 ++ .../{errorCodes.svelte.ts => errorCodes.ts} | 0 .../src/lib/i18n/locales/en.json | 20 +++- Foxnouns.Frontend/src/lib/tippy.ts | 1 + .../src/routes/@[username]/+page.svelte | 2 +- .../settings/members/[id]/+layout@.svelte | 12 ++- .../settings/members/[id]/+page.server.ts | 3 +- .../members/[id]/names-pronouns/+page.svelte | 52 +++++++++ .../routes/settings/profile/+layout@.svelte | 8 +- .../profile/names-pronouns/+page.svelte | 51 +++++++++ 18 files changed, 470 insertions(+), 14 deletions(-) create mode 100644 Foxnouns.Frontend/src/lib/components/IconButton.svelte create mode 100644 Foxnouns.Frontend/src/lib/components/editor/FieldEditor.svelte create mode 100644 Foxnouns.Frontend/src/lib/components/editor/FieldEntryEditor.svelte create mode 100644 Foxnouns.Frontend/src/lib/components/editor/PronounEntryEditor.svelte create mode 100644 Foxnouns.Frontend/src/lib/components/editor/PronounsEditor.svelte create mode 100644 Foxnouns.Frontend/src/lib/defaultPronouns/en.ts create mode 100644 Foxnouns.Frontend/src/lib/defaultPronouns/index.ts rename Foxnouns.Frontend/src/lib/{errorCodes.svelte.ts => errorCodes.ts} (100%) create mode 100644 Foxnouns.Frontend/src/routes/settings/members/[id]/names-pronouns/+page.svelte create mode 100644 Foxnouns.Frontend/src/routes/settings/profile/names-pronouns/+page.svelte diff --git a/Foxnouns.Backend/Utils/ValidationUtils.cs b/Foxnouns.Backend/Utils/ValidationUtils.cs index bb225ff..3374e3e 100644 --- a/Foxnouns.Backend/Utils/ValidationUtils.cs +++ b/Foxnouns.Backend/Utils/ValidationUtils.cs @@ -414,7 +414,7 @@ public static partial class ValidationUtils case > Limits.FieldEntryTextLimit: errors.Add( ( - $"{errorPrefix}.{entryIdx}.value", + $"{errorPrefix}.{entryIdx}.display_text", ValidationError.LengthError( "Pronoun display text is too long", 1, @@ -427,7 +427,7 @@ public static partial class ValidationUtils case < 1: errors.Add( ( - $"{errorPrefix}.{entryIdx}.value", + $"{errorPrefix}.{entryIdx}.display_text", ValidationError.LengthError( "Pronoun display text is too short", 1, diff --git a/Foxnouns.Frontend/src/lib/components/Error.svelte b/Foxnouns.Frontend/src/lib/components/Error.svelte index 09337a9..64f3bc7 100644 --- a/Foxnouns.Frontend/src/lib/components/Error.svelte +++ b/Foxnouns.Frontend/src/lib/components/Error.svelte @@ -1,6 +1,6 @@ + + diff --git a/Foxnouns.Frontend/src/lib/components/editor/FieldEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/FieldEditor.svelte new file mode 100644 index 0000000..3fa87b5 --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/FieldEditor.svelte @@ -0,0 +1,56 @@ + + +

{name}

+ +{#each entries as _, index} + +{/each} + +
+ + + diff --git a/Foxnouns.Frontend/src/lib/components/editor/FieldEntryEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/FieldEntryEditor.svelte new file mode 100644 index 0000000..63e56cc --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/FieldEntryEditor.svelte @@ -0,0 +1,65 @@ + + +
+ moveValue(index, true)} + /> + moveValue(index, true)} + /> + + + + + + + + + {#each prefIds as id} + (value.status = id)} active={value.status === id}> + + {allPreferences[id].tooltip} + + {/each} + + + removeValue(index)} + /> +
diff --git a/Foxnouns.Frontend/src/lib/components/editor/PronounEntryEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/PronounEntryEditor.svelte new file mode 100644 index 0000000..aee6859 --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/PronounEntryEditor.svelte @@ -0,0 +1,100 @@ + + +
+
+ moveValue(index, true)} + /> + moveValue(index, true)} + /> + + + + + + + + + {#each prefIds as id} + (value.status = id)} active={value.status === id}> + + {allPreferences[id].tooltip} + + {/each} + + + (displayOpen = !displayOpen)} + /> + removeValue(index)} + /> +
+ + +
+ {$t("editor.display-text-label")} + + + + + {$t("editor.display-text-info")} + +
+
+
diff --git a/Foxnouns.Frontend/src/lib/components/editor/PronounsEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/PronounsEditor.svelte new file mode 100644 index 0000000..9219c02 --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/PronounsEditor.svelte @@ -0,0 +1,65 @@ + + +

{$t("profile.pronouns-header")}

+ +{#each entries as _, index} + +{/each} + +
+ + + diff --git a/Foxnouns.Frontend/src/lib/defaultPronouns/en.ts b/Foxnouns.Frontend/src/lib/defaultPronouns/en.ts new file mode 100644 index 0000000..412689a --- /dev/null +++ b/Foxnouns.Frontend/src/lib/defaultPronouns/en.ts @@ -0,0 +1,16 @@ +const enPronouns = { + "they/them": { pronouns: ["they", "them", "their", "theirs", "themself"] }, + "they/them (singular)": { + pronouns: ["they", "them", "their", "theirs", "themself"], + display: "they/them (singular)", + }, + "they/them (plural)": { + pronouns: ["they", "them", "their", "theirs", "themselves"], + display: "they/them (plural)", + }, + "he/him": { pronouns: ["he", "him", "his", "his", "himself"] }, + "she/her": { pronouns: ["she", "her", "her", "hers", "herself"] }, + "it/its": { pronouns: ["it", "it", "its", "its", "itself"], display: "it/its" }, +} as Record; + +export default enPronouns; diff --git a/Foxnouns.Frontend/src/lib/defaultPronouns/index.ts b/Foxnouns.Frontend/src/lib/defaultPronouns/index.ts new file mode 100644 index 0000000..e60d38b --- /dev/null +++ b/Foxnouns.Frontend/src/lib/defaultPronouns/index.ts @@ -0,0 +1,7 @@ +import enPronouns from "./en"; + +const defaultPronouns = { + en: enPronouns, +} as Record>; + +export default defaultPronouns; diff --git a/Foxnouns.Frontend/src/lib/errorCodes.svelte.ts b/Foxnouns.Frontend/src/lib/errorCodes.ts similarity index 100% rename from Foxnouns.Frontend/src/lib/errorCodes.svelte.ts rename to Foxnouns.Frontend/src/lib/errorCodes.ts diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json index 4dd0cb6..f743706 100644 --- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json +++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json @@ -55,7 +55,7 @@ "account-already-linked": "This account is already linked with a pronouns.cc account.", "last-auth-method": "You cannot remove your last authentication method.", "validation-max-length-error": "Value is too long, maximum length is {{max}}, current length is {{actual}}.", - "validation-min-length-error": "Value is too long, minimum length is {{min}}, current length is {{actual}}.", + "validation-min-length-error": "Value is too short, minimum length is {{min}}, current length is {{actual}}.", "validation-disallowed-value-1": "The following value is not allowed here", "validation-disallowed-value-2": "Allowed values are", "validation-reason": "Reason", @@ -123,7 +123,7 @@ "fields-tab": "Fields", "flags-links-tab": "Flags & links", "back-to-settings-tab": "Back to settings", - "member-header": "Editing member {{name}}", + "member-header": "Editing profile of {{name}}", "username": "Username", "change-username-info": "As changing your username will also change all of your members' links, you can only change it in your account settings.", "change-username-link": "Go to settings", @@ -131,8 +131,20 @@ "change-member-name": "Change name", "display-name": "Display name", "unlisted-label": "Hide from member list", - "unlisted-note": "This only hides this member from your public member list. They will still be visible to anyone at this link:" + "unlisted-note": "This only hides this member from your public member list. They will still be visible to anyone at this link:", + "edit-names-pronouns-header": "Edit names and pronouns", + "back-to-profile-tab": "Back to profile" }, "save-changes": "Save changes", - "change": "Change" + "change": "Change", + "editor": { + "remove-entry": "Remove entry", + "move-entry-down": "Move entry down", + "move-entry-up": "Move entry up", + "add-entry": "Add entry", + "change-display-text": "Change display text", + "display-text-example": "Optional display text (e.g. it/its)", + "display-text-label": "Display text", + "display-text-info": "This is the short text shown on your profile page. If you leave it empty, it will default to the first two forms of the full set." + } } diff --git a/Foxnouns.Frontend/src/lib/tippy.ts b/Foxnouns.Frontend/src/lib/tippy.ts index 3fce60d..39e2ca0 100644 --- a/Foxnouns.Frontend/src/lib/tippy.ts +++ b/Foxnouns.Frontend/src/lib/tippy.ts @@ -5,6 +5,7 @@ import { createTippy } from "svelte-tippy"; // temporary (probably) until sveltestrap works with svelte 5 const tippy = createTippy({ animation: "scale-subtle", + delay: [null, 0], }); export default tippy; diff --git a/Foxnouns.Frontend/src/routes/@[username]/+page.svelte b/Foxnouns.Frontend/src/routes/@[username]/+page.svelte index f2234c2..903312d 100644 --- a/Foxnouns.Frontend/src/routes/@[username]/+page.svelte +++ b/Foxnouns.Frontend/src/routes/@[username]/+page.svelte @@ -33,7 +33,7 @@

{data.user.member_title || $t("profile.default-members-header")} {#if isMeUser} - + {$t("profile.create-member-button")} diff --git a/Foxnouns.Frontend/src/routes/settings/members/[id]/+layout@.svelte b/Foxnouns.Frontend/src/routes/settings/members/[id]/+layout@.svelte index a2539ab..7de4046 100644 --- a/Foxnouns.Frontend/src/routes/settings/members/[id]/+layout@.svelte +++ b/Foxnouns.Frontend/src/routes/settings/members/[id]/+layout@.svelte @@ -8,14 +8,20 @@ let { data, children }: Props = $props(); const isActive = (path: string) => $page.url.pathname === path; + + let name = $derived( + data.member.display_name === data.member.name + ? data.member.name + : `${data.member.display_name} (${data.member.name})`, + ); - {$t("edit-profile.member-header", { name: data.member.name })} • pronouns.cc + {$t("edit-profile.member-header", { name })} • pronouns.cc
-

{$t("edit-profile.member-header", { name: data.member.name })}

+

{$t("edit-profile.member-header", { name })}

@@ -51,7 +57,7 @@ href="/@{data.user.username}/{data.member.name}" class="list-group-item list-group-item-action text-danger" > - Back to member + {$t("edit-profile.back-to-profile-tab")} {$t("edit-profile.back-to-settings-tab")} diff --git a/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.server.ts b/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.server.ts index 252471d..3ff5ac3 100644 --- a/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.server.ts +++ b/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.server.ts @@ -64,7 +64,8 @@ export const actions = { }, bio: async ({ params, request, fetch, cookies }) => { const body = await request.formData(); - const bio = body.get("bio") as string | null; + let bio = body.get("bio") as string | null; + if (!bio || bio === "") bio = null; try { await fastRequest("PATCH", `/users/@me/members/${params.id}`, { diff --git a/Foxnouns.Frontend/src/routes/settings/members/[id]/names-pronouns/+page.svelte b/Foxnouns.Frontend/src/routes/settings/members/[id]/names-pronouns/+page.svelte new file mode 100644 index 0000000..e21bffc --- /dev/null +++ b/Foxnouns.Frontend/src/routes/settings/members/[id]/names-pronouns/+page.svelte @@ -0,0 +1,52 @@ + + + + +
+ +
+ +
+ +
+ +
+ +
diff --git a/Foxnouns.Frontend/src/routes/settings/profile/+layout@.svelte b/Foxnouns.Frontend/src/routes/settings/profile/+layout@.svelte index 12c16d4..6f3d337 100644 --- a/Foxnouns.Frontend/src/routes/settings/profile/+layout@.svelte +++ b/Foxnouns.Frontend/src/routes/settings/profile/+layout@.svelte @@ -2,9 +2,10 @@ import type { Snippet } from "svelte"; import { page } from "$app/stores"; import { t } from "$lib/i18n"; + import type { LayoutData } from "./$types"; - type Props = { children: Snippet }; - let { children }: Props = $props(); + type Props = { data: LayoutData; children: Snippet }; + let { data, children }: Props = $props(); const isActive = (path: string) => $page.url.pathname === path; @@ -53,6 +54,9 @@ > {$t("edit-profile.flags-links-tab")}
+ + {$t("edit-profile.back-to-profile-tab")} + {$t("edit-profile.back-to-settings-tab")} diff --git a/Foxnouns.Frontend/src/routes/settings/profile/names-pronouns/+page.svelte b/Foxnouns.Frontend/src/routes/settings/profile/names-pronouns/+page.svelte new file mode 100644 index 0000000..4954876 --- /dev/null +++ b/Foxnouns.Frontend/src/routes/settings/profile/names-pronouns/+page.svelte @@ -0,0 +1,51 @@ + + + + +
+ +
+ +
+ +
+ +
+ +