From b5256da3a50c165bf58b81f47a76a07236efc289 Mon Sep 17 00:00:00 2001 From: modeco80 Date: Sun, 24 Mar 2024 08:32:32 -0400 Subject: [PATCH] WIP: Rip out bootstrap Things that have been done: - Remove bootstrap - Switch to a version of the computernewb css ported to scss - (ONLY FOR NOW!!) rip out modals from html and typescript - Change the vm hash system so we use the "hashchange" listener, meaning we don't need a event on the list item anymore. Additionally this means that you can just switch VMs just by changing the hash if you know the ID. This is essentially how the cvm3 webapp works. There are still a ton of things that need to be done: - Fixing general styling - Fix card styling, it's a bit broken at the moment - Adding styling for the navbar so it looks correct - Adding styling for HTML elements the original computernewb homepage CSS didn't have - Reimplementing modals using (better yet, implementing prompt and confirmation dialogs AS modals) - Fixing dropdowns --- package.json | 4 +- src/css/_colors-dark.scss | 15 ++ src/css/cards.scss | 61 ++++++ src/css/main.scss | 362 +++++++++++++++++++++++++++++++ src/css/style.css | 292 ------------------------- src/html/index.html | 99 +-------- src/ts/main.ts | 71 +++--- src/ts/modals/tmp_og_modals.html | 90 ++++++++ tsconfig.json | 5 + yarn.lock | 86 +++++++- 10 files changed, 658 insertions(+), 427 deletions(-) create mode 100644 src/css/_colors-dark.scss create mode 100644 src/css/cards.scss create mode 100644 src/css/main.scss delete mode 100644 src/css/style.css create mode 100644 src/ts/modals/tmp_og_modals.html diff --git a/package.json b/package.json index b77b4d9..bd2a7c1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "kill me", "private": true, "scripts": { - "build": "parcel build --no-source-maps --dist-dir dist --public-url '.' src/html/index.html", + "build": "parcel build --dist-dir dist --public-url '.' src/html/index.html", "serve": "parcel src/html/index.html", "test": "jest", "clean": "run-script-os", @@ -16,7 +16,6 @@ "dependencies": { "@hcaptcha/types": "^1.0.3", "@popperjs/core": "^2.11.8", - "bootstrap": "^5.3.2", "nanoevents": "^7.0.1", "simple-keyboard": "^3.7.53" }, @@ -24,6 +23,7 @@ "@parcel/watcher": "~2.1.0" }, "devDependencies": { + "@parcel/transformer-sass": "2.12.0", "@types/bootstrap": "^5.2.10", "@types/jest": "^29.5.12", "jest": "^29.7.0", diff --git a/src/css/_colors-dark.scss b/src/css/_colors-dark.scss new file mode 100644 index 0000000..9815292 --- /dev/null +++ b/src/css/_colors-dark.scss @@ -0,0 +1,15 @@ +// TODO: Maybe we *should* use CSS variables, so the user can pick any theme +// and maybe put in hooks for that.. but for now this is fine! + +$root-bg-color: rgb(32, 32, 32); +$root-fg-color: rgb(180, 180, 180); + +/** Cards **/ +$card-background-color: rgb(48, 48, 48); +$card-border-color: rgb(58, 58, 58); +$card-box-shadow-color: rgb(0, 0, 0); +/* I have to do different syntax here because you can only do divisors with rgb() ahahah GRRRR */ +$card-image-background-color: #ffffff10; + +$link-color: rgb(100, 140, 200); +$link-visited-color: rgb(160, 140, 200); diff --git a/src/css/cards.scss b/src/css/cards.scss new file mode 100644 index 0000000..fe929ff --- /dev/null +++ b/src/css/cards.scss @@ -0,0 +1,61 @@ +@import 'colors-dark'; + +.cards { + display: grid; + list-style: none; + padding: unset; + gap: 1em; + grid-template-columns: repeat(auto-fit, minmax(0, 20em)); + /* I wish I could do this in certain situations. + * Card sections that need to wrap should be centered, but ones that fit on one line could be left-aligned. */ + /* aah i keep enabling and disabling this i don't know what to dooooo */ + /* justify-content: center; */ + font-size: 0.875rem; +} + +.cards > li > * { + height: 100%; +} + +.cards .card { + display: block; + line-height: 1.5; + overflow: auto; + text-decoration: inherit; + color: inherit; + background-color: $root-fg-color $card-background-color; + border: 4px solid $root-fg-color $card-border-color; + border-radius: 4px; + box-shadow: 0px 0px 1px 0px $root-fg-color $card-box-shadow-color; +} + +.cards .card:hover { + box-shadow: 0px 0px 4px 0px $root-fg-color $card-box-shadow-color; + /* hmm, maybe get a better indication because this isn't the most evident or the best looking */ + outline: 2px solid $root-fg-color $card-border-color; +} + +.cards .card .card-image { + display: block; + width: 100%; + background-color: $root-fg-color $card-image-background-color; + object-fit: contain; + box-sizing: border-box; + margin: auto; + /* this'd be cool if this perfectly fit a square, but then the cards are a bit bigger than i'd like them to be. gah */ + max-height: 15em; +} + +.cards .card .card-body { + padding: 1em; +} + +.cards .card .card-body > * { + margin: unset; +} + +.cards .card .card-heading { + font-size: 1.1em; + font-weight: bold; + margin-bottom: 0.25em; +} diff --git a/src/css/main.scss b/src/css/main.scss new file mode 100644 index 0000000..f8b8f95 --- /dev/null +++ b/src/css/main.scss @@ -0,0 +1,362 @@ +// TODO!!!!!! +@import 'colors-dark'; + +// modules +@import 'cards'; + +html, +body { + background-color: $root-bg-color; + color: $root-fg-color; + font-family: 'Segoe UI', Tahoma, Cantarell, sans-serif; + margin: unset; +} + +.main { + margin: auto; + overflow-wrap: break-word; +} + +/** Prettier links **/ +a { + color: $link-color; + text-decoration: none; +} + +a:visited { + color: $link-visited-color; + text-decoration: none; +} + +// ze webapp + +#vmview { + display: none; +} +/*.vmtile { + text-decoration: none; + color: #FFFFFF; + font-size: 16pt; + border: 2px solid #575757; + border-radius: 15px; + height: fit-content; + width: fit-content; + display: block; + padding: 4px; + }*/ +#vmDisplay, +#btns { + margin-left: auto; + margin-right: auto; + text-align: center; + display: block; + margin-bottom: 10px; +} + +#vmlist > div.row > div { + padding-bottom: 10px; +} +#vmlist div.col-md-3 > div.card:hover { + cursor: pointer; + border-color: rgb(8, 121, 250); +} + +.vmtile > img { + margin-bottom: 2px; +} + +.chat-table, +.username-table { + overflow-y: auto; + border: 1px solid #575757; +} +.chat-table { + height: 30vh; +} + +.username-table { + max-height: 30vh; +} +.username-table > table > thead { + position: sticky; + top: 0; +} + +#turnstatus { + text-align: center; +} +#voteResetPanel { + text-align: center; +} + +.focused { + box-shadow: 0 0 9px 0 rgba(45, 213, 255, 0.75); + -moz-box-shadow: 0 0 9px 0 rgba(45, 213, 255, 0.75); + -webkit-box-shadow: 0 0 9px 0 rgba(45, 213, 255, 0.75); +} + +.waiting { + box-shadow: 0 0 9px 0 rgba(242, 255, 63, 0.75); + -moz-box-shadow: 0 0 9px 0 rgba(242, 255, 63, 0.75); + -webkit-box-shadow: 0 0 9px 0 rgba(242, 255, 63, 0.75); +} + +#staffbtns { + display: none; +} + +#staffbtns > button { + display: none; +} + +#qemuMonitorOutput { + height: 180px; +} + +#xssCheckboxContainer { + display: none; +} + +#forceVotePanel { + display: none; +} + +tr.user-admin > td, +.chat-username-admin, +.username-admin { + color: #ff0000 !important; +} + +tr.user-moderator > td, +.chat-username-moderator, +.username-moderator { + color: #00ff00 !important; +} + +tr.user-turn > td { + background-color: #cfe2ff !important; + --bs-table-bg-state: #cfe2ff !important; + color: #000000; + --bs-table-color: #000000; +} + +tr.user-turn:hover, +tr.user-turn > td:hover { + background-color: #bacbe6 !important; + --bs-table-bg-state: #bacbe6 !important; +} + +tr.user-waiting > td { + background-color: #fff3cd !important; + --bs-table-bg-state: #fff3cd !important; + color: #000000; + --bs-table-color: #000000; +} + +.tr.user-waiting:hover, +tr.user-waiting > td:hover { + background-color: #ece1be !important; + --bs-table-bg-state: #ece1be !important; +} + +.user-current { + font-style: italic; +} + +/* Start OSK */ +.osk-container { + display: flex; + justify-content: center; + width: 1024px; + margin: 0 auto; + margin-bottom: 10px; + border-radius: 5px; +} + +.simple-keyboard.hg-theme-default { + display: inline-block; +} + +.osk-main.simple-keyboard { + width: 640px; + min-width: 640px; + background: none; +} + +.osk-main.simple-keyboard .hg-row:first-child { + margin-bottom: 8.51px; +} + +.osk-arrows.simple-keyboard { + align-self: flex-end; + background: none; +} + +.simple-keyboard .hg-button.selectedButton { + background: rgba(5, 25, 70, 0.53); + color: white; +} + +.simple-keyboard .hg-button.emptySpace { + pointer-events: none; + background: none; + border: none; + box-shadow: none; +} + +.osk-arrows .hg-row { + justify-content: center; +} + +.osk-arrows .hg-button { + width: 50px; + flex-grow: 0 !important; + justify-content: center !important; + display: flex !important; + align-items: center !important; +} + +.controlArrows { + display: flex; + align-items: center; + justify-content: space-between; + flex-flow: column; +} + +.osk-control.simple-keyboard { + background: none; +} + +.osk-control.simple-keyboard .hg-row:first-child { + margin-bottom: 8.51px; +} + +.osk-control .hg-button { + width: 50px; + flex-grow: 0 !important; + justify-content: center !important; + display: flex !important; + align-items: center !important; +} + +.numPad { + display: flex; + align-items: flex-end; +} + +.osk-numpad.simple-keyboard { + background: none; +} + +.osk-numpad.simple-keyboard { + width: 160px; +} + +.osk-numpad.simple-keyboard .hg-button { + width: 50px; + justify-content: center; + display: flex; + align-items: center; +} + +.osk-numpadEnd.simple-keyboard { + width: 50px; + background: none; + margin: 0; + padding: 5px 5px 5px 0; +} + +.osk-numpadEnd.simple-keyboard .hg-button { + align-items: center; + justify-content: center; + display: flex; +} + +.osk-numpadEnd .hg-button.hg-standardBtn.hg-button-plus { + height: 85px; +} + +.osk-numpadEnd.simple-keyboard .hg-button.hg-button-enter { + height: 85px; +} + +.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton { + background: rgba(5, 25, 70, 0.53); + color: white; +} + +.hg-button.hg-functionBtn.hg-button-space { + width: 350px; +} + +/* + Theme: cvmDark + */ + +.simple-keyboard.cvmDark .hg-button { + border-bottom: none; + background: rgba(0, 0, 0, 0.5); + color: white; +} + +.simple-keyboard.cvmDark .hg-button:active { + background: #1c4995; + color: white; +} + +#root .simple-keyboard.cvmDark + .simple-keyboard-preview { + background: #1c4995; +} + +/* + Theme: cvmDisabled + */ +.simple-keyboard.cvmDisabled .hg-button { + border-bottom: none; + pointer-events: none; + background: gray; + color: white; +} + +/* End OSK */ + +#badPasswordAlert { + display: none; +} + +/* VM0 Blur */ +a[data-cvm-node='vm0b0t'] { + img { + filter: blur(40px) !important; + } +} + +// for our new based modals +// This should probably be put into a more uniform file + +/* a bit of a "lazy" curve */ +@keyframes dialogFadeIn { + 0% { + opacity: 0; + } + 35% { + opacity: 0.75; + } + 100% { + opacity: 1; + } +} + +// don't really know how i can animate "out", +// at least without hacks, but oh well +// +// this will also probably be snappier than the mess that is +// the bootstrap modals.. + +dialog::backdrop { + animation: dialogFadeIn 0.7s; +} + +:modal { + animation: dialogFadeIn 0.4s; +} diff --git a/src/css/style.css b/src/css/style.css deleted file mode 100644 index 9cac47e..0000000 --- a/src/css/style.css +++ /dev/null @@ -1,292 +0,0 @@ -#vmview { - display: none; -} -/*.vmtile { - text-decoration: none; - color: #FFFFFF; - font-size: 16pt; - border: 2px solid #575757; - border-radius: 15px; - height: fit-content; - width: fit-content; - display: block; - padding: 4px; -}*/ -#vmDisplay, #btns { - margin-left: auto; - margin-right: auto; - text-align: center; - display: block; - margin-bottom: 10px; -} - -#vmlist > div.row > div { - padding-bottom: 10px; -} -#vmlist div.col-md-3 > div.card:hover { - cursor: pointer; - border-color: rgb(8, 121, 250); -} - -.vmtile > img { - margin-bottom: 2px; -} - -.chat-table, .username-table { - overflow-y: auto; - border: 1px solid #575757; -} -.chat-table { - height: 30vh; -} - -.username-table { - max-height: 30vh; -} -.username-table > table > thead { - position: sticky; - top: 0; -} - -#turnstatus { - text-align: center; -} -#voteResetPanel { - text-align: center; -} - -.focused { - box-shadow: 0 0 9px 0 rgba(45,213,255,.75); - -moz-box-shadow: 0 0 9px 0 rgba(45,213,255,.75); - -webkit-box-shadow: 0 0 9px 0 rgba(45,213,255,.75) -} - -.waiting { - box-shadow: 0 0 9px 0 rgba(242,255,63,.75); - -moz-box-shadow: 0 0 9px 0 rgba(242,255,63,.75); - -webkit-box-shadow: 0 0 9px 0 rgba(242,255,63,.75) -} - -#staffbtns { - display: none; -} - -#staffbtns > button { - display: none; -} - -#qemuMonitorOutput { - height: 180px; -} - -#xssCheckboxContainer { - display: none; -} - -#forceVotePanel { - display: none; -} - -tr.user-admin > td, .chat-username-admin, .username-admin { - color: #FF0000 !important; -} - -tr.user-moderator > td, .chat-username-moderator, .username-moderator { - color: #00FF00 !important; -} - -tr.user-turn > td { - background-color: #cfe2ff !important; - --bs-table-bg-state: #cfe2ff !important; - color: #000000; - --bs-table-color: #000000; -} - -tr.user-turn:hover, tr.user-turn > td:hover { - background-color: #bacbe6 !important; - --bs-table-bg-state: #bacbe6 !important; -} - -tr.user-waiting > td { - background-color: #fff3cd !important; - --bs-table-bg-state: #fff3cd !important; - color: #000000; - --bs-table-color: #000000; -} - -.tr.user-waiting:hover, tr.user-waiting > td:hover { - background-color: #ece1be !important; - --bs-table-bg-state: #ece1be !important; -} - -.user-current { - font-style: italic; -} - -/* Start OSK */ -.osk-container { -display: flex; -justify-content: center; -width: 1024px; -margin: 0 auto; -margin-bottom: 10px; -border-radius: 5px; -} - -.simple-keyboard.hg-theme-default { -display: inline-block; -} - -.osk-main.simple-keyboard { -width: 640px; -min-width: 640px; -background: none; -} - -.osk-main.simple-keyboard .hg-row:first-child { -margin-bottom: 8.51px; -} - -.osk-arrows.simple-keyboard { -align-self: flex-end; -background: none; -} - -.simple-keyboard .hg-button.selectedButton { -background: rgba(5, 25, 70, 0.53); -color: white; -} - -.simple-keyboard .hg-button.emptySpace { -pointer-events: none; -background: none; -border: none; -box-shadow: none; -} - -.osk-arrows .hg-row { -justify-content: center; -} - -.osk-arrows .hg-button { -width: 50px; -flex-grow: 0 !important; -justify-content: center !important; -display: flex !important; -align-items: center !important; -} - -.controlArrows { -display: flex; -align-items: center; -justify-content: space-between; -flex-flow: column; -} - -.osk-control.simple-keyboard { -background: none; -} - -.osk-control.simple-keyboard .hg-row:first-child { -margin-bottom: 8.51px; -} - -.osk-control .hg-button { -width: 50px; -flex-grow: 0 !important; -justify-content: center !important; -display: flex !important; -align-items: center !important; -} - -.numPad { -display: flex; -align-items: flex-end; -} - -.osk-numpad.simple-keyboard { -background: none; -} - -.osk-numpad.simple-keyboard { -width: 160px; -} - -.osk-numpad.simple-keyboard .hg-button { -width: 50px; -justify-content: center; -display: flex; -align-items: center; -} - -.osk-numpadEnd.simple-keyboard { -width: 50px; -background: none; -margin: 0; -padding: 5px 5px 5px 0; -} - -.osk-numpadEnd.simple-keyboard .hg-button { -align-items: center; -justify-content: center; -display: flex; -} - -.osk-numpadEnd .hg-button.hg-standardBtn.hg-button-plus { -height: 85px; -} - -.osk-numpadEnd.simple-keyboard .hg-button.hg-button-enter { -height: 85px; -} - -.simple-keyboard.hg-theme-default .hg-button.hg-selectedButton { -background: rgba(5, 25, 70, 0.53); -color: white; -} - -.hg-button.hg-functionBtn.hg-button-space { -width: 350px; -} - -/* -Theme: cvmDark -*/ - -.simple-keyboard.cvmDark .hg-button { -border-bottom: none; -background: rgba(0, 0, 0, 0.5); -color: white; -} - -.simple-keyboard.cvmDark .hg-button:active { -background: #1c4995; -color: white; -} - -#root .simple-keyboard.cvmDark + .simple-keyboard-preview { -background: #1c4995; -} - -/* -Theme: cvmDisabled -*/ -.simple-keyboard.cvmDisabled .hg-button { -border-bottom: none; -pointer-events: none; -background: gray; -color: white; -} - -/* End OSK */ - -#badPasswordAlert { - display: none; -} - -/* VM0 Blur */ -div[data-cvm-node=vm0b0t] { - img { - filter:blur(40px)!important; - } -} diff --git a/src/html/index.html b/src/html/index.html index e3a7d4d..6dc5fe6 100644 --- a/src/html/index.html +++ b/src/html/index.html @@ -4,8 +4,7 @@ CollabVM - - + @@ -17,95 +16,12 @@ - - -
-
-
+
    +

diff --git a/src/ts/main.ts b/src/ts/main.ts index e2d549d..306c8c9 100644 --- a/src/ts/main.ts +++ b/src/ts/main.ts @@ -8,9 +8,7 @@ import Keyboard from 'simple-keyboard'; import { OSK_buttonToKeysym } from './keyboard'; import 'simple-keyboard/build/css/index.css'; import VoteStatus from './protocol/VoteStatus.js'; -import * as bootstrap from 'bootstrap'; import MuteState from './protocol/MuteState.js'; -import { Unsubscribe } from 'nanoevents'; import { I18nStringKey, TheI18n } from './i18n.js'; import { Format } from './format.js'; @@ -246,7 +244,7 @@ let expectedClose = false; let turn = -1; // Listed VMs const vms: VM[] = []; -const cards: HTMLDivElement[] = []; +const cards: HTMLLIElement[] = []; const users: { user: User; element: HTMLTableRowElement; @@ -282,22 +280,19 @@ async function multicollab(url: string) { // Add to the DOM for (let vm of list) { - let div = document.createElement('div'); - div.classList.add('col-sm-5', 'col-md-3'); - let card = document.createElement('div'); - card.classList.add('card', 'bg-dark', 'text-light'); + // can we have jsx please........ please... i hate thisssss + let div = document.createElement('li'); + + let card = document.createElement('a'); + card.classList.add('card'); card.setAttribute('data-cvm-node', vm.id); - card.addEventListener('click', async () => { - try { - await openVM(vm); - } catch (e) { - alert((e as Error).message); - } - }); - vm.thumbnail.classList.add('card-img-top'); + card.href = `#${vm.id}`; + + vm.thumbnail.classList.add('card-image'); let cardBody = document.createElement('div'); cardBody.classList.add('card-body'); let cardTitle = document.createElement('h5'); + cardTitle.classList.add('card-heading'); cardTitle.innerHTML = vm.displayName; let usersOnline = document.createElement('span'); usersOnline.innerHTML = `( ${online})`; @@ -315,8 +310,7 @@ async function openVM(vm: VM): Promise { // If there's an active VM it must be closed before opening another if (VM !== null) return; expectedClose = false; - // Set hash - location.hash = vm.id; + // Create the client VM = new CollabVMClient(vm.url); @@ -360,7 +354,7 @@ async function openVM(vm: VM): Promise { chatMessage('', `${vm.id}
`); let username = localStorage.getItem('username'); let connected = await VM.connect(vm.id, username); - elements.adminInputVMID.value = vm.id; + //elements.adminInputVMID.value = vm.id; w.VMName = vm.id; if (!connected) { // just give up @@ -368,7 +362,7 @@ async function openVM(vm: VM): Promise { throw new Error('Failed to connect to node'); } // Set the title - document.title = Format("{0} - {1}", vm.id, TheI18n.GetString(I18nStringKey.kGeneric_CollabVM)); + document.title = Format('{0} - {1}', vm.id, TheI18n.GetString(I18nStringKey.kGeneric_CollabVM)); // Append canvas elements.vmDisplay.appendChild(VM!.canvas); // Switch to the VM view @@ -388,7 +382,7 @@ function closeVM() { // Remove the canvas elements.vmDisplay.innerHTML = ''; // Switch to the VM list - elements.vmlist.style.display = 'block'; + elements.vmlist.style.display = ''; elements.vmview.style.display = 'none'; // Clear users users.splice(0, users.length); @@ -415,13 +409,7 @@ function closeVM() { elements.username.classList.add('text-light'); } -async function loadList() { - await Promise.all( - Config.ServerAddresses.map((url) => { - return multicollab(url); - }) - ); - +async function openHash() { // automatically join the vm that's in the url if it exists in the node list let v = vms.find((v) => v.id === window.location.hash.substring(1)); try { @@ -431,12 +419,22 @@ async function loadList() { } } +async function loadList() { + await Promise.all( + Config.ServerAddresses.map((url) => { + return multicollab(url); + }) + ); + + await openHash(); +} + function sortVMList() { cards.sort((a, b) => { return a.children[0].getAttribute('data-cvm-node')! > b.children[0].getAttribute('data-cvm-node')! ? 1 : -1; }); - elements.vmlist.children[0].innerHTML = ''; - cards.forEach((c) => elements.vmlist.children[0].appendChild(c)); + //elements.vmlist.children[0].innerHTML = ''; + cards.forEach((c) => elements.vmlist.appendChild(c)); } function sortUserList() { @@ -667,6 +665,8 @@ elements.voteYesBtn.addEventListener('click', () => VM?.vote(true)); elements.voteNoBtn.addEventListener('click', () => VM?.vote(false)); // Login let usernameClick = false; + +/* const loginModal = new bootstrap.Modal(elements.loginModal); elements.loginModal.addEventListener('shown.bs.modal', () => elements.adminPassword.focus()); elements.username.addEventListener('click', () => { @@ -687,7 +687,7 @@ function doLogin() { elements.adminPassword.value = ''; let u = VM?.on('login', () => { u!(); - loginModal.hide(); + //loginModal.hide(); elements.badPasswordAlert.style.display = 'none'; }); let _u = VM?.on('badpw', () => { @@ -696,6 +696,8 @@ function doLogin() { }); } +*/ + function onLogin(_rank: Rank, _perms: Permissions) { rank = _rank; perms = _perms; @@ -775,6 +777,7 @@ elements.forceVoteNoBtn.addEventListener('click', () => VM?.forceVote(false)); elements.forceVoteYesBtn.addEventListener('click', () => VM?.forceVote(true)); elements.indefTurnBtn.addEventListener('click', () => VM?.indefiniteTurn()); +/* async function sendQEMUCommand() { if (!elements.qemuMonitorInput.value) return; let cmd = elements.qemuMonitorInput.value; @@ -786,6 +789,7 @@ async function sendQEMUCommand() { } elements.qemuMonitorSendBtn.addEventListener('click', () => sendQEMUCommand()); elements.qemuMonitorInput.addEventListener('keypress', (e) => e.key === 'Enter' && sendQEMUCommand()); +*/ elements.osk.addEventListener('click', () => elements.oskContainer.classList.toggle('d-none')); @@ -834,6 +838,11 @@ w.cvmEvents = { }; w.VMName = null; +// could be a neat feature? +window.addEventListener('hashchange', async () => { + await openHash(); +}); + document.addEventListener('DOMContentLoaded', async () => { // Initalize the i18n system await TheI18n.Init(); @@ -843,6 +852,7 @@ document.addEventListener('DOMContentLoaded', async () => { // Load all VMs await loadList(); + /* // Welcome modal let noWelcomeModal = window.localStorage.getItem('no-welcome-modal'); if (noWelcomeModal !== '1') { @@ -857,4 +867,5 @@ document.addEventListener('DOMContentLoaded', async () => { welcomeModalDismissBtn.disabled = false; }, 5000); } + */ }); diff --git a/src/ts/modals/tmp_og_modals.html b/src/ts/modals/tmp_og_modals.html new file mode 100644 index 0000000..a076c25 --- /dev/null +++ b/src/ts/modals/tmp_og_modals.html @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index c40a31e..d49c851 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,6 +14,11 @@ "target": "es2022", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ + + // for later:tm: + //"jsx": "react-jsx", + //"jsxImportSource": "nano-jsx/esm", + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ diff --git a/yarn.lock b/yarn.lock index abdea45..3ce120d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1150,6 +1150,15 @@ "@parcel/utils" "2.12.0" react-refresh "^0.9.0" +"@parcel/transformer-sass@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.12.0.tgz#9132ee78197db04baf51d3024a1bf3c35f1df5ef" + integrity sha512-xLLoSLPST+2AHJwFRLl4foArDjjy6P1RChP3TxMU2MVS1sbKGJnfFhFpHAacH8ASjuGtu5rbpfpHRZePlvoZxw== + dependencies: + "@parcel/plugin" "2.12.0" + "@parcel/source-map" "^2.1.1" + sass "^1.38.0" + "@parcel/transformer-svg@2.12.0": version "2.12.0" resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.12.0.tgz#0281e89bf0f438ec161c19b59a8a8978434a3621" @@ -1535,7 +1544,7 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== -anymatch@^3.0.3: +anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== @@ -1627,16 +1636,16 @@ base-x@^3.0.8: dependencies: safe-buffer "^5.0.1" +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== -bootstrap@^5.3.2: - version "5.3.3" - resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.3.3.tgz#de35e1a765c897ac940021900fcbb831602bac38" - integrity sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1645,7 +1654,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1723,6 +1732,21 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +"chokidar@>=3.0.0 <4.0.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chrome-trace-event@^1.0.2, chrome-trace-event@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -2056,7 +2080,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2: +fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -2091,6 +2115,13 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -2166,6 +2197,11 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +immutable@^4.0.0: + version "4.3.5" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" + integrity sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw== + import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2205,6 +2241,13 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-core-module@^2.13.0: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" @@ -2227,7 +2270,7 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-glob@^4.0.3: +is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -2938,7 +2981,7 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== -normalize-path@^3.0.0: +normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== @@ -3081,7 +3124,7 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -3174,6 +3217,13 @@ react-refresh@^0.9.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + regenerator-runtime@^0.13.7: version "0.13.11" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" @@ -3225,6 +3275,15 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +sass@^1.38.0: + version "1.72.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.72.0.tgz#5b9978943fcfb32b25a6a5acb102fc9dabbbf41c" + integrity sha512-Gpczt3WA56Ly0Mn8Sl21Vj94s1axi9hDIzDFn9Ph9x3C3p4nNyvsqJoQyVXKou6cBlfFWEgRW4rT8Tb4i3XnVA== + dependencies: + chokidar ">=3.0.0 <4.0.0" + immutable "^4.0.0" + source-map-js ">=0.6.2 <2.0.0" + semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -3269,6 +3328,11 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +"source-map-js@>=0.6.2 <2.0.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + source-map-support@0.5.13: version "0.5.13" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"