feat(react/settings): port images

This commit is contained in:
Elian Doran 2025-08-14 22:27:07 +03:00
parent d04897e011
commit c67c3a6861
No known key found for this signature in database
5 changed files with 61 additions and 104 deletions

View File

@ -139,6 +139,11 @@ textarea,
color: var(--muted-text-color);
}
.form-group.disabled {
opacity: 0.5;
pointer-events: none;
}
/* Add a gap between consecutive radios / check boxes */
label.tn-radio + label.tn-radio,
label.tn-checkbox + label.tn-checkbox {

View File

@ -7,11 +7,12 @@ interface FormGroupProps {
className?: string;
children: ComponentChildren;
description?: string | ComponentChildren;
disabled?: boolean;
}
export default function FormGroup({ label, title, className, children, description, labelRef }: FormGroupProps) {
export default function FormGroup({ label, title, className, children, description, labelRef, disabled }: FormGroupProps) {
return (
<div className={`form-group ${className}`} title={title}
<div className={`form-group ${className} ${disabled ? "disabled" : ""}`} title={title}
style={{ "margin-bottom": "15px" }}>
<label style={{ width: "100%" }} ref={labelRef}>
{label && <div style={{ "margin-bottom": "10px" }}>{label}</div> }

View File

@ -45,11 +45,11 @@ import { t } from "../../services/i18n.js";
import LanguageOptions from "./options/i18n/language.js";
import type BasicWidget from "../basic_widget.js";
import CodeTheme from "./options/code_notes/code_theme.js";
import RelatedSettings from "./options/appearance/related_settings.js";
import EditorFeaturesOptions from "./options/text_notes/features.js";
import type { JSX } from "preact/jsx-runtime";
import AppearanceSettings from "./options/appearance.jsx";
import { renderReactWidget } from "../react/ReactBasicWidget.jsx";
import ImageSettings from "./options/images.jsx";
const TPL = /*html*/`<div class="note-detail-content-widget note-detail-printable">
<style>
@ -97,9 +97,7 @@ const CONTENT_WIDGETS: Record<OptionPages | "_backendLog", ((typeof NoteContextA
CodeMimeTypesOptions,
CodeAutoReadOnlySizeOptions
],
_optionsImages: [
ImageOptions
],
_optionsImages: <ImageSettings />,
_optionsSpellcheck: [
SpellcheckOptions
],

View File

@ -0,0 +1,51 @@
import { t } from "../../../services/i18n";
import FormCheckbox from "../../react/FormCheckbox";
import FormGroup from "../../react/FormGroup";
import { FormTextBoxWithUnit } from "../../react/FormTextBox";
import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks";
import OptionsSection from "./components/OptionsSection";
export default function ImageSettings() {
const [ downloadImagesAutomatically, setDownloadImagesAutomatically ] = useTriliumOptionBool("downloadImagesAutomatically");
const [ compressImages, setCompressImages ] = useTriliumOptionBool("compressImages");
const [ imageMaxWidthHeight, setImageMaxWidthHeight ] = useTriliumOption("imageMaxWidthHeight");
const [ imageJpegQuality, setImageJpegQuality ] = useTriliumOption("imageJpegQuality");
return (
<OptionsSection title={t("images.images_section_title")}>
<FormGroup description={t("images.download_images_description")}>
<FormCheckbox
name="download-images-automatically"
label={t("images.download_images_automatically")}
currentValue={downloadImagesAutomatically} onChange={setDownloadImagesAutomatically}
/>
</FormGroup>
<hr/>
<FormCheckbox
name="image-compression-enabled"
label={t("images.enable_image_compression")}
currentValue={compressImages} onChange={setCompressImages}
/>
<FormGroup 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"
min="10" max="100" type="number"
unit="%"
currentValue={imageJpegQuality} onChange={setImageJpegQuality}
/>
</FormGroup>
</OptionsSection>
);
}

View File

@ -1,98 +0,0 @@
import OptionsWidget from "../options_widget.js";
import { t } from "../../../../services/i18n.js";
import type { OptionMap } from "@triliumnext/commons";
const TPL = /*html*/`
<div class="options-section">
<style>
.options-section .disabled-field {
opacity: 0.5;
pointer-events: none;
}
</style>
<h4>${t("images.images_section_title")}</h4>
<label class="tn-checkbox">
<input class="download-images-automatically" type="checkbox" name="download-images-automatically">
${t("images.download_images_automatically")}
</label>
<p class="form-text">${t("images.download_images_description")}</p>
<hr />
<label class="tn-checkbox">
<input class="image-compresion-enabled" type="checkbox" name="image-compression-enabled">
${t("images.enable_image_compression")}
</label>
<div class="image-compression-enabled-wraper">
<div class="form-group">
<label>${t("images.max_image_dimensions")}</label>
<label class="input-group tn-number-unit-pair">
<input class="image-max-width-height form-control options-number-input" type="number" min="1">
<span class="input-group-text">${t("images.max_image_dimensions_unit")}</span>
</label>
</div>
<div class="form-group">
<label>${t("images.jpeg_quality_description")}</label>
<label class="input-group tn-number-unit-pair">
<input class="image-jpeg-quality form-control options-number-input" min="10" max="100" type="number">
<span class="input-group-text">%</span>
</label>
</div>
</div>
</div>
`;
export default class ImageOptions extends OptionsWidget {
private $imageMaxWidthHeight!: JQuery<HTMLElement>;
private $imageJpegQuality!: JQuery<HTMLElement>;
private $downloadImagesAutomatically!: JQuery<HTMLElement>;
private $enableImageCompression!: JQuery<HTMLElement>;
private $imageCompressionWrapper!: JQuery<HTMLElement>;
doRender() {
this.$widget = $(TPL);
this.$imageMaxWidthHeight = this.$widget.find(".image-max-width-height");
this.$imageJpegQuality = this.$widget.find(".image-jpeg-quality");
this.$imageMaxWidthHeight.on("change", () => this.updateOption("imageMaxWidthHeight", this.$imageMaxWidthHeight.val()));
this.$imageJpegQuality.on("change", () => this.updateOption("imageJpegQuality", String(this.$imageJpegQuality.val()).trim() || "75"));
this.$downloadImagesAutomatically = this.$widget.find(".download-images-automatically");
this.$downloadImagesAutomatically.on("change", () => this.updateCheckboxOption("downloadImagesAutomatically", this.$downloadImagesAutomatically));
this.$enableImageCompression = this.$widget.find(".image-compresion-enabled");
this.$imageCompressionWrapper = this.$widget.find(".image-compression-enabled-wraper");
this.$enableImageCompression.on("change", () => {
this.updateCheckboxOption("compressImages", this.$enableImageCompression);
this.setImageCompression();
});
}
optionsLoaded(options: OptionMap) {
this.$imageMaxWidthHeight.val(options.imageMaxWidthHeight);
this.$imageJpegQuality.val(options.imageJpegQuality);
this.setCheckboxState(this.$downloadImagesAutomatically, options.downloadImagesAutomatically);
this.setCheckboxState(this.$enableImageCompression, options.compressImages);
this.setImageCompression();
}
setImageCompression() {
if (this.$enableImageCompression.prop("checked")) {
this.$imageCompressionWrapper.removeClass("disabled-field");
} else {
this.$imageCompressionWrapper.addClass("disabled-field");
}
}
}