This commit is contained in:
metacryst
2026-01-04 07:58:23 -06:00
parent b50468eb5a
commit 6a435ac11a
122 changed files with 13995 additions and 19 deletions

View File

@@ -0,0 +1,63 @@
css(`
email-join-form {
display: flex
}
`)
export default class EmailJoinForm extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.querySelector('#submit-button').addEventListener('click', () => this.submitEmail());
}
isValidEmail(email) {
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,16}$/;
return emailRegex.test(email);
}
showError(message) {
$(this).find('#form-message')
.css('color', 'red')
.text(message);
}
showSuccess(message) {
$(this).find('#form-message')
.css('color', 'green')
.text(message);
}
clearError() {
this.querySelector('#form-message').textContent = '';
}
async submitEmail() {
const email = this.querySelector('#email-input').value.trim();
this.clearError();
if (!this.isValidEmail(email)) {
this.showError('Please enter a valid email address.');
return;
}
const res = await fetch('/api/join', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
if (res.ok) {
this.showSuccess('Email sent.');
} else {
const error = await res.text();
this.showError(error)
}
}
}
customElements.define("email-join-form", EmailJoinForm);

1173
ui/_/code/quill.js Normal file

File diff suppressed because one or more lines are too long

111
ui/_/code/shared.css Normal file
View File

@@ -0,0 +1,111 @@
:root {
--main: var(--brown);
--accent: var(--gold);
--tan: #FFDFB4;
--gold: #F2B36F;
--divider: #bb7c36;
--green: #0857265c;
--red: #BC1C02;
--brown: #812A18;
--darkbrown: #3f0808;
--accent2: var(--green);
}
@media (prefers-color-scheme: dark) {
:root {
--main: var(--brown);
--accent: var(--gold);
--accent2: var(--gold);
}
}
@font-face {
font-family: 'Canterbury';
src: url('/_/fonts/Canterbury/Canterbury.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Bona Nova';
src: url('/_/fonts/BonaNova/BonaNova-Regular.woff') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Bona Nova';
src: url('/_/fonts/BonaNova/BonaNova-Bold.woff') format('truetype');
font-weight: bold;
font-style: normal;
}
body {
margin: 0px;
font-family: 'Bona Nova', sans-serif;
font-size: 16px;
background-color: var(--main);
color: var(--accent);
}
@media (max-width: 480px) {
body, html{
overflow-x: hidden;
}
}
#title {
padding: 5px 10px;
font-size: 1.7rem;
position: fixed; top: 4.5vh; left: 6vw;
cursor: pointer; z-index: 1;
}
a {
cursor: default;
text-decoration: none;
text-underline-offset: 5px;
transition: background .02s, color .2s;
user-select: none;
color: var(--accent);
display: inline-block; /* makes background and padding behave */
padding: 0.2em 0.5em; /* adds breathing room */
}
a:hover {
text-decoration: none;
background: var(--green);
color: var(--tan);
}
a:active {
background: var(--red); /* background color works now */
}
button {
background-color: transparent;
color: var(--accent);
padding: 0.5em;
box-shadow: none;
border: 1px solid var(--accent);
border-radius: 0.3em;
}
input {
background-color: transparent;
border: 1px solid var(--accent2);
padding-left: 1em;
padding-top: 0.5em;
padding-bottom: 0.5em;
border-radius: 0.3em;
}
input::placeholder {
color: var(--accent)
}
input:focus {
outline: 1px solid var(--red);
}

View File

@@ -0,0 +1,62 @@
class Connection {
connectionTries = 0
ws;
linkCreated;
wsStatus;
constructor(receiveCB) {
this.init()
this.receiveCB = receiveCB
}
init() {
if(window.location.hostname.includes("local")) {
this.ws = new WebSocket("ws://" + window.location.host)
} else {
this.ws = new WebSocket("wss://" + window.location.hostname + window.location.pathname)
}
this.ws.addEventListener('open', () => {
this.connectionTries = 0
console.log("Websocket connection established.");
this.ws.addEventListener('message', this.receiveCB)
});
this.ws.addEventListener("close", () => {
this.checkOpen();
console.log('Websocket Closed')
})
}
async checkOpen() {
if (this.ws.readyState === WebSocket.OPEN) {
return true
} else {
await this.sleep(this.connectionTries < 20 ? 5000 : 60000)
this.connectionTries++
console.log('Reestablishing connection')
this.init()
}
}
sleep = (time) => {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
send = (msg) => {
console.log("sending")
if (this.ws.readyState === WebSocket.OPEN) {
this.ws.send(msg);
}
else if(this.connectionTries === 0) {
setTimeout(() => {
this.send(msg)
}, 100)
}
else {
console.error('No websocket connection: Cannot send message');
}
}
}
export default Connection

45
ui/_/code/ws/Socket.js Normal file
View File

@@ -0,0 +1,45 @@
import Connection from "./Connection.js";
export default class Socket {
connection;
disabled = true;
requestID = 1;
pending = new Map();
constructor() {
this.connection = new Connection(this.receive);
}
isOpen() {
if(this.connection.checkOpen()) {
return true;
} else {
return false;
}
}
send(msg) {
return new Promise(resolve => {
const id = (++this.requestID).toString();
this.pending.set(id, resolve);
this.connection.send(JSON.stringify({ id, ...msg }));
});
}
receive = (event) => {
const msg = JSON.parse(event.data);
if (msg.id && this.pending.has(msg.id)) {
this.pending.get(msg.id)(msg);
this.pending.delete(msg.id);
return;
} else {
this.onBroadcast(msg)
}
}
onBroadcast(msg) {
window.dispatchEvent(new CustomEvent(msg.event, {
detail: msg.msg
}));
}
}

8
ui/_/code/zod.js Normal file

File diff suppressed because one or more lines are too long