diff --git a/res/static/bug.svg b/res/static/bug.svg new file mode 100644 index 0000000..0669481 --- /dev/null +++ b/res/static/bug.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/res/static/github.svg b/res/static/github.svg new file mode 100644 index 0000000..408978d --- /dev/null +++ b/res/static/github.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 4bced3e..b813519 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,6 +12,10 @@ export class AppConfig { } public readonly RELEASE_MODE: boolean; + public readonly MAJOR_VERSION: number; + public readonly MINOR_VERSION: number; + public readonly HOTFIX_VERSION: number; + public readonly VERSION_TYPE: 'd' | 'a' | 'r'; // dev, alpha, or release build public readonly RELEASE_VERSION: string; public readonly VOXEL_BUFFER_CHUNK_SIZE: number; @@ -41,7 +45,11 @@ export class AppConfig { private constructor() { this.RELEASE_MODE = false; - this.RELEASE_VERSION = '0.8.0d'; + this.MAJOR_VERSION = 0; + this.MINOR_VERSION = 8; + this.HOTFIX_VERSION = 0; + this.VERSION_TYPE = 'd'; + this.RELEASE_VERSION = `${this.MAJOR_VERSION}.${this.MINOR_VERSION}.${this.HOTFIX_VERSION}${this.VERSION_TYPE}`; this.VOXEL_BUFFER_CHUNK_SIZE = 5_000; const configFile = fs.readFileSync(PathUtil.join(AppPaths.Get.resources, 'config.json'), 'utf8'); diff --git a/src/ui/elements/header_element.ts b/src/ui/elements/header_element.ts new file mode 100644 index 0000000..834519e --- /dev/null +++ b/src/ui/elements/header_element.ts @@ -0,0 +1,140 @@ +import { shell } from 'electron'; + +import { AppConfig } from '../../config'; +import { ASSERT } from '../../util/error_util'; +import { LOG, LOG_ERROR } from '../../util/log_util'; +import { AppPaths, PathUtil } from '../../util/path_util'; +import { UIUtil } from '../../util/ui_util'; +import { BaseUIElement } from './base_element'; +import { ToolbarItemElement } from './toolbar_item'; + + +export class HeaderUIElement extends BaseUIElement { + private static _instance: HeaderUIElement; + public static get Get() { + return this._instance || (this._instance = new this()); + } + + private _githubButton: ToolbarItemElement; + private _bugButton: ToolbarItemElement; + + private constructor() { + super(); + + this._githubButton = new ToolbarItemElement({ icon: 'github' }) + .onClick(() => { + shell.openExternal('https://github.com/LucasDower/ObjToSchematic'); + }); + + this._bugButton = new ToolbarItemElement({ icon: 'bug' }) + .onClick(() => { + shell.openExternal('https://github.com/LucasDower/ObjToSchematic/issues'); + }); + } + + // Header element shouldn't be + protected override _onEnabledChanged(): void { + return; + } + + public override generateHTML(): string { + return ` +
+
+
+
+ +
+
+
+
+ ObjToSchematic +
+
+ Up-to-date +
+
+
+
+
+
+ ${this._githubButton.generateHTML()} +
+
+ ${this._bugButton.generateHTML()} +
+
+
+
+ `; + } + + public override registerEvents(): void { + this._githubButton.registerEvents(); + this._bugButton.registerEvents(); + } + + public override finalise(): void { + const updateElement = UIUtil.getElementById('update-checker') as HTMLDivElement; + updateElement.style.animation = 'pulse-opacity 1.5s infinite'; + updateElement.innerHTML = 'Checking for updates...'; + + fetch('https://api.github.com/repos/LucasDower/ObjToSchematic/releases/latest') + .then((response) => response.json()) + .then((data) => { + const latest: string = data.tag_name; // e.g. v0.7.0 + const versionString = latest.substring(1); // e.g. 0.7.0 + const versionValues = versionString.split('.').map((x) => parseInt(x)); + + // Is the local version older than the latest release on GitHub? + let isGitHubVersionNewer = false; + if (versionValues[0] > AppConfig.Get.MAJOR_VERSION) { + isGitHubVersionNewer = true; + } else { + if (versionValues[1] > AppConfig.Get.MINOR_VERSION) { + isGitHubVersionNewer = true; + } else { + if (versionValues[2] > AppConfig.Get.HOTFIX_VERSION) { + isGitHubVersionNewer = true; + } + } + } + + /* + let isLocalVersionNewer = false; + if (versionValues[0] < AppConfig.Get.MAJOR_VERSION) { + isLocalVersionNewer = true; + } else { + if (versionValues[1] < AppConfig.Get.MINOR_VERSION) { + isLocalVersionNewer = true; + } else { + if (versionValues[2] > AppConfig.Get.HOTFIX_VERSION) { + isLocalVersionNewer = true; + } + } + } + */ + + LOG(`[VERSION]: Current: ${[AppConfig.Get.MAJOR_VERSION, AppConfig.Get.MINOR_VERSION, AppConfig.Get.HOTFIX_VERSION]}, Latest: ${versionValues}`); + + updateElement.style.animation = ''; + if (isGitHubVersionNewer) { + updateElement.innerHTML = `New ${versionString} update available!`; + + const linkElement = UIUtil.getElementById('update-link') as HTMLLinkElement; + linkElement.onclick = () => { + shell.openExternal('https://github.com/LucasDower/ObjToSchematic/releases/latest'); + }; + } else { + // Either using most up-to-date version or local version is newer (using unreleased dev or alpha build) + updateElement.innerHTML = `Version up-to-date!`; + } + }) + .catch((error) => { + LOG_ERROR(error); + + updateElement.style.animation = ''; + updateElement.innerHTML = 'Could not check for updates'; + }); + } +} diff --git a/src/ui/layout.ts b/src/ui/layout.ts index 200a209..5ee987c 100644 --- a/src/ui/layout.ts +++ b/src/ui/layout.ts @@ -19,6 +19,7 @@ import { CheckboxElement } from './elements/checkbox'; import { ComboBoxElement, ComboBoxItem } from './elements/combobox'; import { ConfigUIElement } from './elements/config_element'; import { FileInputElement } from './elements/file_input'; +import { HeaderUIElement } from './elements/header_element'; import { OutputElement } from './elements/output'; import { SliderElement } from './elements/slider'; import { ToolbarItemElement } from './elements/toolbar_item'; @@ -468,7 +469,7 @@ export class UI { } document.getElementById('properties')!.innerHTML = `
- ` + itemHTML + `
`; + ` + HeaderUIElement.Get.generateHTML() + itemHTML + ``; // Build toolbar let toolbarHTML = ''; @@ -567,6 +568,9 @@ export class UI { } public registerEvents() { + HeaderUIElement.Get.registerEvents(); + HeaderUIElement.Get.finalise(); + for (const groupName in this._ui) { const group = this._uiDull[groupName]; for (const elementName in group.elements) { diff --git a/styles.css b/styles.css index bbb34c5..e7d0827 100644 --- a/styles.css +++ b/styles.css @@ -18,6 +18,7 @@ --prop-sunken: hsl(0, 0%, 8%); --text-standard: hsl(0, 0%, 66%); + --text-muted: hsl(0, 0%, 45%); --text-disabled: hsl(0, 0%, 33%); --vertical-divider: hsl(0, 0%, 14%); @@ -797,10 +798,55 @@ svg { display: flex; flex-direction: row; gap: 2px; + align-items: center; } .col-item { display: flex; flex-direction: column; align-items: center; +} + +.logo { + width: 32px; + margin-right: 10px; +} + +.title { + font-size: 110%; +} + +.subtitle { + font-size: 90%; + font-weight: 300; + color: var(--text-muted); +} + +.header-cols { + justify-content: space-between; + width: 100%; + padding-top: 4px; +} + +.button-loading { + box-shadow: 0 0 0 0 rgba(0, 0, 0, 1); +} + +@keyframes pulse-opacity { + 0% { + opacity: 1; + } + + 50% { + opacity: 0.6; + } + + 100% { + opacity: 1; + } +} + +a { + font-weight: 400; + color: var(--prop-accent-hovered) } \ No newline at end of file