pl-fe: allow user to change ui color
Signed-off-by: mkljczk <git@mkljczk.pl>
This commit is contained in:
parent
a535b80546
commit
156a0b0826
6 changed files with 41 additions and 4 deletions
|
@ -17,13 +17,16 @@ const FE_NAME = 'pl_fe';
|
||||||
type SettingOpts = {
|
type SettingOpts = {
|
||||||
/** Whether to display an alert when settings are saved. */
|
/** Whether to display an alert when settings are saved. */
|
||||||
showAlert?: boolean;
|
showAlert?: boolean;
|
||||||
|
save?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveSuccessMessage = defineMessage({ id: 'settings.save.success', defaultMessage: 'Your preferences have been saved!' });
|
const saveSuccessMessage = defineMessage({ id: 'settings.save.success', defaultMessage: 'Your preferences have been saved!' });
|
||||||
|
|
||||||
const changeSetting = (path: string[], value: any, opts?: SettingOpts) => {
|
const changeSetting = (path: string[], value: any, opts?: SettingOpts) => {
|
||||||
useSettingsStore.getState().changeSetting(path, value);
|
useSettingsStore.getState().changeSetting(path, value);
|
||||||
return saveSettings(opts);
|
|
||||||
|
if (opts?.save !== false) return saveSettings(opts);
|
||||||
|
return () => {};
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveSettings = (opts?: SettingOpts) =>
|
const saveSettings = (opts?: SettingOpts) =>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
import debounce from 'lodash/debounce';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
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 List, { ListItem } from 'pl-fe/components/list';
|
||||||
import Form from 'pl-fe/components/ui/form';
|
import Form from 'pl-fe/components/ui/form';
|
||||||
import { Mutliselect, SelectDropdown } from 'pl-fe/features/forms';
|
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 { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
|
||||||
import { useFeatures } from 'pl-fe/hooks/use-features';
|
import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
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 { 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 ThemeToggle from '../ui/components/theme-toggle';
|
||||||
|
|
||||||
|
import type { AppDispatch } from 'pl-fe/store';
|
||||||
|
|
||||||
const languages = {
|
const languages = {
|
||||||
en: 'English',
|
en: 'English',
|
||||||
ar: 'العربية',
|
ar: 'العربية',
|
||||||
|
@ -91,13 +97,19 @@ const messages = defineMessages({
|
||||||
content_type_plaintext: { id: 'preferences.options.content_type_plaintext', defaultMessage: 'Plain text' },
|
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_markdown: { id: 'preferences.options.content_type_markdown', defaultMessage: 'Markdown' },
|
||||||
content_type_html: { id: 'preferences.options.content_type_html', defaultMessage: 'HTML' },
|
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 Preferences = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
|
const plFeConfig = usePlFeConfig();
|
||||||
const instance = useInstance();
|
const instance = useInstance();
|
||||||
|
|
||||||
const onSelectChange = (event: React.ChangeEvent<HTMLSelectElement>, path: string[]) => {
|
const onSelectChange = (event: React.ChangeEvent<HTMLSelectElement>, path: string[]) => {
|
||||||
|
@ -109,7 +121,14 @@ const Preferences = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onToggleChange = (key: string[], checked: boolean) => {
|
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(() => ({
|
const displayMediaOptions = React.useMemo(() => ({
|
||||||
|
@ -152,7 +171,14 @@ const Preferences = () => {
|
||||||
<ListItem label={<FormattedMessage id='preferences.fields.theme' defaultMessage='Theme' />}>
|
<ListItem label={<FormattedMessage id='preferences.fields.theme' defaultMessage='Theme' />}>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</ListItem>
|
</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' />}>
|
<ListItem label={<FormattedMessage id='preferences.fields.language_label' defaultMessage='Display language' />}>
|
||||||
<SelectDropdown
|
<SelectDropdown
|
||||||
className='max-w-[200px]'
|
className='max-w-[200px]'
|
||||||
|
|
|
@ -283,4 +283,4 @@ const ColorListItem: React.FC<IColorListItem> = ({ label, value, onChange }) =>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { ThemeEditor as default };
|
export { ThemeEditor as default, PaletteListItem };
|
||||||
|
|
|
@ -1266,6 +1266,7 @@
|
||||||
"preferences.fields.wrench_label": "Display wrench reaction button",
|
"preferences.fields.wrench_label": "Display wrench reaction button",
|
||||||
"preferences.hints.demetricator": "Decrease social media anxiety by hiding all numbers from the site.",
|
"preferences.hints.demetricator": "Decrease social media anxiety by hiding all numbers from the site.",
|
||||||
"preferences.notifications.advanced": "Show all notification categories",
|
"preferences.notifications.advanced": "Show all notification categories",
|
||||||
|
"preferences.options.brand_color": "Base color",
|
||||||
"preferences.options.content_type_html": "HTML",
|
"preferences.options.content_type_html": "HTML",
|
||||||
"preferences.options.content_type_markdown": "Markdown",
|
"preferences.options.content_type_markdown": "Markdown",
|
||||||
"preferences.options.content_type_mfm": "MFM",
|
"preferences.options.content_type_mfm": "MFM",
|
||||||
|
|
|
@ -38,6 +38,12 @@ const settingsSchema = v.object({
|
||||||
knownLanguages: v.fallback(v.array(v.string()), []),
|
knownLanguages: v.fallback(v.array(v.string()), []),
|
||||||
showWrenchButton: v.fallback(v.boolean(), false),
|
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),
|
systemFont: v.fallback(v.boolean(), false),
|
||||||
demetricator: v.fallback(v.boolean(), false),
|
demetricator: v.fallback(v.boolean(), false),
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ const useSettingsStore = create<State>()(mutative((set) => ({
|
||||||
}),
|
}),
|
||||||
|
|
||||||
changeSetting: (path: string[], value: any) => set((state: State) => {
|
changeSetting: (path: string[], value: any) => set((state: State) => {
|
||||||
|
state.userSettings.saved = false;
|
||||||
changeSetting(state.userSettings, path, value);
|
changeSetting(state.userSettings, path, value);
|
||||||
|
|
||||||
mergeSettings(state);
|
mergeSettings(state);
|
||||||
|
|
Loading…
Reference in a new issue