Well, sending messages took longer than it should have

This commit is contained in:
metacryst
2025-11-25 23:38:59 -06:00
parent dc9b106439
commit 9e87364147
25 changed files with 550 additions and 189 deletions

View File

@@ -1,6 +1,7 @@
/*
Sam Russell
Captured Sun
11.25.25.1 - Added minHeight and minWidth to be counted as numerical styles
11.25.25 - Added onChange for check boxes, added setQuery / onQueryChanged for easy filtering
11.24.25 - Fixing onClick because it was reversed, adding event to onHover params
11.23.25 - Added onSubmit() event for form submission, added marginHorizontal() and marginVertical()
@@ -292,6 +293,8 @@ function extendHTMLElementWithStyleSetters() {
case "height":
case "maxWidth":
case "maxHeight":
case "minWidth":
case "minHeight":
case "left":
case "top":

View File

@@ -4,13 +4,11 @@
--tan: #FFDFB4;
--gold: #F2B36F;
--purple: #251D44;
--divider: #bb7c36;
--green: #0857265c;
--red: #BC1C02;
--brown: #812A18;
--darkbrown: #3f0808;
--orange: #FE9201;
--periwinkle: #655BAF;
--accent2: var(--green);
}
@@ -19,7 +17,6 @@
:root {
--main: var(--brown);
--accent: var(--gold);
--dividerColor: var(--gold);
--accent2: var(--gold);
}
}

View File

@@ -1,4 +1,4 @@
import './MessagesPanel.js'
import './ForumPanel.js'
css(`
forum- {
@@ -40,18 +40,18 @@ class Forum extends Shadow {
.marginLeft(0.4, em)
})
.height(100, vh)
.paddingLeft(2, em)
.paddingRight(2, em)
.paddingTop(2, em)
.paddingLeft(1, em)
.paddingRight(1, em)
.gap(0, em)
.marginTop(13, vh)
VStack(() => {
MessagesPanel()
ForumPanel()
input("Message Hyperia", "93%")
input("Message Hyperia", "98%")
.paddingVertical(1, em)
.paddingHorizontal(2, em)
.paddingLeft(2, pct)
.color("var(--accent)")
.background("var(--darkbrown)")
.marginBottom(6, em)
@@ -64,49 +64,15 @@ class Forum extends Shadow {
}
})
})
.gap(1, em)
.gap(0.5, em)
.width(100, pct)
.height(100, vh)
.alignHorizontal("center")
.alignVertical("end")
})
.width(100, "%")
.height(87, vh)
.x(0).y(13, vh)
HStack(() => {
input("Search...", "45vw")
.attr({
"type": "text"
})
.fontSize(1.1, em)
.paddingLeft(1.3, em)
.background("transparent")
.border("0.5px solid #bb7c36")
.outline("none")
.color("var(--accent)")
.borderRadius(10, px)
button("Search")
.marginLeft(2, em)
.borderRadius(10, px)
.background("transparent")
.border("0.5px solid #bb7c36")
.color("var(--accent)")
.fontFamily("Bona Nova")
.onHover(function (hovering) {
if(hovering) {
this.style.background = "var(--green)"
} else {
this.style.background = "transparent"
}
})
})
.x(55, vw).y(4, vh)
.position("absolute")
.transform("translateX(-50%)")
.x(0).y(0, vh)
})
.width(100, pct)
.height(100, pct)

View File

@@ -1,4 +1,6 @@
class MessagesPanel extends Shadow {
import "../../components/LoadingCircle.js"
class ForumPanel extends Shadow {
forums = [
"HY"
]
@@ -7,15 +9,31 @@ class MessagesPanel extends Shadow {
render() {
VStack(() => {
if(this.messages.length > 0) {
let previousDate = null
for(let i=0; i<this.messages.length; i++) {
let message = this.messages[i]
const dateParts = this.parseDate(message.time);
const { date, time } = dateParts;
if (previousDate !== date) {
previousDate = date;
p(date)
.textAlign("center")
.opacity(0.5)
.marginVertical(1, em)
.color("var(--divider)")
}
VStack(() => {
HStack(() => {
p(message.sentBy)
.fontWeight("bold")
.marginBottom(0.3, em)
p(this.formatTime(message.time))
p(util.formatTime(message.time))
.opacity(0.2)
.marginLeft(1, em)
})
@@ -23,38 +41,23 @@ class MessagesPanel extends Shadow {
})
}
} else {
div()
.borderRadius(100, pct)
.width(2, em).height(2, em)
.x(45, pct).y(50, pct)
.center()
.backgroundColor("var(--accent")
.transition("transform 1.75s ease-in-out")
.onAppear(function () {
let growing = true;
setInterval(() => {
if (growing) {
this.style.transform = "scale(1.5)";
} else {
this.style.transform = "scale(0.7)";
}
growing = !growing;
}, 750);
});
LoadingCircle()
}
})
.gap(1, em)
.position("relative")
.overflow("scroll")
.height(95, pct)
.width(93, pct)
.paddingTop(2, em)
.height(100, pct)
.width(96, pct)
.paddingTop(5, em)
.paddingBottom(2, em)
.paddingHorizontal(2, em)
.paddingLeft(4, pct)
.backgroundColor("var(--darkbrown)")
.onAppear(async () => {
console.log("appear")
requestAnimationFrame(() => {
this.scrollTop = this.scrollHeight
});
let res = await Socket.send({app: "FORUM", operation: "GET", msg: {forum: "HY", number: 100}})
if(!res) console.error("failed to get messages")
if(res.msg.length > 0 && this.messages.length === 0) {
@@ -62,24 +65,26 @@ class MessagesPanel extends Shadow {
this.messages = res.msg
this.rerender()
}
window.addEventListener("new-message", (e) => {
window.addEventListener("new-post", (e) => {
this.messages = e.detail
if(e.detail.length !== this.messages || e.detail.last.time !== this.messages.last.time || e.detail.first.time !== this.messages.first.time) {
this.rerender()
}
})
})
.scrollTop = this.scrollHeight
}
formatTime(str) {
// Extract the time part with am/pm
const match = str.match(/-(\d+:\d+):\d+.*(am|pm)/i);
parseDate(str) {
// Format: MM.DD.YYYY-HH:MM:SSxxxxxx(am|pm)
const match = str.match(/^(\d{1,2})\.(\d{1,2})\.(\d{4})-(\d{1,2}):(\d{2}).*(am|pm)$/i);
if (!match) return null;
const [_, hourMin, ampm] = match;
return hourMin + ampm.toLowerCase();
const [, mm, dd, yyyy, hh, min, ampm] = match;
const date = `${mm}/${dd}/${yyyy}`;
const time = `${hh}:${min}${ampm.toLowerCase()}`;
return { date, time };
}
}
register(MessagesPanel)
register(ForumPanel)

View File

@@ -54,7 +54,7 @@ class Jobs extends Shadow {
.fontSize(1.1, em)
.paddingLeft(1.3, em)
.background("transparent")
.border("1px solid var(--accent2)")
.border("0.3px solid var(--accent2)")
.outline("none")
.color("var(--accent)")
.borderRadius(10, px)
@@ -63,7 +63,7 @@ class Jobs extends Shadow {
.marginLeft(2, em)
.borderRadius(10, px)
.background("transparent")
.border("1px solid var(--accent2)")
.border("0.3px solid var(--accent2)")
.color("var(--accent)")
.fontFamily("Bona Nova")
.onHover(function (hovering) {
@@ -81,7 +81,7 @@ class Jobs extends Shadow {
.marginLeft(1, em)
.borderRadius(10, px)
.background("transparent")
.border("1px solid var(--accent2)")
.border("0.3px solid var(--accent2)")
.color("var(--accent)")
.fontFamily("Bona Nova")
.onHover(function (hovering) {

View File

@@ -37,8 +37,8 @@ class JobsGrid extends Shadow {
p(this.boldUntilFirstSpace(this.jobs[i].salary))
})
.padding(1, em)
.border("1px solid var(--accent2)")
.borderRadius(5, "px")
.background("var(--darkbrown)")
}
})
.display("grid")

View File

@@ -12,6 +12,9 @@ class MarketSidebar extends Shadow {
render() {
VStack(() => {
p("Make")
HStack(() => {
input()
.attr({
@@ -40,6 +43,8 @@ class MarketSidebar extends Shadow {
.marginLeft(0.5, em)
})
p("Condition")
HStack(() => {
input()
.attr({

View File

@@ -1,3 +1,6 @@
import "./MessagesSidebar.js"
import "./MessagesPanel.js"
css(`
messages- {
font-family: 'Bona';
@@ -23,62 +26,76 @@ css(`
`)
class Messages extends Shadow {
friends = []
conversations = []
selectedConvoID = null
onConversationSelect(i) {
console.log("convo selected: ", i)
this.selectedConvoID = i
this.$("messagessidebar-").rerender()
this.$("messagespanel-").rerender()
}
getConvoFromID(id) {
for(let i=0; i<this.conversations.length; i++) {
if(this.conversations[i].id === id) {
return this.conversations[i]
}
}
}
render() {
ZStack(() => {
HStack(() => {
VStack(() => {
h3("Friends")
.marginTop(0)
.marginBottom(1, em)
.marginLeft(0.4, em)
if (this.friends.length > 1) {
for(let i = 0; i < this.friends.length; i++) {
p(this.friends[i].name)
}
} else {
p("No Friends!")
}
})
.height(100, vh)
.paddingLeft(2, em)
.paddingRight(2, em)
.paddingTop(2, em)
.gap(0, em)
.borderRight("1px solid var(--accent2)")
MessagesSidebar(this.conversations, this.selectedConvoID, this.onConversationSelect)
VStack(() => {
h3("Conversations")
.marginTop(0)
.marginBottom(1, em)
.marginLeft(0.4, em)
if (this.conversations.length > 1) {
for(let i = 0; i < this.conversations.length; i++) {
p(this.conversations[i].name)
}
if(this.getConvoFromID(this.selectedConvoID)) {
MessagesPanel(this.getConvoFromID(this.selectedConvoID).messages)
} else {
p("No Conversations!")
MessagesPanel()
}
input("Send Message", "93%")
.paddingVertical(1, em)
.paddingHorizontal(2, em)
.color("var(--accent)")
.background("var(--darkbrown)")
.marginBottom(6, em)
.border("none")
.fontSize(1, em)
.onKeyDown((e) => {
if (e.key === "Enter") {
window.Socket.send({app: "MESSAGES", operation: "SEND", msg: { conversation: `CONVERSATION-${this.selectedConvoID}`, text: e.target.value }})
e.target.value = ""
}
})
})
.gap(1, em)
.width(100, pct)
.alignHorizontal("center")
.alignVertical("end")
})
.onAppear(async () => {
let res = await Socket.send({app: "MESSAGES", operation: "GET"})
if(!res) console.error("failed to get messages")
if(res.msg.length > 0 && this.conversations.length === 0) {
this.conversations = res.msg
this.selectedConvoID = this.conversations[0].id
this.rerender()
}
window.addEventListener("new-message", (e) => {
let convoID = e.detail.conversationID
let messages = e.detail.messages
let convo = this.getConvoFromID(convoID)
convo.messages = messages
this.rerender()
})
.height(100, vh)
.paddingLeft(2, em)
.paddingRight(2, em)
.paddingTop(2, em)
.gap(0, em)
.borderRight("1px solid var(--accent2)")
})
.width(100, "%")
.height(87, vh)
.x(0).y(13, vh)
.borderTop("1px solid var(--accent2)")
p("0 Items")
.position("absolute")
.x(50, vw).y(50, vh)
.transform("translate(-50%, -50%)")
HStack(() => {
input("Search messages...", "45vw")
@@ -88,7 +105,7 @@ class Messages extends Shadow {
.fontSize(1.1, em)
.paddingLeft(1.3, em)
.background("transparent")
.border("1px solid var(--accent2)")
.border("0.5px solid var(--divider)")
.outline("none")
.color("var(--accent)")
.borderRadius(10, px)
@@ -97,7 +114,7 @@ class Messages extends Shadow {
.marginLeft(2, em)
.borderRadius(10, px)
.background("transparent")
.border("1px solid var(--accent2)")
.border("0.5px solid var(--divider)")
.color("var(--accent)")
.fontFamily("Bona Nova")
.onHover(function (hovering) {
@@ -115,7 +132,7 @@ class Messages extends Shadow {
.marginLeft(1, em)
.borderRadius(10, px)
.background("transparent")
.border("1px solid var(--accent2)")
.border("0.5px solid var(--divider)")
.color("var(--accent)")
.fontFamily("Bona Nova")
.onHover(function (hovering) {
@@ -139,40 +156,6 @@ class Messages extends Shadow {
.width(100, "%")
.height(100, "%")
}
SidebarName(name) {
let firstLetter = name[0]
HStack(() => {
div(firstLetter)
.display("flex")
.justifyContent("center")
.alignItems("center")
.width(1.5, em)
.height(1.5, em)
.border("1px solid var(--accent2)")
.borderRadius(100, "%")
p(name)
.marginLeft(1, em)
})
.alignItems("center")
.padding(5, px)
.borderRadius(0.5, em)
.cursor("default")
.onHover(function (hovering) {
if(hovering) {
this.style.background = "var(--green)"
} else {
this.style.background = "transparent"
}
})
}
connectedCallback() {
// Optional additional logic
}
}
register(Messages)

View File

@@ -0,0 +1,56 @@
import "../../components/LoadingCircle.js"
class MessagesPanel extends Shadow {
messages
constructor(messages) {
super()
this.messages = messages
}
render() {
VStack(() => {
if(this.messages) {
for(let i=0; i<this.messages.length; i++) {
let message = this.messages[i]
let fromMe = window.profile.email === message.from.email
VStack(() => {
HStack(() => {
p(message.from.firstName + " " + message.from.lastName)
.fontWeight("bold")
.marginBottom(0.3, em)
p(util.formatTime(message.time))
.opacity(0.2)
.marginLeft(1, em)
})
p(message.text)
})
.paddingVertical(0.5, em)
.marginLeft(fromMe ? 70 : 0, pct)
.paddingRight(fromMe ? 10 : 0, pct)
.marginRight(fromMe ? 0 : 70, pct)
.paddingLeft(fromMe ? 5 : 10, pct)
.background(fromMe ? "var(--brown)" : "var(--green)")
}
} else {
LoadingCircle()
}
})
.onAppear(async () => {
requestAnimationFrame(() => {
this.scrollTop = this.scrollHeight
});
})
.gap(1, em)
.position("relative")
.overflow("scroll")
.height(95, pct)
.width(100, pct)
.paddingTop(2, em)
.paddingBottom(2, em)
.backgroundColor("var(--darkbrown)")
}
}
register(MessagesPanel)

View File

@@ -0,0 +1,73 @@
class MessagesSidebar extends Shadow {
conversations = []
selectedConvoID
onSelect
constructor(conversations, selectedConvoID, onSelect) {
super()
this.conversations = conversations
this.selectedConvoID = selectedConvoID
this.onSelect = onSelect
}
render() {
VStack(() => {
this.conversations.forEach((convo, i) => {
VStack(() => {
HStack(() => {
p(this.makeConvoTitle(convo.between))
.textAlign("left")
.marginLeft(0.5, inches)
.paddingTop(0.2, inches)
.width(100, pct)
.marginTop(0)
.fontSize(1, em)
.fontWeight("bold")
p(util.formatTime(convo.messages.last.time))
.paddingTop(0.2, inches)
.fontSize(0.8, em)
.marginRight(0.1, inches)
.color("var(--divider")
})
.justifyContent("space-between")
.marginBottom(0)
p(convo.messages.last.text)
.fontSize(0.8, em)
.textAlign("left")
.marginLeft(0.5, inches)
.marginBottom(2, em)
.color("var(--divider)")
})
.background(convo.id === this.selectedConvoID ? "var(--darkbrown)" : "")
.onClick(() => {
this.onSelect(i)
})
})
})
.minWidth(15, vw)
.height(100, vh)
.gap(0, em)
}
makeConvoTitle(members) {
let membersString = ""
for(let i=0; i<members.length; i++) {
let member = members[i]
if(member.email === window.profile.email) {
continue;
}
if(members.length > 2) {
membersString += member.firstName
} else {
membersString += member.firstName + " " + member.lastName
}
}
return membersString
}
}
register(MessagesSidebar)

View File

@@ -0,0 +1,25 @@
class LoadingCircle extends Shadow {
render() {
div()
.borderRadius(100, pct)
.width(2, em).height(2, em)
.x(45, pct).y(50, pct)
.center()
.backgroundColor("var(--accent")
.transition("transform 1.75s ease-in-out")
.onAppear(function () {
let growing = true;
setInterval(() => {
if (growing) {
this.style.transform = "scale(1.5)";
} else {
this.style.transform = "scale(0.7)";
}
growing = !growing;
}, 750);
});
}
}
register(LoadingCircle)

View File

@@ -1,5 +1,4 @@
class ProfileMenu extends Shadow {
profile;
render() {
ZStack(() => {
@@ -9,7 +8,7 @@ class ProfileMenu extends Shadow {
p("Email: ")
.fontWeight("bold")
p(this.profile?.email)
p(window.profile?.email)
})
.gap(1, em)
@@ -17,7 +16,7 @@ class ProfileMenu extends Shadow {
p("Name: ")
.fontWeight("bold")
p(this.profile?.name)
p(window.profile?.name)
})
.gap(1, em)
@@ -38,8 +37,8 @@ class ProfileMenu extends Shadow {
.center()
.display("none")
.onAppear(async () => {
if(!this.profile) {
this.profile = await this.fetchProfile()
if(!window.profile) {
window.profile = await this.fetchProfile()
this.rerender()
}
})
@@ -60,7 +59,6 @@ class ProfileMenu extends Shadow {
const profile = await res.json();
console.log(profile);
return profile
} catch (err) {
console.error(err);
}

View File

@@ -1,5 +1,8 @@
import Socket from "./ws/Socket.js"
import "./components/Home.js"
import util from "./util.js"
window.util = util
window.Socket = new Socket()
Home()

9
ui/site/util.js Normal file
View File

@@ -0,0 +1,9 @@
export default class util {
static formatTime(str) {
const match = str.match(/-(\d+:\d+):\d+.*(am|pm)/i);
if (!match) return null;
const [_, hourMin, ampm] = match;
return hourMin + ampm.toLowerCase();
}
}

View File

@@ -38,7 +38,6 @@ export default class Socket {
}
onBroadcast(msg) {
console.log(msg.msg)
window.dispatchEvent(new CustomEvent(msg.event, {
detail: msg.msg
}));