Compare commits
6 Commits
master
...
remove-boo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41a70632b8 | ||
|
|
331b5efd87 | ||
|
|
239df1f510 | ||
|
|
e3f0ec56a2 | ||
|
|
b5256da3a5 | ||
|
|
ed46f171f5 |
|
|
@ -1,4 +1,4 @@
|
|||
dist
|
||||
*.md
|
||||
*.html
|
||||
#*.html
|
||||
*.css
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
31
src/css/_colors-dark.scss
Normal file
31
src/css/_colors-dark.scss
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// 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!
|
||||
// (this really should be called _style-dark @ this point..)
|
||||
|
||||
$root-bg-color: rgb(32, 32, 32);
|
||||
$root-fg-color: rgb(180, 180, 180);
|
||||
|
||||
// Elements
|
||||
$input-bg-color: rgb(51, 51, 51);
|
||||
// Resist the urge to make these radioactive. I made them kinda grungy
|
||||
// on purpose, and it seems to be okay.
|
||||
$button-bg-color: rgb(51, 107, 145);
|
||||
$button-red-bg-color: rgb(159, 51, 51);
|
||||
$button-green-bg-color: rgb(61, 151, 43);
|
||||
|
||||
// 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);
|
||||
|
||||
// Root mixin
|
||||
.root {
|
||||
background-color: $root-bg-color;
|
||||
color: $root-fg-color;
|
||||
font-family: 'Segoe UI', Tahoma, Cantarell, sans-serif;
|
||||
}
|
||||
62
src/css/cards.scss
Normal file
62
src/css/cards.scss
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
// module for cards
|
||||
@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;
|
||||
}
|
||||
44
src/css/dialog.scss
Normal file
44
src/css/dialog.scss
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// for our new <dialog> based modals
|
||||
@import 'colors-dark';
|
||||
|
||||
/* a bit of a "lazy" curve. should probably be in a shared file */
|
||||
@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.3s;
|
||||
background-color: rgba(0, 0, 0, 0.65);
|
||||
}
|
||||
|
||||
dialog {
|
||||
@extend .root;
|
||||
|
||||
color: inherit;
|
||||
background-color: $root-fg-color $card-background-color;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 0px 8px 0px $root-fg-color $card-box-shadow-color;
|
||||
}
|
||||
|
||||
:modal {
|
||||
animation: dialogFadeIn 0.2s;
|
||||
}
|
||||
|
||||
.dialog-alignright {
|
||||
float: right;
|
||||
}
|
||||
58
src/css/elements.scss
Normal file
58
src/css/elements.scss
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// Module for element styling
|
||||
// THIS IS NOT DONE!
|
||||
@import 'colors-dark';
|
||||
|
||||
.button-default {
|
||||
@extend .root;
|
||||
|
||||
background-color: $button-bg-color !important;
|
||||
border-radius: 6px;
|
||||
border-width: 0;
|
||||
color: #ffffff !important;
|
||||
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
|
||||
padding: 10px 12px;
|
||||
|
||||
text-align: center;
|
||||
transition: all 200ms;
|
||||
vertical-align: baseline;
|
||||
white-space: nowrap;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
button {
|
||||
@extend .button-default;
|
||||
}
|
||||
|
||||
.button-red {
|
||||
background-color: $button-red-bg-color !important;
|
||||
}
|
||||
|
||||
.button-green {
|
||||
background-color: $button-green-bg-color !important;
|
||||
}
|
||||
|
||||
|
||||
input[type='text'] {
|
||||
padding: 0.1em;
|
||||
height: 1.75em;
|
||||
//position: relative;
|
||||
|
||||
outline: none;
|
||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||
background-color: $input-bg-color;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
339
src/css/main.scss
Normal file
339
src/css/main.scss
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
// TODO!!!!!!
|
||||
@import 'colors-dark';
|
||||
|
||||
// modules
|
||||
@import 'elements';
|
||||
@import 'cards';
|
||||
@import 'dialog';
|
||||
|
||||
|
||||
html,
|
||||
body {
|
||||
@extend .root;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// shitty bootstrap polyfill
|
||||
.d-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,221 +1,158 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!doctype html>
|
||||
<html prefix="og: https://ogp.me/ns#">
|
||||
<head>
|
||||
<title>CollabVM</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8"/>
|
||||
<link href="../css/style.css" rel="stylesheet" type="text/css"/>
|
||||
<link href="../../node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="https://kit.fontawesome.com/7add23c1ae.js" crossorigin="anonymous"></script>
|
||||
<link rel="icon" href="../assets/favicon.ico">
|
||||
<meta name="description" content="A website that lets you take turns controlling online virtual machines with complete strangers!"/>
|
||||
<!-- Opengraph shit -->
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:title" content="CollabVM"/>
|
||||
<meta property="og:url" content="https://computernewb.com/collab-vm/"/>
|
||||
<meta property="og:description" content="A website that lets you take turns controlling online virtual machines with complete strangers!"/>
|
||||
<meta property="og:site_name" content="Computernewb"/>
|
||||
<meta property="og:image" content="https://computernewb.com/collab-vm/desktop.png"/>
|
||||
</head>
|
||||
<body class="bg-dark">
|
||||
<div class="modal fade" id="qemuMonitorModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">QEMU Monitor</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<textarea id="qemuMonitorOutput" readonly="" class="form-control bg-dark text-light"></textarea>
|
||||
<div class="input-group">
|
||||
<input type="text" id="qemuMonitorInput" class="form-control bg-dark text-light" placeholder="Command"/>
|
||||
<button class="btn btn-outline-secondary btn-primary text-light" type="button" id="qemuMonitorSendBtn">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="welcomeModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" aria-labelledby="welcomeModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header">
|
||||
<h1>Welcome to CollabVM</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Before continuing, please familiarize yourself with our rules:</p>
|
||||
<h3>R1. Don't break the law.</h3>
|
||||
Do not use CollabVM or CollabVM's network to violate United States federal law, New York state law, or international law. If CollabVM becomes aware a crime has been committed through its service, you will be immediately banned, and your activities may be reported to the authorities if necessary.<br><br>CollabVM is required by law to notify law enforcement agencies if it becomes aware of the presence of child pornography on, or being transmitted through its network.<br><br>COPPA is also enforced, please do not use CollabVM if you are under the age of 13 years old.
|
||||
<h3>R2. No running DoS/DDoS tools.</h3>
|
||||
Do not use CollabVM to DoS/DDoS an indivdiual, business, company, or anyone else.
|
||||
<h3>R3. No spam distribution.</h3>
|
||||
Do not spam any emails using this service or push spam in general.
|
||||
<h3>R4. Do not abuse any exploits.</h3>
|
||||
Do not abuse any exploits, additionally if you see someone abusing exploits or you need to report one, please contact me at: computernewbab@gmail.com
|
||||
<h3>R5. Don't impersonate other users.</h3>
|
||||
Do not impersonate other members of CollabVM. If caught, you'll be temporarily disconnected, and banned if necessary.
|
||||
<h3>R6. One vote per person.</h3>
|
||||
Do not use any methods or tools to bypass the vote restriction. Only one vote per person is allowed, no matter what. Anybody who is caught doing this will be banned.
|
||||
<h3>R7. No Remote Administration Tools.</h3>
|
||||
Do not use any remote administration tools (ex: DarkComet, NanoCore, Anydesk, TeamViewer, Orcus, etc.)
|
||||
<h3>R8. No bypassing CollabNet.</h3>
|
||||
Do not attempt to bypass the blocking provided by CollabNet, especially if it is being used to break Rule 1, Rule 2, or Rule 7 (or run stupid over-used things).
|
||||
<h3>R9. No performing destructive actions constantly.</h3>
|
||||
Any user may not destroy the VM (rendering it unusable constantly), install/reinstall the operating system (except on VM7 or VM8), or run bots that do such. This includes bots that spam massive amounts of keyboard/mouse input ("kitting").
|
||||
<h3>R10. No Cryptomining</h3>
|
||||
Attempting to mine cryptocurrency on the VMs will result in a kick, and then a permanent ban if you keep attempting. Besides, it's not like you're gonna make any money off it.
|
||||
<h3>NSFW Warning</h3>
|
||||
Please note that NSFW content is allowed on our anarchy VM (VM0b0t), and is viewed regularly. In addition, while we give a good effort to keep NSFW off the main VMs, people will occasionally slip it through.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="welcomeModalDismiss" class="btn btn-primary" data-bs-dismiss="modal">Understood</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-md">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Login</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger alert-dismissible" id="badPasswordAlert" role="alert">
|
||||
Incorrect password.
|
||||
<button type="button" class="btn-close" aria-label="Close" id="incorrectPasswordDismissBtn"></button>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="hidden" name="username" id="adminInputVMID"/>
|
||||
<span class="input-group-text bg-dark text-light">Password</span>
|
||||
<input id="adminPassword" type="password" class="form-control bg-dark text-light" placeholder="Password" name="password"/>
|
||||
</div>
|
||||
<head>
|
||||
<title>CollabVM</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta charset="utf-8" />
|
||||
<link href="../css/main.scss" rel="stylesheet" />
|
||||
<script src="https://kit.fontawesome.com/7add23c1ae.js" crossorigin="anonymous"></script>
|
||||
<link rel="icon" href="../assets/favicon.ico" />
|
||||
<meta name="description" content="A website that lets you take turns controlling online virtual machines with complete strangers!" />
|
||||
<!-- Opengraph shit -->
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="CollabVM" />
|
||||
<meta property="og:url" content="https://computernewb.com/collab-vm/" />
|
||||
<meta property="og:description" content="A website that lets you take turns controlling online virtual machines with complete strangers!" />
|
||||
<meta property="og:site_name" content="Computernewb" />
|
||||
<meta property="og:image" content="https://computernewb.com/collab-vm/desktop.png" />
|
||||
</head>
|
||||
<body class="main">
|
||||
<!-- Needed for the new modal API, this is where all the modals mount to
|
||||
I know I could probably create it dynamically but I just want it to work OK-->
|
||||
<div id="modalRoot">
|
||||
<!-- TEMP! these will be created in js or jsx -->
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="loginButton" class="btn btn-primary">Login</button>
|
||||
<dialog id="changeUsernameDialog">
|
||||
<form method="dialog">
|
||||
<label>Enter a new username, or leave blank to assign yourself a guest username.</label><br />
|
||||
<section>
|
||||
<input id="usernameInput" type="text" placeholder="A username, or leave blank." />
|
||||
</section>
|
||||
|
||||
<div class="dialog-alignright">
|
||||
<button id="okButton" value="" class="button-green">OK</button>
|
||||
<button id="cancelButton" class="button-red">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<dialog id="alertDialog">
|
||||
<form method="dialog">
|
||||
<label id="alertMessage"></label>
|
||||
<div class="dialog-alignright">
|
||||
<button id="okButton" value="" class="button-green">OK</button>
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"><span id="siteNameText"></span></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a id="homeBtn" href="#" class="nav-link active" aria-current="page"><i class="fa-solid fa-house"></i> <span id="homeBtnText"></span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://computernewb.com/collab-vm/faq/" class="nav-link"><i class="fa-solid fa-circle-question"></i> <span id="faqBtnText"></span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://computernewb.com/collab-vm/rules" class="nav-link"><i class="fa-solid fa-clipboard-check"></i> <span id="rulesBtnText"></span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://discord.gg/a4kqb4mGyX" class="nav-link"><i class="fa-brands fa-discord"></i> Discord</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://reddit.com/r/collabvm" class="nav-link"><i class="fa-brands fa-reddit"></i> Subreddit</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a rel="me" class="nav-link" href="https://fedi.computernewb.com/@collabvm"><i class="fa-brands fa-mastodon"></i> Mastodon</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://computernewb.com/collab-vm/user-vm" class="nav-link"><i class="fa-solid fa-user"></i> UserVM</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<ul class="cards" id="vmlist"></ul>
|
||||
<div class="container-fluid" id="vmview">
|
||||
<div id="vmDisplay"></div>
|
||||
<p id="turnstatus" class="text-light"></p>
|
||||
<div id="voteResetPanel" class="bg-dark text-light" style="display: none">
|
||||
<span id="voteResetHeaderText"></span><br />
|
||||
<button class="button-green" id="voteYesBtn"><i class="fa-solid fa-check"></i> <span id="voteYesBtnText"></span><span class="badge bg-secondary" id="voteYesLabel"></span></button>
|
||||
<button class="button-red" id="voteNoBtn"><i class="fa-solid fa-ban"></i> <span id="voteNoBtnText"></span><span class="badge bg-secondary" id="voteNoLabel"></span></button><br />
|
||||
<span id="voteTimeText"></span>
|
||||
<div id="forceVotePanel">
|
||||
<button class="button-green" id="forceVoteYesBtn"><i class="fa-solid fa-check"></i> <span id="passVoteBtnText"></span></button>
|
||||
<button class="button-red" id="forceVoteNoBtn"><i class="fa-solid fa-ban"></i> <span id="cancelVoteBtnText"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="btns">
|
||||
<button class="btn btn-secondary" id="takeTurnBtn"><i class="fa-solid fa-computer-mouse"></i> <span id="turnBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="oskBtn"><i class="fa-solid fa-keyboard"></i> Keyboard</button>
|
||||
<button class="btn btn-secondary" id="changeUsernameBtn"><i class="fa-solid fa-signature"></i> <span id="changeUsernameBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="voteResetButton"><i class="fa-solid fa-rotate-left"></i> <span id="voteForResetBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="screenshotButton"><i class="fa-solid fa-camera"></i> <span id="screenshotBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="ctrlAltDelBtn"><i class="fa-solid fa-gear"></i> Ctrl+Alt+Del</button>
|
||||
<div id="staffbtns">
|
||||
<button class="btn btn-secondary" id="restoreBtn"><i class="fa-solid fa-rotate-left"></i> Restore</button>
|
||||
<button class="btn btn-secondary" id="rebootBtn"><i class="fa-solid fa-power-off"></i> Reboot</button>
|
||||
<button class="btn btn-secondary" id="clearQueueBtn"><i class="fa-solid fa-eraser"></i> Clear Turn Queue</button>
|
||||
<button class="btn btn-secondary" id="bypassTurnBtn"><i class="fa-solid fa-forward"></i> Bypass Turn</button>
|
||||
<button class="btn btn-secondary" id="endTurnBtn"><i class="fa-solid fa-ban"></i> <span id="endTurnBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="indefTurnBtn"><i class="fa-solid fa-infinity"></i> Indefinite Turn</button>
|
||||
<button class="btn btn-secondary" id="qemuMonitorBtn" data-bs-toggle="modal" data-bs-target="#qemuMonitorModal"><i class="fa-solid fa-terminal"></i> QEMU Monitor</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="hcaptchaModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-body">
|
||||
<div id="captcha-box"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#"><span id="siteNameText"></span></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a id="homeBtn" href="#" class="nav-link active" aria-current="page"><i class="fa-solid fa-house"></i> <span id="homeBtnText"></span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://computernewb.com/collab-vm/faq/" class="nav-link"><i class="fa-solid fa-circle-question"></i> <span id="faqBtnText"></span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://computernewb.com/collab-vm/rules" class="nav-link"><i class="fa-solid fa-clipboard-check"></i> <span id="rulesBtnText"></span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://discord.gg/a4kqb4mGyX" class="nav-link"><i class="fa-brands fa-discord"></i> Discord</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://reddit.com/r/collabvm" class="nav-link"><i class="fa-brands fa-reddit"></i> Subreddit</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a rel="me" class="nav-link" href="https://fedi.computernewb.com/@collabvm"><i class="fa-brands fa-mastodon"></i> Mastodon</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="https://computernewb.com/collab-vm/user-vm" class="nav-link"><i class="fa-solid fa-user"></i> UserVM</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container-fluid" id="vmlist">
|
||||
<div class="row"></div>
|
||||
</div>
|
||||
<div class="container-fluid" id="vmview">
|
||||
<div id="vmDisplay"></div>
|
||||
<p id="turnstatus" class="text-light"></p>
|
||||
<div id="voteResetPanel" class="bg-dark text-light" style="display:none;">
|
||||
<span id="voteResetHeaderText"></span><br/>
|
||||
<button class="btn btn-success" id="voteYesBtn"><i class="fa-solid fa-check"></i> <span id="voteYesBtnText"></span><span class="badge bg-secondary" id="voteYesLabel"></span></button> <button class="btn btn-danger" id="voteNoBtn"><i class="fa-solid fa-ban"></i> <span id="voteNoBtnText"></span><span class="badge bg-secondary" id="voteNoLabel"></span></button><br/>
|
||||
<span id="voteTimeText"></span>
|
||||
<div id="forceVotePanel">
|
||||
<button class="btn btn-info" id="forceVoteYesBtn"><i class="fa-solid fa-check"></i> <span id="passVoteBtnText"></span></button>
|
||||
<button class="btn btn-info" id="forceVoteNoBtn"><i class="fa-solid fa-ban"></i> <span id="cancelVoteBtnText"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="btns">
|
||||
<button class="btn btn-secondary" id="takeTurnBtn"><i class="fa-solid fa-computer-mouse"></i> <span id="turnBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="oskBtn"><i class="fa-solid fa-keyboard"></i> Keyboard</button>
|
||||
<button class="btn btn-secondary" id="changeUsernameBtn"><i class="fa-solid fa-signature"></i> <span id="changeUsernameBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="voteResetButton"><i class="fa-solid fa-rotate-left"></i> <span id="voteForResetBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="screenshotButton"><i class="fa-solid fa-camera"></i> <span id="screenshotBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="ctrlAltDelBtn"><i class="fa-solid fa-gear"></i> Ctrl+Alt+Del</button>
|
||||
<div id="staffbtns">
|
||||
<button class="btn btn-secondary" id="restoreBtn"><i class="fa-solid fa-rotate-left"></i> Restore</button>
|
||||
<button class="btn btn-secondary" id="rebootBtn"><i class="fa-solid fa-power-off"></i> Reboot</button>
|
||||
<button class="btn btn-secondary" id="clearQueueBtn"><i class="fa-solid fa-eraser"></i> Clear Turn Queue</button>
|
||||
<button class="btn btn-secondary" id="bypassTurnBtn"><i class="fa-solid fa-forward"></i> Bypass Turn</button>
|
||||
<button class="btn btn-secondary" id="endTurnBtn"><i class="fa-solid fa-ban"></i> <span id="endTurnBtnText"></span></button>
|
||||
<button class="btn btn-secondary" id="indefTurnBtn"><i class="fa-solid fa-infinity"></i> Indefinite Turn</button>
|
||||
<button class="btn btn-secondary" id="qemuMonitorBtn" data-bs-toggle="modal" data-bs-target="#qemuMonitorModal"><i class="fa-solid fa-terminal"></i> QEMU Monitor</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="osk-container d-none" id="osk-container">
|
||||
<div class="osk-main"></div>
|
||||
<div class="osk-main"></div>
|
||||
|
||||
<div class="controlArrows">
|
||||
<div class="osk-control"></div>
|
||||
<div class="osk-arrows"></div>
|
||||
</div>
|
||||
<div class="controlArrows">
|
||||
<div class="osk-control"></div>
|
||||
<div class="osk-arrows"></div>
|
||||
</div>
|
||||
|
||||
<div class="numPad">
|
||||
<div class="osk-numpad"></div>
|
||||
<div class="osk-numpadEnd"></div>
|
||||
</div>
|
||||
<div class="numPad">
|
||||
<div class="osk-numpad"></div>
|
||||
<div class="osk-numpadEnd"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="table-responsive username-table">
|
||||
<table class="table table-hover table-dark table-borderless">
|
||||
<thead>
|
||||
<th><i class="fa-solid fa-user"></i> <span id="usersOnlineText"></span> (<span id="onlineusercount"></span>)</th>
|
||||
</thead>
|
||||
<tbody id="userlist"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="table-responsive chat-table" id="chatListDiv">
|
||||
<table class="table table-hover table-dark table-borderless">
|
||||
<tbody id="chatList">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-dark text-light" id="username">Username</span>
|
||||
<input type="text" class="form-control bg-dark text-light" id="chat-input"/>
|
||||
<div class="input-group-text bg-dark text-light" id="xssCheckboxContainer">
|
||||
<input class="form-check-input" type="checkbox" value="" id="xssCheckbox"/>
|
||||
<label class="form-check-label" for="xssCheckbox">XSS</label>
|
||||
</div>
|
||||
<button class="btn btn-primary text-light" type="button" id="sendChatBtn"><i class="fa-solid fa-paper-plane"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||
<script type="module" src="../ts/main.ts" type="application/javascript"></script>
|
||||
</body>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="table-responsive username-table">
|
||||
<table class="table table-hover table-dark table-borderless">
|
||||
<thead>
|
||||
<th><i class="fa-solid fa-user"></i> <span id="usersOnlineText"></span> (<span id="onlineusercount"></span>)</th>
|
||||
</thead>
|
||||
<tbody id="userlist"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="table-responsive chat-table" id="chatListDiv">
|
||||
<table class="table table-hover table-dark table-borderless">
|
||||
<tbody id="chatList"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="input-group-text bg-dark text-light" id="username">Username</span>
|
||||
<input type="text" class="form-control bg-dark text-light" id="chat-input" />
|
||||
<div class="input-group-text bg-dark text-light" id="xssCheckboxContainer">
|
||||
<input class="form-check-input" type="checkbox" value="" id="xssCheckbox" />
|
||||
<label class="form-check-label" for="xssCheckbox">XSS</label>
|
||||
</div>
|
||||
<button class="btn btn-primary text-light" type="button" id="sendChatBtn"><i class="fa-solid fa-paper-plane"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
|
||||
<script type="module" src="../ts/main.ts" type="application/javascript"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ 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';
|
||||
import { ChangeUsername_Modal } from './modals/change_username_modal.js';
|
||||
import { Alert_Modal } from './modals/alert_modal.js';
|
||||
|
||||
// Elements
|
||||
const w = window as any;
|
||||
|
|
@ -246,7 +246,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 +282,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 = `(<i class="fa-solid fa-users"></i> ${online})`;
|
||||
|
|
@ -315,8 +312,7 @@ async function openVM(vm: VM): Promise<void> {
|
|||
// 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);
|
||||
|
||||
|
|
@ -331,13 +327,13 @@ async function openVM(vm: VM): Promise<void> {
|
|||
// TODO: i18n these
|
||||
switch (status) {
|
||||
case 'taken':
|
||||
alert(TheI18n.GetString(I18nStringKey.kError_UsernameTaken));
|
||||
Alert_Modal(TheI18n.GetString(I18nStringKey.kError_UsernameTaken));
|
||||
break;
|
||||
case 'invalid':
|
||||
alert(TheI18n.GetString(I18nStringKey.kError_UsernameInvalid));
|
||||
Alert_Modal(TheI18n.GetString(I18nStringKey.kError_UsernameInvalid));
|
||||
break;
|
||||
case 'blacklisted':
|
||||
alert(TheI18n.GetString(I18nStringKey.kError_UsernameBlacklisted));
|
||||
Alert_Modal(TheI18n.GetString(I18nStringKey.kError_UsernameBlacklisted));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
|
@ -345,11 +341,11 @@ async function openVM(vm: VM): Promise<void> {
|
|||
VM!.on('turn', (status) => turnUpdate(status));
|
||||
VM!.on('vote', (status: VoteStatus) => voteUpdate(status));
|
||||
VM!.on('voteend', () => voteEnd());
|
||||
VM!.on('votecd', (voteCooldown) => window.alert(TheI18n.GetString(I18nStringKey.kVM_VoteCooldownTimer, voteCooldown)));
|
||||
VM!.on('votecd', (voteCooldown) => Alert_Modal(TheI18n.GetString(I18nStringKey.kVM_VoteCooldownTimer, voteCooldown)));
|
||||
VM!.on('login', (rank: Rank, perms: Permissions) => onLogin(rank, perms));
|
||||
|
||||
VM!.on('close', () => {
|
||||
if (!expectedClose) alert(TheI18n.GetString(I18nStringKey.kError_UnexpectedDisconnection));
|
||||
if (!expectedClose) Alert_Modal(TheI18n.GetString(I18nStringKey.kError_UnexpectedDisconnection));
|
||||
closeVM();
|
||||
});
|
||||
|
||||
|
|
@ -360,7 +356,7 @@ async function openVM(vm: VM): Promise<void> {
|
|||
chatMessage('', `<b>${vm.id}</b><hr>`);
|
||||
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 +364,7 @@ async function openVM(vm: VM): Promise<void> {
|
|||
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 +384,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,6 +411,16 @@ function closeVM() {
|
|||
elements.username.classList.add('text-light');
|
||||
}
|
||||
|
||||
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 {
|
||||
if (v !== undefined) await openVM(v);
|
||||
} catch (e) {
|
||||
Alert_Modal((e as Error).message);
|
||||
}
|
||||
}
|
||||
|
||||
async function loadList() {
|
||||
await Promise.all(
|
||||
Config.ServerAddresses.map((url) => {
|
||||
|
|
@ -422,21 +428,15 @@ async function loadList() {
|
|||
})
|
||||
);
|
||||
|
||||
// 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 {
|
||||
if (v !== undefined) await openVM(v);
|
||||
} catch (e) {
|
||||
alert((e as Error).message);
|
||||
}
|
||||
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() {
|
||||
|
|
@ -633,8 +633,13 @@ elements.sendChatBtn.addEventListener('click', sendChat);
|
|||
elements.chatinput.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') sendChat();
|
||||
});
|
||||
elements.changeUsernameBtn.addEventListener('click', () => {
|
||||
let newname = prompt(TheI18n.GetString(I18nStringKey.kVMPrompts_EnterNewUsernamePrompt), w.username);
|
||||
elements.changeUsernameBtn.addEventListener('click', async () => {
|
||||
let newname = await ChangeUsername_Modal(w.username);
|
||||
|
||||
// cancelled
|
||||
if(newname == null)
|
||||
return;
|
||||
|
||||
if (newname === w.username) return;
|
||||
VM?.rename(newname);
|
||||
});
|
||||
|
|
@ -667,6 +672,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 +694,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 +703,8 @@ function doLogin() {
|
|||
});
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
function onLogin(_rank: Rank, _perms: Permissions) {
|
||||
rank = _rank;
|
||||
perms = _perms;
|
||||
|
|
@ -746,7 +755,7 @@ function userModOptions(user: { user: User; element: HTMLTableRowElement }) {
|
|||
if (perms.grabip)
|
||||
addUserDropdownItem(ul, 'Get IP', async () => {
|
||||
let ip = await VM!.getip(user.user.username);
|
||||
alert(ip);
|
||||
Alert_Modal(ip);
|
||||
});
|
||||
tr.appendChild(ul);
|
||||
}
|
||||
|
|
@ -775,6 +784,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 +796,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 +845,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 +859,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 +874,5 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
welcomeModalDismissBtn.disabled = false;
|
||||
}, 5000);
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
|
|
|||
9
src/ts/modals/alert_modal.ts
Normal file
9
src/ts/modals/alert_modal.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
const elements = {
|
||||
alertDialog: document.querySelector('#alertDialog') as HTMLDialogElement
|
||||
};
|
||||
|
||||
export function Alert_Modal(text: string) {
|
||||
const alertMessage = elements.alertDialog.querySelector('#alertMessage') as HTMLLabelElement;
|
||||
alertMessage.innerText = text;
|
||||
elements.alertDialog.showModal();
|
||||
}
|
||||
52
src/ts/modals/change_username_modal.ts
Normal file
52
src/ts/modals/change_username_modal.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
const elements = {
|
||||
changeUsernameDialog: document.querySelector('#changeUsernameDialog') as HTMLDialogElement
|
||||
};
|
||||
|
||||
// returns a promise which will resolve with "null" for canceled,
|
||||
// and a username for a username
|
||||
export async function ChangeUsername_Modal(lastUsername: string): Promise<string | null> {
|
||||
return new Promise((res, rej) => {
|
||||
const usernameInput = elements.changeUsernameDialog.querySelector('#usernameInput') as HTMLInputElement;
|
||||
const cancelButton = elements.changeUsernameDialog.querySelector('#cancelButton') as HTMLButtonElement;
|
||||
const okButton = elements.changeUsernameDialog.querySelector('#okButton') as HTMLButtonElement;
|
||||
|
||||
usernameInput.addEventListener('change', (e) => {
|
||||
okButton.value = usernameInput.value;
|
||||
});
|
||||
|
||||
function handleDialog() {
|
||||
resetBox();
|
||||
res(elements.changeUsernameDialog.returnValue);
|
||||
}
|
||||
|
||||
function handleDialogCancel() {
|
||||
resetBox();
|
||||
res(null);
|
||||
}
|
||||
|
||||
function resetBox() {
|
||||
usernameInput.value = '';
|
||||
|
||||
// remove event listener s you google..
|
||||
elements.changeUsernameDialog.removeEventListener('close', handleDialog);
|
||||
elements.changeUsernameDialog.removeEventListener('close', handleDialogCancel);
|
||||
}
|
||||
|
||||
elements.changeUsernameDialog.addEventListener('cancel', (e) => {
|
||||
handleDialogCancel();
|
||||
});
|
||||
|
||||
okButton.addEventListener('click', (ev) => {
|
||||
elements.changeUsernameDialog.addEventListener('close', handleDialog);
|
||||
});
|
||||
|
||||
cancelButton.addEventListener('click', (ev) => {
|
||||
elements.changeUsernameDialog.addEventListener('close', handleDialogCancel);
|
||||
});
|
||||
|
||||
// show the modal!
|
||||
usernameInput.value = lastUsername;
|
||||
okButton.value = lastUsername;
|
||||
elements.changeUsernameDialog.showModal();
|
||||
});
|
||||
}
|
||||
90
src/ts/modals/tmp_og_modals.html
Normal file
90
src/ts/modals/tmp_og_modals.html
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<!-- These are the original modals from the webapp. I wanna make them in JSX or something
|
||||
now that we're dropping bootstrap, but if I'm resigned to, I can just blind port these -->
|
||||
<div class="modal fade" id="qemuMonitorModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">QEMU Monitor</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<textarea id="qemuMonitorOutput" readonly="" class="form-control bg-dark text-light"></textarea>
|
||||
<div class="input-group">
|
||||
<input type="text" id="qemuMonitorInput" class="form-control bg-dark text-light" placeholder="Command"/>
|
||||
<button class="btn btn-outline-secondary btn-primary text-light" type="button" id="qemuMonitorSendBtn">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="welcomeModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false" aria-labelledby="welcomeModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header">
|
||||
<h1>Welcome to CollabVM</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Before continuing, please familiarize yourself with our rules:</p>
|
||||
<h3>R1. Don't break the law.</h3>
|
||||
Do not use CollabVM or CollabVM's network to violate United States federal law, New York state law, or international law. If CollabVM becomes aware a crime has been committed through its service, you will be immediately banned, and your activities may be reported to the authorities if necessary.<br><br>CollabVM is required by law to notify law enforcement agencies if it becomes aware of the presence of child pornography on, or being transmitted through its network.<br><br>COPPA is also enforced, please do not use CollabVM if you are under the age of 13 years old.
|
||||
<h3>R2. No running DoS/DDoS tools.</h3>
|
||||
Do not use CollabVM to DoS/DDoS an indivdiual, business, company, or anyone else.
|
||||
<h3>R3. No spam distribution.</h3>
|
||||
Do not spam any emails using this service or push spam in general.
|
||||
<h3>R4. Do not abuse any exploits.</h3>
|
||||
Do not abuse any exploits, additionally if you see someone abusing exploits or you need to report one, please contact me at: computernewbab@gmail.com
|
||||
<h3>R5. Don't impersonate other users.</h3>
|
||||
Do not impersonate other members of CollabVM. If caught, you'll be temporarily disconnected, and banned if necessary.
|
||||
<h3>R6. One vote per person.</h3>
|
||||
Do not use any methods or tools to bypass the vote restriction. Only one vote per person is allowed, no matter what. Anybody who is caught doing this will be banned.
|
||||
<h3>R7. No Remote Administration Tools.</h3>
|
||||
Do not use any remote administration tools (ex: DarkComet, NanoCore, Anydesk, TeamViewer, Orcus, etc.)
|
||||
<h3>R8. No bypassing CollabNet.</h3>
|
||||
Do not attempt to bypass the blocking provided by CollabNet, especially if it is being used to break Rule 1, Rule 2, or Rule 7 (or run stupid over-used things).
|
||||
<h3>R9. No performing destructive actions constantly.</h3>
|
||||
Any user may not destroy the VM (rendering it unusable constantly), install/reinstall the operating system (except on VM7 or VM8), or run bots that do such. This includes bots that spam massive amounts of keyboard/mouse input ("kitting").
|
||||
<h3>R10. No Cryptomining</h3>
|
||||
Attempting to mine cryptocurrency on the VMs will result in a kick, and then a permanent ban if you keep attempting. Besides, it's not like you're gonna make any money off it.
|
||||
<h3>NSFW Warning</h3>
|
||||
Please note that NSFW content is allowed on our anarchy VM (VM0b0t), and is viewed regularly. In addition, while we give a good effort to keep NSFW off the main VMs, people will occasionally slip it through.
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="welcomeModalDismiss" class="btn btn-primary" data-bs-dismiss="modal">Understood</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-md">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Login</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-danger alert-dismissible" id="badPasswordAlert" role="alert">
|
||||
Incorrect password.
|
||||
<button type="button" class="btn-close" aria-label="Close" id="incorrectPasswordDismissBtn"></button>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<input type="hidden" name="username" id="adminInputVMID"/>
|
||||
<span class="input-group-text bg-dark text-light">Password</span>
|
||||
<input id="adminPassword" type="password" class="form-control bg-dark text-light" placeholder="Password" name="password"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" id="loginButton" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="hcaptchaModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content bg-dark text-light">
|
||||
<div class="modal-body">
|
||||
<div id="captcha-box"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -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'. */
|
||||
|
|
|
|||
86
yarn.lock
86
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"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user