diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..fdd8651 --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "plugins": ["@babel/plugin-proposal-class-properties"] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4972456..e8c7d3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.3] - 2020-02-08 +### Added +- Added tools panel +- Added save/open functionality +### Changed +- Changed plugin system + ## [0.0.2] - 2020-02-02 ### Added - Added orbit camera control @@ -7,5 +14,6 @@ ## [0.0.1] - 2020-02-01 ### Initial release +[0.0.3]: https://github.com/Perkovec/Vuxel/compare/v0.0.2...v0.0.3 [0.0.2]: https://github.com/Perkovec/Vuxel/compare/v0.0.1...v0.0.2 [0.0.1]: https://github.com/Perkovec/Vuxel/releases/tag/v0.0.1 \ No newline at end of file diff --git a/README.md b/README.md index 03dab61..2cbead3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/Perkovec/Vuxel.svg?branch=master)](https://travis-ci.org/Perkovec/Vuxel) [![Greenkeeper badge](https://badges.greenkeeper.io/Perkovec/Vuxel.svg)](https://greenkeeper.io/) -Version 0.0.2 +Version 0.0.3 By Ilya Karpuk perkovec24@gmail.com @@ -37,7 +37,7 @@ npm run build - [ ] Orientation indicator and controller - [ ] Painting tools - [ ] Advanced color picker -- [ ] Export/import models +- [x] Export/import models - [ ] Layers ## Licence diff --git a/demo.png b/demo.png index 6789476..f36d4a3 100644 Binary files a/demo.png and b/demo.png differ diff --git a/package-lock.json b/package-lock.json index d6d4cc7..57cf171 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "vuxel", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -137,6 +137,20 @@ "semver": "^5.5.0" } }, + "@babel/helper-create-class-features-plugin": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.8.3.tgz", + "integrity": "sha512-qmp4pD7zeTxsv0JNecSBsEmG1ei2MqwJq4YQcK3ZWm/0t07QstWfvuV/vm3Qt5xNMFETn2SZqpMx2MQzbtq+KA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.8.3", + "@babel/helper-member-expression-to-functions": "^7.8.3", + "@babel/helper-optimise-call-expression": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/helper-replace-supers": "^7.8.3", + "@babel/helper-split-export-declaration": "^7.8.3" + } + }, "@babel/helper-create-regexp-features-plugin": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.3.tgz", @@ -348,6 +362,16 @@ "@babel/plugin-syntax-async-generators": "^7.8.0" } }, + "@babel/plugin-proposal-class-properties": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz", + "integrity": "sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3" + } + }, "@babel/plugin-proposal-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz", @@ -2822,6 +2846,11 @@ "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", "dev": true }, + "event-lite": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.2.tgz", + "integrity": "sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g==" + }, "events": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", @@ -4684,6 +4713,11 @@ "to-regex": "^3.0.2" } }, + "micromodal": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/micromodal/-/micromodal-0.4.2.tgz", + "integrity": "sha512-tL8Z6Vi72haNUNlkhLjJJv1Q16eqUWMPAGT4RF7mwDM5DNyJXC67Yj8jw/yVgGYdhnCEBBf3X5JM3d/MpXSEKg==" + }, "miller-rabin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", diff --git a/package.json b/package.json index 3531581..4a1dc19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vuxel", - "version": "0.0.2", + "version": "0.0.3", "description": "Open Source Voxel editor", "scripts": { "start": "parcel src/index.html", @@ -10,10 +10,14 @@ "author": "perkovec", "license": "MIT", "dependencies": { + "event-lite": "^0.1.2", + "micromodal": "^0.4.2", "purecss": "^1.0.1", "three": "^0.113.1" }, "devDependencies": { + "@babel/core": "^7.8.4", + "@babel/plugin-proposal-class-properties": "^7.8.3", "parcel": "^1.12.4", "posthtml-include": "^1.3.3" } diff --git a/src/app.js b/src/app.js index ed3ac05..4e0dec2 100644 --- a/src/app.js +++ b/src/app.js @@ -25,32 +25,30 @@ export class App { this.createLight(); this.createGround(); - this.createCubes(); window.addEventListener('resize', () => this.onWindowResize(), false); - this.editorContainer.addEventListener('mousemove', event => this.onDocumentMouseMove(event), false); - this.editorContainer.addEventListener('mousedown', event => this.onDocumentMouseDown(event), false); - document.addEventListener('keydown', event => this.onDocumentKeyDown(event), false); - document.addEventListener('keyup', event => this.onDocumentKeyUp(event), false); - this.renderer = new THREE.WebGLRenderer({ antialias: true }); this.renderer.setSize(this.editorContainer.clientWidth, this.editorContainer.clientHeight); this.editorContainer.appendChild(this.renderer.domElement); this.rect = this.renderer.domElement.getBoundingClientRect(); + + this.pluginsInstances = {}; const pluginsConfig = { THREE, - brushMaterial: this.cubeMaterial, renderer: this.renderer, camera: this.camera, render: this.render.bind(this), scene: this.scene, sceneObjects: this.sceneObjects, + objects: this.objects, + plugins: this.pluginsInstances, + rect: this.rect, } plugins.forEach(Plugin => { - new Plugin(pluginsConfig); + this.pluginsInstances[Plugin.meta.name] = new Plugin(pluginsConfig); }); } @@ -65,18 +63,6 @@ export class App { this.scene.add(directionalLight); } - createCubes() { - const THREE = this.THREE; - - const rollOverGeo = new THREE.BoxBufferGeometry(50, 50, 50); - const rollOverMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, opacity: 0.5, transparent: true }); - this.rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial); - this.scene.add(this.rollOverMesh); - - this.cubeGeo = new THREE.BoxBufferGeometry(50, 50, 50); - this.cubeMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff }); - } - createGround() { const THREE = this.THREE; const geometry = new THREE.PlaneBufferGeometry(1000, 1000); @@ -95,70 +81,6 @@ export class App { this.render(); } - onDocumentMouseMove(event) { - event.preventDefault(); - - this.mouse.set( - ((event.clientX - this.rect.left) / this.editorContainer.clientWidth) * 2 - 1, - -((event.clientY - this.rect.top) / this.editorContainer.clientHeight) * 2 + 1 - ); - this.raycaster.setFromCamera(this.mouse, this.camera); - - const intersects = this.raycaster.intersectObjects([...this.objects, ...this.sceneObjects]); - if (intersects.length > 0) { - const intersect = intersects[0]; - this.rollOverMesh.position.copy(intersect.point).add(intersect.face.normal); - this.rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25); - } - - this.render(); - } - - onDocumentMouseDown(event) { - event.preventDefault(); - const THREE = this.THREE; - - this.mouse.set( - ((event.clientX - this.rect.left) / this.editorContainer.clientWidth) * 2 - 1, - -((event.clientY - this.rect.top) / this.editorContainer.clientHeight) * 2 + 1 - ); - this.raycaster.setFromCamera(this.mouse, this.camera); - - const intersects = this.raycaster.intersectObjects([...this.objects, ...this.sceneObjects]); - if (intersects.length > 0) { - const intersect = intersects[0]; - - // delete cube - if (this.isShiftDown) { - if (intersect.object !== this.plane) { - this.scene.remove(intersect.object); - this.sceneObjects.splice(this.sceneObjects.indexOf(intersect.object), 1); - } - } else { - // create cube - const voxel = new THREE.Mesh(this.cubeGeo, this.cubeMaterial.clone()); - voxel.position.copy(intersect.point).add(intersect.face.normal); - voxel.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25); - this.scene.add(voxel); - - this.sceneObjects.push(voxel); - } - this.render(); - } - } - - onDocumentKeyDown(event) { - switch (event.keyCode) { - case 16: this.isShiftDown = true; break; - } - } - - onDocumentKeyUp(event) { - switch (event.keyCode) { - case 16: this.isShiftDown = false; break; - } - } - render() { this.renderer.render(this.scene, this.camera); } diff --git a/src/fonts/Flaticon.eot b/src/fonts/Flaticon.eot new file mode 100644 index 0000000..67ccf30 Binary files /dev/null and b/src/fonts/Flaticon.eot differ diff --git a/src/fonts/Flaticon.svg b/src/fonts/Flaticon.svg new file mode 100644 index 0000000..a09317e --- /dev/null +++ b/src/fonts/Flaticon.svg @@ -0,0 +1,48 @@ + + + + + +Created by FontForge 20170731 at Sun Feb 2 23:18:40 2020 + By root + + + + + + + + + + + + + diff --git a/src/fonts/Flaticon.ttf b/src/fonts/Flaticon.ttf new file mode 100644 index 0000000..1c4c1be Binary files /dev/null and b/src/fonts/Flaticon.ttf differ diff --git a/src/fonts/Flaticon.woff b/src/fonts/Flaticon.woff new file mode 100644 index 0000000..41bc485 Binary files /dev/null and b/src/fonts/Flaticon.woff differ diff --git a/src/fonts/Flaticon.woff2 b/src/fonts/Flaticon.woff2 new file mode 100644 index 0000000..3b1d80d Binary files /dev/null and b/src/fonts/Flaticon.woff2 differ diff --git a/src/index.html b/src/index.html index 2ca5f2f..d4b4497 100644 --- a/src/index.html +++ b/src/index.html @@ -13,6 +13,10 @@
+ + + + \ No newline at end of file diff --git a/src/index.js b/src/index.js index 673ddd4..d873dcc 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,6 @@ import 'purecss/build/pure-min.css'; -import './index.css'; +import './styles/flaticon.css'; +import './styles/index.css'; const loader = document.getElementById('loader'); const loaderContainer = document.getElementById('loader-container'); @@ -21,11 +22,16 @@ const progressPromise = (promises, tickCallback) => { } const assets = [ + // CORE import('./three.js'), import('./app.js'), + // LIBS + import('micromodal/dist/micromodal.min.js'), + // PLUGINS import('./plugins/file-manager/file-manager.js'), + import('./plugins/tools/index.js'), import('./plugins/color-picker.js'), import('./plugins/camera-control.js'), ]; @@ -37,16 +43,24 @@ const update = (completed, total) => { progressPromise(assets, update) .then(([ + // CORE { THREE }, { App }, + // LIBS + MicroModal, + // PLUGINS { FileManager }, + { Tools }, { ColorPicker }, { CameraControl }, ]) => { + MicroModal.init(); + const plugins = [ FileManager, + Tools, ColorPicker, CameraControl, ]; diff --git a/src/plugins/camera-control.js b/src/plugins/camera-control.js index 0c7328b..7236d94 100644 --- a/src/plugins/camera-control.js +++ b/src/plugins/camera-control.js @@ -1,6 +1,10 @@ /* BASED ON https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js */ export class CameraControl { + static meta = { + name: 'camera-control', + }; + constructor(configs) { const THREE = this.THREE = configs.THREE; @@ -511,4 +515,4 @@ export class CameraControl { this._panOffset.add( v ); }; } -} \ No newline at end of file +} diff --git a/src/plugins/color-picker.js b/src/plugins/color-picker.js index 7a55c62..514eb8a 100644 --- a/src/plugins/color-picker.js +++ b/src/plugins/color-picker.js @@ -1,12 +1,27 @@ export class ColorPicker { + static meta = { + name: 'color-picker', + }; + constructor(configs) { this.configs = configs; + this.plugins = configs.plugins; - this.colorInput = document.getElementById('brush-color-input'); + this.avaliableTools = ['single_voxel']; + this.colorInput = document.getElementById('brush-color-input'); this.presets = document.querySelectorAll('.brush-color'); + this.containers = document.querySelectorAll('[data-plugin-color-picker]'); - this.colorInput.value = '#' + this.configs.brushMaterial.color.getHexString(); + if (this.plugins['tools']) { + if (this.avaliableTools.includes(this.plugins['tools'].currentToolName)) { + this.colorInput.value = '#' + this.plugins['tools'].currentTool.mainMaterial.color.getHexString(); + } + this.setupListeners(); + } else { + console.warn('Color picker plugin could not find Tools plugin.'); + this.hide(); + } this.presets.forEach(preset => { preset.addEventListener('click', () => { @@ -18,7 +33,32 @@ export class ColorPicker { this.colorInput.addEventListener('input', ev => this.setBrushColor(ev.target.value)); } + hide() { + this.containers.forEach(container => { + container.style.display = 'none'; + }) + } + + show() { + this.containers.forEach(container => { + container.style.display = 'block'; + }) + } + + setupListeners() { + const toolsPlugin = this.plugins['tools']; + + toolsPlugin.on('tool_enabled', (toolName, tool) => { + if (this.avaliableTools.includes(toolName)) { + this.colorInput.value = '#' + tool.mainMaterial.color.getHexString(); + this.show(); + } else { + this.hide(); + } + }); + } + setBrushColor(color) { - this.configs.brushMaterial.color.setStyle(color); + this.plugins['tools'].currentTool.mainMaterial.color.setStyle(color); } -} \ No newline at end of file +} diff --git a/src/plugins/file-manager/file-manager.js b/src/plugins/file-manager/file-manager.js index 6a8602d..f0d3d18 100644 --- a/src/plugins/file-manager/file-manager.js +++ b/src/plugins/file-manager/file-manager.js @@ -2,6 +2,10 @@ import { exporter } from './exporter'; import { loader } from './loader'; export class FileManager { + static meta = { + name: 'file-manager', + }; + constructor(configs) { this.configs = configs; @@ -90,4 +94,4 @@ export class FileManager { event.target.value = null; } -} \ No newline at end of file +} diff --git a/src/plugins/tools/index.js b/src/plugins/tools/index.js new file mode 100644 index 0000000..9b0cc3f --- /dev/null +++ b/src/plugins/tools/index.js @@ -0,0 +1,46 @@ +import EventEmitter from 'event-lite'; +import { SingleVoxel } from './single-voxel'; +import { RemoveVoxel } from './remove-voxel'; + +export class Tools extends EventEmitter { + static meta = { + name: 'tools', + }; + + constructor(configs) { + super(); + this.configs = configs; + + this.toolInstances = { + 'single_voxel': new SingleVoxel(configs), + 'remove_voxel': new RemoveVoxel(configs), + }; + + this.tools = document.querySelectorAll('.tool-item'); + this.currentTool = null; + this.currentToolName = null; + + this.tools.forEach(tool => { + tool.addEventListener('click', () => { + this.setTool(tool.dataset.tool); + }); + }); + + this.setTool(this.tools[0].dataset.tool); + } + + setTool(toolName) { + if (this.currentTool && this.currentTool.destroy) { + this.currentTool.destroy(); + this.currentToolName = null; + this.emit('tool_disabled'); + } + + this.currentTool = this.toolInstances[toolName]; + this.currentToolName = toolName; + if (this.currentTool && this.currentTool.init) { + this.currentTool.init(); + this.emit('tool_enabled', toolName, this.currentTool); + } + } +} diff --git a/src/plugins/tools/remove-voxel.js b/src/plugins/tools/remove-voxel.js new file mode 100644 index 0000000..bca89ad --- /dev/null +++ b/src/plugins/tools/remove-voxel.js @@ -0,0 +1,82 @@ +export class RemoveVoxel { + constructor(configs) { + const THREE = this.THREE = configs.THREE; + + this.scene = configs.scene; + this.renderer = configs.renderer; + this.camera = configs.camera; + this.sceneObjects = configs.sceneObjects; + this.render = configs.render; + this.rect = configs.rect; + + this.raycaster = new THREE.Raycaster(); + this.mouse = new THREE.Vector2(); + + const rollOverGeo = new THREE.BoxBufferGeometry(50, 50, 50); + const rollOverMaterial = new THREE.MeshBasicMaterial({ + color: 0xff0000, + opacity: 0.5, + transparent: true, + visible: false, + }); + this.rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial); + + this.onDocumentMouseMove = this.onDocumentMouseMove.bind(this); + this.onDocumentMouseDown = this.onDocumentMouseDown.bind(this); + } + + init() { + this.scene.add(this.rollOverMesh); + + this.renderer.domElement.addEventListener('mousemove', this.onDocumentMouseMove, false); + this.renderer.domElement.addEventListener('mousedown', this.onDocumentMouseDown, false); + } + + destroy() { + this.scene.remove(this.rollOverMesh); + + this.renderer.domElement.removeEventListener('mousemove', this.onDocumentMouseMove, false); + this.renderer.domElement.removeEventListener('mousedown', this.onDocumentMouseDown, false); + } + + onDocumentMouseMove(event) { + event.preventDefault(); + + this.mouse.set( + ((event.clientX - this.rect.left) / this.renderer.domElement.clientWidth) * 2 - 1, + -((event.clientY - this.rect.top) / this.renderer.domElement.clientHeight) * 2 + 1 + ); + this.raycaster.setFromCamera(this.mouse, this.camera); + + const intersects = this.raycaster.intersectObjects(this.sceneObjects); + if (intersects.length > 0) { + const intersect = intersects[0]; + this.rollOverMesh.material.visible = true; + this.rollOverMesh.position.copy(intersect.object.position); + } else { + this.rollOverMesh.material.visible = false; + } + + this.render(); + } + + onDocumentMouseDown(event) { + event.preventDefault(); + + this.mouse.set( + ((event.clientX - this.rect.left) / this.renderer.domElement.clientWidth) * 2 - 1, + -((event.clientY - this.rect.top) / this.renderer.domElement.clientHeight) * 2 + 1 + ); + this.raycaster.setFromCamera(this.mouse, this.camera); + + const intersects = this.raycaster.intersectObjects(this.sceneObjects); + if (intersects.length > 0) { + const intersect = intersects[0]; + + this.scene.remove(intersect.object); + this.sceneObjects.splice(this.sceneObjects.indexOf(intersect.object), 1); + + this.render(); + } + } +} \ No newline at end of file diff --git a/src/plugins/tools/single-voxel.js b/src/plugins/tools/single-voxel.js new file mode 100644 index 0000000..aff472d --- /dev/null +++ b/src/plugins/tools/single-voxel.js @@ -0,0 +1,92 @@ +export class SingleVoxel { + constructor(configs) { + const THREE = this.THREE = configs.THREE; + + this.scene = configs.scene; + this.renderer = configs.renderer; + this.camera = configs.camera; + this.objects = configs.objects; + this.sceneObjects = configs.sceneObjects; + this.render = configs.render; + this.rect = configs.rect; + + this.raycaster = new THREE.Raycaster(); + this.mouse = new THREE.Vector2(); + + const rollOverGeo = new THREE.BoxBufferGeometry(50, 50, 50); + const rollOverMaterial = new THREE.MeshBasicMaterial({ + color: 0x00ff00, + opacity: 0.5, + transparent: true, + visible: false, + }); + this.rollOverMesh = new THREE.Mesh(rollOverGeo, rollOverMaterial); + + this.cubeGeo = new THREE.BoxBufferGeometry(50, 50, 50); + this.mainMaterial = new THREE.MeshLambertMaterial({ color: 0xffffff }); + + this.onDocumentMouseMove = this.onDocumentMouseMove.bind(this); + this.onDocumentMouseDown = this.onDocumentMouseDown.bind(this); + } + + init() { + this.scene.add(this.rollOverMesh); + + this.renderer.domElement.addEventListener('mousemove', this.onDocumentMouseMove, false); + this.renderer.domElement.addEventListener('mousedown', this.onDocumentMouseDown, false); + } + + destroy() { + this.scene.remove(this.rollOverMesh); + + this.renderer.domElement.removeEventListener('mousemove', this.onDocumentMouseMove, false); + this.renderer.domElement.removeEventListener('mousedown', this.onDocumentMouseDown, false); + } + + onDocumentMouseMove(event) { + event.preventDefault(); + + this.mouse.set( + ((event.clientX - this.rect.left) / this.renderer.domElement.clientWidth) * 2 - 1, + -((event.clientY - this.rect.top) / this.renderer.domElement.clientHeight) * 2 + 1 + ); + this.raycaster.setFromCamera(this.mouse, this.camera); + + const intersects = this.raycaster.intersectObjects([...this.objects, ...this.sceneObjects]); + if (intersects.length > 0) { + const intersect = intersects[0]; + this.rollOverMesh.material.visible = true; + this.rollOverMesh.position.copy(intersect.point).add(intersect.face.normal); + this.rollOverMesh.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25); + } else { + this.rollOverMesh.material.visible = false; + } + + this.render(); + } + + onDocumentMouseDown(event) { + event.preventDefault(); + const THREE = this.THREE; + + this.mouse.set( + ((event.clientX - this.rect.left) / this.renderer.domElement.clientWidth) * 2 - 1, + -((event.clientY - this.rect.top) / this.renderer.domElement.clientHeight) * 2 + 1 + ); + this.raycaster.setFromCamera(this.mouse, this.camera); + + const intersects = this.raycaster.intersectObjects([...this.objects, ...this.sceneObjects]); + if (intersects.length > 0) { + const intersect = intersects[0]; + + const voxel = new THREE.Mesh(this.cubeGeo, this.mainMaterial.clone()); + voxel.position.copy(intersect.point).add(intersect.face.normal); + voxel.position.divideScalar(50).floor().multiplyScalar(50).addScalar(25); + this.scene.add(voxel); + + this.sceneObjects.push(voxel); + + this.render(); + } + } +} \ No newline at end of file diff --git a/src/styles/flaticon.css b/src/styles/flaticon.css new file mode 100644 index 0000000..8bb0790 --- /dev/null +++ b/src/styles/flaticon.css @@ -0,0 +1,34 @@ + /* + Flaticon icon font: Flaticon + Creation date: 02/02/2020 23:18 + */ + +@font-face { + font-family: "Flaticon"; + src: url("../fonts/Flaticon.eot"); + src: url("../fonts/Flaticon.eot?#iefix") format("embedded-opentype"), + url("../fonts/Flaticon.woff2") format("woff2"), + url("../fonts/Flaticon.woff") format("woff"), + url("../fonts/Flaticon.ttf") format("truetype"), + url("../fonts/Flaticon.svg#Flaticon") format("svg"); + font-weight: normal; + font-style: normal; +} + +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: "Flaticon"; + src: url("../fonts/Flaticon.svg#Flaticon") format("svg"); + } +} + +[class^="flaticon-"]:before, [class*=" flaticon-"]:before, +[class^="flaticon-"]:after, [class*=" flaticon-"]:after { + font-family: Flaticon; + font-style: normal; +} + +.flaticon-rubik:before { content: "\f100"; } +.flaticon-3d:before { content: "\f101"; } +.flaticon-eraser:before { content: "\f102"; } +.flaticon-cancel:before { content: "\f103"; } \ No newline at end of file diff --git a/src/index.css b/src/styles/index.css similarity index 66% rename from src/index.css rename to src/styles/index.css index 1935154..40741c2 100644 --- a/src/index.css +++ b/src/styles/index.css @@ -93,6 +93,24 @@ html, body { margin: 20px 0px; } +.tools-container { + padding: 0px 15px; +} + +.tool-item { + width: 26px; + height: 26px; + padding: 0; + border: 1px solid black; + margin: 5px; + background-color: #ffffff; + font-size: 20px; +} + +.tool-item.flaticon-3d:before { + margin-left: 2px; +} + /* (UI) LOADER */ .ui-loader { @@ -137,6 +155,10 @@ html, body { flex: 1; } +.ui-sidebar .pure-menu-item { + height: auto; +} + .ui-sidebar .ui-sidebar-guide-block { padding: 10px; font-size: 14px; @@ -158,3 +180,53 @@ html, body { margin-left: 20px; cursor: pointer; } + +/* (UI) MODAL */ + +.ui-modal { + display: none; +} + +.ui-modal.is-open { + display: block; +} + +.ui-modal .modal-overlay { + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-color: rgba(0, 0, 0, 0.2); + display: flex; + align-items: center; + justify-content: center; +} + +.ui-modal .modal-container { + background-color: #ffffff; + min-width: 300px; + border-radius: 5px; +} + +.ui-modal .modal-container header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0px 10px; + border-bottom: 1px solid grey; +} + +.ui-modal .modal-container .modal-content { + padding: 0px 10px 10px; +} + +.ui-modal .modal-container .modal-close { + border: none; + padding: 3px; + width: 24px; + height: 24px; + font-size: 14px; + background: none; + outline: none; +} diff --git a/src/ui-parts/modals/about-modal.html b/src/ui-parts/modals/about-modal.html new file mode 100644 index 0000000..7024302 --- /dev/null +++ b/src/ui-parts/modals/about-modal.html @@ -0,0 +1,16 @@ + \ No newline at end of file diff --git a/src/ui-parts/sidebar.html b/src/ui-parts/sidebar.html index 5d63b41..61eded6 100644 --- a/src/ui-parts/sidebar.html +++ b/src/ui-parts/sidebar.html @@ -1,26 +1,29 @@
-

Click - add voxel

-

Shift + Click - remove voxel

Click + Move - rotate camera

Right Click + Move - move camera

Mouse Wheel - camera zoom

diff --git a/src/ui-parts/topbar.html b/src/ui-parts/topbar.html index 2c91613..7f71fc3 100644 --- a/src/ui-parts/topbar.html +++ b/src/ui-parts/topbar.html @@ -9,5 +9,8 @@ +
  • + About +
  • \ No newline at end of file