From 8fb58815b9b5acb98f5ab4dad95b45234fa1619d Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 14:20:33 +0100 Subject: [PATCH 1/9] * Added tooltips to toolbar buttons * Refactored component styles for easier use with CSS selectors --- src/ui/components/file_input.ts | 15 ++++-- src/ui/components/header.ts | 9 ++-- src/ui/components/toolbar_item.ts | 20 ++++++- src/ui/layout.ts | 42 ++++++++++----- src/util/ui_util.ts | 31 +++++------ styles.css | 88 +++++++++++++++++++++++++------ 6 files changed, 147 insertions(+), 58 deletions(-) diff --git a/src/ui/components/file_input.ts b/src/ui/components/file_input.ts index a2d36e8..67acd4d 100644 --- a/src/ui/components/file_input.ts +++ b/src/ui/components/file_input.ts @@ -3,20 +3,21 @@ import * as path from 'path'; import { ASSERT } from '../../util/error_util'; import { UIUtil } from '../../util/ui_util'; import { ConfigComponent } from './config'; +import { AppIcons } from '../icons'; export class FileComponent extends ConfigComponent { - private _loadedFilePath: string; + private _loadedFilePath: string | null; public constructor() { super(); - this._loadedFilePath = ''; + this._loadedFilePath = null; } protected override _generateInnerHTML() { return `
- ${this._loadedFilePath} + ${this._loadedFilePath ?? 'No file chosen'}
`; } @@ -62,8 +63,12 @@ export class FileComponent extends ConfigComponent { } protected override _updateStyles() { - const parsedPath = path.parse(this._loadedFilePath); - this._getElement().innerHTML = parsedPath.name + parsedPath.ext; + if (this._loadedFilePath) { + const parsedPath = path.parse(this._loadedFilePath); + this._getElement().innerHTML = parsedPath.name + parsedPath.ext; + } else { + this._getElement().innerHTML = 'No file chosen'; + } UIUtil.updateStyles(this._getElement(), { isHovered: this.hovered, diff --git a/src/ui/components/header.ts b/src/ui/components/header.ts index e7c9b48..2aa0484 100644 --- a/src/ui/components/header.ts +++ b/src/ui/components/header.ts @@ -22,17 +22,20 @@ export class HeaderComponent extends BaseComponent { this._githubButton = new ToolbarItemComponent({ id: 'gh', iconSVG: AppIcons.GITHUB }) .onClick(() => { window.open('https://github.com/LucasDower/ObjToSchematic'); - }); + }) + .setTooltip('Open GitHub repo'); this._bugButton = new ToolbarItemComponent({ id: 'bug', iconSVG: AppIcons.BUG }) .onClick(() => { window.open('https://github.com/LucasDower/ObjToSchematic/issues'); - }); + }) + .setTooltip('Open GitHub issues'); this._discordButton = new ToolbarItemComponent({ id: 'disc', iconSVG: AppIcons.DISCORD }) .onClick(() => { window.open('https://discord.gg/McS2VrBZPD'); - }); + }) + .setTooltip('Open Discord server'); } // Header element shouldn't be diff --git a/src/ui/components/toolbar_item.ts b/src/ui/components/toolbar_item.ts index 2e2f383..4ea8dd6 100644 --- a/src/ui/components/toolbar_item.ts +++ b/src/ui/components/toolbar_item.ts @@ -12,6 +12,7 @@ export type TToolbarItemParams = { export class ToolbarItemComponent extends BaseComponent { private _iconSVG: SVGSVGElement; private _label: string; + private _tooltip: string | null; private _onClick?: () => void; private _isActive: boolean; private _grow: boolean; @@ -33,6 +34,7 @@ export class ToolbarItemComponent extends BaseComponent { } this._label = ''; + this._tooltip = null; } public setGrow() { @@ -90,6 +92,11 @@ export class ToolbarItemComponent extends BaseComponent { return this; } + public setTooltip(text: string) { + this._tooltip = text; + return this; + } + public generateHTML() { if (this._grow) { return ` @@ -98,11 +105,20 @@ export class ToolbarItemComponent extends BaseComponent { `; } else { - return ` -
+ if (this._tooltip === null) { + return ` +
${this._iconSVG.outerHTML} ${this._label}
`; + } else { + return ` +
+ ${this._iconSVG.outerHTML} ${this._label} + ${this._tooltip} +
+ `; + } } } diff --git a/src/ui/layout.ts b/src/ui/layout.ts index 6d053a4..2ebe505 100644 --- a/src/ui/layout.ts +++ b/src/ui/layout.ts @@ -378,7 +378,8 @@ export class UI { }) .isEnabled(() => { return Renderer.Get.getModelsAvailable() >= MeshType.TriangleMesh; - }), + }) + .setTooltip('View mesh'), 'voxelMesh': new ToolbarItemComponent({ id: 'voxelMesh', iconSVG: AppIcons.VOXEL }) .onClick(() => { Renderer.Get.setModelToUse(MeshType.VoxelMesh); @@ -388,7 +389,8 @@ export class UI { }) .isEnabled(() => { return Renderer.Get.getModelsAvailable() >= MeshType.VoxelMesh; - }), + }) + .setTooltip('View voxel mesh'), 'blockMesh': new ToolbarItemComponent({ id: 'blockMesh', iconSVG: AppIcons.BLOCK }) .onClick(() => { Renderer.Get.setModelToUse(MeshType.BlockMesh); @@ -398,7 +400,8 @@ export class UI { }) .isEnabled(() => { return Renderer.Get.getModelsAvailable() >= MeshType.BlockMesh; - }), + }) + .setTooltip('View block mesh'), }, componentOrder: ['mesh', 'voxelMesh', 'blockMesh'], }, @@ -413,14 +416,16 @@ export class UI { }) .isEnabled(() => { return Renderer.Get.getActiveMeshType() !== MeshType.None; - }), + }) + .setTooltip('Toggle grid'), 'axes': new ToolbarItemComponent({ id: 'axes', iconSVG: AppIcons.AXES }) .onClick(() => { Renderer.Get.toggleIsAxesEnabled(); }) .isActive(() => { return Renderer.Get.isAxesEnabled(); - }), + }) + .setTooltip('Toggle axes'), 'night-vision': new ToolbarItemComponent({ id: 'night', iconSVG: AppIcons.BULB }) .onClick(() => { Renderer.Get.toggleIsNightVisionEnabled(); @@ -430,7 +435,8 @@ export class UI { }) .isEnabled(() => { return Renderer.Get.canToggleNightVision(); - }), + }) + .setTooltip('Toggle night vision'), }, componentOrder: ['grid', 'axes', 'night-vision'], }, @@ -445,7 +451,8 @@ export class UI { }) .isActive(() => { return Renderer.Get.isSliceViewerEnabled(); - }), + }) + .setTooltip('Toggle slice viewer'), 'plus': new ToolbarItemComponent({ id: 'plus', iconSVG: AppIcons.PLUS }) .onClick(() => { Renderer.Get.incrementSliceHeight(); @@ -453,7 +460,8 @@ export class UI { .isEnabled(() => { return Renderer.Get.isSliceViewerEnabled() && Renderer.Get.canIncrementSliceHeight(); - }), + }) + .setTooltip('Decrement slice'), 'minus': new ToolbarItemComponent({ id: 'minus', iconSVG: AppIcons.MINUS }) .onClick(() => { Renderer.Get.decrementSliceHeight(); @@ -461,7 +469,8 @@ export class UI { .isEnabled(() => { return Renderer.Get.isSliceViewerEnabled() && Renderer.Get.canDecrementSliceHeight(); - }), + }) + .setTooltip('Increment slice'), }, componentOrder: ['slice', 'plus', 'minus'], }, @@ -476,15 +485,18 @@ export class UI { 'zoomOut': new ToolbarItemComponent({ id: 'zout', iconSVG: AppIcons.MINUS }) .onClick(() => { ArcballCamera.Get.onZoomOut(); - }), + }) + .setTooltip('Zoom out'), 'zoomIn': new ToolbarItemComponent({ id: 'zin', iconSVG: AppIcons.PLUS }) .onClick(() => { ArcballCamera.Get.onZoomIn(); - }), + }) + .setTooltip('Zoom in'), 'reset': new ToolbarItemComponent({ id: 'reset', iconSVG: AppIcons.CENTRE }) .onClick(() => { ArcballCamera.Get.reset(); - }), + }) + .setTooltip('Reset camera'), }, componentOrder: ['zoomOut', 'zoomIn', 'reset'], }, @@ -496,14 +508,16 @@ export class UI { }) .isActive(() => { return ArcballCamera.Get.isPerspective(); - }), + }) + .setTooltip('Perspective camera'), 'orthographic': new ToolbarItemComponent({ id: 'orth', iconSVG: AppIcons.ORTHOGRAPHIC }) .onClick(() => { ArcballCamera.Get.setCameraMode('orthographic'); }) .isActive(() => { return ArcballCamera.Get.isOrthographic(); - }), + }) + .setTooltip('Orthographic camera'), }, componentOrder: ['perspective', 'orthographic'], }, diff --git a/src/util/ui_util.ts b/src/util/ui_util.ts index 06e8d32..35bf8db 100644 --- a/src/util/ui_util.ts +++ b/src/util/ui_util.ts @@ -14,31 +14,24 @@ export namespace UIUtil { } export function clearStyles(element: HTMLElement) { - element.classList.remove('style-inactive-disabled'); - element.classList.remove('style-inactive-enabled'); - element.classList.remove('style-inactive-hover'); - element.classList.remove('style-active-disabled'); - element.classList.remove('style-active-enabled'); - element.classList.remove('style-active-hover'); + element.classList.remove('disabled'); + element.classList.remove('hover'); + element.classList.remove('active'); } export function updateStyles(element: HTMLElement, style: TStyleParams) { clearStyles(element); - let styleToApply = `style`; - - styleToApply += style.isActive ? '-active' : '-inactive'; - - if (style.isEnabled) { - if (style.isHovered) { - styleToApply += '-hover'; - } else { - styleToApply += '-enabled'; - } - } else { - styleToApply += '-disabled'; + if (style.isActive) { + element.classList.add('active'); } - element.classList.add(styleToApply); + if (!style.isEnabled) { + element.classList.add('disabled'); + } + + if (style.isHovered && style.isEnabled) { + element.classList.add('hover'); + } } } diff --git a/styles.css b/styles.css index b00fb7f..58c34e8 100644 --- a/styles.css +++ b/styles.css @@ -253,6 +253,9 @@ select { transition: width 0.2s; } + + + .struct-prop { display: flex; align-items: center; @@ -264,42 +267,49 @@ select { border-style: solid; } -.style-inactive-disabled { +.struct-prop.disabled { border-color: var(--gray-500); color: var(--text-dark); background: var(--gray-400); cursor: inherit; } -.style-inactive-enabled { - border-color: var(--gray-600); - color: var(--text-standard); - background: var(--gray-500); -} -.style-inactive-hover { + +.struct-prop.hover { border-color: var(--gray-700); color: var(--text-light); background: var(--gray-600); cursor: pointer; } -.style-active-disabled { +.struct-prop:not(.disabled):not(.hover) { + border-color: var(--gray-600); + color: var(--text-standard); + background: var(--gray-500); +} + +.struct-prop.active.disabled { border-color: var(--blue-450); color: var(--text-dim); background: var(--blue-400); cursor: inherit; } -.style-active-enabled { - border-color: var(--blue-600); - color: var(--text-bright); - background: var(--blue-500); -} -.style-active-hover { + +.struct-prop.active.hover { border-color: var(--blue-700); color: var(--text-bright); background: var(--blue-600); cursor: pointer; } +.struct-prop.active:not(.disabled):not(.hover) { + border-color: var(--blue-600); + color: var(--text-bright); + background: var(--blue-500); +} + + + + .h-div { height: 0px; border-radius: 2px; @@ -348,7 +358,7 @@ select { justify-content: center; flex-grow: 1; } -.spinbox-value.style-inactive-hover { +.spinbox-value .inactive .hover { cursor: e-resize; } @@ -676,4 +686,52 @@ a { .hide { display: none; +} + + + +.tooltip-text { + visibility: hidden; + opacity: 0; + position: absolute; + z-index: 1; + font-size: var(--font-size-small); + color: var(--text-light); + background-color: var(--gray-600); + padding: 5px 10px; + border-radius: 5px; + border: 1px solid var(--gray-700); + transition: 0.15s; + pointer-events: none; + box-shadow: rgba(0, 0, 0, 0.1) 0px 0px 16px; + white-space: nowrap; +} + +.hover-text:hover:not(.disabled) .tooltip-text { + visibility: visible; + opacity: 1; +} + +.top { + top: -40px; + left: -50%; +} + +.bottom { + top: 25px; + left: -50%; +} + +.left { + top: 1px; + right: 120%; +} + +.right { + top: 2px; + left: 120%; +} + +.hover-text { + position: relative; } \ No newline at end of file From d67e4451e1f285b79283a00abdae26746d1d97f3 Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 14:23:04 +0100 Subject: [PATCH 2/9] Fixed enabling non-existent action groups --- src/ui/layout.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ui/layout.ts b/src/ui/layout.ts index 2ebe505..ed20e14 100644 --- a/src/ui/layout.ts +++ b/src/ui/layout.ts @@ -790,10 +790,12 @@ export class UI { * Enable a specific action. */ public enable(action: EAction) { - this._forEachComponent(action, (component) => { - component.setEnabled(true); - }); - this._getGroup(action).execButton?.setEnabled(true); + if (action < EAction.MAX) { + this._forEachComponent(action, (component) => { + component.setEnabled(true); + }); + this._getGroup(action).execButton?.setEnabled(true); + } } /** From 2f1978f8bb9da471afd86013708a873745164e13 Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 14:25:17 +0100 Subject: [PATCH 3/9] Disabled checkbox text no longer dim text colour --- src/ui/components/checkbox.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/components/checkbox.ts b/src/ui/components/checkbox.ts index fb48571..07469f2 100644 --- a/src/ui/components/checkbox.ts +++ b/src/ui/components/checkbox.ts @@ -152,7 +152,7 @@ export class CheckboxComponent extends ConfigComponent Date: Mon, 26 Jun 2023 16:11:22 +0100 Subject: [PATCH 4/9] * Refactored analytics * Added tracking disclaimer * Usage events are now tracked to improve usage --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/analytics.ts | 28 ++++++++++++++++++++++++++++ src/app_context.ts | 30 ++++++++++++++++++++++++++++++ src/ui/components/header.ts | 7 +++++-- styles.css | 5 +++++ template.html | 14 -------------- 7 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 src/analytics.ts diff --git a/package-lock.json b/package-lock.json index af77eb5..c0b4192 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "eslint-config-google": "^0.14.0", "eslint-plugin-simple-import-sort": "^8.0.0", "file-loader": "^6.2.0", + "ga-gtag": "^1.1.7", "hsv-rgb": "^1.0.0", "html-webpack-plugin": "^5.5.0", "i18next": "^22.4.14", @@ -4925,6 +4926,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "node_modules/ga-gtag": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/ga-gtag/-/ga-gtag-1.1.7.tgz", + "integrity": "sha512-fT/D87hhuNIAmEB2z9mxz88gMFYc1olpX/fETHidZ51sYJ4y6OFch8HZ0DoNWPGFw1BCHB0fqt68dUWvd8kM1Q==", + "dev": true + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -14573,6 +14580,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, + "ga-gtag": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/ga-gtag/-/ga-gtag-1.1.7.tgz", + "integrity": "sha512-fT/D87hhuNIAmEB2z9mxz88gMFYc1olpX/fETHidZ51sYJ4y6OFch8HZ0DoNWPGFw1BCHB0fqt68dUWvd8kM1Q==", + "dev": true + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", diff --git a/package.json b/package.json index 504dbe4..86d9241 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "eslint-config-google": "^0.14.0", "eslint-plugin-simple-import-sort": "^8.0.0", "file-loader": "^6.2.0", + "ga-gtag": "^1.1.7", "hsv-rgb": "^1.0.0", "html-webpack-plugin": "^5.5.0", "i18next": "^22.4.14", diff --git a/src/analytics.ts b/src/analytics.ts new file mode 100644 index 0000000..3284928 --- /dev/null +++ b/src/analytics.ts @@ -0,0 +1,28 @@ +import { AppConsole } from './ui/console'; +const gtag = require('ga-gtag'); + +export class AppAnalytics { + private _ready: boolean; + + private static _instance: AppAnalytics; + public static get Get() { + return this._instance || (this._instance = new this()); + } + + private constructor() { + this._ready = false; + } + + public static Init() { + gtag.install('G-W0SCWQ7HGJ', { 'send_page_view': true }); + gtag.gtag('config', 'G-W0SCWQ7HGJ', { 'debug_mode': true }); + this.Get._ready = true; + } + + public static Event(id: string, attributes?: any) { + if (this.Get._ready) { + console.log('[Analytics]: Tracked event', id, attributes); + gtag.gtag('event', id, Object.assign(attributes ?? {}, { 'debug_mode': true })); + } + } +} \ No newline at end of file diff --git a/src/app_context.ts b/src/app_context.ts index a737a5d..0d22c37 100644 --- a/src/app_context.ts +++ b/src/app_context.ts @@ -1,4 +1,5 @@ import '../styles.css'; +import { AppAnalytics } from './analytics'; import { FallableBehaviour } from './block_mesh'; import { ArcballCamera } from './camera'; @@ -38,6 +39,8 @@ export class AppContext { } public static async init() { + AppAnalytics.Init(); + await Localiser.Get.init(); AppConsole.info(LOC('init.initialising')); @@ -81,11 +84,13 @@ export class AppContext { private async _import(): Promise { // Gather data from the UI to send to the worker const components = UI.Get.layout.import.components; + let filetype: string; AppConsole.info(LOC('import.importing_mesh')); { // Instruct the worker to perform the job and await the result const file = components.input.getValue(); + filetype = file.type; const resultImport = await this._workerController.execute({ action: 'Import', @@ -131,6 +136,9 @@ export class AppContext { } AppConsole.success(LOC('import.rendered_mesh')); + AppAnalytics.Event('import', { + 'filetype': filetype, + }); return true; } @@ -163,6 +171,7 @@ export class AppContext { } AppConsole.success(LOC('materials.updated_materials')); + AppAnalytics.Event('materials') return true; } @@ -222,6 +231,14 @@ export class AppContext { } AppConsole.success(LOC('voxelise.rendered_voxel_mesh')); + AppAnalytics.Event('voxelise', { + constraintAxis: components.constraintAxis.getValue(), + voxeliser: components.voxeliser.getValue(), + size: components.size.getValue(), + useMultisampleColouring: components.multisampleColouring.getValue(), + enableAmbientOcclusion: components.ambientOcclusion.getValue(), + voxelOverlapRule: components.voxelOverlapRule.getValue(), + }); return true; } @@ -287,6 +304,16 @@ export class AppContext { } AppConsole.success(LOC('assign.rendered_block_mesh')); + AppAnalytics.Event('assign', { + dithering: components.dithering.getValue(), + ditheringMagnitude: components.ditheringMagnitude.getValue(), + fallable: components.fallable.getValue() as FallableBehaviour, + resolution: Math.pow(2, components.colourAccuracy.getValue()), + calculateLighting: components.calculateLighting.getValue(), + lightThreshold: components.lightThreshold.getValue(), + contextualAveraging: components.contextualAveraging.getValue(), + errorWeight: components.errorWeight.getValue() / 10, + }); return true; } @@ -327,6 +354,9 @@ export class AppContext { } AppConsole.success(LOC('export.exported_structure')); + AppAnalytics.Event('export', { + exporter: components.export.getValue(), + }); return true; } diff --git a/src/ui/components/header.ts b/src/ui/components/header.ts index 2aa0484..fa6d850 100644 --- a/src/ui/components/header.ts +++ b/src/ui/components/header.ts @@ -67,10 +67,13 @@ export class HeaderComponent extends BaseComponent { ${this._discordButton.generateHTML()}
-
-
+
+
${LOC('description')}
+
+ This site may use cookies and similar tracking technologies (like web beacons) to access and store information about usage. +
`; } diff --git a/styles.css b/styles.css index 58c34e8..d74f7a4 100644 --- a/styles.css +++ b/styles.css @@ -734,4 +734,9 @@ a { .hover-text { position: relative; +} + +.privacy-disclaimer { + font-size: var(--font-size-small); + color: var(--text-dim); } \ No newline at end of file diff --git a/template.html b/template.html index 6b7e1f0..019ddd0 100644 --- a/template.html +++ b/template.html @@ -1,20 +1,6 @@ - - - ObjToSchematic Web Date: Mon, 26 Jun 2023 16:38:21 +0100 Subject: [PATCH 5/9] Remove debug mode on analytic events for release builds --- src/analytics.ts | 7 +++++-- src/config.ts | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/analytics.ts b/src/analytics.ts index 3284928..ace50f9 100644 --- a/src/analytics.ts +++ b/src/analytics.ts @@ -1,3 +1,4 @@ +import { AppConfig } from './config'; import { AppConsole } from './ui/console'; const gtag = require('ga-gtag'); @@ -15,14 +16,16 @@ export class AppAnalytics { public static Init() { gtag.install('G-W0SCWQ7HGJ', { 'send_page_view': true }); - gtag.gtag('config', 'G-W0SCWQ7HGJ', { 'debug_mode': true }); + if (AppConfig.Get.VERSION_TYPE === 'd') { + gtag.gtag('config', 'G-W0SCWQ7HGJ', { 'debug_mode': true }); + } this.Get._ready = true; } public static Event(id: string, attributes?: any) { if (this.Get._ready) { console.log('[Analytics]: Tracked event', id, attributes); - gtag.gtag('event', id, Object.assign(attributes ?? {}, { 'debug_mode': true })); + gtag.gtag('event', id, Object.assign(attributes ?? {}, AppConfig.Get.VERSION_TYPE === 'd' ? { 'debug_mode': true } : {})); } } } \ No newline at end of file diff --git a/src/config.ts b/src/config.ts index 019b85a..aa98424 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,11 +8,11 @@ export class AppConfig { return this._instance || (this._instance = new this()); } - public readonly RELEASE_MODE = true; + public readonly RELEASE_MODE; public readonly MAJOR_VERSION = 0; public readonly MINOR_VERSION = 8; - public readonly HOTFIX_VERSION = 5; - public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'r'; // dev, alpha, or release build + public readonly HOTFIX_VERSION = 6; + public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'd'; // dev, alpha, or release build public readonly MINECRAFT_VERSION = '1.19.4'; public readonly LOCALE = 'en_GB'; @@ -43,6 +43,7 @@ export class AppConfig { public readonly FRESNEL_MIX = 0.3; private constructor() { + this.RELEASE_MODE = this.VERSION_TYPE === 'r'; } public dumpConfig() { From 2576d122782245d938bac6a70c492dbb68282109 Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 16:40:59 +0100 Subject: [PATCH 6/9] Update to release build --- src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index aa98424..5adeba7 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,7 +12,7 @@ export class AppConfig { public readonly MAJOR_VERSION = 0; public readonly MINOR_VERSION = 8; public readonly HOTFIX_VERSION = 6; - public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'd'; // dev, alpha, or release build + public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'r'; // dev, alpha, or release build public readonly MINECRAFT_VERSION = '1.19.4'; public readonly LOCALE = 'en_GB'; From 5efbbab234e615503bd8971832788d1c4921f004 Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 17:08:05 +0100 Subject: [PATCH 7/9] Added missing translation keys for tooltips --- loc/en_GB.ts | 20 +++++++++++++++ src/config.ts | 2 +- src/localiser.ts | 2 ++ src/ui/components/file_input.ts | 9 +++++-- src/ui/components/header.ts | 10 +++++--- src/ui/components/toolbar_item.ts | 19 +++++++++----- src/ui/layout.ts | 42 ++++++++++++++++++++----------- 7 files changed, 78 insertions(+), 26 deletions(-) diff --git a/loc/en_GB.ts b/loc/en_GB.ts index 7c40944..216ff9e 100644 --- a/loc/en_GB.ts +++ b/loc/en_GB.ts @@ -39,6 +39,7 @@ export const en_GB = { unsupported_image_type: 'Cannot read \'{{file_name}}\', unsupported file type \'{{file_type}}\'', components: { input: '3D Model (.obj, .glb)', + no_file_chosen: 'No file chosen', rotation: 'Rotation', }, }, @@ -162,5 +163,24 @@ export const en_GB = { off: 'Off', advanced_settings: 'Advanced settings' }, + toolbar: { + view_mesh: 'View mesh', + view_voxel_mesh: 'View voxel mesh', + view_block_mesh: 'View block mesh', + toggle_grid: 'Toggle grid', + toggle_axes: 'Toggle axes', + toggle_night_vision: 'Toggle night vision', + toggle_slice_viewer: 'Toggle slice viewer', + decrement_slice: 'Decrement slice', + increment_slice: 'Increment slice', + zoom_in: 'Zoom in', + zoom_out: 'Zoom out', + reset_camera: 'Reset camera', + perspective_camera: 'Perspective camera', + orthographic_camera: 'Orthographic camera', + open_github_repo: 'Open GitHub repo', + open_github_issues: 'Open GitHub issues', + join_discord: 'Join Discord server', + } }, }; diff --git a/src/config.ts b/src/config.ts index 5adeba7..cfe52c9 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,7 +11,7 @@ export class AppConfig { public readonly RELEASE_MODE; public readonly MAJOR_VERSION = 0; public readonly MINOR_VERSION = 8; - public readonly HOTFIX_VERSION = 6; + public readonly HOTFIX_VERSION = 7; public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'r'; // dev, alpha, or release build public readonly MINECRAFT_VERSION = '1.19.4'; diff --git a/src/localiser.ts b/src/localiser.ts index cf5b371..6b867eb 100644 --- a/src/localiser.ts +++ b/src/localiser.ts @@ -23,6 +23,8 @@ export type Concat = export type TLocalisedString = TBrand; +export type TLocalisedKey = DeepLeafKeys; + export class Localiser { /* Singleton */ private static _instance: Localiser; diff --git a/src/ui/components/file_input.ts b/src/ui/components/file_input.ts index 67acd4d..1c1499c 100644 --- a/src/ui/components/file_input.ts +++ b/src/ui/components/file_input.ts @@ -4,6 +4,7 @@ import { ASSERT } from '../../util/error_util'; import { UIUtil } from '../../util/ui_util'; import { ConfigComponent } from './config'; import { AppIcons } from '../icons'; +import { LOC } from '../../localiser'; export class FileComponent extends ConfigComponent { private _loadedFilePath: string | null; @@ -17,7 +18,7 @@ export class FileComponent extends ConfigComponent { return `
- ${this._loadedFilePath ?? 'No file chosen'} + ${this._loadedFilePath ?? LOC('import.components.no_file_chosen')}
`; } @@ -67,7 +68,7 @@ export class FileComponent extends ConfigComponent { const parsedPath = path.parse(this._loadedFilePath); this._getElement().innerHTML = parsedPath.name + parsedPath.ext; } else { - this._getElement().innerHTML = 'No file chosen'; + this._getElement().innerHTML = `${LOC('import.components.no_file_chosen')}`; } UIUtil.updateStyles(this._getElement(), { @@ -76,4 +77,8 @@ export class FileComponent extends ConfigComponent { isActive: false, }); } + + public override refresh(): void { + this._getElement().innerHTML = `${LOC('import.components.no_file_chosen')}`; + } } diff --git a/src/ui/components/header.ts b/src/ui/components/header.ts index fa6d850..353f4bb 100644 --- a/src/ui/components/header.ts +++ b/src/ui/components/header.ts @@ -23,19 +23,19 @@ export class HeaderComponent extends BaseComponent { .onClick(() => { window.open('https://github.com/LucasDower/ObjToSchematic'); }) - .setTooltip('Open GitHub repo'); + .setTooltip('toolbar.open_github_repo'); this._bugButton = new ToolbarItemComponent({ id: 'bug', iconSVG: AppIcons.BUG }) .onClick(() => { window.open('https://github.com/LucasDower/ObjToSchematic/issues'); }) - .setTooltip('Open GitHub issues'); + .setTooltip('toolbar.open_github_issues'); this._discordButton = new ToolbarItemComponent({ id: 'disc', iconSVG: AppIcons.DISCORD }) .onClick(() => { window.open('https://discord.gg/McS2VrBZPD'); }) - .setTooltip('Open Discord server'); + .setTooltip('toolbar.join_discord'); } // Header element shouldn't be @@ -80,6 +80,10 @@ export class HeaderComponent extends BaseComponent { public refresh() { UIUtil.getElementById('header-desc').innerText = LOC('description'); + + this._githubButton.updateTranslation(); + this._bugButton.updateTranslation(); + this._discordButton.updateTranslation(); } public override registerEvents(): void { diff --git a/src/ui/components/toolbar_item.ts b/src/ui/components/toolbar_item.ts index 4ea8dd6..b779312 100644 --- a/src/ui/components/toolbar_item.ts +++ b/src/ui/components/toolbar_item.ts @@ -1,6 +1,7 @@ import { ASSERT } from '../../util/error_util'; import { UIUtil } from '../../util/ui_util'; import { BaseComponent } from './base'; +import { LOC, TLocalisedKey } from '../../localiser'; export type TToolbarBooleanProperty = 'enabled' | 'active'; @@ -12,10 +13,10 @@ export type TToolbarItemParams = { export class ToolbarItemComponent extends BaseComponent { private _iconSVG: SVGSVGElement; private _label: string; - private _tooltip: string | null; private _onClick?: () => void; private _isActive: boolean; private _grow: boolean; + private _tooltipLocKey: TLocalisedKey | null; public constructor(params: TToolbarItemParams) { super(); @@ -34,7 +35,7 @@ export class ToolbarItemComponent extends BaseComponent { } this._label = ''; - this._tooltip = null; + this._tooltipLocKey = null; } public setGrow() { @@ -42,6 +43,12 @@ export class ToolbarItemComponent extends BaseComponent { return this; } + public updateTranslation() { + if (this._tooltipLocKey) { + UIUtil.getElementById(this._getId() + '-tooltip').innerHTML = LOC(this._tooltipLocKey); + } + } + public setActive(isActive: boolean) { this._isActive = isActive; this._updateStyles(); @@ -92,8 +99,8 @@ export class ToolbarItemComponent extends BaseComponent { return this; } - public setTooltip(text: string) { - this._tooltip = text; + public setTooltip(text: TLocalisedKey) { + this._tooltipLocKey = text; return this; } @@ -105,7 +112,7 @@ export class ToolbarItemComponent extends BaseComponent {
`; } else { - if (this._tooltip === null) { + if (this._tooltipLocKey === null) { return `
${this._iconSVG.outerHTML} ${this._label} @@ -115,7 +122,7 @@ export class ToolbarItemComponent extends BaseComponent { return `
${this._iconSVG.outerHTML} ${this._label} - ${this._tooltip} + ${LOC(this._tooltipLocKey)}
`; } diff --git a/src/ui/layout.ts b/src/ui/layout.ts index ed20e14..972de4d 100644 --- a/src/ui/layout.ts +++ b/src/ui/layout.ts @@ -379,7 +379,7 @@ export class UI { .isEnabled(() => { return Renderer.Get.getModelsAvailable() >= MeshType.TriangleMesh; }) - .setTooltip('View mesh'), + .setTooltip('toolbar.view_mesh'), 'voxelMesh': new ToolbarItemComponent({ id: 'voxelMesh', iconSVG: AppIcons.VOXEL }) .onClick(() => { Renderer.Get.setModelToUse(MeshType.VoxelMesh); @@ -390,7 +390,7 @@ export class UI { .isEnabled(() => { return Renderer.Get.getModelsAvailable() >= MeshType.VoxelMesh; }) - .setTooltip('View voxel mesh'), + .setTooltip('toolbar.view_voxel_mesh'), 'blockMesh': new ToolbarItemComponent({ id: 'blockMesh', iconSVG: AppIcons.BLOCK }) .onClick(() => { Renderer.Get.setModelToUse(MeshType.BlockMesh); @@ -401,7 +401,7 @@ export class UI { .isEnabled(() => { return Renderer.Get.getModelsAvailable() >= MeshType.BlockMesh; }) - .setTooltip('View block mesh'), + .setTooltip('toolbar.view_block_mesh'), }, componentOrder: ['mesh', 'voxelMesh', 'blockMesh'], }, @@ -417,7 +417,7 @@ export class UI { .isEnabled(() => { return Renderer.Get.getActiveMeshType() !== MeshType.None; }) - .setTooltip('Toggle grid'), + .setTooltip('toolbar.toggle_grid'), 'axes': new ToolbarItemComponent({ id: 'axes', iconSVG: AppIcons.AXES }) .onClick(() => { Renderer.Get.toggleIsAxesEnabled(); @@ -425,7 +425,7 @@ export class UI { .isActive(() => { return Renderer.Get.isAxesEnabled(); }) - .setTooltip('Toggle axes'), + .setTooltip('toolbar.toggle_axes'), 'night-vision': new ToolbarItemComponent({ id: 'night', iconSVG: AppIcons.BULB }) .onClick(() => { Renderer.Get.toggleIsNightVisionEnabled(); @@ -436,7 +436,7 @@ export class UI { .isEnabled(() => { return Renderer.Get.canToggleNightVision(); }) - .setTooltip('Toggle night vision'), + .setTooltip('toolbar.toggle_night_vision'), }, componentOrder: ['grid', 'axes', 'night-vision'], }, @@ -452,7 +452,7 @@ export class UI { .isActive(() => { return Renderer.Get.isSliceViewerEnabled(); }) - .setTooltip('Toggle slice viewer'), + .setTooltip('toolbar.toggle_slice_viewer'), 'plus': new ToolbarItemComponent({ id: 'plus', iconSVG: AppIcons.PLUS }) .onClick(() => { Renderer.Get.incrementSliceHeight(); @@ -461,7 +461,7 @@ export class UI { return Renderer.Get.isSliceViewerEnabled() && Renderer.Get.canIncrementSliceHeight(); }) - .setTooltip('Decrement slice'), + .setTooltip('toolbar.decrement_slice'), 'minus': new ToolbarItemComponent({ id: 'minus', iconSVG: AppIcons.MINUS }) .onClick(() => { Renderer.Get.decrementSliceHeight(); @@ -470,7 +470,7 @@ export class UI { return Renderer.Get.isSliceViewerEnabled() && Renderer.Get.canDecrementSliceHeight(); }) - .setTooltip('Increment slice'), + .setTooltip('toolbar.increment_slice'), }, componentOrder: ['slice', 'plus', 'minus'], }, @@ -486,17 +486,17 @@ export class UI { .onClick(() => { ArcballCamera.Get.onZoomOut(); }) - .setTooltip('Zoom out'), + .setTooltip('toolbar.zoom_out'), 'zoomIn': new ToolbarItemComponent({ id: 'zin', iconSVG: AppIcons.PLUS }) .onClick(() => { ArcballCamera.Get.onZoomIn(); }) - .setTooltip('Zoom in'), + .setTooltip('toolbar.zoom_in'), 'reset': new ToolbarItemComponent({ id: 'reset', iconSVG: AppIcons.CENTRE }) .onClick(() => { ArcballCamera.Get.reset(); }) - .setTooltip('Reset camera'), + .setTooltip('toolbar.reset_camera'), }, componentOrder: ['zoomOut', 'zoomIn', 'reset'], }, @@ -509,7 +509,7 @@ export class UI { .isActive(() => { return ArcballCamera.Get.isPerspective(); }) - .setTooltip('Perspective camera'), + .setTooltip('toolbar.perspective_camera'), 'orthographic': new ToolbarItemComponent({ id: 'orth', iconSVG: AppIcons.ORTHOGRAPHIC }) .onClick(() => { ArcballCamera.Get.setCameraMode('orthographic'); @@ -517,7 +517,7 @@ export class UI { .isActive(() => { return ArcballCamera.Get.isOrthographic(); }) - .setTooltip('Orthographic camera'), + .setTooltip('toolbar.orthographic_camera'), }, componentOrder: ['perspective', 'orthographic'], }, @@ -679,6 +679,20 @@ export class UI { private _handleLanguageChange() { HeaderComponent.Get.refresh(); + + Object.values(this._toolbarLeft.groups).forEach((group) => { + Object.values(group.components).forEach((comp) => { + comp.updateTranslation(); + }); + }); + + Object.values(this._toolbarRight.groups).forEach((group) => { + Object.values(group.components).forEach((comp) => { + comp.updateTranslation(); + }); + }); + + for (let i = 0; i < EAction.MAX; ++i) { const group = this._getGroup(i); const header = UIUtil.getElementById(`component_header_${group.id}`); From 82acb0133d88b790169b7e62c580777a747d59fc Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 17:22:07 +0100 Subject: [PATCH 8/9] Minor update to analytics init --- src/analytics.ts | 9 ++++++--- src/config.ts | 4 ++++ src/ui/components/header.ts | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/analytics.ts b/src/analytics.ts index ace50f9..2997da4 100644 --- a/src/analytics.ts +++ b/src/analytics.ts @@ -16,10 +16,13 @@ export class AppAnalytics { public static Init() { gtag.install('G-W0SCWQ7HGJ', { 'send_page_view': true }); - if (AppConfig.Get.VERSION_TYPE === 'd') { - gtag.gtag('config', 'G-W0SCWQ7HGJ', { 'debug_mode': true }); - } + gtag.gtag('js', new Date()); + gtag.gtag('config', 'G-W0SCWQ7HGJ', AppConfig.Get.VERSION_TYPE === 'd' ? { 'debug_mode': true } : {}); this.Get._ready = true; + + this.Event('init', { + version: AppConfig.Get.getVersionString(), + }) } public static Event(id: string, attributes?: any) { diff --git a/src/config.ts b/src/config.ts index cfe52c9..d3179c2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -49,4 +49,8 @@ export class AppConfig { public dumpConfig() { LOG(this); } + + public getVersionString() { + return `v${this.MAJOR_VERSION}.${this.MINOR_VERSION}.${this.HOTFIX_VERSION}${this.VERSION_TYPE}`; + } } diff --git a/src/ui/components/header.ts b/src/ui/components/header.ts index 353f4bb..f34e4d0 100644 --- a/src/ui/components/header.ts +++ b/src/ui/components/header.ts @@ -56,7 +56,7 @@ export class HeaderComponent extends BaseComponent { ObjToSchematic
- v${AppConfig.Get.MAJOR_VERSION}.${AppConfig.Get.MINOR_VERSION}.${AppConfig.Get.HOTFIX_VERSION}${AppConfig.Get.VERSION_TYPE} • Minecraft ${AppConfig.Get.MINECRAFT_VERSION} + ${AppConfig.Get.getVersionString()} • Minecraft ${AppConfig.Get.MINECRAFT_VERSION}
From 8e9d527bee4ffc343ead3df515ad42c910a08d17 Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Mon, 26 Jun 2023 17:22:42 +0100 Subject: [PATCH 9/9] Bump version --- src/config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.ts b/src/config.ts index d3179c2..5da6194 100644 --- a/src/config.ts +++ b/src/config.ts @@ -11,7 +11,7 @@ export class AppConfig { public readonly RELEASE_MODE; public readonly MAJOR_VERSION = 0; public readonly MINOR_VERSION = 8; - public readonly HOTFIX_VERSION = 7; + public readonly HOTFIX_VERSION = 8; public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'r'; // dev, alpha, or release build public readonly MINECRAFT_VERSION = '1.19.4';