diff --git a/src/public/app/dialogs/options/appearance.js b/src/public/app/dialogs/options/appearance.js index 3fc914498..3bf3f6b40 100644 --- a/src/public/app/dialogs/options/appearance.js +++ b/src/public/app/dialogs/options/appearance.js @@ -1,6 +1,7 @@ import server from "../../services/server.js"; import utils from "../../services/utils.js"; import appContext from "../../services/app_context.js"; +import convertUtils from "../../services/convert_utils.js"; const FONT_FAMILIES = [ { value: "theme", label: "Theme defined" }, @@ -28,6 +29,12 @@ const FONT_FAMILIES = [ ]; const TPL = ` + +

Settings on this options tab are saved automatically after each change.

diff --git a/src/public/app/layouts/desktop_layout.js b/src/public/app/layouts/desktop_layout.js index 346f12aa9..5e83106f9 100644 --- a/src/public/app/layouts/desktop_layout.js +++ b/src/public/app/layouts/desktop_layout.js @@ -45,6 +45,7 @@ import EditedNotesWidget from "../widgets/ribbon_widgets/edited_notes.js"; import OpenNoteButtonWidget from "../widgets/buttons/open_note_button_widget.js"; import MermaidWidget from "../widgets/mermaid.js"; import BookmarkButtons from "../widgets/bookmark_buttons.js"; +import UpdateAvailableWidget from "../widgets/buttons/update_available.js"; export default class DesktopLayout { constructor(customWidgets) { diff --git a/src/public/app/services/convert_utils.js b/src/public/app/services/convert_utils.js new file mode 100644 index 000000000..8312562f0 --- /dev/null +++ b/src/public/app/services/convert_utils.js @@ -0,0 +1,7 @@ +function parseBoolean(value) { + return value.toLowerCase() === "true"; +} + +export default { + parseBoolean +} diff --git a/src/public/app/widgets/buttons/global_menu.js b/src/public/app/widgets/buttons/global_menu.js index 671783fab..7bcf23f9e 100644 --- a/src/public/app/widgets/buttons/global_menu.js +++ b/src/public/app/widgets/buttons/global_menu.js @@ -1,5 +1,7 @@ import BasicWidget from "../basic_widget.js"; import utils from "../../services/utils.js"; +import UpdateAvailableWidget from "./update_available.js"; +const axios = require("axios"); const TPL = ` `; +const RELEASES_API_URL = "https://api.github.com/repos/zadam/trilium/releases/latest"; +const CURRENT_VERSION = process.env.npm_package_version; export default class GlobalMenuWidget extends BasicWidget { + static getVersionChange(oldVersion, newVersion) { + const [oldMajor, oldMinor, oldPatch] = oldVersion.split(".").map(Number); + const [newMajor, newMinor, newPatch] = newVersion.split(".").map(Number); + + if (newMajor !== oldMajor) { + return "major"; + } else if (newMinor !== oldMinor) { + return "minor"; + } else if (newPatch !== oldPatch) { + return "patch"; + } + } + doRender() { this.$widget = $(TPL); @@ -114,7 +150,32 @@ export default class GlobalMenuWidget extends BasicWidget { this.$widget.find(".open-dev-tools-button").toggle(isElectron); this.$widget.find(".switch-to-mobile-version-button").toggle(!isElectron); + this.$widget.on('click', '.dropdown-item', () => this.$widget.find("[data-toggle='dropdown']").dropdown('toggle')); + + this.loadUpdateAvailable(); + } + + async loadUpdateAvailable() { + const newVersion = await this.fetchNewVersion(); + + if (!newVersion) { + return; + } + + const versionChange = "major"; + + this.$widget.find(".global-menu-button-update-available").append( + new UpdateAvailableWidget() + .withVersionChange(versionChange) + .render() + ) + } + + async fetchNewVersion() { + const {data} = await axios.get(RELEASES_API_URL); + + return data.tag_name.substring(1); } } diff --git a/src/public/app/widgets/buttons/update_available.js b/src/public/app/widgets/buttons/update_available.js new file mode 100644 index 000000000..32ac5f31c --- /dev/null +++ b/src/public/app/widgets/buttons/update_available.js @@ -0,0 +1,70 @@ +import BasicWidget from "../basic_widget.js"; + +const TPL = ` + + +` +const VERSION_CHANGE_COLOR_MAP = { + patch: "#666666", + minor: "#5bc625", + major: "#ec2f2f" +} +const VERSION_CHANGE_BACKGROUND_COLOR_MAP = Object.fromEntries( + Object.entries( + VERSION_CHANGE_COLOR_MAP).map(([key, value]) => [ + key, + `${value}40` + ] + ) +) + +export default class UpdateAvailableWidget extends BasicWidget { + versionChange = undefined + + doRender() { + this.$widget = $(TPL); + + this.setButton(); + } + + setButton() { + switch (this.versionChange) { + case "major": + case "minor": + case "patch": + this.$widget.show(); + this.$widget.css({ + color: VERSION_CHANGE_COLOR_MAP[this.versionChange], + backgroundColor: VERSION_CHANGE_BACKGROUND_COLOR_MAP[this.versionChange] + }); + break; + default: + this.$widget.hide(); + } + } + + withVersionChange(versionChange) { + this.versionChange = versionChange; + + return this; + } +} diff --git a/src/services/options_init.js b/src/services/options_init.js index 31b64927e..fcfcd28c3 100644 --- a/src/services/options_init.js +++ b/src/services/options_init.js @@ -90,7 +90,7 @@ const defaultOptions = [ { name: 'dailyBackupEnabled', value: 'true', isSynced: false }, { name: 'weeklyBackupEnabled', value: 'true', isSynced: false }, { name: 'monthlyBackupEnabled', value: 'true', isSynced: false }, - { name: 'maxContentWidth', value: '1200', isSynced: false }, + { name: 'maxContentWidth', value: '1200', isSynced: false } ]; function initStartupOptions() {