forked from mirror/ObjToSchematic
Merge branch 'main' of https://github.com/LucasDower/ObjToSchematic
This commit is contained in:
commit
334f5e07f4
20
loc/en_GB.ts
20
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',
|
||||
}
|
||||
},
|
||||
};
|
||||
|
13
package-lock.json
generated
13
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
34
src/analytics.ts
Normal file
34
src/analytics.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { AppConfig } from './config';
|
||||
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('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) {
|
||||
if (this.Get._ready) {
|
||||
console.log('[Analytics]: Tracked event', id, attributes);
|
||||
gtag.gtag('event', id, Object.assign(attributes ?? {}, AppConfig.Get.VERSION_TYPE === 'd' ? { 'debug_mode': true } : {}));
|
||||
}
|
||||
}
|
||||
}
|
@ -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<boolean> {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,10 @@ 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 HOTFIX_VERSION = 8;
|
||||
public readonly VERSION_TYPE: 'd' | 'a' | 'r' = 'r'; // dev, alpha, or release build
|
||||
public readonly MINECRAFT_VERSION = '1.19.4';
|
||||
|
||||
@ -43,9 +43,14 @@ export class AppConfig {
|
||||
public readonly FRESNEL_MIX = 0.3;
|
||||
|
||||
private constructor() {
|
||||
this.RELEASE_MODE = this.VERSION_TYPE === 'r';
|
||||
}
|
||||
|
||||
public dumpConfig() {
|
||||
LOG(this);
|
||||
}
|
||||
|
||||
public getVersionString() {
|
||||
return `v${this.MAJOR_VERSION}.${this.MINOR_VERSION}.${this.HOTFIX_VERSION}${this.VERSION_TYPE}`;
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ export type Concat<K extends string, P extends string> =
|
||||
|
||||
export type TLocalisedString = TBrand<string, 'loc'>;
|
||||
|
||||
export type TLocalisedKey = DeepLeafKeys<TTranslationMap>;
|
||||
|
||||
export class Localiser {
|
||||
/* Singleton */
|
||||
private static _instance: Localiser;
|
||||
|
@ -152,7 +152,7 @@ export class CheckboxComponent extends ConfigComponent<boolean, HTMLSelectElemen
|
||||
if (this.enabled) {
|
||||
if (this.hovered) {
|
||||
checkboxTextElement.classList.add('text-light');
|
||||
} else if (this.getValue()) {
|
||||
} else {
|
||||
checkboxTextElement.classList.add('text-standard');
|
||||
}
|
||||
} else {
|
||||
|
@ -3,20 +3,22 @@ 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';
|
||||
import { LOC } from '../../localiser';
|
||||
|
||||
export class FileComponent extends ConfigComponent<File, HTMLDivElement> {
|
||||
private _loadedFilePath: string;
|
||||
private _loadedFilePath: string | null;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this._loadedFilePath = '';
|
||||
this._loadedFilePath = null;
|
||||
}
|
||||
|
||||
protected override _generateInnerHTML() {
|
||||
return `
|
||||
<div class="input-file struct-prop" id="${this._getId()}">
|
||||
<input type="file" accept=".obj,,.glb" style="display: none;" id="${this._getId()}-input">
|
||||
${this._loadedFilePath}
|
||||
${this._loadedFilePath ?? LOC('import.components.no_file_chosen')}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@ -62,8 +64,12 @@ export class FileComponent extends ConfigComponent<File, HTMLDivElement> {
|
||||
}
|
||||
|
||||
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 = `<i>${LOC('import.components.no_file_chosen')}</i>`;
|
||||
}
|
||||
|
||||
UIUtil.updateStyles(this._getElement(), {
|
||||
isHovered: this.hovered,
|
||||
@ -71,4 +77,8 @@ export class FileComponent extends ConfigComponent<File, HTMLDivElement> {
|
||||
isActive: false,
|
||||
});
|
||||
}
|
||||
|
||||
public override refresh(): void {
|
||||
this._getElement().innerHTML = `<i>${LOC('import.components.no_file_chosen')}</i>`;
|
||||
}
|
||||
}
|
||||
|
@ -22,17 +22,20 @@ export class HeaderComponent extends BaseComponent<HTMLDivElement> {
|
||||
this._githubButton = new ToolbarItemComponent({ id: 'gh', iconSVG: AppIcons.GITHUB })
|
||||
.onClick(() => {
|
||||
window.open('https://github.com/LucasDower/ObjToSchematic');
|
||||
});
|
||||
})
|
||||
.setTooltip('toolbar.open_github_repo');
|
||||
|
||||
this._bugButton = new ToolbarItemComponent({ id: 'bug', iconSVG: AppIcons.BUG })
|
||||
.onClick(() => {
|
||||
window.open('https://github.com/LucasDower/ObjToSchematic/issues');
|
||||
});
|
||||
})
|
||||
.setTooltip('toolbar.open_github_issues');
|
||||
|
||||
this._discordButton = new ToolbarItemComponent({ id: 'disc', iconSVG: AppIcons.DISCORD })
|
||||
.onClick(() => {
|
||||
window.open('https://discord.gg/McS2VrBZPD');
|
||||
});
|
||||
})
|
||||
.setTooltip('toolbar.join_discord');
|
||||
}
|
||||
|
||||
// Header element shouldn't be
|
||||
@ -53,7 +56,7 @@ export class HeaderComponent extends BaseComponent<HTMLDivElement> {
|
||||
ObjToSchematic
|
||||
</div>
|
||||
<div class="row-item subtitle">
|
||||
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}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -64,16 +67,23 @@ export class HeaderComponent extends BaseComponent<HTMLDivElement> {
|
||||
${this._discordButton.generateHTML()}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-container header-cols">
|
||||
<div class="col-container" style="padding-top: 5px;" id="header-desc">
|
||||
<div class="row-container header-cols">
|
||||
<div class="row-container" style="padding-top: 5px;" id="header-desc">
|
||||
${LOC('description')}
|
||||
</div>
|
||||
<div class="row-container privacy-disclaimer" style="padding-top: 5px;">
|
||||
This site may use cookies and similar tracking technologies (like web beacons) to access and store information about usage.
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
public refresh() {
|
||||
UIUtil.getElementById('header-desc').innerText = LOC('description');
|
||||
|
||||
this._githubButton.updateTranslation();
|
||||
this._bugButton.updateTranslation();
|
||||
this._discordButton.updateTranslation();
|
||||
}
|
||||
|
||||
public override registerEvents(): void {
|
||||
|
@ -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';
|
||||
|
||||
@ -15,6 +16,7 @@ export class ToolbarItemComponent extends BaseComponent<HTMLDivElement> {
|
||||
private _onClick?: () => void;
|
||||
private _isActive: boolean;
|
||||
private _grow: boolean;
|
||||
private _tooltipLocKey: TLocalisedKey | null;
|
||||
|
||||
public constructor(params: TToolbarItemParams) {
|
||||
super();
|
||||
@ -33,6 +35,7 @@ export class ToolbarItemComponent extends BaseComponent<HTMLDivElement> {
|
||||
}
|
||||
|
||||
this._label = '';
|
||||
this._tooltipLocKey = null;
|
||||
}
|
||||
|
||||
public setGrow() {
|
||||
@ -40,6 +43,12 @@ export class ToolbarItemComponent extends BaseComponent<HTMLDivElement> {
|
||||
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();
|
||||
@ -90,6 +99,11 @@ export class ToolbarItemComponent extends BaseComponent<HTMLDivElement> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public setTooltip(text: TLocalisedKey) {
|
||||
this._tooltipLocKey = text;
|
||||
return this;
|
||||
}
|
||||
|
||||
public generateHTML() {
|
||||
if (this._grow) {
|
||||
return `
|
||||
@ -98,11 +112,20 @@ export class ToolbarItemComponent extends BaseComponent<HTMLDivElement> {
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
return `
|
||||
<div class="struct-prop container-icon-button" style="aspect-ratio: 1;" id="${this._getId()}">
|
||||
if (this._tooltipLocKey === null) {
|
||||
return `
|
||||
<div class="struct-prop container-icon-button " style="aspect-ratio: 1;" id="${this._getId()}">
|
||||
${this._iconSVG.outerHTML} ${this._label}
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
return `
|
||||
<div class="struct-prop container-icon-button hover-text" style="aspect-ratio: 1;" id="${this._getId()}">
|
||||
${this._iconSVG.outerHTML} ${this._label}
|
||||
<span class="tooltip-text left" id="${this._getId()}-tooltip">${LOC(this._tooltipLocKey)}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +378,8 @@ export class UI {
|
||||
})
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getModelsAvailable() >= MeshType.TriangleMesh;
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.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('toolbar.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('toolbar.view_block_mesh'),
|
||||
},
|
||||
componentOrder: ['mesh', 'voxelMesh', 'blockMesh'],
|
||||
},
|
||||
@ -413,14 +416,16 @@ export class UI {
|
||||
})
|
||||
.isEnabled(() => {
|
||||
return Renderer.Get.getActiveMeshType() !== MeshType.None;
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.toggle_grid'),
|
||||
'axes': new ToolbarItemComponent({ id: 'axes', iconSVG: AppIcons.AXES })
|
||||
.onClick(() => {
|
||||
Renderer.Get.toggleIsAxesEnabled();
|
||||
})
|
||||
.isActive(() => {
|
||||
return Renderer.Get.isAxesEnabled();
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.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('toolbar.toggle_night_vision'),
|
||||
},
|
||||
componentOrder: ['grid', 'axes', 'night-vision'],
|
||||
},
|
||||
@ -445,7 +451,8 @@ export class UI {
|
||||
})
|
||||
.isActive(() => {
|
||||
return Renderer.Get.isSliceViewerEnabled();
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.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('toolbar.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('toolbar.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('toolbar.zoom_out'),
|
||||
'zoomIn': new ToolbarItemComponent({ id: 'zin', iconSVG: AppIcons.PLUS })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.onZoomIn();
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.zoom_in'),
|
||||
'reset': new ToolbarItemComponent({ id: 'reset', iconSVG: AppIcons.CENTRE })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.reset();
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.reset_camera'),
|
||||
},
|
||||
componentOrder: ['zoomOut', 'zoomIn', 'reset'],
|
||||
},
|
||||
@ -496,14 +508,16 @@ export class UI {
|
||||
})
|
||||
.isActive(() => {
|
||||
return ArcballCamera.Get.isPerspective();
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.perspective_camera'),
|
||||
'orthographic': new ToolbarItemComponent({ id: 'orth', iconSVG: AppIcons.ORTHOGRAPHIC })
|
||||
.onClick(() => {
|
||||
ArcballCamera.Get.setCameraMode('orthographic');
|
||||
})
|
||||
.isActive(() => {
|
||||
return ArcballCamera.Get.isOrthographic();
|
||||
}),
|
||||
})
|
||||
.setTooltip('toolbar.orthographic_camera'),
|
||||
},
|
||||
componentOrder: ['perspective', 'orthographic'],
|
||||
},
|
||||
@ -665,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}`);
|
||||
@ -776,10 +804,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
93
styles.css
93
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,57 @@ 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;
|
||||
}
|
||||
|
||||
.privacy-disclaimer {
|
||||
font-size: var(--font-size-small);
|
||||
color: var(--text-dim);
|
||||
}
|
@ -1,20 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script
|
||||
async
|
||||
src="https://www.googletagmanager.com/gtag/js?id=G-W0SCWQ7HGJ"
|
||||
></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag("js", new Date());
|
||||
|
||||
gtag("config", "G-W0SCWQ7HGJ");
|
||||
</script>
|
||||
<meta charset="utf8" />
|
||||
<title>ObjToSchematic Web</title>
|
||||
<meta
|
||||
|
Loading…
Reference in New Issue
Block a user