appearance tab in hidden subtree

This commit is contained in:
zadam 2022-12-06 17:05:21 +01:00
parent d619a7a2d7
commit 9e83368f87
5 changed files with 372 additions and 21 deletions

View File

@ -218,20 +218,20 @@ export default class DesktopLayout {
.child(new DeleteNotesDialog()) .child(new DeleteNotesDialog())
.child(new InfoDialog()) .child(new InfoDialog())
.child(new ConfirmDialog()) .child(new ConfirmDialog())
.child(new PromptDialog()) .child(new PromptDialog());
.child(new OptionsDialog() // .child(new OptionsDialog()
.child(new AppearanceOptions()) // .child(new AppearanceOptions())
.child(new KeyboardShortcutsOptions()) // .child(new KeyboardShortcutsOptions())
.child(new TextNotesOptions()) // .child(new TextNotesOptions())
.child(new CodeNotesOptions()) // .child(new CodeNotesOptions())
.child(new ImageOptions()) // .child(new ImageOptions())
.child(new SpellcheckOptions()) // .child(new SpellcheckOptions())
.child(new PasswordOptions()) // .child(new PasswordOptions())
.child(new EtapiOptions()) // .child(new EtapiOptions())
.child(new BackupOptions()) // .child(new BackupOptions())
.child(new SyncOptions()) // .child(new SyncOptions())
.child(new OtherOptions()) // .child(new OtherOptions())
.child(new AdvancedOptions()) // .child(new AdvancedOptions())
); // );
} }
} }

View File

@ -1,8 +1,8 @@
import BasicWidget from "../../basic_widget.js";
import server from "../../../services/server.js"; import server from "../../../services/server.js";
import toastService from "../../../services/toast.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) { async updateOption(name, value) {
const opts = { [name]: value }; const opts = { [name]: value };
@ -34,4 +34,10 @@ export default class OptionsTab extends BasicWidget {
setCheckboxState($checkbox, optionValue) { setCheckboxState($checkbox, optionValue) {
$checkbox.prop('checked', optionValue === 'true'); $checkbox.prop('checked', optionValue === 'true');
} }
async refreshWithNote(note) {
const options = await server.get('options');
this.optionsLoaded(options);
}
} }

View File

@ -1,12 +1,22 @@
import TypeWidget from "./type_widget.js"; import TypeWidget from "./type_widget.js";
import AppearanceOptions from "./options/appearance.js";
const TPL = `<div class="note-detail-widget note-detail-printable"></div>`; const TPL = `<div class="note-detail-content-widget note-detail-printable">
<style>
.note-detail-content-widget-content {
padding: 15px;
}
</style>
<div class="note-detail-content-widget-content"></div>
</div>`;
export default class ContentWidgetTypeWidget extends TypeWidget { export default class ContentWidgetTypeWidget extends TypeWidget {
static getType() { return "content-widget"; } static getType() { return "content-widget"; }
doRender() { doRender() {
this.$widget = $(TPL); this.$widget = $(TPL);
this.$content = this.$widget.find(".note-detail-content-widget-content");
super.doRender(); super.doRender();
} }
@ -14,10 +24,19 @@ export default class ContentWidgetTypeWidget extends TypeWidget {
async doRefresh(note) { async doRefresh(note) {
const contentWidget = note.getLabelValue('contentWidget'); const contentWidget = note.getLabelValue('contentWidget');
this.$content.empty();
this.children = [];
if (contentWidget === 'optionsAppearance') { 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 { } else {
this.$widget.empty().append(`Unknown widget of type "${contentWidget}"`); this.$content.append(`Unknown widget of type "${contentWidget}"`);
} }
} }
} }

View File

@ -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 = `
<div>
<p><strong>Settings on this options tab are saved automatically after each change.</strong></p>
<style>
.options-section .row {
/* rows otherwise overflow horizontally and force a scrollbar */
margin-left: auto;
margin-right: auto;
}
</style>
<div class="options-section">
<div class="form-group row">
<div class="col-6">
<label>Zoom factor (desktop build only)</label>
<input type="number" class="zoom-factor-select form-control" min="0.3" max="2.0" step="0.1"/>
</div>
<div class="col-6">
<label>Native title bar (requires app restart)</label>
<select class="native-title-bar-select form-control">
<option value="show">enabled</option>
<option value="hide">disabled</option>
</select>
</div>
</div>
<p>Zooming can be controlled with CTRL+- and CTRL+= shortcuts as well.</p>
</div>
<div class="options-section">
<h4>Theme</h4>
<div class="form-group row">
<div class="col-6">
<label>Theme</label>
<select class="theme-select form-control"></select>
</div>
<div class="col-6">
<label>Override theme fonts</label>
<input type="checkbox" class="override-theme-fonts form-control">
</div>
</div>
</div>
<div class="overriden-font-settings options-section">
<h4>Fonts</h4>
<h5>Main font</h5>
<div class="form-group row">
<div class="col-6">
<label>Font family</label>
<select class="main-font-family form-control"></select>
</div>
<div class="col-6">
<label>Size</label>
<div class="input-group">
<input type="number" class="main-font-size form-control" min="50" max="200" step="10"/>
<div class="input-group-append">
<span class="input-group-text">%</span>
</div>
</div>
</div>
</div>
<h5>Note tree font</h5>
<div class="form-group row">
<div class="col-4">
<label>Font family</label>
<select class="tree-font-family form-control"></select>
</div>
<div class="col-4">
<label>Size</label>
<div class="input-group">
<input type="number" class="tree-font-size form-control" min="50" max="200" step="10"/>
<div class="input-group-append">
<span class="input-group-text">%</span>
</div>
</div>
</div>
</div>
<h5>Note detail font</h5>
<div class="form-group row">
<div class="col-4">
<label>Font family</label>
<select class="detail-font-family form-control"></select>
</div>
<div class="col-4">
<label>Size</label>
<div class="input-group">
<input type="number" class="detail-font-size form-control" min="50" max="200" step="10"/>
<div class="input-group-append">
<span class="input-group-text">%</span>
</div>
</div>
</div>
</div>
<h5>Monospace (code) font</h5>
<div class="form-group row">
<div class="col-4">
<label>Font family</label>
<select class="monospace-font-family form-control"></select>
</div>
<div class="col-4">
<label>Size</label>
<div class="input-group">
<input type="number" class="monospace-font-size form-control" min="50" max="200" step="10"/>
<div class="input-group-append">
<span class="input-group-text">%</span>
</div>
</div>
</div>
</div>
<p>Note that tree and detail font sizing is relative to the main font size setting.</p>
<p>Not all listed fonts may be available on your system.</p>
</div>
<p>
To apply font changes, click on
<button class="btn btn-micro reload-frontend-button">reload frontend</button>
</p>
<div class="options-section">
<h4>Content width</h4>
<p>Trilium by default limits max content width to improve readability for maximized screens on wide screens.</p>
<div class="form-group row">
<div class="col-4">
<label>Max content width in pixels</label>
<input type="number" min="200" step="10" class="max-content-width form-control">
</div>
</div>
<p>
To content width changes, click on
<button class="btn btn-micro reload-frontend-button">reload frontend</button>
</p>
</div>
</div>`;
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($("<option>")
.attr("value", theme.val)
.attr("data-note-id", theme.noteId)
.text(theme.title));
}
this.$themeSelect.val(options.theme);
this.setCheckboxState(this.$overrideThemeFonts, options.overrideThemeFonts);
this.$overridenFontSettings.toggle(options.overrideThemeFonts === 'true');
this.$mainFontSize.val(options.mainFontSize);
this.fillFontFamilyOptions(this.$mainFontFamily, options.mainFontFamily);
this.$treeFontSize.val(options.treeFontSize);
this.fillFontFamilyOptions(this.$treeFontFamily, options.treeFontFamily);
this.$detailFontSize.val(options.detailFontSize);
this.fillFontFamilyOptions(this.$detailFontFamily, options.detailFontFamily);
this.$monospaceFontSize.val(options.monospaceFontSize);
this.fillFontFamilyOptions(this.$monospaceFontFamily, options.monospaceFontFamily);
this.$maxContentWidth.val(options.maxContentWidth);
}
fillFontFamilyOptions($select, currentValue) {
$select.empty();
for (const {value, label} of FONT_FAMILIES) {
$select.append($("<option>")
.attr("value", value)
.prop("selected", value === currentValue)
.text(label));
}
}
}

View File

@ -582,7 +582,7 @@ function createOptionNotes() {
branchId: OPTIONS_ROOT, branchId: OPTIONS_ROOT,
noteId: OPTIONS_ROOT, noteId: OPTIONS_ROOT,
title: 'Options', title: 'Options',
type: 'doc', type: 'book',
content: '', content: '',
parentNoteId: getHiddenRoot().noteId parentNoteId: getHiddenRoot().noteId
}); });