diff --git a/Foxnouns.Frontend/package.json b/Foxnouns.Frontend/package.json index 0e74736..bd5ed64 100644 --- a/Foxnouns.Frontend/package.json +++ b/Foxnouns.Frontend/package.json @@ -29,6 +29,7 @@ "prettier-plugin-svelte": "^3.2.6", "sass": "^1.81.0", "svelte": "^5.0.0", + "svelte-bootstrap-icons": "^3.1.1", "svelte-check": "^4.0.0", "sveltekit-i18n": "^2.4.2", "typescript": "^5.0.0", diff --git a/Foxnouns.Frontend/pnpm-lock.yaml b/Foxnouns.Frontend/pnpm-lock.yaml index bb1a839..d2289ec 100644 --- a/Foxnouns.Frontend/pnpm-lock.yaml +++ b/Foxnouns.Frontend/pnpm-lock.yaml @@ -93,6 +93,9 @@ importers: svelte: specifier: ^5.0.0 version: 5.2.2 + svelte-bootstrap-icons: + specifier: ^3.1.1 + version: 3.1.1 svelte-check: specifier: ^4.0.0 version: 4.0.9(picomatch@4.0.2)(svelte@5.2.2)(typescript@5.6.3) @@ -1321,6 +1324,9 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + svelte-bootstrap-icons@3.1.1: + resolution: {integrity: sha512-ghJlt6TX3IX35M7wSvGyrmVgXeT5GMRF+7+q6L4OUT2RJWF09mQIvZTZ04Ii3FBfg10KdzFdvVuoB8M0cVHfzw==} + svelte-check@4.0.9: resolution: {integrity: sha512-SVNCz2L+9ZELGli7G0n3B3QE5kdf0u27RtKr2ZivWQhcWIXatZxwM4VrQ6AiA2k9zKp2mk5AxkEhdjbpjv7rEw==} engines: {node: '>= 18.0.0'} @@ -2564,6 +2570,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + svelte-bootstrap-icons@3.1.1: {} + svelte-check@4.0.9(picomatch@4.0.2)(svelte@5.2.2)(typescript@5.6.3): dependencies: '@jridgewell/trace-mapping': 0.3.25 diff --git a/Foxnouns.Frontend/src/lib/components/IconButton.svelte b/Foxnouns.Frontend/src/lib/components/IconButton.svelte index 4633dd1..1feedd9 100644 --- a/Foxnouns.Frontend/src/lib/components/IconButton.svelte +++ b/Foxnouns.Frontend/src/lib/components/IconButton.svelte @@ -10,11 +10,18 @@ type?: "submit" | "reset" | "button"; id?: string; onclick?: MouseEventHandler; + outline?: boolean; }; - let { icon, tooltip, color = "primary", type, id, onclick }: Props = $props(); + let { icon, tooltip, color = "primary", type, id, onclick, outline }: Props = $props(); - diff --git a/Foxnouns.Frontend/src/lib/components/editor/FlagButton.svelte b/Foxnouns.Frontend/src/lib/components/editor/FlagButton.svelte new file mode 100644 index 0000000..51b87c4 --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/FlagButton.svelte @@ -0,0 +1,35 @@ + + + + + diff --git a/Foxnouns.Frontend/src/lib/components/editor/FlagEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/FlagEditor.svelte index 8b542da..8cb994c 100644 --- a/Foxnouns.Frontend/src/lib/components/editor/FlagEditor.svelte +++ b/Foxnouns.Frontend/src/lib/components/editor/FlagEditor.svelte @@ -24,11 +24,16 @@ {flag.description
- + diff --git a/Foxnouns.Frontend/src/lib/components/editor/FlagSearch.svelte b/Foxnouns.Frontend/src/lib/components/editor/FlagSearch.svelte new file mode 100644 index 0000000..78a6c0f --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/FlagSearch.svelte @@ -0,0 +1,48 @@ + + + + +
+ {#each filteredFlags as flag (flag.id)} + select(flag)} padding /> + {:else} +
+

+ +

+

+ {#if query} + {$t("editor.flag-search-no-flags")} + {:else} + {$t("editor.flag-search-no-account-flags")} + {/if} +

+
+ {/each} + {#if flags.length > 0} +

+ + {$t("editor.flag-search-hint")} + {$t("editor.flag-manage-your-flags")} +

+ {:else} +

{$t("editor.flag-manage-your-flags")}

+ {/if} +
diff --git a/Foxnouns.Frontend/src/lib/components/editor/ProfileFlagsEditor.svelte b/Foxnouns.Frontend/src/lib/components/editor/ProfileFlagsEditor.svelte new file mode 100644 index 0000000..5bd62fd --- /dev/null +++ b/Foxnouns.Frontend/src/lib/components/editor/ProfileFlagsEditor.svelte @@ -0,0 +1,95 @@ + + +
+
+

+ {$t("settings.flag-title")} + +

+ + {#each flags as flag, i} +
+
+ moveFlag(i, true)} + /> + moveFlag(i, false)} + /> + removeFlag(flag)} + tooltip={$t("editor.remove-this-flag")} + /> +
+
+ {:else} +

+ {$t("editor.no-flags-hint")} +

+ {/each} +
+
+

{$t("editor.add-flags-header")}

+ +
+
+ + diff --git a/Foxnouns.Frontend/src/lib/i18n/locales/en.json b/Foxnouns.Frontend/src/lib/i18n/locales/en.json index 20e8404..eb80a83 100644 --- a/Foxnouns.Frontend/src/lib/i18n/locales/en.json +++ b/Foxnouns.Frontend/src/lib/i18n/locales/en.json @@ -128,7 +128,10 @@ "flag-current-flags-title": "Current flags ({{count}}/{{max}})", "flag-title": "Flags", "flag-upload-title": "Upload a new flag", - "flag-upload-button": "Upload" + "flag-upload-button": "Upload", + "flag-description-placeholder": "Description", + "flag-name-placeholder": "Name", + "flag-upload-success": "Successfully uploaded your flag! It may take a few seconds before it's saved." }, "yes": "Yes", "no": "No", @@ -188,7 +191,18 @@ "remove-field": "Remove field", "field-name": "Field name", "add-field": "Add field", - "new-entry": "New entry" + "new-entry": "New entry", + "add-this-flag": "Add this flag", + "add-flags-header": "Add flags", + "move-flag-up": "Move flag up", + "move-flag-down": "Move flag down", + "remove-this-flag": "Remove this flag", + "no-flags-hint": "This profile doesn't have any flags yet! Add some with the search box.", + "flag-search-placeholder": "Type to start searching", + "flag-search-no-flags": "No flags matched your search query.", + "flag-search-no-account-flags": "You haven't uploaded any flags yet.", + "flag-search-hint": "Can't find the flag you're looking for? Try using the search bar above.", + "flag-manage-your-flags": "Manage your flags" }, "cancel": "Cancel" } diff --git a/Foxnouns.Frontend/src/routes/settings/flags/+page.svelte b/Foxnouns.Frontend/src/routes/settings/flags/+page.svelte index 3e806f9..942e90f 100644 --- a/Foxnouns.Frontend/src/routes/settings/flags/+page.svelte +++ b/Foxnouns.Frontend/src/routes/settings/flags/+page.svelte @@ -78,10 +78,7 @@
- +

{$t("settings.flag-upload-title")}

- - + + diff --git a/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.svelte b/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.svelte index b4b38e2..c286c38 100644 --- a/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.svelte +++ b/Foxnouns.Frontend/src/routes/settings/members/[id]/+page.svelte @@ -6,6 +6,7 @@ import ApiError from "$api/error"; import log from "$lib/log"; import { Icon, InputGroup } from "@sveltestrap/sveltestrap"; + import InfoCircleFill from "svelte-bootstrap-icons/lib/InfoCircleFill.svelte"; import { t } from "$lib/i18n"; import AvatarEditor from "$components/editor/AvatarEditor.svelte"; import ErrorAlert from "$components/ErrorAlert.svelte"; @@ -133,7 +134,7 @@

- + {$t("edit-profile.unlisted-note")} {PUBLIC_BASE_URL.substring("https://".length)}/@{data.member.user.username}/{data.member diff --git a/Foxnouns.Frontend/src/routes/settings/profile/flags-links/+page.server.ts b/Foxnouns.Frontend/src/routes/settings/profile/flags-links/+page.server.ts new file mode 100644 index 0000000..0b3a452 --- /dev/null +++ b/Foxnouns.Frontend/src/routes/settings/profile/flags-links/+page.server.ts @@ -0,0 +1,7 @@ +import { apiRequest } from "$api"; +import type { PrideFlag } from "$api/models/user"; + +export const load = async ({ fetch, cookies }) => { + const flags = await apiRequest("GET", "/users/@me/flags", { fetch, cookies }); + return { flags }; +}; diff --git a/Foxnouns.Frontend/src/routes/settings/profile/flags-links/+page.svelte b/Foxnouns.Frontend/src/routes/settings/profile/flags-links/+page.svelte new file mode 100644 index 0000000..0273e6b --- /dev/null +++ b/Foxnouns.Frontend/src/routes/settings/profile/flags-links/+page.svelte @@ -0,0 +1,28 @@ + + +