Glass redesign

This commit is contained in:
Lucas Dower 2021-10-05 00:32:03 +01:00
parent e904fdef7d
commit 8c71dbb14b
11 changed files with 444 additions and 332 deletions

View File

@ -5,92 +5,70 @@
<meta charset="utf8">
<title>ObjToSchematic</title>
<link rel="stylesheet" href="./styles.css">
<link rel="stylesheet" href="./src/vendor/bootstrap.css">
</head>
<body>
<canvas id="c"></canvas>
<div class="toolbar">
<div class="row">
<div class="col">
<div class="input-group">
<span id="buttonChooseFile" class="input-group-addon button pill-left">
Choose file
</span><input id="inputFile" class="text-field pill-right" style="cursor: pointer" type="text" value="">
<div id="main">
<canvas id="c"></canvas>
<div class="toolbar-container">
<div class="toolbar-container glass pill-left pill-right">
<div class="toolbar-item pill-left toolbar-item-1">
<div class="input-group">
<button id="buttonChooseFile" class="input-group-item pill-left">
Choose file
</button>
<input id="inputFile" type="text"
class="input-group-item input-group-item-dominant pill-right text-field cursor-pointer" value=""
readonly></input>
</div>
</div>
</div>
<div class="col">
<div class="input-group">
<span class="input-group-addon button pill-left">
Voxel size
</span><input class="text-field" type="number" value="0.1">
<button class="button pill-right bg-blue">Voxelise</button>
<div class="toolbar-item toolbar-item-2">
<div id="groupVoxel" class="input-group transparent">
<div class="input-group-item pill-left">Voxel size</div>
<input id="inputVoxelSize" type="number" class="input-group-item input-group-item-dominant text-field"
value="0.1" disabled>
</input>
<button id="buttonVoxelise" class="input-group-item pill-right bg-primary cursor-pointer" disabled>
Voxelise
</button>
</div>
</div>
</div>
<div class="col">
<button class="button bg-red pill-left half-width">Export .schematic</button><button class="button bg-red pill-right half-width">Export .litematic</button>
</div>
</div>
</div>
<div class="box">
<div class="box-div">Model loaded successfully</div>
</div>
<div id="toast" class="toast canvas-toast align-items-center text-white bg-danger border-0" role="alert"
aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div id="toastText" class="toast-body ms-2">
toastText
</div>
</div>
</div>
<!-- EXPORT DISCLAIMER -->
<div id="modalExport" class="modal custom-modal-background fade" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div id="modalExportText" class="modal-body">
<p>modalText</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button id="exportBtn" type="button" class="btn btn-danger">
<img src="./resources/svg/save.svg" alt="">
Export
</button>
<div class="toolbar-item pill-right toolbar-item-3">
<div id="groupExport" class="input-group transparent">
<button id="buttonSchematic" class="input-group-item input-group-item-dominant pill-left bg-secondary"
disabled>
Export .schematic
</button>
<button id="buttonLitematic" class="input-group-item input-group-item-dominant pill-right bg-secondary"
disabled>
Export .litematic
</button>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- GENERAL DISCLAIMER -->
<div id="modalGeneral" class="modal custom-modal-background fade" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div id="modalGeneralText" class="modal-body">
<p>modalText</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Okay</button>
</div>
<div id="toast" class="status-container pill-left pill-right glass toast hide"></div>
<div id="modal" class="pill-left pill-right glass modal" hidden>
<div class="content">
<div id="textModal" class="modalTop"></div>
<div class="modalBottom">
<button id="buttonModalAction" class="button pill bg-secondary"></button>
<button id="buttonModalClose" class="button pill bg-primary">Close</button>
</div>
</div>
</div>
</body>
<script src="./src/vendor/jquery-3.6.0.min.js"></script>
<script src="./src/vendor/jquery-3.3.1.slim.min.js"></script>
<script src="./src/vendor/popper.min.js"></script>
<script src="./src/vendor/bootstrap.min.js"></script>
<script>
require("./dist/client.js")
</script>
</body>
<script src="./src/vendor/jquery-3.6.0.min.js"></script>
<script src="./src/vendor/jquery-3.3.1.slim.min.js"></script>
<script src="./src/vendor/popper.min.js"></script>
<script>
require("./dist/client.js");
</script>
</html>

View File

@ -8,7 +8,7 @@
},
"scripts": {
"build": "tsc",
"start": "npm run build && electron ./dist/main.js",
"start": "npm run-script build && electron ./dist/main.js --enable-logging",
"export": "electron-packager . ObjToSchematic --platform=win32 --arch=x64"
},
"repository": {

View File

@ -1,11 +1,12 @@
import { Renderer } from "./renderer";
import { Mesh } from "./mesh";
import { VoxelManager } from "./voxel_manager";
import { Vector3 } from "./vector.js";
import { Schematic, Litematic, Exporter } from "./schematic";
//const dialog = from 'electron').remote.dialog;
import {remote} from 'electron';
import * as bootstrap from "bootstrap";
import { VoxelManager } from "./voxel_manager";
import { Renderer } from "./renderer";
import { Toast, ToastStyle } from "./ui/toast";
import { Modal } from "./ui/modal";
import { Mesh } from "./mesh";
import { remote } from 'electron';
import path from "path";
enum ToastColour {
RED = "bg-danger",
@ -13,11 +14,6 @@ enum ToastColour {
GREEN = "bg-success"
}
export enum ExportFormat {
SCHEMATIC = "schematic",
LITEMATIC = "litematic"
}
export class AppContext {
@ -27,12 +23,6 @@ export class AppContext {
private _voxelManager: VoxelManager;
private _loadedMesh?: Mesh;
private _toast: bootstrap.Toast;
private _modalExport: bootstrap.Modal;
//private _modalVoxelise: bootstrap.Modal;
private _modalGeneral: bootstrap.Modal;
private _cachedFormat?: ExportFormat;
constructor() {
this._voxelSize = $("#voxelInput").prop("value");
@ -46,71 +36,49 @@ export class AppContext {
this._renderer = new Renderer(this._gl);
this._voxelManager = new VoxelManager(this._voxelSize);
this._toast = new bootstrap.Toast(<HTMLElement>document.getElementById('toast'), {delay: 3000});
this._modalExport = new bootstrap.Modal(<HTMLElement>document.getElementById('modalExport'), {});
//this._modalVoxelise = new bootstrap.Modal(<HTMLElement>document.getElementById('modalVoxelise'), {});
this._modalGeneral = new bootstrap.Modal(<HTMLElement>document.getElementById('modalGeneral'), {});
//this._showModalGeneral("Note that in this current version, all blocks in the schematic will be exported as Stone blocks. This will be changed in version 0.4.");
}
public load() {
const files = $("#fileInput").prop("files");
public load(files: Array<string>) {
if (files.length != 1) {
return;
}
const file = files[0];
if (!file.name.endsWith(".obj") && !file.name.endsWith(".OBJ")) {
this._showToast("Files must be .obj format", ToastColour.RED);
if (!file.endsWith(".obj") && !file.endsWith(".OBJ")) {
Toast.show("Files must be .obj format", ToastStyle.Failure);
return;
}
const parsedPath = path.parse(file);
try {
this._loadedMesh = new Mesh(files[0].path, this._gl);
this._loadedMesh = new Mesh(file, this._gl);
} catch (err: any) {
this._showToast(err.message, ToastColour.RED);
console.log(err);
Toast.show("Could not load mesh", ToastStyle.Failure);
return;
}
this._renderer.clear();
this._renderer.registerMesh(this._loadedMesh);
this._renderer.compile();
$('#voxelInput').prop('disabled', false);
$('#voxelBtn').prop('disabled', false);
$('#splitBtn').prop('disabled', true);
$('#exportSchematic').prop('disabled', true);
$('#exportLitematic').prop('disabled', true);
this._showToast(`Successfully loaded ${file.name}`, ToastColour.GREEN);
}
/*
split() {
this.voxelSize /= 2;
$("#voxelInput").prop('value', this.voxelSize);
this.voxelManager.splitVoxels();
this.renderer.clear();
this.renderer.registerVoxelMesh(this.voxelManager);
this.renderer.compile();
}
*/
public voxeliseDisclaimer() {
//this._modalVoxelise.show();
this.voxelise();
$('#inputFile').prop("value", parsedPath.base);
$('#groupVoxel').removeClass("transparent");
$('#inputVoxelSize').prop('disabled', false);
$('#buttonVoxelise').prop('disabled', false);
$('#buttonSchematic').prop('disabled', true);
$('#buttonLitematic').prop('disabled', true);
Toast.show("Loaded successfully", ToastStyle.Success);
}
public voxelise() {
const newVoxelSize = $("#voxelInput").prop('value');
const newVoxelSize = $("#inputVoxelSize").prop('value');
if (newVoxelSize < 0.001) {
this._showToast("Voxel size must be at least 0.001", ToastColour.RED);
Toast.show("Voxel size must be at least 0.001", ToastStyle.Failure);
return;
}
this._voxelSize = newVoxelSize;
@ -128,49 +96,43 @@ export class AppContext {
this._renderer.registerVoxelMesh(this._voxelManager);
this._renderer.compile();
} catch (err: any) {
this._showToast(err.message, ToastColour.RED);
Toast.show(err.message, ToastStyle.Failure);
return;
}
$('#exportSchematic').prop('disabled', false);
$('#exportLitematic').prop('disabled', false);
$('#groupExport').removeClass("transparent");
$('#buttonSchematic').prop('disabled', false);
$('#buttonLitematic').prop('disabled', false);
this._showToast("Voxelised successfully", ToastColour.GREEN);
Toast.show("Voxelised successfully", ToastStyle.Success);
}
public exportDisclaimer(exportFormat: ExportFormat) {
public exportDisclaimer(exporter: Exporter) {
const schematicHeight = Math.ceil(this._voxelManager.maxZ - this._voxelManager.minZ);
let message = "";
if (schematicHeight > 320) {
message += `Note, this structure is <b>${schematicHeight}</b> blocks tall, this is larger than the height of a Minecraft world (320 in 1.17, 256 in <=1.16). `;
}
if (exportFormat == ExportFormat.SCHEMATIC) {
message += "Schematic files only support pre-1.13 blocks. As a result, all blocks will be exported as Stone. To export the blocks use the .litematic format with the Litematica mod.";
const formatDisclaimer = exporter.getFormatDisclaimer();
if (formatDisclaimer) {
message += "\n" + formatDisclaimer;
}
this._cachedFormat = exportFormat;
if (message.length == 0) {
this.export();
this.export(exporter);
} else {
this._showModalExport(message);
Modal.setButton("Export", () => { this.export(exporter); });
Modal.show(message);
}
}
public export() {
this._modalExport.hide();
public export(exporter: Exporter) {
const filePath = remote.dialog.showSaveDialogSync({
title: "Save structure",
buttonLabel: "Save",
filters: this._cachedFormat == ExportFormat.SCHEMATIC ? [{
name: 'Schematic',
extensions: ['schematic']
}] : [{
name: 'Litematic',
extensions: ['litematic']
}]
filters: [ exporter.getFormatFilter() ]
});
if (filePath === undefined) {
@ -179,20 +141,14 @@ export class AppContext {
}
try {
let exporter: Exporter;
if (this._cachedFormat == ExportFormat.SCHEMATIC) {
exporter = new Schematic(this._voxelManager);
} else {
exporter = new Litematic(this._voxelManager);
}
exporter.export(filePath);
exporter.export(filePath, this._voxelManager);
} catch (err) {
this._showToast("Failed to export", ToastColour.RED);
console.error(err);
Toast.show("Failed to export", ToastStyle.Failure)
return;
}
this._showToast("Successfully saved", ToastColour.GREEN);
Toast.show("Successfully exported", ToastStyle.Success);
}
@ -200,29 +156,4 @@ export class AppContext {
this._renderer.draw(this._voxelManager._voxelSize);
}
private _showToast(text: string, colour: ToastColour) {
$("#toast").removeClass(ToastColour.RED);
$("#toast").removeClass(ToastColour.ORANGE);
$("#toast").removeClass(ToastColour.GREEN);
$("#toast").addClass(colour);
$("#toastText").html(text);
//$("#toast").toast({ delay: 3000 });
//$("#toast").toast('show');
this._toast.show();
}
private _showModalExport(text: string) {
$("#modalExportText").html(text);
this._modalExport.show();
}
private _showModalGeneral(text: string) {
$("#modalGeneralText").html(text);
this._modalGeneral.show();
}
}
module.exports.AppContext = AppContext;
}

View File

@ -1,37 +1,43 @@
import { AppContext } from "./app_context";
import { ExportFormat } from "./app_context";
import { Schematic, Litematic } from "./schematic";
import { remote } from "electron";
const context = new AppContext();
function handleFileLoad() {
const files = remote.dialog.showOpenDialogSync({
title: "Load Waveform .obj file",
buttonLabel: "Load",
filters: [{
name: 'Waveform obj file',
extensions: ['obj']
}]
});
$("#loadBtn").on("click", () => {
context.load();
if (files) {
context.load(files);
}
}
$("#buttonChooseFile").on("click", () => {
handleFileLoad();
});
$("#voxelBtn").on("click", () => {
context.voxeliseDisclaimer();
$("#inputFile").on("click", () => {
handleFileLoad();
});
/*
$("#splitBtn").on("click", () => {
context.split();
});
*/
$("#exportBtn").on("click", async () => {
context.export();
$("#buttonVoxelise").on("click", () => {
context.voxelise();
});
$("#exportSchematic").on("click", async () => {
context.exportDisclaimer(ExportFormat.SCHEMATIC);
$("#buttonSchematic").on("click", async () => {
context.exportDisclaimer(new Schematic());
});
$("#exportLitematic").on("click", async () => {
context.exportDisclaimer(ExportFormat.LITEMATIC);
$("#buttonLitematic").on("click", async () => {
context.exportDisclaimer(new Litematic());
});

View File

@ -14,8 +14,10 @@ function createWindow () {
//const appIcon = new Tray("../resources/icon.png");
mainWindow = new BrowserWindow({
width,
height,
width: width,
height: height,
minWidth: 1280,
minHeight: 720,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,

View File

@ -5,26 +5,28 @@ import { Vector3 } from "./vector";
import { VoxelManager } from "./voxel_manager";
import { Block } from "./block_atlas";
export abstract class Exporter {
protected _voxelManager: VoxelManager
protected _minPos: Vector3
protected _maxPos: Vector3
protected _sizeVector: Vector3
protected _voxelManager!: VoxelManager
protected _minPos!: Vector3
protected _maxPos!: Vector3
protected _sizeVector!: Vector3
constructor(voxelManager: VoxelManager) {
abstract convertToNBT(): NBT
abstract getFormatFilter(): Electron.FileFilter;
abstract getFormatName(): string;
getFormatDisclaimer(): string | undefined {
return;
}
export(filePath: string, voxelManager: VoxelManager): boolean {
this._voxelManager = voxelManager;
this._minPos = new Vector3(voxelManager.minX, voxelManager.minY, voxelManager.minZ);
this._maxPos = new Vector3(voxelManager.maxX, voxelManager.maxY, voxelManager.maxZ);
this._sizeVector = Vector3.sub(this._maxPos, this._minPos).addScalar(1);
console.log(this._minPos, this._maxPos);
}
abstract convertToNBT(): NBT
export(filePath: string): boolean {
const nbt = this.convertToNBT();
const outBuffer = fs.createWriteStream(filePath);
@ -79,6 +81,21 @@ export class Schematic extends Exporter {
return (sizeVector.z * sizeVector.x * vec.y) + (sizeVector.x * vec.z) + vec.x;
}
getFormatFilter() {
return {
name: this.getFormatName(),
extensions: ['schematic']
}
}
getFormatName() {
return "Schematic";
}
getFormatDisclaimer() {
return "Schematic files only support pre-1.13 blocks. As a result, all blocks will be exported as Stone. To export the blocks, use the .litematic format with the Litematica mod.";
}
}
type BlockID = number;
@ -243,5 +260,16 @@ export class Litematic extends Exporter {
return nbt;
}
getFormatFilter() {
return {
name: this.getFormatName(),
extensions: ['litematic']
}
}
getFormatName() {
return "Litematic";
}
}

26
src/ui/modal.ts Normal file
View File

@ -0,0 +1,26 @@
export class Modal {
public static show(text: string) {
this._setText(text);
this._show();
}
public static setButton(text: string, onClick: (() => void)) {
$("#buttonModalAction").html(text);
$("#buttonModalAction").on("click", () => { this._hide(); onClick(); } );
$("#buttonModalClose").on("click", () => { this._hide(); });
}
private static _setText(text: string) {
$("#textModal").html(text);
}
private static _show() {
$("#modal").show()
}
private static _hide() {
$("#modal").hide();
}
}

36
src/ui/toast.ts Normal file
View File

@ -0,0 +1,36 @@
export enum ToastStyle {
Success = "bg-success",
Failure = "bg-failure"
}
export class Toast {
private static current: ToastStyle = ToastStyle.Success;
private static autoHideDelay: number = 4000;
public static show(text: string, style: ToastStyle) {
this._setText(text);
this._setStyle(style);
this._show();
setTimeout(() => { this._hide(); }, this.autoHideDelay);
}
private static _setText(text: string) {
$("#toast").html(text);
}
private static _setStyle(style: ToastStyle) {
$("#toast").removeClass(Toast.current);
$("#toast").addClass(style);
Toast.current = style;
}
private static _show() {
$("#toast").removeClass("hide");
}
private static _hide() {
$("#toast").addClass("hide");
}
}

View File

@ -6,10 +6,12 @@ import { BlockAtlas, BlockInfo } from "./block_atlas";
import { UV, RGB } from "./util";
import { Triangle } from "./triangle";
import { Mesh, MaterialType } from "./mesh";
import fs from "fs";
interface Block {
position: Vector3;
colours: Array<RGB>;
colours?: Array<RGB>;
colour?: RGB;
block?: string
}
@ -112,15 +114,18 @@ export class VoxelManager {
this.blockPalette = [];
for (let i = 0; i < this.voxels.length; ++i) {
let averageColour = this.voxels[i].colours.reduce((a, c) => {return {r: a.r + c.r, g: a.g + c.g, b: a.b + c.b}})
let n = this.voxels[i].colours.length;
let averageColour = this.voxels[i].colours!.reduce((a, c) => {return {r: a.r + c.r, g: a.g + c.g, b: a.b + c.b}})
let n = this.voxels[i].colours!.length;
averageColour.r /= n;
averageColour.g /= n;
averageColour.b /= n;
const block = this.blockAtlas.getBlock(averageColour);
this.voxels[i].block = block.name;
this.voxels[i].colour = averageColour;
delete this.voxels[i].colours;
this.voxelTexcoords.push(block.texcoord);
if (!this.blockPalette.includes(block.name)) {
this.blockPalette.push(block.name);
}
@ -146,7 +151,7 @@ export class VoxelManager {
if (this.voxelsHash.contains(pos)) {
for (let i = 0; i < this.voxels.length; ++i) {
if (this.voxels[i].position.equals(pos)) {
this.voxels[i].colours.push(block.colour);
this.voxels[i].colours!.push(block.colour);
//console.log("Overlap");
return;
}
@ -414,7 +419,14 @@ export class VoxelManager {
}
}
this.assignBlocks();
console.log(this.blockPalette);
this._dumpVoxelsToFile();
}
private _dumpVoxelsToFile() {
const json = JSON.stringify(this.voxels);
console.log(this.voxels.length);
fs.writeFileSync('block_dump.json', json);
}
}

View File

@ -1,144 +1,237 @@
@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@300;400&display=swap');
body {
margin: 0;
padding: 0;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
background-color: #101214;
}
.toolbar {
position: absolute;
margin-left: 20%;
margin-top: 30px;
padding: 10px;
padding-top: 8.5px;
width: 60%;
height: 60px;
body {
margin: 0px;
background-color: rgb(25, 25, 25);
background-size: 100%;
font-family: 'Lexend', sans-serif;
}
input {
font-family: 'Lexend', sans-serif;
font-size: medium;
}
input:enabled {
outline: none;
}
button {
font-family: 'Lexend', sans-serif;
font-size: medium;
}
button:hover:enabled {
cursor: pointer;
transition: 0.2s;
border-color: rgba(0, 0, 0, 0.3);
}
button:disabled {
cursor: default;
transition: 0.2s;
}
.toolbar-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: auto;
margin: auto;
}
.status-container {
position: fixed;
left: 50%;
bottom: 25px;
transform: translate(-50%, -50%);
margin: 0 auto;
}
.glass {
background-color: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(20px);
border-radius: 100px;
border: solid;
border-color: rgba(255, 255, 255, 0.1);
border-width: 1.5px;
border-style: solid;
border-color: rgba(255, 255, 255, 0.03);
box-shadow: 0 1rem 2rem rgba(0, 0, 0, .175);
margin-top: 25px;
}
.canvas-toast {
position:absolute;
left:10px;
top:68px;
.toast {
padding: 10px 50px !important;
font-weight: 300;
transition: 0.5s;
}
.custom-modal-background {
background-color: rgba(0, 0, 0, .25);
backdrop-filter: blur(5px);
.hide {
opacity: 0;
transition: 0.5s;
}
.bg-success {
background-color: rgba(40, 167, 69, 0.5) !important;
color: white !important;
}
.bg-failure {
background-color: rgba(220, 53, 69, 0.5) !important;
color: white !important;
}
.transparent {
opacity: 0.5;
}
.toolbar-item {
padding: 10px;
cursor: default;
}
.input-group {
display: flex;
align-content: stretch;
}
.input-group > input {
flex: 1 0 auto;
.input-group-item {
background-color: #EFEFEF;
padding: 10px 14px;
border: solid;
border-color: rgba(0, 0, 0, 0.25);
border-width: 1.5px 0px;
}
.input-group-addon {
padding: 0.5em 1em;
}
.bg-blue {
background-color: #0D6EFD !important;
color: white !important;
}
.bg-red {
background-color: #BB2D3B !important;
color: white !important;
.input-group-item-dominant {
flex-grow: 1;
}
.pill-left {
border-top-left-radius: 20px;
border-bottom-left-radius: 20px;
padding-left: 20px;
border-top-left-radius: 32px;
border-bottom-left-radius: 32px;
border-left-width: 1.5px;
border-right-width: 0px;
}
.pill-right {
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
padding-right: 20px;
}
.button {
height: 40px;
padding-left: 15px;
padding-right: 15px;
font-size: 15px;
font-family: 'Lexend', sans-serif;
font-weight: 400;
border: none;
color: #33393F;
background: #EFEFEF;
line-height: 25px;
}
.button:hover {
cursor: pointer;
border-top-right-radius: 32px;
border-bottom-right-radius: 32px;
border-right-width: 1.5px;
border-left-width: 0px;
}
.text-field {
background-color: white;
height: 40px;
padding-left: 15px;
padding-right: 15px;
font-family: 'Lexend', sans-serif;
font-size: 15px;
color: gray;
font-weight: 300;
border: none;
cursor: text;
color: #808080;
}
input:focus {
border: none;
.text-field:read-only {
cursor: pointer;
}
.half-width {
width: 50%;
.text-field:disabled {
background-color: #EFEFEF;
cursor: default;
}
input:focus {
outline: none;
}
.box {
display: flex;
align-items: center;
justify-content: center;
}
.box-div {
position: absolute;
margin-top: 280px;
height: 40px;
padding-left: 50px;
padding-right: 50px;
background-color: #28a746c4;
backdrop-filter: blur(20px);
border-radius: 100px;
text-align: center;
padding-top: 6px;
.bg-primary {
background-color: #007bff;
color: white;
}
.bg-secondary {
background-color: #dc3545;
color: white;
}
.bg-primary:disabled {
background-color: #5AAAFF;
}
.bg-secondary:disabled {
background-color: #E87C87;
}
.bg-primary:hover:enabled {
background-color: #0069D9;
}
.bg-secondary:hover:enabled {
background-color: #C82333;
}
@media (max-width: 1200px) {
.toolbar-container {
flex-direction: column;
align-content: center;
align-items: center;
}
.input-group-item-dominant {
flex-grow: 0;
}
.toolbar-item-1 {
border-top-right-radius: 200px;
border-bottom-right-radius: 200px;
border-right-width: 1.5px;
border-left-width: 0px;
}
.toolbar-item-2 {
border-top-left-radius: 200px;
border-bottom-left-radius: 200px;
border-top-right-radius: 200px;
border-bottom-right-radius: 200px;
border-right-width: 1.5px;
border-left-width: 1.5px;
}
.toolbar-item-3 {
border-top-left-radius: 200px;
border-bottom-left-radius: 200px;
border-right-width: 0px;
border-left-width: 1.5px;
}
}
.pill {
border-radius: 32px;
border-width: 1.5px;
border-style: solid;
border-color: rgba(255, 255, 255, 0.03);
border-color: rgba(0, 0, 0, 0.3);
}
.modal {
position: absolute;
padding: 40px;
margin: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
}
div.content {
display: flex;
flex-direction: column;
}
.modalTop {
color: white;
flex: 1;
font-weight: 300;
}
.modalBottom {
flex: none;
padding-top: 50px;
}
.button {
padding: 8px 40px;
}

View File

@ -3,7 +3,7 @@
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
//"resolveJsonModule": true,