Forum changes

- Added 2 new svg icons
- Fixed visual styling bugs on Forum page involving overflowing containers
- Added current network name underneath "Forum" title
- Input in Forum.js now sends ws message to server with new post, which is then broadcasted through the ws
- Forum app now displays a list of posts for the current network showing the author, time, text, whether it's been edited, and whether it's yours
- ForumPanel.js .onClick() contains the ws calls for DELETE and PUT
- Fixed bug where Forum would not scroll to top upon a new post/onAppear
- Modified ws GET call in ForumPanel.js to reflect new format
- Added .onEvent() handlers inForumPanel.js for "new-post", "deleted-post", and "edited-post"
- Changed AppMenu People icon
-
This commit is contained in:
2026-02-08 22:44:19 -05:00
parent 3bf23daa7a
commit 770d3bb012
6 changed files with 187 additions and 37 deletions

View File

@@ -45,6 +45,7 @@ class Home extends Shadow {
AppMenu() AppMenu()
}) })
.height(100, pct) .height(100, pct)
.minHeight(0)
.onNavigate(() => { .onNavigate(() => {
console.log("navigate") console.log("navigate")
this.rerender() this.rerender()

24
src/_/icons/people.svg Normal file
View File

@@ -0,0 +1,24 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="100px" height="100px" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg" fill="#000000">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier">
<title>ionicons-v5-j</title>
<path d="M402,168c-2.93,40.67-33.1,72-66,72s-63.12-31.32-66-72c-3-42.31,26.37-72,66-72S405,126.46,402,168Z" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
<path d="M336,304c-65.17,0-127.84,32.37-143.54,95.41-2.08,8.34,3.15,16.59,11.72,16.59H467.83c8.57,0,13.77-8.25,11.72-16.59C463.85,335.36,401.18,304,336,304Z" style="fill:none;stroke:#000000;stroke-miterlimit:10;stroke-width:32px"/>
<path d="M200,185.94C197.66,218.42,173.28,244,147,244S96.3,218.43,94,185.94C91.61,152.15,115.34,128,147,128S202.39,152.77,200,185.94Z" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-width:32px"/>
<path d="M206,306c-18.05-8.27-37.93-11.45-59-11.45-52,0-102.1,25.85-114.65,76.2C30.7,377.41,34.88,384,41.72,384H154" style="fill:none;stroke:#000000;stroke-linecap:round;stroke-miterlimit:10;stroke-width:32px"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
src/_/icons/trash.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path d="M 20.5 4 A 1.50015 1.50015 0 0 0 19.066406 6 L 14.640625 6 C 12.803372 6 11.082924 6.9194511 10.064453 8.4492188 L 7.6972656 12 L 7.5 12 A 1.50015 1.50015 0 1 0 7.5 15 L 8.2636719 15 A 1.50015 1.50015 0 0 0 8.6523438 15.007812 L 11.125 38.085938 C 11.423352 40.868277 13.795836 43 16.59375 43 L 31.404297 43 C 34.202211 43 36.574695 40.868277 36.873047 38.085938 L 39.347656 15.007812 A 1.50015 1.50015 0 0 0 39.728516 15 L 40.5 15 A 1.50015 1.50015 0 1 0 40.5 12 L 40.302734 12 L 37.935547 8.4492188 C 36.916254 6.9202798 35.196001 6 33.359375 6 L 28.933594 6 A 1.50015 1.50015 0 0 0 27.5 4 L 20.5 4 z M 14.640625 9 L 33.359375 9 C 34.196749 9 34.974746 9.4162203 35.439453 10.113281 L 36.697266 12 L 11.302734 12 L 12.560547 10.113281 A 1.50015 1.50015 0 0 0 12.5625 10.111328 C 13.025982 9.4151428 13.801878 9 14.640625 9 z M 11.669922 15 L 36.330078 15 L 33.890625 37.765625 C 33.752977 39.049286 32.694383 40 31.404297 40 L 16.59375 40 C 15.303664 40 14.247023 39.049286 14.109375 37.765625 L 11.669922 15 z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -29,18 +29,24 @@ css(`
`) `)
class Forum extends Shadow { class Forum extends Shadow {
selectedForum = "HY"
render() { render() {
ZStack(() => { ZStack(() => {
VStack(() => { VStack(() => {
h1("Forum")
.color("var(--quillred)")
.textAlign("center")
.marginBottom(0)
h3(global.currentNetwork.name)
.color("var(--quillred)")
.textAlign("center")
.margin(0)
ForumPanel() ForumPanel()
input("Message", "70%") input("Message", "70%")
.paddingVertical(0.75, em) .paddingVertical(0.75, em)
.paddingLeft(2, em) .boxSizing("border-box")
.paddingHorizontal(2, em)
.color("var(--accent)") .color("var(--accent)")
.background("#fff1dd") .background("#fff1dd")
.marginBottom(5.5, em) .marginBottom(5.5, em)
@@ -48,9 +54,17 @@ class Forum extends Shadow {
.borderRadius(100, px) .borderRadius(100, px)
.fontFamily("Arial") .fontFamily("Arial")
.fontSize(1, em) .fontSize(1, em)
.onKeyDown(function (e) { .onKeyDown(async function(e) {
if (e.key === "Enter") { if (e.key === "Enter") {
window.Socket.send({app: "FORUM", operation: "SEND", msg: {forum: "HY", text: this.value }}) let msg = {
forum: global.currentNetwork.abbreviation,
text: this.value
}
await global.Socket.send({
app: "FORUM",
operation: "SEND",
msg: msg
})
this.value = "" this.value = ""
} }
}) })
@@ -61,11 +75,14 @@ class Forum extends Shadow {
.height(100, pct) .height(100, pct)
.horizontalAlign("center") .horizontalAlign("center")
.verticalAlign("end") .verticalAlign("end")
.minHeight(0)
}) })
.backgroundColor("var(--main)") .backgroundColor("var(--main)")
.boxSizing("border-box") .boxSizing("border-box")
.paddingVertical(1, em)
.width(100, pct) .width(100, pct)
.height(100, pct) .minHeight(0)
.flex("1 1 auto")
} }

View File

@@ -1,19 +1,38 @@
import "../../components/LoadingCircle.js" import "../../components/LoadingCircle.js"
css(`
forumpanel- {
scrollbar-width: none;
-ms-overflow-style: none;
}
forumpanel-::-webkit-scrollbar {
display: none;
width: 0px;
height: 0px;
}
forumpanel-::-webkit-scrollbar-thumb {
background: transparent;
}
forumpanel-::-webkit-scrollbar-track {
background: transparent;
}
`)
class ForumPanel extends Shadow { class ForumPanel extends Shadow {
forums = [
"HY"
]
messages = [] messages = []
isSending = false
render() { render() {
VStack(() => { VStack(() => {
if(this.messages.length > 0) { if(this.messages.length > 0) {
let previousDate = null let previousDate = null
for(let i=0; i<this.messages.length; i++) { for(let i=0; i<this.messages.length; i++) {
let message = this.messages[i] let message = this.messages[i]
const isMe = message.authorId === global.profile.id
const dateParts = this.parseDate(message.time); const dateParts = this.parseDate(message.time);
const { date, time } = dateParts; const { date, time } = dateParts;
@@ -22,22 +41,64 @@ class ForumPanel extends Shadow {
p(date) p(date)
.textAlign("center") .textAlign("center")
.opacity(0.5) .opacity(0.6)
.marginVertical(1, em) .fontWeight("bold")
.color("var(--divider)") .paddingTop(1, em)
.paddingBottom(0.5, em)
.color("var(--quillred)")
.borderTop(`1px solid var(--${i == 0 ? "transparent" : "divider"})`)
} }
VStack(() => { VStack(() => {
HStack(() => { HStack(() => {
p(message.sentBy) h3(isMe ? "Me" : message.sentBy)
.fontWeight("bold") .color(isMe ? "var(--quillred)" : "var(--brown")
.marginBottom(0.3, em) .margin(0)
p(util.formatTime(message.time)) h3(`${date} ${time}`)
.opacity(0.2) .opacity(0.5)
.marginLeft(1, em) .color("var(--brown)")
.margin(0)
.marginLeft(0.5, em)
.fontSize(1, em)
if (message.edited) {
p("(edited)")
.color("var(--brown)")
.letterSpacing(0.8, "px")
.opacity(0.8)
.fontWeight("bold")
.paddingLeft(0.25, em)
.fontSize(0.9, em)
}
}) })
.verticalAlign("center")
.marginBottom(0.1, em)
p(message.text) p(message.text)
.color("var(--accent)")
.borderLeft("1.5px solid var(--divider)")
.borderBottomLeftRadius("7.5px")
.paddingLeft(0.5, em)
.marginHorizontal(0.2, em)
.paddingVertical(0.2, em)
.boxSizing("border-box")
})
.marginBottom(0.05, em)
.onClick(async (finished, e) => {
if (finished) {
console.log(message.id)
let msg = {
forum: global.currentNetwork.abbreviation,
id: message.id,
text: "EDITED TEXT TEST!"
}
await global.Socket.send({
app: "FORUM",
operation: "PUT",
msg: msg
})
}
}) })
} }
} else { } else {
@@ -45,31 +106,68 @@ class ForumPanel extends Shadow {
} }
}) })
.gap(1, em) .gap(1, em)
.fontSize(1.1, em)
.boxSizing("border-box")
.position("relative") .position("relative")
.overflow("scroll") .flex("1 1 auto")
.height(100, pct) .minHeight(0)
.width(96, pct) .overflowY("auto")
.paddingTop(5, em) .width(100, pct)
.paddingBottom(2, em) .paddingBottom(2, em)
.paddingLeft(4, pct) .paddingHorizontal(4, pct)
.backgroundColor("var(--main)") .backgroundColor("var(--main)")
.onAppear(async () => { .onAppear(async () => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
this.scrollTop = this.scrollHeight this.scrollTo({ top: 0, behavior: "smooth" });
}); });
let res = await global.Socket.send({app: "FORUM", operation: "GET", msg: {forum: "HY", number: 100}}) if (!this.isSending) {
if(!res) console.error("failed to get messages") this.isSending = true
if(res.msg.length > 0 && this.messages.length === 0) { let res = await global.Socket.send({
this.messages = res.msg app: "FORUM",
this.rerender() operation: "GET",
} msg: {
window.addEventListener("new-post", (e) => { forum: global.currentNetwork.abbreviation,
this.messages = e.detail by: "network",
if(e.detail.length !== this.messages || e.detail.last.time !== this.messages.last.time || e.detail.first.time !== this.messages.first.time) { authorId: -999 // default
}
})
if(!res) console.error("failed to get messages")
if(res.msg.length > 0 && this.messages.length === 0) {
this.messages = res.msg.reverse()
this.rerender() this.rerender()
} }
}) this.isSending = false
}
}) })
.onEvent("new-post", this.onNewPost)
.onEvent("deleted-post", this.onDeletedPost)
.onEvent("edited-post", this.onEditedPost)
}
onNewPost = (e) => {
let newPost = e.detail
if (this.messages && !this.messages.some(post => post.id === newPost.id)) {
this.messages.unshift(newPost)
this.rerender()
}
}
onDeletedPost = (e) => {
let deletedId = e.detail
const i = this.messages.findIndex(post => post.id === deletedId)
if (i !== -1) this.messages.splice(i, 1);
this.rerender()
}
onEditedPost = (e) => {
let editedPost = e.detail
const i = this.messages.findIndex(post => post.id === editedPost.id)
if (i !== -1) {
this.messages.splice(i, 1)
this.messages.unshift(editedPost)
}
this.rerender()
} }
parseDate(str) { parseDate(str) {
@@ -83,6 +181,14 @@ class ForumPanel extends Shadow {
return { date, time }; return { date, time };
} }
formatTime(str) {
const match = str.match(/-(\d+:\d+):\d+.*(am|pm)/i);
if (!match) return null;
const [_, hourMin, ampm] = match;
return hourMin + ampm.toLowerCase();
}
} }
register(ForumPanel) register(ForumPanel)

View File

@@ -38,7 +38,7 @@ class AppMenu extends Shadow {
window.navigateTo("/messages") window.navigateTo("/messages")
} }
}) })
img("/_/icons/jobs.svg", "1.5em", "1.5em") img("/_/icons/people.svg", "1.5em", "1.5em")
.attr({app: "people"}) .attr({app: "people"})
.padding(0.5, em) .padding(0.5, em)
.borderRadius(10, px) .borderRadius(10, px)
@@ -61,6 +61,7 @@ class AppMenu extends Shadow {
.paddingVertical(1, em) .paddingVertical(1, em)
.width(100, vw) .width(100, vw)
.boxSizing("border-box") .boxSizing("border-box")
.flex("0 0 auto")
} }
} }