mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +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")}> | ||||
|             <FormGroup name="shrink-images" label={t("upload_attachments.options")}> | ||||
|                 <FormCheckbox                     | ||||
|                     name="shrink-images" | ||||
|                     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 | ||||
|   | ||||
| @@ -29,3 +29,15 @@ export default function FormGroup({ name, label, title, className, children, des | ||||
|         </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")}> | ||||
|                 <FormGroup name="ai-enabled" description={t("ai_llm.enable_ai_description")}> | ||||
|                     <FormCheckbox                         | ||||
|                         name="ai-enabled" | ||||
|                         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")}> | ||||
|                 <FormGroup name="max-content-width" label={t("max_content_width.max_width_label")}> | ||||
|                     <FormTextBoxWithUnit                         | ||||
|                         name="max-content-width" | ||||
|                         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}> | ||||
|             <FormGroup name="auto-readonly-size-text" label={label}> | ||||
|                 <FormTextBoxWithUnit                     | ||||
|                     name="auto-readonly-size-text" | ||||
|                     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")}> | ||||
|             <FormGroup name="download-images-automatically" description={t("images.download_images_description")}> | ||||
|                 <FormCheckbox                     | ||||
|                     name="download-images-automatically" | ||||
|                     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}> | ||||
|             <FormGroup name="image-jpeg-quality" label={t("images.jpeg_quality_description")} disabled={!compressImages}> | ||||
|                 <FormTextBoxWithUnit                     | ||||
|                     name="image-jpeg-quality" | ||||
|                     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,7 +104,7 @@ 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")}> | ||||
|             <FormGroup name="erase-entities-after" label={t("note_erasure_timeout.erase_notes_after")}> | ||||
|                 <TimeSelector            | ||||
|                     name="erase-entities-after"          | ||||
|                     optionValueId="eraseEntitiesAfterTimeInSeconds" optionTimeScaleId="eraseEntitiesAfterTimeScale" | ||||
| @@ -128,7 +128,7 @@ 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" | ||||
|                     optionValueId="eraseUnusedAttachmentsAfterSeconds" optionTimeScaleId="eraseUnusedAttachmentsAfterTimeScale" | ||||
| @@ -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> | ||||
|             <FormGroup name="revision-snapshot-number-limit"> | ||||
|                 <FormTextBoxWithUnit                     | ||||
|                     name="revision-snapshot-number-limit"   | ||||
|                     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")}> | ||||
|             <FormGroup name="redirectBareDomain" description={t("share.redirect_bare_domain_description")}> | ||||
|                 <FormCheckbox                     | ||||
|                     name="redirectBareDomain" | ||||
|                     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")}> | ||||
|             <FormGroup name="showLoginInShareTheme" description={t("share.show_login_link_description")}> | ||||
|                 <FormCheckbox                     | ||||
|                     name="showLoginInShareTheme" | ||||
|                     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")}> | ||||
|                 <FormGroup name="old-password" label={t("password.old_password")}> | ||||
|                     <FormTextBox                         | ||||
|                         name="old-password" | ||||
|                         type="password" | ||||
|                         currentValue={oldPassword} onChange={setOldPassword} | ||||
|                     />                     | ||||
|                 </FormGroup> | ||||
|  | ||||
|                 <FormGroup label={t("password.new_password")}> | ||||
|                 <FormGroup name="new-password1" label={t("password.new_password")}> | ||||
|                     <FormTextBox                         | ||||
|                         name="new-password1" | ||||
|                         type="password" | ||||
|                         currentValue={newPassword1} onChange={setNewPassword1} | ||||
|                     /> | ||||
|                 </FormGroup> | ||||
|  | ||||
|                 <FormGroup label={t("password.new_password_confirmation")}> | ||||
|                 <FormGroup name="new-password2" label={t("password.new_password_confirmation")}> | ||||
|                     <FormTextBox                         | ||||
|                         name="new-password2" | ||||
|                         type="password" | ||||
|                         currentValue={newPassword2} onChange={setNewPassword2} | ||||
|                     /> | ||||
| @@ -114,7 +111,7 @@ 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")}> | ||||
|             <FormGroup name="protected-session-timeout" label={t("password.protected_session_timeout_label")}> | ||||
|                 <TimeSelector                     | ||||
|                     name="protected-session-timeout" | ||||
|                     optionValueId="protectedSessionTimeout" optionTimeScaleId="protectedSessionTimeoutTimeScale" | ||||
|   | ||||
| @@ -81,9 +81,8 @@ export default function ShortcutSettings() { | ||||
|                 <RawHtml html={t("shortcuts.electron_documentation")} /> | ||||
|             </FormText> | ||||
|  | ||||
|             <FormGroup> | ||||
|             <FormGroup name="keyboard-shortcut-filter"> | ||||
|                 <FormTextBox                     | ||||
|                     name="keyboard-shortcut-filter" | ||||
|                     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")}> | ||||
|             <FormGroup name="spell-check-languages" label={t("spellcheck.language_code_label")} description={t("spellcheck.multiple_languages_info")}> | ||||
|                 <FormTextBox                                         | ||||
|                     name="spell-check-languages" | ||||
|                     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")}> | ||||
|                 <FormGroup name="sync-server-host" label={t("sync_2.server_address")}> | ||||
|                     <FormTextBox                         | ||||
|                         name="sync-server-host" | ||||
|                         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" | ||||
|                         placeholder="https://<host>:<port>" | ||||
|                         currentValue={syncProxy.current} onChange={(newValue) => syncProxy.current = newValue} | ||||
|                     /> | ||||
|                 </FormGroup> | ||||
|  | ||||
|                 <FormGroup label={t("sync_2.timeout")}> | ||||
|                 <FormGroup name="sync-server-timeout" label={t("sync_2.timeout")}> | ||||
|                     <FormTextBoxWithUnit                         | ||||
|                         name="sync-server-timeout" | ||||
|                         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")}> | ||||
|             <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                         | ||||
|                         name="custom-date-time-format" | ||||
|                         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