feat(react/settings): port text formatting toolbar

This commit is contained in:
Elian Doran
2025-08-18 09:34:16 +03:00
parent 5614891d92
commit 71b627fbc7
7 changed files with 80 additions and 85 deletions

View File

@@ -2,7 +2,7 @@ import { Tooltip } from "bootstrap";
import { useEffect, useRef, useMemo, useCallback } from "preact/hooks";
import { escapeQuotes } from "../../services/utils";
import { ComponentChildren } from "preact";
import { memo } from "preact/compat";
import { CSSProperties, memo } from "preact/compat";
interface FormCheckboxProps {
name: string;
@@ -14,9 +14,10 @@ interface FormCheckboxProps {
currentValue: boolean;
disabled?: boolean;
onChange(newValue: boolean): void;
containerStyle?: CSSProperties;
}
const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint }: FormCheckboxProps) => {
const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
const labelRef = useRef<HTMLLabelElement>(null);
// Fix: Move useEffect outside conditional
@@ -46,7 +47,7 @@ const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint
const titleText = useMemo(() => hint ? escapeQuotes(hint) : undefined, [hint]);
return (
<div className="form-checkbox">
<div className="form-checkbox" style={containerStyle}>
<label
className="form-check-label tn-checkbox"
style={labelStyle}

View File

@@ -7,6 +7,7 @@ interface FormRadioProps {
values: {
value: string;
label: string | ComponentChildren;
inlineDescription?: string | ComponentChildren;
}[];
onChange(newValue: string): void;
}
@@ -14,9 +15,14 @@ interface FormRadioProps {
export default function FormRadioGroup({ values, ...restProps }: FormRadioProps) {
return (
<>
{(values || []).map(({ value, label }) => (
{(values || []).map(({ value, label, inlineDescription }) => (
<div className="form-checkbox">
<FormRadio value={value} label={label} {...restProps} labelClassName="form-check-label" />
<FormRadio
value={value}
label={label} inlineDescription={inlineDescription}
labelClassName="form-check-label"
{...restProps}
/>
</div>
))}
</>
@@ -31,7 +37,7 @@ export function FormInlineRadioGroup({ values, ...restProps }: FormRadioProps) {
)
}
function FormRadio({ name, value, label, currentValue, onChange, labelClassName }: Omit<FormRadioProps, "values"> & { value: string, label: ComponentChildren, labelClassName?: string }) {
function FormRadio({ name, value, label, currentValue, onChange, labelClassName, inlineDescription }: Omit<FormRadioProps, "values"> & { value: string, label: ComponentChildren, inlineDescription?: ComponentChildren, labelClassName?: string }) {
return (
<label className={`tn-radio ${labelClassName ?? ""}`}>
<input
@@ -42,7 +48,9 @@ function FormRadio({ name, value, label, currentValue, onChange, labelClassName
checked={value === currentValue}
onChange={e => onChange((e.target as HTMLInputElement).value)}
/>
{label}
{inlineDescription ?
<><strong>{label}</strong> - {inlineDescription}</>
: label}
</label>
)
}

View File

@@ -100,6 +100,16 @@ export function useSpacedUpdate(callback: () => Promise<void>, interval = 1000)
return spacedUpdateRef.current;
}
/**
* Allows a React component to read and write a Trilium option, while also watching for external changes.
*
* Conceptually, `useTriliumOption` works just like `useState`, but the value is also automatically updated if
* the option is changed somewhere else in the client.
*
* @param name the name of the option to listen for.
* @param needsRefresh whether to reload the frontend whenever the value is changed.
* @returns an array where the first value is the current option value and the second value is the setter.
*/
export function useTriliumOption(name: OptionNames, needsRefresh?: boolean): [string, (newValue: OptionValue) => Promise<void>] {
const initialValue = options.get(name);
const [ value, setValue ] = useState(initialValue);
@@ -127,8 +137,8 @@ export function useTriliumOption(name: OptionNames, needsRefresh?: boolean): [st
]
}
export function useTriliumOptionBool(name: OptionNames): [boolean, (newValue: boolean) => Promise<void>] {
const [ value, setValue ] = useTriliumOption(name);
export function useTriliumOptionBool(name: OptionNames, needsRefresh?: boolean): [boolean, (newValue: boolean) => Promise<void>] {
const [ value, setValue ] = useTriliumOption(name, needsRefresh);
return [
(value === "true"),
(newValue) => setValue(newValue ? "true" : "false")