feat: each settings component handles state, + fix selects again lol
This commit is contained in:
parent
482caf0c5b
commit
74f9b1a022
|
@ -243,9 +243,11 @@ function ThemesTab() {
|
||||||
switch (varInfo.type) {
|
switch (varInfo.type) {
|
||||||
case "text":
|
case "text":
|
||||||
case "color":
|
case "color":
|
||||||
case "select":
|
|
||||||
normalizedValue = varInfo.default;
|
normalizedValue = varInfo.default;
|
||||||
break;
|
break;
|
||||||
|
case "select":
|
||||||
|
normalizedValue = varInfo.options.find(v => v.name === varInfo.default)!.value;
|
||||||
|
break;
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
normalizedValue = varInfo.default ? "1" : "0";
|
normalizedValue = varInfo.default ? "1" : "0";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import { useSettings } from "@api/Settings";
|
import { useSettings } from "@api/Settings";
|
||||||
import { Flex } from "@components/Flex";
|
import { Flex } from "@components/Flex";
|
||||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||||
import { Text, useState } from "@webpack/common";
|
import { Text } from "@webpack/common";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
import { UserstyleHeader } from "usercss-meta";
|
import { UserstyleHeader } from "usercss-meta";
|
||||||
|
|
||||||
|
@ -24,98 +24,79 @@ export function UserCSSSettingsModal({ modalProps, theme }: UserCSSSettingsModal
|
||||||
|
|
||||||
const controls: ReactNode[] = [];
|
const controls: ReactNode[] = [];
|
||||||
|
|
||||||
function updateSetting(key: string, value: string, setValue: (value: string) => void) {
|
function updateSetting(key: string, value: string) {
|
||||||
themeSettings[key] = value;
|
themeSettings[key] = value;
|
||||||
setValue(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [name, varInfo] of Object.entries(theme.vars)) {
|
for (const [name, varInfo] of Object.entries(theme.vars)) {
|
||||||
switch (varInfo.type) {
|
switch (varInfo.type) {
|
||||||
case "text": {
|
case "text": {
|
||||||
const [value, setValue] = useState(themeSettings[name]);
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<SettingTextComponent
|
<SettingTextComponent
|
||||||
label={varInfo.label}
|
label={varInfo.label}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
themeSettings={themeSettings}
|
||||||
onChange={v => updateSetting(name, v, setValue)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "checkbox": {
|
case "checkbox": {
|
||||||
const [value, setValue] = useState(themeSettings[name]);
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<SettingBooleanComponent
|
<SettingBooleanComponent
|
||||||
label={varInfo.label}
|
label={varInfo.label}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
themeSettings={themeSettings}
|
||||||
onChange={v => updateSetting(name, v, setValue)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "color": {
|
case "color": {
|
||||||
const [value, setValue] = useState(themeSettings[name]);
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<SettingColorComponent
|
<SettingColorComponent
|
||||||
label={varInfo.label}
|
label={varInfo.label}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
themeSettings={themeSettings}
|
||||||
onChange={v => updateSetting(name, v, setValue)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "number": {
|
case "number": {
|
||||||
const [value, setValue] = useState(themeSettings[name]);
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<SettingNumberComponent
|
<SettingNumberComponent
|
||||||
label={varInfo.label}
|
label={varInfo.label}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
themeSettings={themeSettings}
|
||||||
onChange={v => updateSetting(name, v, setValue)}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "select": {
|
case "select": {
|
||||||
const [value, setValue] = useState(themeSettings[name]);
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<SettingSelectComponent
|
<SettingSelectComponent
|
||||||
label={varInfo.label}
|
label={varInfo.label}
|
||||||
name={name}
|
name={name}
|
||||||
options={varInfo.options}
|
options={varInfo.options}
|
||||||
value={value}
|
|
||||||
default={varInfo.default}
|
default={varInfo.default}
|
||||||
onChange={v => updateSetting(name, v, setValue)}
|
themeSettings={themeSettings}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "range": {
|
case "range": {
|
||||||
const [value, setValue] = useState(themeSettings[name]);
|
|
||||||
|
|
||||||
controls.push(
|
controls.push(
|
||||||
<SettingRangeComponent
|
<SettingRangeComponent
|
||||||
label={varInfo.label}
|
label={varInfo.label}
|
||||||
name={name}
|
name={name}
|
||||||
value={value}
|
|
||||||
default={varInfo.default}
|
default={varInfo.default}
|
||||||
min={varInfo.min}
|
min={varInfo.min}
|
||||||
max={varInfo.max}
|
max={varInfo.max}
|
||||||
step={varInfo.step}
|
step={varInfo.step}
|
||||||
onChange={v => updateSetting(name, v, setValue)}
|
themeSettings={themeSettings}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -4,22 +4,31 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Forms, Switch } from "@webpack/common";
|
import { Forms, Switch, useState } from "@webpack/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
themeSettings: Record<string, string>;
|
||||||
onChange: (value: string) => void;
|
}
|
||||||
|
|
||||||
|
export function SettingBooleanComponent({ label, name, themeSettings }: Props) {
|
||||||
|
const [value, setValue] = useState(themeSettings[name]);
|
||||||
|
|
||||||
|
function handleChange(value: boolean) {
|
||||||
|
const corrected = value ? "1" : "0";
|
||||||
|
|
||||||
|
setValue(corrected);
|
||||||
|
|
||||||
|
themeSettings[name] = corrected;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingBooleanComponent({ label, name, value, onChange }: Props) {
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<Switch
|
<Switch
|
||||||
key={name}
|
key={name}
|
||||||
value={value === "1"}
|
value={value === "1"}
|
||||||
onChange={v => onChange(v ? "1" : "0")}
|
onChange={handleChange}
|
||||||
hideBorder
|
hideBorder
|
||||||
style={{ marginBottom: "0.5em" }}
|
style={{ marginBottom: "0.5em" }}
|
||||||
>
|
>
|
||||||
|
|
|
@ -55,11 +55,20 @@ function ColorPicker(props: ColorPickerProps) {
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
themeSettings: Record<string, string>;
|
||||||
onChange: (value: string) => void;
|
}
|
||||||
|
|
||||||
|
export function SettingColorComponent({ label, name, themeSettings }: Props) {
|
||||||
|
const [value, setValue] = useState(themeSettings[name]);
|
||||||
|
|
||||||
|
function handleChange(value: number) {
|
||||||
|
const corrected = "#" + (value?.toString(16).padStart(6, "0") ?? "000000");
|
||||||
|
|
||||||
|
setValue(corrected);
|
||||||
|
|
||||||
|
themeSettings[name] = corrected;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingColorComponent({ label, name, value, onChange }: Props) {
|
|
||||||
const normalizedValue = TinyColor(value).toHex();
|
const normalizedValue = TinyColor(value).toHex();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -68,7 +77,7 @@ export function SettingColorComponent({ label, name, value, onChange }: Props) {
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
key={name}
|
key={name}
|
||||||
value={parseInt(normalizedValue, 16)}
|
value={parseInt(normalizedValue, 16)}
|
||||||
onChange={v => onChange("#" + (v?.toString(16).padStart(6, "0") ?? "000000"))}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,16 +4,23 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Forms, TextInput } from "@webpack/common";
|
import { Forms, TextInput, useState } from "@webpack/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
themeSettings: Record<string, string>;
|
||||||
onChange: (value: string) => void;
|
}
|
||||||
|
|
||||||
|
export function SettingNumberComponent({ label, name, themeSettings }: Props) {
|
||||||
|
const [value, setValue] = useState(themeSettings[name]);
|
||||||
|
|
||||||
|
function handleChange(value: string) {
|
||||||
|
setValue(value);
|
||||||
|
|
||||||
|
themeSettings[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingNumberComponent({ label, name, value, onChange }: Props) {
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<Forms.FormTitle tag="h5">{label}</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">{label}</Forms.FormTitle>
|
||||||
|
@ -22,7 +29,7 @@ export function SettingNumberComponent({ label, name, value, onChange }: Props)
|
||||||
pattern="-?[0-9]+"
|
pattern="-?[0-9]+"
|
||||||
key={name}
|
key={name}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,20 +4,29 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Forms, Slider } from "@webpack/common";
|
import { Forms, Slider, useState } from "@webpack/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
|
||||||
default: number;
|
default: number;
|
||||||
min?: number;
|
min?: number;
|
||||||
max?: number;
|
max?: number;
|
||||||
step?: number;
|
step?: number;
|
||||||
onChange: (value: string) => void;
|
themeSettings: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingRangeComponent({ label, name, default: def, min, max, step, themeSettings }: Props) {
|
||||||
|
const [value, setValue] = useState(themeSettings[name]);
|
||||||
|
|
||||||
|
function handleChange(value: number) {
|
||||||
|
const corrected = value.toString();
|
||||||
|
|
||||||
|
setValue(corrected);
|
||||||
|
|
||||||
|
themeSettings[name] = corrected;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingRangeComponent({ label, name, value, default: def, min, max, step, onChange }: Props) {
|
|
||||||
const markers: number[] = [];
|
const markers: number[] = [];
|
||||||
|
|
||||||
// defaults taken from https://github.com/openstyles/stylus/wiki/Writing-UserCSS#default-value
|
// defaults taken from https://github.com/openstyles/stylus/wiki/Writing-UserCSS#default-value
|
||||||
|
@ -31,7 +40,7 @@ export function SettingRangeComponent({ label, name, value, default: def, min, m
|
||||||
<Slider
|
<Slider
|
||||||
initialValue={parseInt(value, 10)}
|
initialValue={parseInt(value, 10)}
|
||||||
defaultValue={def}
|
defaultValue={def}
|
||||||
onValueChange={v => onChange(v.toString())}
|
onValueChange={handleChange}
|
||||||
minValue={min}
|
minValue={min}
|
||||||
maxValue={max}
|
maxValue={max}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { identity } from "@utils/misc";
|
import { identity } from "@utils/misc";
|
||||||
import { ComponentTypes, Forms, Select } from "@webpack/common";
|
import { ComponentTypes, Forms, Select, useState } from "@webpack/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
|
@ -15,12 +15,19 @@ interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
}[];
|
}[];
|
||||||
value: string;
|
|
||||||
default: string;
|
default: string;
|
||||||
onChange: (value: string) => void;
|
themeSettings: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SettingSelectComponent({ label, name, options, default: def, themeSettings }: Props) {
|
||||||
|
const [value, setValue] = useState(themeSettings[name]);
|
||||||
|
|
||||||
|
function handleChange(value: string) {
|
||||||
|
setValue(value);
|
||||||
|
|
||||||
|
themeSettings[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingSelectComponent({ label, name, options, value, default: def, onChange }: Props) {
|
|
||||||
const opts = options.map(option => ({
|
const opts = options.map(option => ({
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
|
||||||
|
@ -39,7 +46,7 @@ export function SettingSelectComponent({ label, name, options, value, default: d
|
||||||
options={opts}
|
options={opts}
|
||||||
closeOnSelect={true}
|
closeOnSelect={true}
|
||||||
|
|
||||||
select={onChange}
|
select={handleChange}
|
||||||
isSelected={v => v === value}
|
isSelected={v => v === value}
|
||||||
serialize={identity}
|
serialize={identity}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -4,23 +4,30 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Forms, TextInput } from "@webpack/common";
|
import { Forms, TextInput, useState } from "@webpack/common";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
label: string;
|
label: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
themeSettings: Record<string, string>;
|
||||||
onChange: (value: string) => void;
|
}
|
||||||
|
|
||||||
|
export function SettingTextComponent({ label, name, themeSettings }: Props) {
|
||||||
|
const [value, setValue] = useState(themeSettings[name]);
|
||||||
|
|
||||||
|
function handleChange(value: string) {
|
||||||
|
setValue(value);
|
||||||
|
|
||||||
|
themeSettings[name] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingTextComponent({ label, name, value, onChange }: Props) {
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection>
|
<Forms.FormSection>
|
||||||
<Forms.FormTitle tag="h5">{label}</Forms.FormTitle>
|
<Forms.FormTitle tag="h5">{label}</Forms.FormTitle>
|
||||||
<TextInput
|
<TextInput
|
||||||
key={name}
|
key={name}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Forms.FormSection>
|
</Forms.FormSection>
|
||||||
);
|
);
|
||||||
|
|
|
@ -88,11 +88,6 @@ export async function compileUsercss(fileName: string) {
|
||||||
varsToPass[k] = `${varsToPass[k]}${v.units ?? "px"}`;
|
varsToPass[k] = `${varsToPass[k]}${v.units ?? "px"}`;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case "select": {
|
|
||||||
varsToPass[k] = v.options.find(opt => opt.name === varsToPass[k])!.value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue