mirror of
https://github.com/zadam/trilium.git
synced 2025-10-28 08:46:43 +01:00
refactor(react/settings): add names to all form groups
This commit is contained in:
@@ -107,7 +107,7 @@ function AddLinkDialogComponent() {
|
||||
}}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("add_link.note")}>
|
||||
<FormGroup label={t("add_link.note")} name="note">
|
||||
<NoteAutocomplete
|
||||
inputRef={autocompleteRef}
|
||||
onChange={setSuggestion}
|
||||
|
||||
@@ -64,7 +64,7 @@ function BranchPrefixDialogComponent() {
|
||||
footer={<Button text={t("branch_prefix.save")} />}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("branch_prefix.prefix")}>
|
||||
<FormGroup label={t("branch_prefix.prefix")} name="prefix">
|
||||
<div class="input-group">
|
||||
<input class="branch-prefix-input form-control" value={prefix} ref={branchInput}
|
||||
onChange={(e) => setPrefix((e.target as HTMLInputElement).value)} />
|
||||
|
||||
@@ -69,15 +69,15 @@ function CloneToDialogComponent() {
|
||||
>
|
||||
<h5>{t("clone_to.notes_to_clone")}</h5>
|
||||
<NoteList style={{ maxHeight: "200px", overflow: "auto" }} noteIds={clonedNoteIds} />
|
||||
<FormGroup label={t("clone_to.target_parent_note")}>
|
||||
<FormGroup name="target-parent-note" label={t("clone_to.target_parent_note")}>
|
||||
<NoteAutocomplete
|
||||
placeholder={t("clone_to.search_for_note_by_its_name")}
|
||||
onChange={setSuggestion}
|
||||
inputRef={autoCompleteRef}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup label={t("clone_to.prefix_optional")} title={t("clone_to.cloned_note_prefix_title")}>
|
||||
<FormTextBox name="clone-prefix" onChange={setPrefix} />
|
||||
<FormGroup name="clone-prefix" label={t("clone_to.prefix_optional")} title={t("clone_to.cloned_note_prefix_title")}>
|
||||
<FormTextBox onChange={setPrefix} />
|
||||
</FormGroup>
|
||||
</Modal>
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import tree from "../../services/tree";
|
||||
import Button from "../react/Button";
|
||||
import FormCheckbox from "../react/FormCheckbox";
|
||||
import FormFileUpload from "../react/FormFileUpload";
|
||||
import FormGroup from "../react/FormGroup";
|
||||
import FormGroup, { FormMultiGroup } from "../react/FormGroup";
|
||||
import Modal from "../react/Modal";
|
||||
import RawHtml from "../react/RawHtml";
|
||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||
@@ -55,11 +55,11 @@ function ImportDialogComponent() {
|
||||
footer={<Button text={t("import.import")} primary disabled={!files} />}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
|
||||
<FormGroup name="files" label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
|
||||
<FormFileUpload multiple onChange={setFiles} />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("import.options")}>
|
||||
<FormMultiGroup label={t("import.options")}>
|
||||
<FormCheckbox
|
||||
name="safe-import" hint={t("import.safeImportTooltip")} label={t("import.safeImport")}
|
||||
currentValue={safeImport} onChange={setSafeImport}
|
||||
@@ -84,7 +84,7 @@ function ImportDialogComponent() {
|
||||
name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")}
|
||||
currentValue={replaceUnderscoresWithSpaces} onChange={setReplaceUnderscoresWithSpaces}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FormMultiGroup>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ function IncludeNoteDialogComponent() {
|
||||
footer={<Button text={t("include_note.button_include")} keyboardShortcut="Enter" />}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("include_note.label_note")}>
|
||||
<FormGroup name="note" label={t("include_note.label_note")}>
|
||||
<NoteAutocomplete
|
||||
placeholder={t("include_note.placeholder_search")}
|
||||
onChange={setSuggestion}
|
||||
@@ -55,8 +55,9 @@ function IncludeNoteDialogComponent() {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("include_note.box_size_prompt")}>
|
||||
<FormRadioGroup name="include-note-box-size"
|
||||
<FormGroup name="include-note-box-size" label={t("include_note.box_size_prompt")}>
|
||||
<FormRadioGroup
|
||||
name="include-note-box-size"
|
||||
currentValue={boxSize} onChange={setBoxSize}
|
||||
values={[
|
||||
{ label: t("include_note.box_size_small"), value: "small" },
|
||||
|
||||
@@ -57,7 +57,7 @@ function MoveToDialogComponent() {
|
||||
<h5>{t("move_to.notes_to_move")}</h5>
|
||||
<NoteList branchIds={movedBranchIds} />
|
||||
|
||||
<FormGroup label={t("move_to.target_parent_note")}>
|
||||
<FormGroup name="parent-note" label={t("move_to.target_parent_note")}>
|
||||
<NoteAutocomplete
|
||||
onChange={setSuggestion}
|
||||
inputRef={autoCompleteRef}
|
||||
|
||||
@@ -83,7 +83,7 @@ function NoteTypeChooserDialogComponent() {
|
||||
show={shown}
|
||||
stackable
|
||||
>
|
||||
<FormGroup label={t("note_type_chooser.change_path_prompt")}>
|
||||
<FormGroup name="parent-note" label={t("note_type_chooser.change_path_prompt")}>
|
||||
<NoteAutocomplete
|
||||
onChange={setParentNote}
|
||||
placeholder={t("note_type_chooser.search_placeholder")}
|
||||
@@ -95,7 +95,7 @@ function NoteTypeChooserDialogComponent() {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("note_type_chooser.modal_body")}>
|
||||
<FormGroup name="note-type" label={t("note_type_chooser.modal_body")}>
|
||||
<FormList onSelect={onNoteTypeSelected}>
|
||||
{noteTypes.map((_item) => {
|
||||
if (_item.title === "----") {
|
||||
|
||||
@@ -74,9 +74,8 @@ function PromptDialogComponent() {
|
||||
show={shown}
|
||||
stackable
|
||||
>
|
||||
<FormGroup label={opts.current?.message} labelRef={labelRef}>
|
||||
<FormGroup name="prompt-dialog-answer" label={opts.current?.message} labelRef={labelRef}>
|
||||
<FormTextBox
|
||||
name="prompt-dialog-answer"
|
||||
inputRef={answerRef}
|
||||
currentValue={value} onChange={setValue}
|
||||
readOnly={opts.current?.readOnly}
|
||||
|
||||
@@ -83,11 +83,8 @@ function SortChildNotesDialogComponent() {
|
||||
label={t("sort_child_notes.sort_with_respect_to_different_character_sorting")}
|
||||
currentValue={sortNatural} onChange={setSortNatural}
|
||||
/>
|
||||
<FormGroup className="form-check" label={t("sort_child_notes.natural_sort_language")} description={t("sort_child_notes.the_language_code_for_natural_sort")}>
|
||||
<FormTextBox
|
||||
name="sort-locale"
|
||||
currentValue={sortLocale} onChange={setSortLocale}
|
||||
/>
|
||||
<FormGroup name="sort-locale" className="form-check" label={t("sort_child_notes.natural_sort_language")} description={t("sort_child_notes.the_language_code_for_natural_sort")}>
|
||||
<FormTextBox currentValue={sortLocale} onChange={setSortLocale} />
|
||||
</FormGroup>
|
||||
</Modal>
|
||||
)
|
||||
|
||||
@@ -51,13 +51,12 @@ function UploadAttachmentsDialogComponent() {
|
||||
onHidden={() => setShown(false)}
|
||||
show={shown}
|
||||
>
|
||||
<FormGroup label={t("upload_attachments.choose_files")} description={description}>
|
||||
<FormGroup name="files" label={t("upload_attachments.choose_files")} description={description}>
|
||||
<FormFileUpload onChange={setFiles} multiple />
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("upload_attachments.options")}>
|
||||
<FormCheckbox
|
||||
name="shrink-images"
|
||||
<FormGroup name="shrink-images" label={t("upload_attachments.options")}>
|
||||
<FormCheckbox
|
||||
hint={t("upload_attachments.tooltip")} label={t("upload_attachments.shrink_images")}
|
||||
currentValue={shrinkImages} onChange={setShrinkImages}
|
||||
/>
|
||||
|
||||
@@ -3,9 +3,11 @@ import { useEffect, useRef, useMemo, useCallback } from "preact/hooks";
|
||||
import { escapeQuotes } from "../../services/utils";
|
||||
import { ComponentChildren } from "preact";
|
||||
import { CSSProperties, memo } from "preact/compat";
|
||||
import { useUniqueName } from "./hooks";
|
||||
|
||||
interface FormCheckboxProps {
|
||||
id?: string;
|
||||
name?: string;
|
||||
label: string | ComponentChildren;
|
||||
/**
|
||||
* If set, the checkbox label will be underlined and dotted, indicating a hint. When hovered, it will show the hint text.
|
||||
@@ -17,7 +19,8 @@ interface FormCheckboxProps {
|
||||
containerStyle?: CSSProperties;
|
||||
}
|
||||
|
||||
const FormCheckbox = memo(({ id, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
|
||||
const FormCheckbox = memo(({ name, id: _id, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
|
||||
const id = _id ?? useUniqueName(name);
|
||||
const labelRef = useRef<HTMLLabelElement>(null);
|
||||
|
||||
// Fix: Move useEffect outside conditional
|
||||
|
||||
@@ -28,4 +28,16 @@ export default function FormGroup({ name, label, title, className, children, des
|
||||
{description && <small className="form-text">{description}</small>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link FormGroup} but allows more than one child. Due to this behaviour, there is no automatic ID assignment.
|
||||
*/
|
||||
export function FormMultiGroup({ label, children }: { label: string, children: ComponentChildren }) {
|
||||
return (
|
||||
<div className={`form-group`}>
|
||||
{label && <label>{label}</label>}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -31,9 +31,9 @@ export default function FormRadioGroup({ values, ...restProps }: FormRadioProps)
|
||||
|
||||
export function FormInlineRadioGroup({ values, ...restProps }: FormRadioProps) {
|
||||
return (
|
||||
<>
|
||||
<div role="group">
|
||||
{values.map(({ value, label }) => (<FormRadio value={value} label={label} {...restProps} />))}
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { RefObject } from "preact";
|
||||
import type { CSSProperties } from "preact/compat";
|
||||
|
||||
interface NoteAutocompleteProps {
|
||||
id?: string;
|
||||
inputRef?: RefObject<HTMLInputElement>;
|
||||
text?: string;
|
||||
placeholder?: string;
|
||||
@@ -18,7 +19,7 @@ interface NoteAutocompleteProps {
|
||||
noteId?: string;
|
||||
}
|
||||
|
||||
export default function NoteAutocomplete({ inputRef: _ref, text, placeholder, onChange, onTextChange, container, containerStyle, opts, noteId, noteIdChanged }: NoteAutocompleteProps) {
|
||||
export default function NoteAutocomplete({ id, inputRef: _ref, text, placeholder, onChange, onTextChange, container, containerStyle, opts, noteId, noteIdChanged }: NoteAutocompleteProps) {
|
||||
const ref = _ref ?? useRef<HTMLInputElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -74,6 +75,7 @@ export default function NoteAutocomplete({ inputRef: _ref, text, placeholder, on
|
||||
return (
|
||||
<div className="input-group" style={containerStyle}>
|
||||
<input
|
||||
id={id}
|
||||
ref={ref}
|
||||
className="note-autocomplete form-control"
|
||||
placeholder={placeholder ?? t("add_link.search_note")} />
|
||||
|
||||
@@ -190,6 +190,6 @@ export function useTriliumOptions<T extends OptionNames>(...names: T[]) {
|
||||
* @param prefix a prefix to add to the unique name.
|
||||
* @returns a name with the given prefix and a random alpanumeric string appended to it.
|
||||
*/
|
||||
export function useUniqueName(prefix: string) {
|
||||
return useMemo(() => prefix + "-" + utils.randomString(10), [ prefix]);
|
||||
export function useUniqueName(prefix?: string) {
|
||||
return useMemo(() => (prefix ? prefix + "-" : "") + utils.randomString(10), [ prefix ]);
|
||||
}
|
||||
@@ -28,9 +28,8 @@ function EnableAiSettings() {
|
||||
return (
|
||||
<>
|
||||
<OptionsSection title={t("ai_llm.title")}>
|
||||
<FormGroup description={t("ai_llm.enable_ai_description")}>
|
||||
<FormCheckbox
|
||||
name="ai-enabled"
|
||||
<FormGroup name="ai-enabled" description={t("ai_llm.enable_ai_description")}>
|
||||
<FormCheckbox
|
||||
label={t("ai_llm.enable_ai_features")}
|
||||
currentValue={aiEnabled} onChange={(isEnabled) => {
|
||||
if (isEnabled) {
|
||||
@@ -56,7 +55,7 @@ function ProviderSettings() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("ai_llm.provider_configuration")}>
|
||||
<FormGroup label={t("ai_llm.selected_provider")} description={t("ai_llm.selected_provider_description")}>
|
||||
<FormGroup name="selected-provider" label={t("ai_llm.selected_provider")} description={t("ai_llm.selected_provider_description")}>
|
||||
<FormSelect
|
||||
values={[
|
||||
{ value: "", text: t("ai_llm.select_provider") },
|
||||
@@ -103,15 +102,14 @@ function ProviderSettings() {
|
||||
<></>
|
||||
}
|
||||
|
||||
<FormGroup label={t("ai_llm.temperature")} description={t("ai_llm.temperature_description")}>
|
||||
<FormGroup name="ai-temperature" label={t("ai_llm.temperature")} description={t("ai_llm.temperature_description")}>
|
||||
<FormTextBox
|
||||
name="ai-temperature"
|
||||
type="number" min="0" max="2" step="0.1"
|
||||
currentValue={aiTemperature} onChange={setAiTemperature}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("ai_llm.system_prompt")} description={t("ai_llm.system_prompt_description")}>
|
||||
<FormGroup name="system-prompt" label={t("ai_llm.system_prompt")} description={t("ai_llm.system_prompt_description")}>
|
||||
<FormTextArea
|
||||
rows={3}
|
||||
currentValue={aiSystemPrompt} onBlur={setAiSystemPrompt}
|
||||
@@ -149,7 +147,7 @@ function SingleProviderSettings({ provider, title, apiKeyDescription, baseUrlDes
|
||||
{!isValid && <Admonition type="caution">{validationErrorMessage}</Admonition> }
|
||||
|
||||
{apiKeyOption && (
|
||||
<FormGroup label={t("ai_llm.api_key")} description={apiKeyDescription}>
|
||||
<FormGroup name="api-key" label={t("ai_llm.api_key")} description={apiKeyDescription}>
|
||||
<FormTextBox
|
||||
type="password" autoComplete="off"
|
||||
currentValue={apiKey} onChange={setApiKey}
|
||||
@@ -157,14 +155,14 @@ function SingleProviderSettings({ provider, title, apiKeyDescription, baseUrlDes
|
||||
</FormGroup>
|
||||
)}
|
||||
|
||||
<FormGroup label={t("ai_llm.url")} description={baseUrlDescription}>
|
||||
<FormGroup name="base-url" label={t("ai_llm.url")} description={baseUrlDescription}>
|
||||
<FormTextBox
|
||||
currentValue={baseUrl ?? "https://api.openai.com/v1"} onChange={setBaseUrl}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
{isValid &&
|
||||
<FormGroup label={t("ai_llm.model")} description={modelDescription}>
|
||||
<FormGroup name="model" label={t("ai_llm.model")} description={modelDescription}>
|
||||
<ModelSelector provider={provider} baseUrl={baseUrl} modelOption={modelOption} />
|
||||
</FormGroup>
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ function Font({ title, fontFamilyOption, fontSizeOption }: { title: string, font
|
||||
<>
|
||||
<h5>{title}</h5>
|
||||
<div className="row">
|
||||
<FormGroup className="col-md-4" label={t("fonts.font_family")}>
|
||||
<FormGroup name="font-family" className="col-md-4" label={t("fonts.font_family")}>
|
||||
<FormSelectWithGroups
|
||||
values={FONT_FAMILIES}
|
||||
currentValue={fontFamily} onChange={setFontFamily}
|
||||
@@ -197,7 +197,7 @@ function Font({ title, fontFamilyOption, fontSizeOption }: { title: string, font
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup className="col-md-6" label={t("fonts.size")}>
|
||||
<FormGroup name="font-size" className="col-md-6" label={t("fonts.size")}>
|
||||
<FormTextBoxWithUnit
|
||||
name="tree-font-size"
|
||||
type="number" min={50} max={200} step={10}
|
||||
@@ -217,7 +217,7 @@ function ElectronIntegration() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("electron_integration.desktop-application")}>
|
||||
<FormGroup label={t("electron_integration.zoom-factor")} description={t("zoom_factor.description")}>
|
||||
<FormGroup name="zoom-factor" label={t("electron_integration.zoom-factor")} description={t("zoom_factor.description")}>
|
||||
<FormTextBox
|
||||
type="number"
|
||||
min="0.3" max="2.0" step="0.1"
|
||||
@@ -226,16 +226,16 @@ function ElectronIntegration() {
|
||||
</FormGroup>
|
||||
<hr/>
|
||||
|
||||
<FormGroup description={t("electron_integration.native-title-bar-description")}>
|
||||
<FormGroup name="native-title-bar" description={t("electron_integration.native-title-bar-description")}>
|
||||
<FormCheckbox
|
||||
name="native-title-bar" label={t("electron_integration.native-title-bar")}
|
||||
label={t("electron_integration.native-title-bar")}
|
||||
currentValue={nativeTitleBarVisible} onChange={setNativeTitleBarVisible}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup description={t("electron_integration.background-effects-description")}>
|
||||
<FormGroup name="background-effects" description={t("electron_integration.background-effects-description")}>
|
||||
<FormCheckbox
|
||||
name="background-effects" label={t("electron_integration.background-effects")}
|
||||
label={t("electron_integration.background-effects")}
|
||||
currentValue={backgroundEffects} onChange={setBackgroundEffects}
|
||||
/>
|
||||
</FormGroup>
|
||||
@@ -253,9 +253,8 @@ function MaxContentWidth() {
|
||||
<FormText>{t("max_content_width.default_description")}</FormText>
|
||||
|
||||
<Column md={6}>
|
||||
<FormGroup label={t("max_content_width.max_width_label")}>
|
||||
<FormTextBoxWithUnit
|
||||
name="max-content-width"
|
||||
<FormGroup name="max-content-width" label={t("max_content_width.max_width_label")}>
|
||||
<FormTextBoxWithUnit
|
||||
type="number" min={MIN_CONTENT_WIDTH} step="10"
|
||||
currentValue={maxContentWidth} onChange={setMaxContentWidth}
|
||||
unit={t("max_content_width.max_width_unit")}
|
||||
|
||||
@@ -4,7 +4,7 @@ import server from "../../../services/server";
|
||||
import toast from "../../../services/toast";
|
||||
import Button from "../../react/Button";
|
||||
import FormCheckbox from "../../react/FormCheckbox";
|
||||
import FormGroup from "../../react/FormGroup";
|
||||
import FormGroup, { FormMultiGroup } from "../../react/FormGroup";
|
||||
import FormText from "../../react/FormText";
|
||||
import { useTriliumOptionBool } from "../../react/hooks";
|
||||
import OptionsSection from "./components/OptionsSection";
|
||||
@@ -45,7 +45,7 @@ export function AutomaticBackup() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("backup.automatic_backup")}>
|
||||
<FormGroup label={t("backup.automatic_backup_description")}>
|
||||
<FormMultiGroup label={t("backup.automatic_backup_description")}>
|
||||
<FormCheckbox
|
||||
name="daily-backup-enabled"
|
||||
label={t("backup.enable_daily_backup")}
|
||||
@@ -63,7 +63,7 @@ export function AutomaticBackup() {
|
||||
label={t("backup.enable_monthly_backup")}
|
||||
currentValue={monthlyBackupEnabled} onChange={setMonthlyBackupEnabled}
|
||||
/>
|
||||
</FormGroup>
|
||||
</FormMultiGroup>
|
||||
|
||||
<FormText>{t("backup.backup_recommendation")}</FormText>
|
||||
</OptionsSection>
|
||||
|
||||
@@ -32,9 +32,8 @@ function Editor() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("code-editor-options.title")}>
|
||||
<FormGroup description={t("vim_key_bindings.enable_vim_keybindings")}>
|
||||
<FormGroup name="vim-keymap-enabled" description={t("vim_key_bindings.enable_vim_keybindings")}>
|
||||
<FormCheckbox
|
||||
name="vim-keymap-enabled"
|
||||
label={t("vim_key_bindings.use_vim_keybindings_in_code_notes")}
|
||||
currentValue={vimKeymapEnabled} onChange={setVimKeymapEnabled}
|
||||
/>
|
||||
@@ -57,7 +56,7 @@ function Appearance() {
|
||||
return (
|
||||
<OptionsSection title={t("code_theme.title")}>
|
||||
<div className="row" style={{ marginBottom: "15px" }}>
|
||||
<FormGroup label={t("code_theme.color-scheme")} className="col-md-6" style={{ marginBottom: 0 }}>
|
||||
<FormGroup name="color-scheme" label={t("code_theme.color-scheme")} className="col-md-6" style={{ marginBottom: 0 }}>
|
||||
<FormSelect
|
||||
values={themes}
|
||||
keyProperty="id" titleProperty="name"
|
||||
|
||||
@@ -18,9 +18,8 @@ export default function AutoReadOnlySize({ label, option }: AutoReadOnlySizeProp
|
||||
<OptionsSection title={t("text_auto_read_only_size.title")}>
|
||||
<FormText>{t("text_auto_read_only_size.description")}</FormText>
|
||||
|
||||
<FormGroup label={label}>
|
||||
<FormTextBoxWithUnit
|
||||
name="auto-readonly-size-text"
|
||||
<FormGroup name="auto-readonly-size-text" label={label}>
|
||||
<FormTextBoxWithUnit
|
||||
type="number" min={0}
|
||||
unit={t("text_auto_read_only_size.unit")}
|
||||
currentValue={autoReadonlyOpt} onChange={setAutoReadonlyOpt}
|
||||
|
||||
@@ -36,11 +36,11 @@ function LocalizationOptions() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("i18n.title")}>
|
||||
<OptionsRow label={t("i18n.language")}>
|
||||
<OptionsRow name="language" label={t("i18n.language")}>
|
||||
<LocaleSelector locales={uiLocales} currentValue={locale} onChange={setLocale} />
|
||||
</OptionsRow>
|
||||
|
||||
{isElectron() && <OptionsRow label={t("i18n.formatting-locale")}>
|
||||
{isElectron() && <OptionsRow name="formatting-locale" label={t("i18n.formatting-locale")}>
|
||||
<LocaleSelector locales={contentLocales} currentValue={formattingLocale} onChange={setFormattingLocale} />
|
||||
</OptionsRow>}
|
||||
|
||||
@@ -65,34 +65,30 @@ function DateSettings() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<OptionsRow label={t("i18n.first-day-of-the-week")}>
|
||||
<div role="group">
|
||||
<FormInlineRadioGroup
|
||||
name="first-day-of-week"
|
||||
values={[
|
||||
{ value: "0", label: t("i18n.sunday") },
|
||||
{ value: "1", label: t("i18n.monday") }
|
||||
]}
|
||||
currentValue={firstDayOfWeek} onChange={setFirstDayOfWeek}
|
||||
/>
|
||||
</div>
|
||||
<OptionsRow name="first-day-of-week" label={t("i18n.first-day-of-the-week")}>
|
||||
<FormInlineRadioGroup
|
||||
name="first-day-of-week"
|
||||
values={[
|
||||
{ value: "0", label: t("i18n.sunday") },
|
||||
{ value: "1", label: t("i18n.monday") }
|
||||
]}
|
||||
currentValue={firstDayOfWeek} onChange={setFirstDayOfWeek}
|
||||
/>
|
||||
</OptionsRow>
|
||||
|
||||
<OptionsRow label={t("i18n.first-week-of-the-year")}>
|
||||
<div role="group">
|
||||
<FormRadioGroup
|
||||
name="first-week-of-year"
|
||||
currentValue={firstWeekOfYear} onChange={setFirstWeekOfYear}
|
||||
values={[
|
||||
{ value: "0", label: t("i18n.first-week-contains-first-day") },
|
||||
{ value: "1", label: t("i18n.first-week-contains-first-thursday") },
|
||||
{ value: "2", label: t("i18n.first-week-has-minimum-days") }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<OptionsRow name="first-week-of-year" label={t("i18n.first-week-of-the-year")}>
|
||||
<FormRadioGroup
|
||||
name="first-week-of-year"
|
||||
currentValue={firstWeekOfYear} onChange={setFirstWeekOfYear}
|
||||
values={[
|
||||
{ value: "0", label: t("i18n.first-week-contains-first-day") },
|
||||
{ value: "1", label: t("i18n.first-week-contains-first-thursday") },
|
||||
{ value: "2", label: t("i18n.first-week-has-minimum-days") }
|
||||
]}
|
||||
/>
|
||||
</OptionsRow>
|
||||
|
||||
{firstWeekOfYear === "2" && <OptionsRow label={t("i18n.min-days-in-first-week")}>
|
||||
{firstWeekOfYear === "2" && <OptionsRow name="min-days-in-first-week" label={t("i18n.min-days-in-first-week")}>
|
||||
<FormSelect
|
||||
keyProperty="days"
|
||||
currentValue={minDaysInFirstWeek} onChange={setMinDaysInFirstWeek}
|
||||
@@ -109,7 +105,7 @@ function DateSettings() {
|
||||
{t("i18n.first-week-warning")}
|
||||
</Admonition>
|
||||
|
||||
<OptionsRow centered>
|
||||
<OptionsRow name="restart" centered>
|
||||
<Button
|
||||
text={t("electron_integration.restart-app-button")}
|
||||
size="micro"
|
||||
|
||||
@@ -13,9 +13,8 @@ export default function ImageSettings() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("images.images_section_title")}>
|
||||
<FormGroup description={t("images.download_images_description")}>
|
||||
<FormCheckbox
|
||||
name="download-images-automatically"
|
||||
<FormGroup name="download-images-automatically" description={t("images.download_images_description")}>
|
||||
<FormCheckbox
|
||||
label={t("images.download_images_automatically")}
|
||||
currentValue={downloadImagesAutomatically} onChange={setDownloadImagesAutomatically}
|
||||
/>
|
||||
@@ -29,18 +28,16 @@ export default function ImageSettings() {
|
||||
currentValue={compressImages} onChange={setCompressImages}
|
||||
/>
|
||||
|
||||
<FormGroup label={t("images.max_image_dimensions")} disabled={!compressImages}>
|
||||
<FormGroup name="image-max-width-height" label={t("images.max_image_dimensions")} disabled={!compressImages}>
|
||||
<FormTextBoxWithUnit
|
||||
name="image-max-width-height"
|
||||
type="number" min="1"
|
||||
unit={t("images.max_image_dimensions_unit")}
|
||||
currentValue={imageMaxWidthHeight} onChange={setImageMaxWidthHeight}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("images.jpeg_quality_description")} disabled={!compressImages}>
|
||||
<FormTextBoxWithUnit
|
||||
name="image-jpeg-quality"
|
||||
<FormGroup name="image-jpeg-quality" label={t("images.jpeg_quality_description")} disabled={!compressImages}>
|
||||
<FormTextBoxWithUnit
|
||||
min="10" max="100" type="number"
|
||||
unit={t("units.percentage")}
|
||||
currentValue={imageJpegQuality} onChange={setImageJpegQuality}
|
||||
|
||||
@@ -4,7 +4,6 @@ import FormText from "../../react/FormText"
|
||||
import OptionsSection from "./components/OptionsSection"
|
||||
import FormCheckbox from "../../react/FormCheckbox"
|
||||
import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks"
|
||||
import FormGroup from "../../react/FormGroup"
|
||||
import { FormInlineRadioGroup } from "../../react/FormRadioGroup"
|
||||
import Admonition from "../../react/Admonition"
|
||||
import { useCallback, useEffect, useMemo, useState } from "preact/hooks"
|
||||
|
||||
@@ -7,7 +7,7 @@ import FormText from "../../react/FormText";
|
||||
import OptionsSection from "./components/OptionsSection";
|
||||
import TimeSelector from "./components/TimeSelector";
|
||||
import { useMemo } from "preact/hooks";
|
||||
import { useTriliumOption, useTriliumOptionBool, useTriliumOptionInt, useTriliumOptionJson } from "../../react/hooks";
|
||||
import { useTriliumOption, useTriliumOptionBool, useTriliumOptionJson } from "../../react/hooks";
|
||||
import { SANITIZER_DEFAULT_ALLOWED_TAGS } from "@triliumnext/commons";
|
||||
import FormCheckbox from "../../react/FormCheckbox";
|
||||
import FormGroup from "../../react/FormGroup";
|
||||
@@ -51,7 +51,7 @@ function SearchEngineSettings() {
|
||||
<OptionsSection title={t("search_engine.title")}>
|
||||
<FormText>{t("search_engine.custom_search_engine_info")}</FormText>
|
||||
|
||||
<FormGroup label={t("search_engine.predefined_templates_label")}>
|
||||
<FormGroup name="predefined-search-engine" label={t("search_engine.predefined_templates_label")}>
|
||||
<FormSelect
|
||||
values={searchEngines}
|
||||
currentValue={customSearchEngineUrl}
|
||||
@@ -68,14 +68,14 @@ function SearchEngineSettings() {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("search_engine.custom_name_label")}>
|
||||
<FormGroup name="custom-name" label={t("search_engine.custom_name_label")}>
|
||||
<FormTextBox
|
||||
currentValue={customSearchEngineName} onChange={setCustomSearchEngineName}
|
||||
placeholder={t("search_engine.custom_name_placeholder")}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("search_engine.custom_url_label")}>
|
||||
<FormGroup name="custom-url" label={t("search_engine.custom_url_label")}>
|
||||
<FormTextBox
|
||||
currentValue={customSearchEngineUrl} onChange={setCustomSearchEngineUrl}
|
||||
placeholder={t("search_engine.custom_url_placeholder")}
|
||||
@@ -104,9 +104,9 @@ function NoteErasureTimeout() {
|
||||
return (
|
||||
<OptionsSection title={t("note_erasure_timeout.note_erasure_timeout_title")}>
|
||||
<FormText>{t("note_erasure_timeout.note_erasure_description")}</FormText>
|
||||
<FormGroup label={t("note_erasure_timeout.erase_notes_after")}>
|
||||
<TimeSelector
|
||||
name="erase-entities-after"
|
||||
<FormGroup name="erase-entities-after" label={t("note_erasure_timeout.erase_notes_after")}>
|
||||
<TimeSelector
|
||||
name="erase-entities-after"
|
||||
optionValueId="eraseEntitiesAfterTimeInSeconds" optionTimeScaleId="eraseEntitiesAfterTimeScale"
|
||||
/>
|
||||
</FormGroup>
|
||||
@@ -128,9 +128,9 @@ function AttachmentErasureTimeout() {
|
||||
return (
|
||||
<OptionsSection title={t("attachment_erasure_timeout.attachment_erasure_timeout")}>
|
||||
<FormText>{t("attachment_erasure_timeout.attachment_auto_deletion_description")}</FormText>
|
||||
<FormGroup label={t("attachment_erasure_timeout.erase_attachments_after")}>
|
||||
<FormGroup name="erase-unused-attachments-after" label={t("attachment_erasure_timeout.erase_attachments_after")}>
|
||||
<TimeSelector
|
||||
name="erase-unused-attachments-after"
|
||||
name="erase-unused-attachments-after"
|
||||
optionValueId="eraseUnusedAttachmentsAfterSeconds" optionTimeScaleId="eraseUnusedAttachmentsAfterTimeScale"
|
||||
/>
|
||||
</FormGroup>
|
||||
@@ -157,7 +157,7 @@ function RevisionSnapshotInterval() {
|
||||
components={{ doc: <a href="https://triliumnext.github.io/Docs/Wiki/note-revisions.html" class="external" />}}
|
||||
/>
|
||||
</FormText>
|
||||
<FormGroup label={t("revisions_snapshot_interval.snapshot_time_interval_label")}>
|
||||
<FormGroup name="revision-snapshot-time-interval" label={t("revisions_snapshot_interval.snapshot_time_interval_label")}>
|
||||
<TimeSelector
|
||||
name="revision-snapshot-time-interval"
|
||||
optionValueId="revisionSnapshotTimeInterval" optionTimeScaleId="revisionSnapshotTimeIntervalTimeScale"
|
||||
@@ -175,9 +175,8 @@ function RevisionSnapshotLimit() {
|
||||
<OptionsSection title={t("revisions_snapshot_limit.note_revisions_snapshot_limit_title")}>
|
||||
<FormText>{t("revisions_snapshot_limit.note_revisions_snapshot_limit_description")}</FormText>
|
||||
|
||||
<FormGroup>
|
||||
<FormTextBoxWithUnit
|
||||
name="revision-snapshot-number-limit"
|
||||
<FormGroup name="revision-snapshot-number-limit">
|
||||
<FormTextBoxWithUnit
|
||||
type="number" min={-1}
|
||||
currentValue={revisionSnapshotNumberLimit}
|
||||
unit={t("revisions_snapshot_limit.snapshot_number_limit_unit")}
|
||||
@@ -246,9 +245,8 @@ function ShareSettings() {
|
||||
|
||||
return (
|
||||
<OptionsSection title={t("share.title")}>
|
||||
<FormGroup description={t("share.redirect_bare_domain_description")}>
|
||||
<FormCheckbox
|
||||
name="redirectBareDomain"
|
||||
<FormGroup name="redirectBareDomain" description={t("share.redirect_bare_domain_description")}>
|
||||
<FormCheckbox
|
||||
label={t(t("share.redirect_bare_domain"))}
|
||||
currentValue={redirectBareDomain}
|
||||
onChange={async value => {
|
||||
@@ -269,9 +267,8 @@ function ShareSettings() {
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup description={t("share.show_login_link_description")}>
|
||||
<FormCheckbox
|
||||
name="showLoginInShareTheme"
|
||||
<FormGroup name="showLoginInShareTheme" description={t("share.show_login_link_description")}>
|
||||
<FormCheckbox
|
||||
label={t("share.show_login_link")}
|
||||
currentValue={showLogInShareTheme} onChange={setShowLogInShareTheme}
|
||||
/>
|
||||
|
||||
@@ -72,25 +72,22 @@ function ChangePassword() {
|
||||
toast.showError(result.message);
|
||||
}
|
||||
}}>
|
||||
<FormGroup label={t("password.old_password")}>
|
||||
<FormTextBox
|
||||
name="old-password"
|
||||
<FormGroup name="old-password" label={t("password.old_password")}>
|
||||
<FormTextBox
|
||||
type="password"
|
||||
currentValue={oldPassword} onChange={setOldPassword}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("password.new_password")}>
|
||||
<FormTextBox
|
||||
name="new-password1"
|
||||
<FormGroup name="new-password1" label={t("password.new_password")}>
|
||||
<FormTextBox
|
||||
type="password"
|
||||
currentValue={newPassword1} onChange={setNewPassword1}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("password.new_password_confirmation")}>
|
||||
<FormTextBox
|
||||
name="new-password2"
|
||||
<FormGroup name="new-password2" label={t("password.new_password_confirmation")}>
|
||||
<FormTextBox
|
||||
type="password"
|
||||
currentValue={newPassword2} onChange={setNewPassword2}
|
||||
/>
|
||||
@@ -114,9 +111,9 @@ function ProtectedSessionTimeout() {
|
||||
<a class="tn-link" href="https://triliumnext.github.io/Docs/Wiki/protected-notes.html" className="external">{t("password.wiki")}</a> {t("password.for_more_info")}
|
||||
</FormText>
|
||||
|
||||
<FormGroup label={t("password.protected_session_timeout_label")}>
|
||||
<TimeSelector
|
||||
name="protected-session-timeout"
|
||||
<FormGroup name="protected-session-timeout" label={t("password.protected_session_timeout_label")}>
|
||||
<TimeSelector
|
||||
name="protected-session-timeout"
|
||||
optionValueId="protectedSessionTimeout" optionTimeScaleId="protectedSessionTimeoutTimeScale"
|
||||
minimumSeconds={60}
|
||||
/>
|
||||
|
||||
@@ -81,9 +81,8 @@ export default function ShortcutSettings() {
|
||||
<RawHtml html={t("shortcuts.electron_documentation")} />
|
||||
</FormText>
|
||||
|
||||
<FormGroup>
|
||||
<FormTextBox
|
||||
name="keyboard-shortcut-filter"
|
||||
<FormGroup name="keyboard-shortcut-filter">
|
||||
<FormTextBox
|
||||
placeholder={t("shortcuts.type_text_to_filter")}
|
||||
currentValue={filter} onChange={(value) => setFilter(value.toLowerCase())}
|
||||
/>
|
||||
|
||||
@@ -39,9 +39,8 @@ function ElectronSpellcheckSettings() {
|
||||
currentValue={spellCheckEnabled} onChange={setSpellCheckEnabled}
|
||||
/>
|
||||
|
||||
<FormGroup label={t("spellcheck.language_code_label")} description={t("spellcheck.multiple_languages_info")}>
|
||||
<FormTextBox
|
||||
name="spell-check-languages"
|
||||
<FormGroup name="spell-check-languages" label={t("spellcheck.language_code_label")} description={t("spellcheck.multiple_languages_info")}>
|
||||
<FormTextBox
|
||||
placeholder={t("spellcheck.language_code_placeholder")}
|
||||
currentValue={spellCheckLanguageCode} onChange={setSpellCheckLanguageCode}
|
||||
/>
|
||||
|
||||
@@ -37,28 +37,27 @@ export function SyncConfiguration() {
|
||||
});
|
||||
e.preventDefault();
|
||||
}}>
|
||||
<FormGroup label={t("sync_2.server_address")}>
|
||||
<FormTextBox
|
||||
name="sync-server-host"
|
||||
<FormGroup name="sync-server-host" label={t("sync_2.server_address")}>
|
||||
<FormTextBox
|
||||
placeholder="https://<host>:<port>"
|
||||
currentValue={syncServerHost.current} onChange={(newValue) => syncServerHost.current = newValue}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("sync_2.proxy_label")} description={<>
|
||||
<strong>{t("sync_2.note")}:</strong> {t("sync_2.note_description")}<br/>
|
||||
<RawHtml html={t("sync_2.special_value_description")} /></>}
|
||||
<FormGroup name="sync-proxy" label={t("sync_2.proxy_label")}
|
||||
description={<>
|
||||
<strong>{t("sync_2.note")}:</strong> {t("sync_2.note_description")}<br/>
|
||||
<RawHtml html={t("sync_2.special_value_description")} />
|
||||
</>}
|
||||
>
|
||||
<FormTextBox
|
||||
name="sync-proxy"
|
||||
<FormTextBox
|
||||
placeholder="https://<host>:<port>"
|
||||
currentValue={syncProxy.current} onChange={(newValue) => syncProxy.current = newValue}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup label={t("sync_2.timeout")}>
|
||||
<FormTextBoxWithUnit
|
||||
name="sync-server-timeout"
|
||||
<FormGroup name="sync-server-timeout" label={t("sync_2.timeout")}>
|
||||
<FormTextBoxWithUnit
|
||||
min={1} max={10000000} type="number"
|
||||
unit={t("sync_2.timeout_unit")}
|
||||
currentValue={syncServerTimeout.current} onChange={(newValue) => syncServerTimeout.current = newValue}
|
||||
|
||||
@@ -154,7 +154,7 @@ function CodeBlockStyle() {
|
||||
return (
|
||||
<OptionsSection title={t("highlighting.title")}>
|
||||
<div className="row" style={{ marginBottom: "15px" }}>
|
||||
<FormGroup className="col-md-6" label={t("highlighting.color-scheme")} style={{ marginBottom: 0 }}>
|
||||
<FormGroup name="theme" className="col-md-6" label={t("highlighting.color-scheme")} style={{ marginBottom: 0 }}>
|
||||
<FormSelectWithGroups
|
||||
values={themes}
|
||||
keyProperty="val" titleProperty="title"
|
||||
@@ -244,7 +244,7 @@ function TableOfContent() {
|
||||
<OptionsSection title={t("table_of_contents.title")}>
|
||||
<FormText>{t("table_of_contents.description")}</FormText>
|
||||
|
||||
<FormGroup>
|
||||
<FormGroup name="min-toc-headings">
|
||||
<FormTextBoxWithUnit
|
||||
type="number"
|
||||
min={0} max={999999999999999} step={1}
|
||||
@@ -300,21 +300,20 @@ function DateTimeFormatOptions() {
|
||||
/>
|
||||
</FormText>
|
||||
|
||||
<FormGroup className="row align-items-center">
|
||||
<FormGroup className="col-md-6" label={t("custom_date_time_format.format_string")}>
|
||||
<FormTextBox
|
||||
name="custom-date-time-format"
|
||||
<div className="row align-items-center">
|
||||
<FormGroup name="custom-date-time-format" className="col-md-6" label={t("custom_date_time_format.format_string")}>
|
||||
<FormTextBox
|
||||
placeholder="YYYY-MM-DD HH:mm"
|
||||
currentValue={customDateTimeFormat || "YYYY-MM-DD HH:mm"} onChange={setCustomDateTimeFormat}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup className="col-md-6" label={t("custom_date_time_format.formatted_time")}>
|
||||
<div className="formatted-date">
|
||||
<FormGroup name="formatted-date" className="col-md-6" label={t("custom_date_time_format.formatted_time")}>
|
||||
<div>
|
||||
{formatDateTime(new Date(), customDateTimeFormat)}
|
||||
</div>
|
||||
</FormGroup>
|
||||
</FormGroup>
|
||||
</div>
|
||||
</OptionsSection>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user