mirror of
https://github.com/zadam/trilium.git
synced 2025-10-21 15:49:00 +02:00
feat(react/settings): port content languages
This commit is contained in:
parent
c039f06c2b
commit
c368ec3c38
@ -40,7 +40,8 @@ function FormRadio({ name, value, label, currentValue, onChange, labelClassName
|
|||||||
name={useUniqueName(name)}
|
name={useUniqueName(name)}
|
||||||
value={value}
|
value={value}
|
||||||
checked={value === currentValue}
|
checked={value === currentValue}
|
||||||
onChange={e => onChange((e.target as HTMLInputElement).value)} />
|
onChange={e => onChange((e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
)
|
)
|
||||||
|
@ -142,6 +142,14 @@ export function useTriliumOptionInt(name: OptionNames): [number, (newValue: numb
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useTriliumOptionJson<T>(name: OptionNames): [ T, (newValue: T) => Promise<void> ] {
|
||||||
|
const [ value, setValue ] = useTriliumOption(name);
|
||||||
|
return [
|
||||||
|
(JSON.parse(value) as T),
|
||||||
|
(newValue => setValue(JSON.stringify(newValue)))
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a unique name via a random alphanumeric string of a fixed length.
|
* Generates a unique name via a random alphanumeric string of a fixed length.
|
||||||
*
|
*
|
||||||
|
@ -24,7 +24,6 @@ import HtmlImportTagsOptions from "./options/other/html_import_tags.js";
|
|||||||
import BackendLogWidget from "./content/backend_log.js";
|
import BackendLogWidget from "./content/backend_log.js";
|
||||||
import AttachmentErasureTimeoutOptions from "./options/other/attachment_erasure_timeout.js";
|
import AttachmentErasureTimeoutOptions from "./options/other/attachment_erasure_timeout.js";
|
||||||
import MultiFactorAuthenticationOptions from './options/multi_factor_authentication.js';
|
import MultiFactorAuthenticationOptions from './options/multi_factor_authentication.js';
|
||||||
import LocalizationOptions from "./options/i18n/i18n.js";
|
|
||||||
import CodeBlockOptions from "./options/text_notes/code_block.js";
|
import CodeBlockOptions from "./options/text_notes/code_block.js";
|
||||||
import EditorOptions from "./options/text_notes/editor.js";
|
import EditorOptions from "./options/text_notes/editor.js";
|
||||||
import ShareSettingsOptions from "./options/other/share_settings.js";
|
import ShareSettingsOptions from "./options/other/share_settings.js";
|
||||||
@ -32,7 +31,6 @@ import AiSettingsOptions from "./options/ai_settings.js";
|
|||||||
import type FNote from "../../entities/fnote.js";
|
import type FNote from "../../entities/fnote.js";
|
||||||
import type NoteContextAwareWidget from "../note_context_aware_widget.js";
|
import type NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||||
import { t } from "../../services/i18n.js";
|
import { t } from "../../services/i18n.js";
|
||||||
import LanguageOptions from "./options/i18n/language.js";
|
|
||||||
import type BasicWidget from "../basic_widget.js";
|
import type BasicWidget from "../basic_widget.js";
|
||||||
import CodeTheme from "./options/code_notes/code_theme.js";
|
import CodeTheme from "./options/code_notes/code_theme.js";
|
||||||
import EditorFeaturesOptions from "./options/text_notes/features.js";
|
import EditorFeaturesOptions from "./options/text_notes/features.js";
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
interface CheckboxListProps<T> {
|
||||||
|
values: T[];
|
||||||
|
keyProperty: keyof T;
|
||||||
|
titleProperty?: keyof T;
|
||||||
|
currentValue: string[];
|
||||||
|
onChange: (newValues: string[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CheckboxList<T>({ values, keyProperty, titleProperty, currentValue, onChange }: CheckboxListProps<T>) {
|
||||||
|
function toggleValue(value: string) {
|
||||||
|
if (currentValue.includes(value)) {
|
||||||
|
// Already there, needs removing.
|
||||||
|
onChange(currentValue.filter(v => v !== value));
|
||||||
|
} else {
|
||||||
|
// Not there, needs adding.
|
||||||
|
onChange([ ...currentValue, value ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul style={{ listStyleType: "none", marginBottom: 0, columnWidth: "400px" }}>
|
||||||
|
{values.map(value => (
|
||||||
|
<li>
|
||||||
|
<label className="tn-checkbox">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-check-input"
|
||||||
|
value={String(value[keyProperty])}
|
||||||
|
checked={currentValue.includes(String(value[keyProperty]))}
|
||||||
|
onChange={e => toggleValue((e.target as HTMLInputElement).value)}
|
||||||
|
/>
|
||||||
|
{String(value[titleProperty ?? keyProperty] ?? value[keyProperty])}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { getAvailableLocales, t } from "../../../services/i18n";
|
|||||||
import FormSelect from "../../react/FormSelect";
|
import FormSelect from "../../react/FormSelect";
|
||||||
import OptionsRow from "./components/OptionsRow";
|
import OptionsRow from "./components/OptionsRow";
|
||||||
import OptionsSection from "./components/OptionsSection";
|
import OptionsSection from "./components/OptionsSection";
|
||||||
import { useTriliumOption, useTriliumOptionInt } from "../../react/hooks";
|
import { useTriliumOption, useTriliumOptionInt, useTriliumOptionJson } from "../../react/hooks";
|
||||||
import type { Locale } from "@triliumnext/commons";
|
import type { Locale } from "@triliumnext/commons";
|
||||||
import { isElectron, restartDesktopApp } from "../../../services/utils";
|
import { isElectron, restartDesktopApp } from "../../../services/utils";
|
||||||
import FormRadioGroup, { FormInlineRadioGroup } from "../../react/FormRadioGroup";
|
import FormRadioGroup, { FormInlineRadioGroup } from "../../react/FormRadioGroup";
|
||||||
@ -11,11 +11,13 @@ import FormText from "../../react/FormText";
|
|||||||
import RawHtml from "../../react/RawHtml";
|
import RawHtml from "../../react/RawHtml";
|
||||||
import Admonition from "../../react/Admonition";
|
import Admonition from "../../react/Admonition";
|
||||||
import Button from "../../react/Button";
|
import Button from "../../react/Button";
|
||||||
|
import CheckboxList from "./components/CheckboxList";
|
||||||
|
|
||||||
export default function InternationalizationOptions() {
|
export default function InternationalizationOptions() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LocalizationOptions />
|
<LocalizationOptions />
|
||||||
|
<ContentLanguages />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -115,4 +117,21 @@ function DateSettings() {
|
|||||||
</OptionsRow>
|
</OptionsRow>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ContentLanguages() {
|
||||||
|
const locales = useMemo(() => getAvailableLocales(), []);
|
||||||
|
const [ languages, setLanguages ] = useTriliumOptionJson<string[]>("languages");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OptionsSection title={t("content_language.title")}>
|
||||||
|
<FormText>{t("content_language.description")}</FormText>
|
||||||
|
|
||||||
|
<CheckboxList
|
||||||
|
values={locales}
|
||||||
|
keyProperty="id" titleProperty="name"
|
||||||
|
currentValue={languages} onChange={setLanguages}
|
||||||
|
/>
|
||||||
|
</OptionsSection>
|
||||||
|
);
|
||||||
}
|
}
|
@ -1,63 +0,0 @@
|
|||||||
import OptionsWidget from "../options_widget.js";
|
|
||||||
import type { OptionMap } from "@triliumnext/commons";
|
|
||||||
import { getAvailableLocales } from "../../../../services/i18n.js";
|
|
||||||
import { t } from "../../../../services/i18n.js";
|
|
||||||
|
|
||||||
const TPL = /*html*/`
|
|
||||||
<div class="options-section">
|
|
||||||
<h4>${t("content_language.title")}</h4>
|
|
||||||
<p class="form-text">${t("content_language.description")}</p>
|
|
||||||
|
|
||||||
<ul class="options-languages">
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
ul.options-languages {
|
|
||||||
list-style-type: none;
|
|
||||||
margin-bottom: 0;
|
|
||||||
column-width: 400px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
export default class LanguageOptions extends OptionsWidget {
|
|
||||||
|
|
||||||
private $languagesContainer!: JQuery<HTMLElement>;
|
|
||||||
|
|
||||||
doRender() {
|
|
||||||
this.$widget = $(TPL);
|
|
||||||
this.$languagesContainer = this.$widget.find(".options-languages");
|
|
||||||
}
|
|
||||||
|
|
||||||
async save() {
|
|
||||||
const enabledLanguages: string[] = [];
|
|
||||||
|
|
||||||
this.$languagesContainer.find("input:checked").each((i, el) => {
|
|
||||||
const languageId = $(el).attr("data-language-id");
|
|
||||||
if (languageId) {
|
|
||||||
enabledLanguages.push(languageId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await this.updateOption("languages", JSON.stringify(enabledLanguages));
|
|
||||||
}
|
|
||||||
|
|
||||||
async optionsLoaded(options: OptionMap) {
|
|
||||||
const availableLocales = getAvailableLocales();
|
|
||||||
const enabledLanguages = (JSON.parse(options.languages) as string[]);
|
|
||||||
|
|
||||||
this.$languagesContainer.empty();
|
|
||||||
for (const locale of availableLocales) {
|
|
||||||
const checkbox = $('<input type="checkbox" class="form-check-input">')
|
|
||||||
.attr("data-language-id", locale.id)
|
|
||||||
.prop("checked", enabledLanguages.includes(locale.id));
|
|
||||||
const wrapper = $(`<label class="tn-checkbox">`)
|
|
||||||
.append(checkbox)
|
|
||||||
.on("change", () => this.save())
|
|
||||||
.append(locale.name);
|
|
||||||
this.$languagesContainer.append($("<li>").append(wrapper));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user