diff options
author | 2024-03-25 18:32:24 +0100 | |
---|---|---|
committer | 2024-03-25 17:32:24 +0000 | |
commit | 8953f57d887c060c3b58f83c38d2010d27a45ef3 (patch) | |
tree | 05f8b1157a86afaa3ed0d6d0b87c9d0d37030362 /web/source | |
parent | [feature] Add healthcheck endpoints `/livez` and `/readyz` (#2783) (diff) | |
download | gotosocial-8953f57d887c060c3b58f83c38d2010d27a45ef3.tar.xz |
[feature] User-selectable preset CSS themes for accounts (#2777)
* [feature] User-selectable preset themes
* docs, more theme stuff
* lint, tests
* fix css name
* correct some little issues
* add another theme
* fix poll background
* okay last theme i swear
* make retrieval of apimodel themes more conventional
* preallocate stylesheet slices
Diffstat (limited to 'web/source')
-rw-r--r-- | web/source/settings/lib/query/user/index.ts | 7 | ||||
-rw-r--r-- | web/source/settings/lib/types/theme.ts | 24 | ||||
-rw-r--r-- | web/source/settings/style.css | 8 | ||||
-rw-r--r-- | web/source/settings/user/profile.tsx | 39 |
4 files changed, 73 insertions, 5 deletions
diff --git a/web/source/settings/lib/query/user/index.ts b/web/source/settings/lib/query/user/index.ts index 8cf64197b..8c4e5215b 100644 --- a/web/source/settings/lib/query/user/index.ts +++ b/web/source/settings/lib/query/user/index.ts @@ -23,6 +23,7 @@ import type { MoveAccountFormData, UpdateAliasesFormData } from "../../types/migration"; +import type { Theme } from "../../types/theme"; const extended = gtsApi.injectEndpoints({ endpoints: (build) => ({ @@ -66,6 +67,11 @@ const extended = gtsApi.injectEndpoints({ url: `/api/v1/accounts/move`, body: data }) + }), + accountThemes: build.query<Theme[], void>({ + query: () => ({ + url: `/api/v1/accounts/themes` + }) }) }) }); @@ -75,4 +81,5 @@ export const { usePasswordChangeMutation, useAliasAccountMutation, useMoveAccountMutation, + useAccountThemesQuery, } = extended; diff --git a/web/source/settings/lib/types/theme.ts b/web/source/settings/lib/types/theme.ts new file mode 100644 index 000000000..e605192f8 --- /dev/null +++ b/web/source/settings/lib/types/theme.ts @@ -0,0 +1,24 @@ +/* + GoToSocial + Copyright (C) GoToSocial Authors admin@gotosocial.org + SPDX-License-Identifier: AGPL-3.0-or-later + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +export interface Theme { + title: string; + description: string; + file_name: string; +} diff --git a/web/source/settings/style.css b/web/source/settings/style.css index 501e9dbef..372031203 100644 --- a/web/source/settings/style.css +++ b/web/source/settings/style.css @@ -439,7 +439,7 @@ section.with-sidebar > div, section.with-sidebar > form { display: grid; max-width: 60rem; grid-template-columns: 70% 30%; - grid-template-rows: 100%; + grid-template-rows: auto; gap: 1rem; .files { @@ -465,6 +465,12 @@ section.with-sidebar > div, section.with-sidebar > form { gap: 0.5rem; } } + + .theme, .form-field.radio { + display: flex; + flex-direction: column; + gap: 0.5rem; + } } .migration-details { diff --git a/web/source/settings/user/profile.tsx b/web/source/settings/user/profile.tsx index a03d4d247..cd4b17227 100644 --- a/web/source/settings/user/profile.tsx +++ b/web/source/settings/user/profile.tsx @@ -23,7 +23,8 @@ import { useTextInput, useFileInput, useBoolInput, - useFieldArrayInput + useFieldArrayInput, + useRadioInput } from "../lib/form"; import useFormSubmit from "../lib/form/submit"; @@ -33,14 +34,15 @@ import { TextInput, TextArea, FileInput, - Checkbox + Checkbox, + RadioGroup } from "../components/form/inputs"; import FormWithData from "../lib/form/form-with-data"; import FakeProfile from "../components/fake-profile"; import MutationButton from "../components/form/mutation-button"; -import { useInstanceV1Query } from "../lib/query"; +import { useAccountThemesQuery, useInstanceV1Query } from "../lib/query"; import { useUpdateCredentialsMutation } from "../lib/query/user"; import { useVerifyCredentialsQuery } from "../lib/query/oauth"; @@ -64,6 +66,7 @@ function UserProfileForm({ data: profile }) { - file header - bool enable_rss - string custom_css (if enabled) + - string theme */ const { data: instance } = useInstanceV1Query(); @@ -73,13 +76,24 @@ function UserProfileForm({ data: profile }) { maxPinnedFields: instance?.configuration?.accounts?.max_profile_fields ?? 6 }; }, [instance]); + + // Parse out available theme options into nice format. + const { data: themes } = useAccountThemesQuery(); + let themeOptions = { "": "Default" }; + themes?.forEach((theme) => { + let key = theme.file_name; + let value = theme.title; + if (theme.description) { + value += " - " + theme.description; + } + themeOptions[key] = value; + }); const form = { avatar: useFileInput("avatar", { withPreview: true }), header: useFileInput("header", { withPreview: true }), displayName: useTextInput("display_name", { source: profile }), note: useTextInput("note", { source: profile, valueSelector: (p) => p.source?.note }), - customCSS: useTextInput("custom_css", { source: profile, nosubmit: !instanceConfig.allowCustomCSS }), bot: useBoolInput("bot", { source: profile }), locked: useBoolInput("locked", { source: profile }), discoverable: useBoolInput("discoverable", { source: profile}), @@ -88,6 +102,11 @@ function UserProfileForm({ data: profile }) { defaultValue: profile?.source?.fields, length: instanceConfig.maxPinnedFields }), + customCSS: useTextInput("custom_css", { source: profile, nosubmit: !instanceConfig.allowCustomCSS }), + theme: useRadioInput("theme", { + source: profile, + options: themeOptions, + }), }; const [submitForm, result] = useFormSubmit(form, useUpdateCredentialsMutation(), { @@ -125,6 +144,18 @@ function UserProfileForm({ data: profile }) { /> </div> </div> + + <div className="theme"> + <div> + <b id="theme-label">Theme</b> + <br/> + <span>After choosing theme and saving, <a href={profile.url} target="_blank">open your profile</a> and refresh to see changes.</span> + </div> + <RadioGroup + aria-labelledby="theme-label" + field={form.theme} + /> + </div> </div> <div className="form-section-docs"> |