pl-fe: allow user to change ui color

Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
mkljczk 2024-12-06 11:12:02 +01:00
parent a535b80546
commit 156a0b0826
6 changed files with 41 additions and 4 deletions

View file

@ -17,13 +17,16 @@ const FE_NAME = 'pl_fe';
type SettingOpts = {
/** Whether to display an alert when settings are saved. */
showAlert?: boolean;
save?: boolean;
}
const saveSuccessMessage = defineMessage({ id: 'settings.save.success', defaultMessage: 'Your preferences have been saved!' });
const changeSetting = (path: string[], value: any, opts?: SettingOpts) => {
useSettingsStore.getState().changeSetting(path, value);
return saveSettings(opts);
if (opts?.save !== false) return saveSettings(opts);
return () => {};
};
const saveSettings = (opts?: SettingOpts) =>

View file

@ -1,7 +1,8 @@
import debounce from 'lodash/debounce';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { changeSetting } from 'pl-fe/actions/settings';
import { changeSetting, saveSettings } from 'pl-fe/actions/settings';
import List, { ListItem } from 'pl-fe/components/list';
import Form from 'pl-fe/components/ui/form';
import { Mutliselect, SelectDropdown } from 'pl-fe/features/forms';
@ -9,10 +10,15 @@ import SettingToggle from 'pl-fe/features/notifications/components/setting-toggl
import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useFeatures } from 'pl-fe/hooks/use-features';
import { useInstance } from 'pl-fe/hooks/use-instance';
import { usePlFeConfig } from 'pl-fe/hooks/use-pl-fe-config';
import { useSettings } from 'pl-fe/hooks/use-settings';
import colors from 'pl-fe/utils/colors';
import { PaletteListItem } from '../theme-editor';
import ThemeToggle from '../ui/components/theme-toggle';
import type { AppDispatch } from 'pl-fe/store';
const languages = {
en: 'English',
ar: 'العربية',
@ -91,13 +97,19 @@ const messages = defineMessages({
content_type_plaintext: { id: 'preferences.options.content_type_plaintext', defaultMessage: 'Plain text' },
content_type_markdown: { id: 'preferences.options.content_type_markdown', defaultMessage: 'Markdown' },
content_type_html: { id: 'preferences.options.content_type_html', defaultMessage: 'HTML' },
brandColor: { id: 'preferences.options.brand_color', defaultMessage: 'Base color' },
});
const debouncedSave = debounce((dispatch: AppDispatch) => {
dispatch(saveSettings({ showAlert: true }));
}, 1000);
const Preferences = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const features = useFeatures();
const settings = useSettings();
const plFeConfig = usePlFeConfig();
const instance = useInstance();
const onSelectChange = (event: React.ChangeEvent<HTMLSelectElement>, path: string[]) => {
@ -109,7 +121,14 @@ const Preferences = () => {
};
const onToggleChange = (key: string[], checked: boolean) => {
dispatch(changeSetting(key, checked, { showAlert: true }));
dispatch(changeSetting(key, checked));
};
const onBrandColorChange = (brandColor: string) => {
if (!settings.theme?.brandColor && brandColor === (plFeConfig.brandColor || '#d80482')) return;
dispatch(changeSetting(['theme', 'brandColor'], brandColor, { showAlert: true, save: false }));
debouncedSave(dispatch);
};
const displayMediaOptions = React.useMemo(() => ({
@ -152,7 +171,14 @@ const Preferences = () => {
<ListItem label={<FormattedMessage id='preferences.fields.theme' defaultMessage='Theme' />}>
<ThemeToggle />
</ListItem>
<PaletteListItem
label={intl.formatMessage(messages.brandColor)}
palette={colors(settings.theme?.brandColor || plFeConfig.brandColor || '#d80482')}
onChange={(palette) => onBrandColorChange(palette['500'])}
/>
</List>
<List>
<ListItem label={<FormattedMessage id='preferences.fields.language_label' defaultMessage='Display language' />}>
<SelectDropdown
className='max-w-[200px]'

View file

@ -283,4 +283,4 @@ const ColorListItem: React.FC<IColorListItem> = ({ label, value, onChange }) =>
);
};
export { ThemeEditor as default };
export { ThemeEditor as default, PaletteListItem };

View file

@ -1266,6 +1266,7 @@
"preferences.fields.wrench_label": "Display wrench reaction button",
"preferences.hints.demetricator": "Decrease social media anxiety by hiding all numbers from the site.",
"preferences.notifications.advanced": "Show all notification categories",
"preferences.options.brand_color": "Base color",
"preferences.options.content_type_html": "HTML",
"preferences.options.content_type_markdown": "Markdown",
"preferences.options.content_type_mfm": "MFM",

View file

@ -38,6 +38,12 @@ const settingsSchema = v.object({
knownLanguages: v.fallback(v.array(v.string()), []),
showWrenchButton: v.fallback(v.boolean(), false),
theme: v.fallback(v.optional(v.object({
brandColor: v.fallback(v.string(), ''),
accentColor: v.fallback(v.string(), ''),
colors: v.any(),
})), undefined),
systemFont: v.fallback(v.boolean(), false),
demetricator: v.fallback(v.boolean(), false),

View file

@ -62,6 +62,7 @@ const useSettingsStore = create<State>()(mutative((set) => ({
}),
changeSetting: (path: string[], value: any) => set((state: State) => {
state.userSettings.saved = false;
changeSetting(state.userSettings, path, value);
mergeSettings(state);