ThemeEditor: allow importing a theme
This commit is contained in:
parent
c624fbcba3
commit
716cc311c7
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useRef, useState } from 'react';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import List, { ListItem } from 'soapbox/components/list';
|
||||||
import { Button, Column, Form, FormActions } from 'soapbox/components/ui';
|
import { Button, Column, Form, FormActions } from 'soapbox/components/ui';
|
||||||
import DropdownMenuContainer from 'soapbox/containers/dropdown-menu-container';
|
import DropdownMenuContainer from 'soapbox/containers/dropdown-menu-container';
|
||||||
import { useAppDispatch, useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
|
import { useAppDispatch, useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
|
||||||
|
import { normalizeSoapboxConfig } from 'soapbox/normalizers';
|
||||||
import { download } from 'soapbox/utils/download';
|
import { download } from 'soapbox/utils/download';
|
||||||
|
|
||||||
import Palette, { ColorGroup } from './components/palette';
|
import Palette, { ColorGroup } from './components/palette';
|
||||||
|
@ -18,6 +19,8 @@ const messages = defineMessages({
|
||||||
title: { id: 'admin.theme.title', defaultMessage: 'Theme' },
|
title: { id: 'admin.theme.title', defaultMessage: 'Theme' },
|
||||||
saved: { id: 'theme_editor.saved', defaultMessage: 'Theme updated!' },
|
saved: { id: 'theme_editor.saved', defaultMessage: 'Theme updated!' },
|
||||||
export: { id: 'theme_editor.export', defaultMessage: 'Export theme' },
|
export: { id: 'theme_editor.export', defaultMessage: 'Export theme' },
|
||||||
|
import: { id: 'theme_editor.import', defaultMessage: 'Import theme' },
|
||||||
|
importSuccess: { id: 'theme_editor.import_success', defaultMessage: 'Theme was successfully imported!' },
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IThemeEditor {
|
interface IThemeEditor {
|
||||||
|
@ -36,6 +39,8 @@ const ThemeEditor: React.FC<IThemeEditor> = () => {
|
||||||
const [submitting, setSubmitting] = useState(false);
|
const [submitting, setSubmitting] = useState(false);
|
||||||
const [resetKey, setResetKey] = useState(uuidv4());
|
const [resetKey, setResetKey] = useState(uuidv4());
|
||||||
|
|
||||||
|
const fileInput = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
const updateColors = (key: string) => {
|
const updateColors = (key: string) => {
|
||||||
return (newColors: ColorGroup) => {
|
return (newColors: ColorGroup) => {
|
||||||
setColors({
|
setColors({
|
||||||
|
@ -63,6 +68,23 @@ const ThemeEditor: React.FC<IThemeEditor> = () => {
|
||||||
download(data, 'theme.json');
|
download(data, 'theme.json');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const importTheme = () => {
|
||||||
|
fileInput.current?.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectFile: React.ChangeEventHandler<HTMLInputElement> = async (e) => {
|
||||||
|
const file = e.target.files?.item(0);
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
const text = await file.text();
|
||||||
|
const json = JSON.parse(text);
|
||||||
|
const colors = normalizeSoapboxConfig({ colors: json }).colors.toJS();
|
||||||
|
|
||||||
|
setColors(colors);
|
||||||
|
dispatch(snackbar.success(intl.formatMessage(messages.importSuccess)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async() => {
|
const handleSubmit = async() => {
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
|
@ -126,8 +148,13 @@ const ThemeEditor: React.FC<IThemeEditor> = () => {
|
||||||
<FormActions>
|
<FormActions>
|
||||||
<DropdownMenuContainer
|
<DropdownMenuContainer
|
||||||
items={[{
|
items={[{
|
||||||
|
text: intl.formatMessage(messages.import),
|
||||||
|
action: importTheme,
|
||||||
|
icon: require('@tabler/icons/upload.svg'),
|
||||||
|
}, {
|
||||||
text: intl.formatMessage(messages.export),
|
text: intl.formatMessage(messages.export),
|
||||||
action: exportTheme,
|
action: exportTheme,
|
||||||
|
icon: require('@tabler/icons/download.svg'),
|
||||||
}]}
|
}]}
|
||||||
/>
|
/>
|
||||||
<Button theme='secondary' onClick={resetTheme}>
|
<Button theme='secondary' onClick={resetTheme}>
|
||||||
|
@ -139,6 +166,15 @@ const ThemeEditor: React.FC<IThemeEditor> = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</FormActions>
|
</FormActions>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type='file'
|
||||||
|
ref={fileInput}
|
||||||
|
multiple
|
||||||
|
accept='application/json'
|
||||||
|
className='hidden'
|
||||||
|
onChange={handleSelectFile}
|
||||||
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue