From 618c0013ee3e36d3f1b371dd7472ea3d059515b9 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Tue, 6 Feb 2024 15:11:29 -0600 Subject: [PATCH] split out react UI --- index.html | 156 +-------------- public/styles.css | 188 +++++++++++++++++++ src/controllers/right.ts | 3 - src/diagram/diagramManager.ts | 16 +- src/diagram/types/diagramListing.ts | 18 -- src/integration/pouchdbPersistenceManager.ts | 70 +------ src/menus/diagramListingMenu.ts | 94 ---------- src/react/webApp.tsx | 67 ++++--- src/webApp.ts | 2 +- 9 files changed, 246 insertions(+), 368 deletions(-) create mode 100644 public/styles.css delete mode 100644 src/diagram/types/diagramListing.ts delete mode 100644 src/menus/diagramListingMenu.ts diff --git a/index.html b/index.html index 5552e35..bbfc41f 100644 --- a/index.html +++ b/index.html @@ -3,165 +3,11 @@ + Deep Diagram - - diff --git a/public/styles.css b/public/styles.css new file mode 100644 index 0000000..70b5cab --- /dev/null +++ b/public/styles.css @@ -0,0 +1,188 @@ +body { + width: 100vw; + height: 100vh; + margin: 0px; + padding: 0px; + aspect-ratio: auto; + font-family: Roboto, sans-serif; + font-size: large; + color: #4444ee; +} + +.scene { + width: 100vw; + height: 100vh; + overflow: hidden; + +} + +#gameCanvas { + width: 100%; + height: 100%; + margin: 0px; + padding: 0px; + background: transparent; +} + + +div.overlay { + position: absolute; + background: #000; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: 12; + width: 320px; + height: 120px; +} + +div.overlay div { + background-color: #000000; + color: #FFD700; + padding: 15px 25px; + text-align: center; + text-decoration: none; + cursor: pointer; + border: none; +} + +div.overlay div a { + display: inline-block; + text-decoration: none; + border-color: #FFD700; + border-style: solid; + border-width: 1px; + padding: 10px; + width: 200px; +} + +div.overlay div a:visited, div.overlay div a:link { + color: white; +} + +div.overlay div a:hover { + background-color: #FFD700; + color: #000000; +} + +div.overlay div a { + +} + +div.overlay input { + display: inline-block; + margin: 10px auto; + text-decoration: none; + border-color: #FFD700; + border-style: solid; + border-width: 1px; + padding: 10px; + width: 200px; +} + +div#create { + left: 600px; + top: 400px; + transform: translate(-50%, -50%); + z-index: 14; + width: 320px; + height: 344px; + border: 3px inset #FFD700; + display: none; +} + +div.overlay div a.cancel { + font-size: small; + font-weight: lighter; + font-style: italic; + background-color: #222211; + color: #EEC755; +} + +#diagramListContent ul { + list-style-type: none; + text-align: left; + padding: 0; + padding-inline-start: 0; + +} + +#diagramList { + overflow: scroll; +} + +#diagramList > h1 { + width: 100%; + text-align: center; +} + +#diagramListContent li { + margin: 12px; +} + +#diagramListContent li a { + width: 90%; +} + +div.overlay div a.cancel:hover { + background-color: #EEC700; + color: #000000; +} + + +#main.mini { + left: 100px; + top: 200px; + width: 160px; +} + +#main.mini img, #tutorial img { + width: 160px; + height: 60px; +} + +#main.mini div a, #tutorial div a { + width: 80px; +} + +h1 { + font-size: x-large; + font-weight: bolder; + text-align: center; + color: #F9F9E9; +} + +#tutorial { + z-index: 15; + left: 100px; + top: 560px; + width: 160px; + height: 210px; +} + +#diagramList { + left: 340px; + top: 240px; + height: 300px; +} + +#create { + left: 500px; + top: 340px; +} + + +#closekey, #closekey a:active, #closekey a:visited, #closekey a:link { + position: relative; + color: #ffffff; +} + +#enterXR { + display: none; +} + +#loadingGrid { + z-index: -1; + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/src/controllers/right.ts b/src/controllers/right.ts index fd8e508..e83b88b 100644 --- a/src/controllers/right.ts +++ b/src/controllers/right.ts @@ -11,11 +11,9 @@ import { import {ControllerEventType, Controllers} from "./controllers"; import log from "loglevel"; import {DiagramManager} from "../diagram/diagramManager"; -import {DiagramListingMenu} from "../menus/diagramListingMenu"; import {RoundButton} from "../objects/roundButton"; export class Right extends Base { - private listingMenu: DiagramListingMenu; private startPosition: Vector3 = null; @@ -42,7 +40,6 @@ export class Right extends Base { controllers: Controllers, ) { super(controller, scene, xr, controllers, diagramManager); - this.listingMenu = new DiagramListingMenu(this.scene, xr, this.controllers, diagramManager); this.controller.onMotionControllerInitObservable.add((init) => { this.initTrigger(init.components['xr-standard-trigger']); if (init.components['a-button']) { diff --git a/src/diagram/diagramManager.ts b/src/diagram/diagramManager.ts index 1151e81..d1ee678 100644 --- a/src/diagram/diagramManager.ts +++ b/src/diagram/diagramManager.ts @@ -14,12 +14,11 @@ import {toDiagramEntity} from "./functions/toDiagramEntity"; import {v4 as uuidv4} from 'uuid'; import {buildEntityActionManager} from "./functions/buildEntityActionManager"; import {isDiagramEntity} from "./functions/isDiagramEntity"; -import {DiagramListingEvent} from "./types/diagramListing"; export class DiagramManager { public readonly onDiagramEventObservable: Observable = new Observable(); - public readonly onDiagramEventListingObservable: Observable = new Observable(); + private readonly logger = log.getLogger('DiagramManager'); private readonly toolbox: Toolbox; private readonly scene: Scene; @@ -68,12 +67,6 @@ export class DiagramManager { }); } - //@TODO Refactor - /*public setPersistenceManager(persistenceManager: IPersistenceManager) { - this.persistenceManager = persistenceManager; - this._config = new AppConfig(persistenceManager); - this.persistenceManager.updateObserver.add(this.onRemoteEvent, -1, true, this); - }*/ public createCopy(mesh: AbstractMesh, copy: boolean = false): AbstractMesh { let newMesh; if (!mesh.isAnInstance) { @@ -97,13 +90,6 @@ export class DiagramManager { if (this.config.current?.physicsEnabled) { applyPhysics(this.sounds, newMesh, this.scene); } - //@TODO Refactor - /*this.onDiagramEventObservable.notifyObservers({ - type: DiagramEventType.ADD, - entity: toDiagramEntity(newMesh) - }, 2);*/ - //this.persistenceManager.add(toDiagramEntity(newMesh)); - return newMesh; } diff --git a/src/diagram/types/diagramListing.ts b/src/diagram/types/diagramListing.ts deleted file mode 100644 index 38d9f22..0000000 --- a/src/diagram/types/diagramListing.ts +++ /dev/null @@ -1,18 +0,0 @@ -export enum DiagramListingEventType { - GET, - ADD, - REMOVE, - MODIFY, - GETALL, -} - -export type DiagramListingEvent = { - type: DiagramListingEventType; - listing?: DiagramListing; -} -export type DiagramListing = { - id: string; - name: string; - description?: string; - sharekey?: string; -} \ No newline at end of file diff --git a/src/integration/pouchdbPersistenceManager.ts b/src/integration/pouchdbPersistenceManager.ts index 42433c9..db32eb0 100644 --- a/src/integration/pouchdbPersistenceManager.ts +++ b/src/integration/pouchdbPersistenceManager.ts @@ -6,8 +6,6 @@ import {v4 as uuidv4} from 'uuid'; import axios from "axios"; import {DiagramManager} from "../diagram/diagramManager"; import log, {Logger} from "loglevel"; -import {DiagramListing, DiagramListingEventType} from "../diagram/types/diagramListing"; - export class PouchdbPersistenceManager { configObserver: Observable = new Observable(); @@ -16,30 +14,14 @@ export class PouchdbPersistenceManager { //implement IPersistenceManager interface with pouchdb apis private db: PouchDB; private remote: PouchDB; - private config: PouchDB; + private diagramListings: PouchDB; private readonly logger: Logger = log.getLogger('PouchdbPersistenceManager'); constructor() { - this.config = new PouchDB("config"); this.diagramListings = new PouchDB("diagramListings"); } - public async getDiagramListings() { - return this.diagramListings.allDocs({include_docs: true}); - } public setDiagramManager(diagramManager: DiagramManager) { - diagramManager.onDiagramEventListingObservable.add((evt) => { - if (evt.type == DiagramListingEventType.GETALL) { - this.diagramListings.allDocs({include_docs: true}).then((all) => { - for (const entity of all.rows) { - diagramManager.onDiagramEventListingObservable.notifyObservers({ - type: DiagramListingEventType.ADD, - listing: {id: entity.doc._id, name: entity.doc.name} - }, -1, false, this); - } - }); - } - }, -1, false, this); diagramManager.onDiagramEventObservable.add((evt) => { switch (evt.type) { case DiagramEventType.CHANGECOLOR: @@ -125,34 +107,6 @@ export class PouchdbPersistenceManager { this.logger.error(err); } } - - public async addDiagram(diagram: DiagramListing) { - try { - const doc = await this.diagramListings.get(diagram.id); - - } catch (err) { - this.diagramListings.put({...diagram, _id: diagram.id}); - } - } - - public async removeDiagram(diagram: DiagramListing) { - try { - this.diagramListings.delete(diagram.id); - } catch (err) { - this.logger.error(err); - } - } - - public async modifyDiagram(diagram: DiagramListing) { - try { - const doc = await this.db.get(diagram.id); - this.db.put({...doc, ...diagram}); - } catch (err) { - this.logger.error(err); - } - - } - public async getNewRelicData(): Promise { return []; } @@ -161,25 +115,23 @@ export class PouchdbPersistenceManager { return data; } - public async setConfig(config: any, initial: boolean = false): Promise { + public async setConfig(config: AppConfigType, initial: boolean = false) { if (!initial) { - const doc = await this.config.get('1'); - const newConf = {...config, _id: '1', _rev: doc._rev}; - return this.config.put(newConf); + localStorage.setItem('config', JSON.stringify(config)); } else { - const newConf = {...config, _id: '1'}; - return this.config.put(newConf); + localStorage.setItem('config', JSON.stringify(config)); } } - public async getConfig(): Promise { - return this.config.get('1'); + public getConfig(): AppConfigType { + return JSON.parse(localStorage.getItem('config')) as AppConfigType; } public async initialize() { try { let current = this.getPath(); - const config = await this.config.get('1'); + const configString = localStorage.getItem('config'); + const config = JSON.parse(configString) as AppConfigType; if (!current && config.currentDiagramId) { this.db = new PouchDB(config.currentDiagramId); @@ -192,7 +144,7 @@ export class PouchdbPersistenceManager { } this.db = new PouchDB(config.currentDiagramId); await this.beginSync(config.currentDiagramId); - await this.config.put(config); + localStorage.setItem('config', JSON.stringify(config)); } this.configObserver.notifyObservers(config); } catch (err) { @@ -264,10 +216,6 @@ export class PouchdbPersistenceManager { } } - setCurrentDiagram(diagram: DiagramListing) { - this.currentDiagramId = diagram.id; - } - sync() { } diff --git a/src/menus/diagramListingMenu.ts b/src/menus/diagramListingMenu.ts deleted file mode 100644 index c436c95..0000000 --- a/src/menus/diagramListingMenu.ts +++ /dev/null @@ -1,94 +0,0 @@ -import {AbstractMesh, MeshBuilder, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; -import {AbstractMenu} from "./abstractMenu"; -import {ControllerEventType, Controllers} from "../controllers/controllers"; -import {AdvancedDynamicTexture, Button, Control, ScrollViewer, StackPanel, TextBlock} from "@babylonjs/gui"; -import {setMenuPosition} from "../util/functions/setMenuPosition"; -import {DiagramManager} from "../diagram/diagramManager"; -import {DiagramListingEvent, DiagramListingEventType} from "../diagram/types/diagramListing"; -import {DiagramEventType} from "../diagram/types/diagramEntity"; - - -export class DiagramListingMenu extends AbstractMenu { - private mesh: AbstractMesh; - private panel: StackPanel; - private readonly diagramManager: DiagramManager; - - constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers, diagramManager: DiagramManager) { - super(scene, xr, controllers); - this.diagramManager = diagramManager; - this.buildMenu(); - this.controllers.controllerObserver.add((event) => { - if (event.type == ControllerEventType.B_BUTTON) { - this.toggle(); - } - }); - } - - public toggle() { - setMenuPosition(this.handle.mesh, this.scene, new Vector3(0, .4, 0)); - this.mesh.isVisible = !this.mesh.isVisible; - this.populateData(); - (this.mesh.parent as AbstractMesh).isVisible = this.mesh.isVisible; - } - - public populateData() { - this.panel.clearControls(); - this.diagramManager.onDiagramEventListingObservable.notifyObservers({type: DiagramListingEventType.GETALL}, -1); - } - - private buildMenu() { - const configPlane = MeshBuilder - .CreatePlane("gridSizePlane", - { - width: 1, - height: .5 - }, this.scene); - this.mesh = configPlane; - this.createHandle(this.mesh); - this.mesh.position = new Vector3(0, .32, 0); - const configTexture = AdvancedDynamicTexture.CreateForMesh(configPlane, 2048, 1024); - - configTexture.background = "white"; - const scrollViewer = new ScrollViewer('diagramListingScroll'); - configTexture.addControl(scrollViewer); - this.panel = new StackPanel('diagramListingStack'); - scrollViewer.addControl(this.panel); - - //configPlane.position.y = .5; - setMenuPosition(this.handle.mesh, this.scene, new Vector3(0, .4, 0)); - this.mesh.isVisible = false; - (this.mesh.parent as AbstractMesh).isVisible = false; - this.diagramManager.onDiagramEventListingObservable.add((event: DiagramListingEvent) => { - if (event.type == DiagramListingEventType.ADD) { - this.addRow(event.listing.id, event.listing.name); - } - }, -1, false, this); - - } - - private addRow(id: string, name: string) { - const row = new StackPanel('diagramListingRow ' + id); - row.isVertical = false; - row.height = "68px"; - row.width = 1; - this.panel.addControl(row); - const selectButton = Button.CreateSimpleButton('diagramListingText ' + id, id); - selectButton.height = "64px"; - selectButton.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; - selectButton.width = "220px"; - selectButton.color = "white"; - selectButton.fontSize = "48px"; - selectButton.background = "#333333"; - selectButton.onPointerClickObservable.add(() => { - this.diagramManager.onDiagramEventObservable.notifyObservers({type: DiagramEventType.RESET}); - console.log(id); - }, -1, false, this); - const textBlock = new TextBlock('diagramListingText ' + name, 'Diagram ' + name); - textBlock.width = "1000px"; - textBlock.horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; - textBlock.textHorizontalAlignment = Control.HORIZONTAL_ALIGNMENT_LEFT; - textBlock.fontSize = "48px"; - row.addControl(selectButton); - row.addControl(textBlock); - } -} \ No newline at end of file diff --git a/src/react/webApp.tsx b/src/react/webApp.tsx index 6066d2b..5739938 100644 --- a/src/react/webApp.tsx +++ b/src/react/webApp.tsx @@ -1,26 +1,34 @@ -import {useState} from "react"; +import {useEffect, useState} from "react"; function MainMenu({onClick}) { return ( -
+ ) } -function CreateMenu({display}) { +function CreateMenu({display, toggleCreateMenu}) { + const onCreateClick = (evt) => { + evt.preventDefault(); + const name = (document.querySelector('#createName') as HTMLInputElement).value; + if (name && name.length > 4) { + document.location.href = '/db/' + name; + } else { + window.alert('Name must be longer than 4 characters'); + } + } return (
- -
) } @@ -30,7 +38,6 @@ function TutorialMenu({onClick}) {

Help

-
) } @@ -45,15 +52,26 @@ function KeyboardHelp({display, onClick}) { ) } -function DiagramList() { +function DiagramList({display, onClick}) { + const [dbList, setDbList] = useState([]); + useEffect(() => { + const listDb = async () => { + const data = await indexedDB.databases(); + setDbList(data.filter((item) => item.name.indexOf('_pouch_') > -1).map((item) => { + return {name: item.name.replace('_pouch_', '')} + })); + }; + listDb(); + }, []); + + return ( -
-

Existing Diagrams

+
+

Diagrams

+
@@ -64,21 +82,30 @@ function Menu() { const [createState, setCreateState] = useState('none'); const [desktopTutorialState, setDesktopTutorialState] = useState('none'); + const [diagramListState, setDiagramListState] = useState('none'); - function handleCreateClick() { + function handleCreateClick(evt: React.MouseEvent) { + evt.preventDefault(); setCreateState(createState == 'none' ? 'block' : 'none'); } - function handleDesktopTutorialClick() { + function handleDesktopTutorialClick(evt: React.MouseEvent) { + evt.preventDefault(); setDesktopTutorialState(desktopTutorialState == 'none' ? 'block' : 'none'); } + function handleDiagramListClick(evt: React.MouseEvent) { + evt.preventDefault(); + setDiagramListState(diagramListState == 'none' ? 'block' : 'none'); + } + return (
- + - + +
) } @@ -89,8 +116,6 @@ export default function WebApp() {
) - - } /* const create = document.querySelector('#startCreateLink'); diff --git a/src/webApp.ts b/src/webApp.ts index 72af8a5..09feebd 100644 --- a/src/webApp.ts +++ b/src/webApp.ts @@ -2,4 +2,4 @@ import {createRoot} from "react-dom/client"; import WebApp from "./react/webApp"; const root = createRoot(document.getElementById('webApp')); -root.render(WebApp()); \ No newline at end of file +root.render(WebApp());