Announcements page
- Updated handlers.js - Repurposed Forum and ForumPanel for Announcements - Adjusted styling - Commented out long drag logs
This commit is contained in:
@@ -41,7 +41,7 @@ class Home extends Shadow {
|
|||||||
.top(20, px)
|
.top(20, px)
|
||||||
.borderLeft("1px solid var(--accent)")
|
.borderLeft("1px solid var(--accent)")
|
||||||
.onTouch((start, e) => {
|
.onTouch((start, e) => {
|
||||||
console.log(e)
|
// console.log(e)
|
||||||
if(this.sidebarOpen) {
|
if(this.sidebarOpen) {
|
||||||
this.sidebarOpenDrag(start, e)
|
this.sidebarOpenDrag(start, e)
|
||||||
} else {
|
} else {
|
||||||
@@ -81,7 +81,7 @@ class Home extends Shadow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sidebarClosedDrag(start, e) {
|
sidebarClosedDrag(start, e) {
|
||||||
console.log(e)
|
// console.log(e)
|
||||||
if(start) {
|
if(start) {
|
||||||
let oneTenth = window.outerWidth / 10
|
let oneTenth = window.outerWidth / 10
|
||||||
let amount = e.targetTouches[0].clientX
|
let amount = e.targetTouches[0].clientX
|
||||||
|
|||||||
@@ -83,6 +83,54 @@ const handlers = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async addAnnouncement(text, networkId, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.announcements.add(text, networkId, userId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async editAnnouncement(newAnnouncement, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.announcements.edit(newAnnouncement, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async deleteAnnouncement(id, userId) {
|
||||||
|
try {
|
||||||
|
return await global.db.announcements.delete(id, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAnnouncement(id) {
|
||||||
|
try {
|
||||||
|
return global.db.announcements.getById(id)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getAnnouncements(networkId) {
|
||||||
|
try {
|
||||||
|
return global.db.announcements.getByNetwork(networkId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getUserAnnouncements(userId) {
|
||||||
|
try {
|
||||||
|
return global.db.announcements.getByCreator(userId)
|
||||||
|
} catch (e) {
|
||||||
|
return { status: e.status, error: e.message }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async editBio(newBio, userId) {
|
async editBio(newBio, userId) {
|
||||||
try {
|
try {
|
||||||
return global.db.members.editBio(newBio, userId)
|
return global.db.members.editBio(newBio, userId)
|
||||||
|
|||||||
@@ -1,20 +1,148 @@
|
|||||||
import "../../components/TopBar.js"
|
import './Panel.js'
|
||||||
|
import server from '../../_/code/bridge/serverFunctions.js'
|
||||||
|
|
||||||
class Announcements extends Shadow {
|
css(`
|
||||||
render() {
|
announcements- {
|
||||||
VStack(() => {
|
font-family: 'Bona';
|
||||||
|
|
||||||
})
|
|
||||||
.boxSizing("border-box")
|
|
||||||
.backgroundColor("var(--main)")
|
|
||||||
.gap(0.5, em)
|
|
||||||
.boxSizing("border-box")
|
|
||||||
.width(100, pct)
|
|
||||||
.height(100, pct)
|
|
||||||
.minHeight(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
announcements- input::placeholder {
|
||||||
|
font-family: 'Bona Nova';
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
input::placeholder {
|
||||||
|
font-family: Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
appearance: none; /* remove default style */
|
||||||
|
-webkit-appearance: none;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
border: 1px solid var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"]:checked {
|
||||||
|
background-color: var(--red);
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
class Announcements extends Shadow {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.announcements = global.currentNetwork.data.announcements.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
console.log(this.announcements)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
ZStack(() => {
|
||||||
|
VStack(() => {
|
||||||
|
|
||||||
|
Panel(this.announcements)
|
||||||
|
|
||||||
|
input("Message", "70%")
|
||||||
|
.paddingVertical(0.75, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.paddingHorizontal(2, em)
|
||||||
|
.color("var(--text)")
|
||||||
|
.background("var(--searchbackground)")
|
||||||
|
.marginBottom(1, em)
|
||||||
|
.border("0.5px solid var(--accent)")
|
||||||
|
.outline("none")
|
||||||
|
.borderRadius(100, px)
|
||||||
|
.fontFamily("Arial")
|
||||||
|
.fontSize(1, em)
|
||||||
|
.onKeyDown(async function(e) {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
const result = await server.addAnnouncement(this.value, global.currentNetwork.id, global.profile.id)
|
||||||
|
if (result.data.status === 200) {
|
||||||
|
window.dispatchEvent(new CustomEvent('new-announcement', {
|
||||||
|
detail: { announcement: result.data.announcement }
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// error
|
||||||
|
}
|
||||||
|
this.value = ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.gap(1, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.width(100, pct)
|
||||||
|
.height(100, pct)
|
||||||
|
.horizontalAlign("center")
|
||||||
|
.verticalAlign("end")
|
||||||
|
.minHeight(0)
|
||||||
|
})
|
||||||
|
.backgroundColor("var(--main)")
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.paddingVertical(1, em)
|
||||||
|
.width(100, pct)
|
||||||
|
.height(100, pct)
|
||||||
|
.flex("1 1 auto")
|
||||||
|
.onEvent("new-announcement", this.onNewAnnouncement)
|
||||||
|
.onEvent("deleted-announcement", this.onDeletedAnnouncement)
|
||||||
|
.onEvent("edited-announcement", this.onEditedAnnouncement)
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.getAnnouncements(global.currentNetwork.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForUpdates(currentAnnouncements, fetchedAnnouncements) {
|
||||||
|
if (currentAnnouncements.length !== fetchedAnnouncements.length) return true;
|
||||||
|
|
||||||
|
const currentMap = new Map(currentAnnouncements.map(ann => [ann.id, ann]));
|
||||||
|
|
||||||
|
for (const fetchedAnn of fetchedAnnouncements) {
|
||||||
|
const currentAnn = currentMap.get(fetchedAnn.id);
|
||||||
|
|
||||||
|
// new event added
|
||||||
|
if (!currentAnn) return true;
|
||||||
|
|
||||||
|
// existing event changed
|
||||||
|
if (currentAnn.updated_at !== fetchedAnn.updated_at) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAnnouncements(networkId) {
|
||||||
|
const fetchedAnnouncements = await server.getAnnouncements(networkId)
|
||||||
|
if (this.checkForUpdates(this.announcements, fetchedAnnouncements.data)) {
|
||||||
|
console.log("found updates")
|
||||||
|
this.announcements = fetchedAnnouncements.data.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
global.currentNetwork.data.announcements = this.announcements
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onNewAnnouncement = (e) => {
|
||||||
|
let newAnnouncement = e.detail.announcement;
|
||||||
|
this.announcements.push(newAnnouncement)
|
||||||
|
this.announcements.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeletedAnnouncement = (e) => {
|
||||||
|
let deletedId = e.detail.id
|
||||||
|
const i = this.announcements.findIndex(ann => ann.id === deletedId)
|
||||||
|
if (i !== -1) this.announcements.splice(i, 1);
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
|
|
||||||
|
onEditedAnnouncement = (e) => {
|
||||||
|
let editedAnnouncement = e.detail
|
||||||
|
const i = this.announcements.findIndex(ann => ann.id === editedPost.id)
|
||||||
|
if (i !== -1) {
|
||||||
|
this.announcements.splice(i, 1)
|
||||||
|
this.announcements.unshift(editedAnnouncement)
|
||||||
|
}
|
||||||
|
this.rerender()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
register(Announcements)
|
register(Announcements)
|
||||||
151
src/apps/Announcements/Panel.js
Normal file
151
src/apps/Announcements/Panel.js
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
import "../../components/LoadingCircle.js"
|
||||||
|
import server from "../../_/code/bridge/serverFunctions.js"
|
||||||
|
|
||||||
|
css(`
|
||||||
|
panel- {
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel-::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel-::-webkit-scrollbar-thumb {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel-::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
class Panel extends Shadow {
|
||||||
|
announcements = []
|
||||||
|
isSending = false
|
||||||
|
|
||||||
|
constructor(announcements) {
|
||||||
|
super()
|
||||||
|
this.announcements = announcements
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
VStack(() => {
|
||||||
|
if(this.announcements.length > 0) {
|
||||||
|
let previousDate = null
|
||||||
|
|
||||||
|
for(let i=0; i<this.announcements.length; i++) {
|
||||||
|
let announcement = this.announcements[i]
|
||||||
|
const isMe = announcement.creator_id === global.profile.id
|
||||||
|
const dateParts = this.parseDate(announcement.created);
|
||||||
|
const { date, time } = dateParts;
|
||||||
|
|
||||||
|
if (previousDate !== date) {
|
||||||
|
previousDate = date;
|
||||||
|
|
||||||
|
p(date)
|
||||||
|
.textAlign("center")
|
||||||
|
.opacity(0.6)
|
||||||
|
.fontWeight("bold")
|
||||||
|
.paddingTop(1, em)
|
||||||
|
.paddingBottom(0.5, em)
|
||||||
|
.color("var(--quillred)")
|
||||||
|
.borderTop(`1px solid var(--${i == 0 ? "transparent" : "divider"})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(() => {
|
||||||
|
HStack(() => {
|
||||||
|
h3(isMe ? "Me" : this.getAuthorName(announcement))
|
||||||
|
.color(isMe ? "var(--quillred)" : "var(--headertext")
|
||||||
|
.opacity(0.75)
|
||||||
|
.margin(0)
|
||||||
|
|
||||||
|
h3(`${date} ${time}`)
|
||||||
|
.opacity(0.5)
|
||||||
|
.color("var(--headertext)")
|
||||||
|
.margin(0)
|
||||||
|
.marginLeft(0.5, em)
|
||||||
|
.fontSize(1, em)
|
||||||
|
|
||||||
|
if (announcement.created !== announcement.updated_at) {
|
||||||
|
p("(edited)")
|
||||||
|
.color("var(--headertext)")
|
||||||
|
.letterSpacing(0.8, "px")
|
||||||
|
.opacity(0.5)
|
||||||
|
.fontWeight("bold")
|
||||||
|
.paddingLeft(0.25, em)
|
||||||
|
.fontSize(0.9, em)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.verticalAlign("center")
|
||||||
|
.marginBottom(0.1, em)
|
||||||
|
|
||||||
|
p(announcement.text)
|
||||||
|
.color("var(--text)")
|
||||||
|
.marginHorizontal(0.2, em)
|
||||||
|
.paddingVertical(0.2, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
})
|
||||||
|
.marginBottom(0.05, em)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LoadingCircle()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.gap(1, em)
|
||||||
|
.fontSize(1.1, em)
|
||||||
|
.boxSizing("border-box")
|
||||||
|
.flex("1 1 auto")
|
||||||
|
.minHeight(0)
|
||||||
|
.overflowY("auto")
|
||||||
|
.width(100, pct)
|
||||||
|
.paddingBottom(2, em)
|
||||||
|
.paddingHorizontal(4, pct)
|
||||||
|
.backgroundColor("var(--main)")
|
||||||
|
.onAppear(async () => {
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
this.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getAuthorName(announcement) {
|
||||||
|
const members = global.currentNetwork.data.members;
|
||||||
|
const creator = members.find(m => m.id === announcement.creator_id);
|
||||||
|
if (creator) {
|
||||||
|
return `${creator.first_name} ${creator.last_name}`
|
||||||
|
} else {
|
||||||
|
return "No name"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseDate(str) {
|
||||||
|
// Format: YYYY-MM-DDTHH:MM:SS.mmmZ
|
||||||
|
const match = str.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):\d{2}\.\d+Z$/);
|
||||||
|
if (!match) return null;
|
||||||
|
|
||||||
|
const [, yyyy, mm, dd, hh, min] = match;
|
||||||
|
|
||||||
|
// Convert 24h to 12h
|
||||||
|
const hour24 = parseInt(hh, 10);
|
||||||
|
const ampm = hour24 >= 12 ? 'pm' : 'am';
|
||||||
|
const hour12 = hour24 % 12 || 12;
|
||||||
|
|
||||||
|
const date = `${mm}/${dd}/${yyyy}`;
|
||||||
|
const time = `${hour12}:${min}${ampm}`;
|
||||||
|
|
||||||
|
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(Panel)
|
||||||
Reference in New Issue
Block a user