diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js
index 2b3463cb1..c04aa42d7 100644
--- a/src/public/app/layouts/desktop_layout.js
+++ b/src/public/app/layouts/desktop_layout.js
@@ -218,20 +218,20 @@ export default class DesktopLayout {
.child(new DeleteNotesDialog())
.child(new InfoDialog())
.child(new ConfirmDialog())
- .child(new PromptDialog())
- .child(new OptionsDialog()
- .child(new AppearanceOptions())
- .child(new KeyboardShortcutsOptions())
- .child(new TextNotesOptions())
- .child(new CodeNotesOptions())
- .child(new ImageOptions())
- .child(new SpellcheckOptions())
- .child(new PasswordOptions())
- .child(new EtapiOptions())
- .child(new BackupOptions())
- .child(new SyncOptions())
- .child(new OtherOptions())
- .child(new AdvancedOptions())
- );
+ .child(new PromptDialog());
+ // .child(new OptionsDialog()
+ // .child(new AppearanceOptions())
+ // .child(new KeyboardShortcutsOptions())
+ // .child(new TextNotesOptions())
+ // .child(new CodeNotesOptions())
+ // .child(new ImageOptions())
+ // .child(new SpellcheckOptions())
+ // .child(new PasswordOptions())
+ // .child(new EtapiOptions())
+ // .child(new BackupOptions())
+ // .child(new SyncOptions())
+ // .child(new OtherOptions())
+ // .child(new AdvancedOptions())
+ // );
}
}
diff --git a/src/public/app/widgets/dialogs/options/options_tab.js b/src/public/app/widgets/dialogs/options/options_tab.js
index 3e74dcbc7..e5541acb6 100644
--- a/src/public/app/widgets/dialogs/options/options_tab.js
+++ b/src/public/app/widgets/dialogs/options/options_tab.js
@@ -1,8 +1,8 @@
-import BasicWidget from "../../basic_widget.js";
import server from "../../../services/server.js";
import toastService from "../../../services/toast.js";
+import NoteContextAwareWidget from "../../note_context_aware_widget.js";
-export default class OptionsTab extends BasicWidget {
+export default class OptionsTab extends NoteContextAwareWidget {
async updateOption(name, value) {
const opts = { [name]: value };
@@ -34,4 +34,10 @@ export default class OptionsTab extends BasicWidget {
setCheckboxState($checkbox, optionValue) {
$checkbox.prop('checked', optionValue === 'true');
}
+
+ async refreshWithNote(note) {
+ const options = await server.get('options');
+
+ this.optionsLoaded(options);
+ }
}
diff --git a/src/public/app/widgets/type_widgets/content_widget.js b/src/public/app/widgets/type_widgets/content_widget.js
index 9cac12438..66e62eb45 100644
--- a/src/public/app/widgets/type_widgets/content_widget.js
+++ b/src/public/app/widgets/type_widgets/content_widget.js
@@ -1,12 +1,22 @@
import TypeWidget from "./type_widget.js";
+import AppearanceOptions from "./options/appearance.js";
-const TPL = `
`;
+const TPL = ``;
export default class ContentWidgetTypeWidget extends TypeWidget {
static getType() { return "content-widget"; }
doRender() {
this.$widget = $(TPL);
+ this.$content = this.$widget.find(".note-detail-content-widget-content");
super.doRender();
}
@@ -14,10 +24,19 @@ export default class ContentWidgetTypeWidget extends TypeWidget {
async doRefresh(note) {
const contentWidget = note.getLabelValue('contentWidget');
+ this.$content.empty();
+ this.children = [];
+
if (contentWidget === 'optionsAppearance') {
- this.$widget.empty().append("HI!");
+ const widget = new AppearanceOptions();
+
+ await widget.handleEvent('setNoteContext', { noteContext: this.noteContext });
+ this.child(widget);
+
+ this.$content.append(widget.render());
+ await widget.refresh();
} else {
- this.$widget.empty().append(`Unknown widget of type "${contentWidget}"`);
+ this.$content.append(`Unknown widget of type "${contentWidget}"`);
}
}
}
diff --git a/src/public/app/widgets/type_widgets/options/appearance.js b/src/public/app/widgets/type_widgets/options/appearance.js
new file mode 100644
index 000000000..798eca0f7
--- /dev/null
+++ b/src/public/app/widgets/type_widgets/options/appearance.js
@@ -0,0 +1,326 @@
+import server from "../../../services/server.js";
+import utils from "../../../services/utils.js";
+import appContext from "../../../components/app_context.js";
+import OptionsTab from "../../dialogs/options/options_tab.js";
+
+const FONT_FAMILIES = [
+ { value: "theme", label: "Theme defined" },
+ { value: "serif", label: "Serif" },
+ { value: "sans-serif", label: "Sans Serif" },
+ { value: "monospace", label: "Monospace" },
+ { value: "Arial", label: "Arial" },
+ { value: "Verdana", label: "Verdana" },
+ { value: "Helvetica", label: "Helvetica" },
+ { value: "Tahoma", label: "Tahoma" },
+ { value: "Trebuchet MS", label: "Trebuchet MS" },
+ { value: "Times New Roman", label: "Times New Roman" },
+ { value: "Georgia", label: "Georgia" },
+ { value: "Garamond", label: "Garamond" },
+ { value: "Courier New", label: "Courier New" },
+ { value: "Brush Script MT", label: "Brush Script MT" },
+ { value: "Impact", label: "Impact" },
+ { value: "American Typewriter", label: "American Typewriter" },
+ { value: "Andalé Mono", label: "Andalé Mono" },
+ { value: "Lucida Console", label: "Lucida Console" },
+ { value: "Monaco", label: "Monaco" },
+ { value: "Bradley Hand", label: "Bradley Hand" },
+ { value: "Luminari", label: "Luminari" },
+ { value: "Comic Sans MS", label: "Comic Sans MS" },
+];
+
+const TPL = `
+
+
Settings on this options tab are saved automatically after each change.
+
+
+
+
+
+
+
Zooming can be controlled with CTRL+- and CTRL+= shortcuts as well.
+
+
+
+
+
+
Fonts
+
+
Main font
+
+
+
+
Note tree font
+
+
+
+
Note detail font
+
+
+
+
Monospace (code) font
+
+
+
+
Note that tree and detail font sizing is relative to the main font size setting.
+
+
Not all listed fonts may be available on your system.
+
+
+
+ To apply font changes, click on
+
+
+
+
+
Content width
+
+
Trilium by default limits max content width to improve readability for maximized screens on wide screens.
+
+
+
+
+ To content width changes, click on
+
+
+
+
`;
+
+export default class AppearanceOptions extends OptionsTab {
+ get tabTitle() { return "Appearance" }
+
+ doRender() {
+ this.$widget = $(TPL);
+
+ this.$zoomFactorSelect = this.$widget.find(".zoom-factor-select");
+ this.$nativeTitleBarSelect = this.$widget.find(".native-title-bar-select");
+
+ this.$themeSelect = this.$widget.find(".theme-select");
+ this.$overrideThemeFonts = this.$widget.find(".override-theme-fonts");
+
+ this.$overridenFontSettings = this.$widget.find(".overriden-font-settings");
+
+ this.$mainFontSize = this.$widget.find(".main-font-size");
+ this.$mainFontFamily = this.$widget.find(".main-font-family");
+
+ this.$treeFontSize = this.$widget.find(".tree-font-size");
+ this.$treeFontFamily = this.$widget.find(".tree-font-family");
+
+ this.$detailFontSize = this.$widget.find(".detail-font-size");
+ this.$detailFontFamily = this.$widget.find(".detail-font-family");
+
+ this.$monospaceFontSize = this.$widget.find(".monospace-font-size");
+ this.$monospaceFontFamily = this.$widget.find(".monospace-font-family");
+
+ this.$widget.find(".reload-frontend-button").on("click", () => utils.reloadFrontendApp("changes from appearance options"));
+
+ this.$body = this.$widget.find("body");
+
+ this.$themeSelect.on('change', async () => {
+ const newTheme = this.$themeSelect.val();
+
+ await server.put('options/theme/' + newTheme);
+
+ utils.reloadFrontendApp("theme change");
+ });
+
+ this.$overrideThemeFonts.on('change', async () => {
+ this.updateCheckboxOption('overrideThemeFonts', this.$overrideThemeFonts);
+
+ this.$overridenFontSettings.toggle(this.$overrideThemeFonts.is(":checked"));
+ });
+
+ this.$zoomFactorSelect.on('change', () => { appContext.triggerCommand('setZoomFactorAndSave', {zoomFactor: this.$zoomFactorSelect.val()}); });
+
+ this.$nativeTitleBarSelect.on('change', () => {
+ const nativeTitleBarVisible = this.$nativeTitleBarSelect.val() === 'show' ? 'true' : 'false';
+
+ this.updateOption('nativeTitleBarVisible', nativeTitleBarVisible);
+ });
+
+ const optionsToSave = [
+ 'mainFontFamily', 'mainFontSize',
+ 'treeFontFamily', 'treeFontSize',
+ 'detailFontFamily', 'detailFontSize',
+ 'monospaceFontFamily', 'monospaceFontSize'
+ ];
+
+ for (const optionName of optionsToSave) {
+ this['$' + optionName].on('change', () =>
+ this.updateOption(optionName, this['$' + optionName].val()));
+ }
+
+ this.$maxContentWidth = this.$widget.find(".max-content-width");
+
+ this.$maxContentWidth.on('change', async () =>
+ this.updateOption('maxContentWidth', this.$maxContentWidth.val()))
+ }
+
+ toggleBodyClass(prefix, value) {
+ for (const clazz of Array.from(this.$body[0].classList)) { // create copy to safely iterate over while removing classes
+ if (clazz.startsWith(prefix)) {
+ this.$body.removeClass(clazz);
+ }
+ }
+
+ this.$body.addClass(prefix + value);
+ }
+
+ async optionsLoaded(options) {
+ if (utils.isElectron()) {
+ this.$zoomFactorSelect.val(options.zoomFactor);
+ }
+ else {
+ this.$zoomFactorSelect.prop('disabled', true);
+ }
+
+ this.$nativeTitleBarSelect.val(options.nativeTitleBarVisible === 'true' ? 'show' : 'hide');
+
+ const themes = [
+ { val: 'light', title: 'Light' },
+ { val: 'dark', title: 'Dark' }
+ ].concat(await server.get('options/user-themes'));
+
+ this.$themeSelect.empty();
+
+ for (const theme of themes) {
+ this.$themeSelect.append($("