Settings: Improve layout of a setting section and error
This commit is contained in:
parent
828358bd2e
commit
d0869c41cd
10 changed files with 77 additions and 33 deletions
|
|
@ -116,7 +116,11 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return <Flex flexDirection="column" style={{ gap: 12, marginBottom: 16 }}>{options}</Flex>;
|
return (
|
||||||
|
<div className="vc-plugins-settings">
|
||||||
|
{options}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMoreUsers(_label: string, count: number) {
|
function renderMoreUsers(_label: string, count: number) {
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,11 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
import { Switch } from "@components/settings/Switch";
|
||||||
import { PluginOptionBoolean } from "@utils/types";
|
import { PluginOptionBoolean } from "@utils/types";
|
||||||
import { Forms, React, Switch, useState } from "@webpack/common";
|
import { React, useState } from "@webpack/common";
|
||||||
|
|
||||||
import { resolveError, SettingProps } from "./Common";
|
import { resolveError, SettingProps, SettingsSection } from "./Common";
|
||||||
|
|
||||||
export function BooleanSetting({ option, pluginSettings, definedSettings, id, onChange }: SettingProps<PluginOptionBoolean>) {
|
export function BooleanSetting({ option, pluginSettings, definedSettings, id, onChange }: SettingProps<PluginOptionBoolean>) {
|
||||||
const def = pluginSettings[id] ?? option.default;
|
const def = pluginSettings[id] ?? option.default;
|
||||||
|
|
@ -40,20 +40,9 @@ export function BooleanSetting({ option, pluginSettings, definedSettings, id, on
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection>
|
<SettingsSection name={id} description={option.description} error={error} inlineSetting>
|
||||||
<Switch
|
<Switch checked={state} onChange={handleChange} />
|
||||||
value={state}
|
</SettingsSection>
|
||||||
onChange={handleChange}
|
|
||||||
note={option.description}
|
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
|
||||||
{...option.componentProps}
|
|
||||||
hideBorder
|
|
||||||
style={{ marginBottom: "0.5em" }}
|
|
||||||
>
|
|
||||||
{wordsToTitle(wordsFromCamel(id))}
|
|
||||||
</Switch>
|
|
||||||
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
|
|
||||||
</Forms.FormSection>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,15 @@
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Margins } from "@utils/margins";
|
import { classNameFactory } from "@api/Styles";
|
||||||
|
import { classes } from "@utils/misc";
|
||||||
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
import { wordsFromCamel, wordsToTitle } from "@utils/text";
|
||||||
import { DefinedSettings, PluginOptionBase } from "@utils/types";
|
import { DefinedSettings, PluginOptionBase } from "@utils/types";
|
||||||
import { Forms } from "@webpack/common";
|
import { Text } from "@webpack/common";
|
||||||
import { PropsWithChildren } from "react";
|
import { PropsWithChildren } from "react";
|
||||||
|
|
||||||
|
export const cl = classNameFactory("vc-plugins-setting-");
|
||||||
|
|
||||||
interface SettingBaseProps<T> {
|
interface SettingBaseProps<T> {
|
||||||
option: T;
|
option: T;
|
||||||
onChange(newValue: any): void;
|
onChange(newValue: any): void;
|
||||||
|
|
@ -34,15 +37,20 @@ interface SettingsSectionProps extends PropsWithChildren {
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
|
inlineSetting?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingsSection({ name, description, error, children }: SettingsSectionProps) {
|
export function SettingsSection({ name, description, error, inlineSetting, children }: SettingsSectionProps) {
|
||||||
return (
|
return (
|
||||||
<Forms.FormSection>
|
<div className={cl("section")}>
|
||||||
<Forms.FormTitle>{wordsToTitle(wordsFromCamel(name))}</Forms.FormTitle>
|
<div className={classes(cl("content"), inlineSetting && cl("inline"))}>
|
||||||
<Forms.FormText className={Margins.bottom20} type="description">{description}</Forms.FormText>
|
<div className={cl("label")}>
|
||||||
{children}
|
{name && <Text className={cl("title")} variant="text-md/medium">{wordsToTitle(wordsFromCamel(name))}</Text>}
|
||||||
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
|
{description && <Text className={cl("description")} variant="text-sm/normal">{description}</Text>}
|
||||||
</Forms.FormSection>
|
</div>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
{error && <Text className={cl("error")} variant="text-sm/normal">{error}</Text>}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,9 @@ export function NumberSetting({ option, pluginSettings, definedSettings, id, onC
|
||||||
<TextInput
|
<TextInput
|
||||||
type="number"
|
type="number"
|
||||||
pattern="-?[0-9]+"
|
pattern="-?[0-9]+"
|
||||||
|
placeholder={option.placeholder ?? "Enter a number"}
|
||||||
value={state}
|
value={state}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder={option.placeholder ?? "Enter a number"}
|
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,14 @@ export function SelectSetting({ option, pluginSettings, definedSettings, onChang
|
||||||
return (
|
return (
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<SettingsSection name={id} description={option.description} error={error}>
|
||||||
<Select
|
<Select
|
||||||
isDisabled={option.disabled?.call(definedSettings) ?? false}
|
|
||||||
options={option.options}
|
|
||||||
placeholder={option.placeholder ?? "Select an option"}
|
placeholder={option.placeholder ?? "Select an option"}
|
||||||
|
options={option.options}
|
||||||
maxVisibleItems={5}
|
maxVisibleItems={5}
|
||||||
closeOnSelect={true}
|
closeOnSelect={true}
|
||||||
select={handleChange}
|
select={handleChange}
|
||||||
isSelected={v => v === state}
|
isSelected={v => v === state}
|
||||||
serialize={v => String(v)}
|
serialize={v => String(v)}
|
||||||
|
isDisabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ export function SliderSetting({ option, pluginSettings, definedSettings, id, onC
|
||||||
return (
|
return (
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<SettingsSection name={id} description={option.description} error={error}>
|
||||||
<Slider
|
<Slider
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
|
||||||
markers={option.markers}
|
markers={option.markers}
|
||||||
minValue={option.markers[0]}
|
minValue={option.markers[0]}
|
||||||
maxValue={option.markers[option.markers.length - 1]}
|
maxValue={option.markers[option.markers.length - 1]}
|
||||||
|
|
@ -47,6 +46,7 @@ export function SliderSetting({ option, pluginSettings, definedSettings, id, onC
|
||||||
onValueChange={handleChange}
|
onValueChange={handleChange}
|
||||||
onValueRender={(v: number) => String(v.toFixed(2))}
|
onValueRender={(v: number) => String(v.toFixed(2))}
|
||||||
stickToMarkers={option.stickToMarkers ?? true}
|
stickToMarkers={option.stickToMarkers ?? true}
|
||||||
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
|
||||||
|
|
@ -40,11 +40,11 @@ export function TextSetting({ option, pluginSettings, definedSettings, id, onCha
|
||||||
<SettingsSection name={id} description={option.description} error={error}>
|
<SettingsSection name={id} description={option.description} error={error}>
|
||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
|
placeholder={option.placeholder ?? "Enter a value"}
|
||||||
value={state}
|
value={state}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
placeholder={option.placeholder ?? "Enter a value"}
|
|
||||||
disabled={option.disabled?.call(definedSettings) ?? false}
|
|
||||||
maxLength={null}
|
maxLength={null}
|
||||||
|
disabled={option.disabled?.call(definedSettings) ?? false}
|
||||||
{...option.componentProps}
|
{...option.componentProps}
|
||||||
/>
|
/>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import "./styles.css";
|
||||||
|
|
||||||
import { OptionType } from "@utils/types";
|
import { OptionType } from "@utils/types";
|
||||||
import { ComponentType } from "react";
|
import { ComponentType } from "react";
|
||||||
|
|
||||||
|
|
|
||||||
35
src/components/settings/tabs/plugins/components/styles.css
Normal file
35
src/components/settings/tabs/plugins/components/styles.css
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
.vc-plugins-setting-section {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugins-setting-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugins-setting-inline {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugins-setting-label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugins-setting-title {
|
||||||
|
color: var(--header-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugins-setting-description {
|
||||||
|
color: var(--header-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vc-plugins-setting-error {
|
||||||
|
color: var(--text-danger);
|
||||||
|
}
|
||||||
|
|
@ -74,3 +74,9 @@
|
||||||
.vc-plugins-info-icon:not(:hover, :focus) {
|
.vc-plugins-info-icon:not(:hover, :focus) {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vc-plugins-settings {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.25em;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue