Files
apps/announcements/desktop/announcements.js
metacryst 0d6c7683ff init
2026-04-28 20:05:00 -05:00

179 lines
7.5 KiB
JavaScript

import "./DesktopAnnouncementsFeed.js"
import "./DesktopAnnouncementsViewer.js"
import server from "/@server/server.js"
css(`
announcements- {
font-family: 'Arial';
scrollbar-width: none;
-ms-overflow-style: none;
}
announcements- input::placeholder {
color: var(--headertext);
opacity: 0.35;
}
announcements- textarea::placeholder {
color: var(--headertext);
opacity: 0.3;
}
`)
class Announcements extends Shadow {
announcements = []
selectedId = null
searchText = ""
get canPost() { return global.currentNetwork.permissions.includes("announcements.add") }
get canEdit() { return global.currentNetwork.permissions.includes("announcements.edit") }
get canDelete() { return global.currentNetwork.permissions.includes("announcements.delete") }
get filtered() {
if (!this.searchText) return this.announcements
const q = this.searchText.toLowerCase()
return this.announcements.filter(a => a.text.toLowerCase().includes(q))
}
get selectedAnnouncement() {
return this.announcements.find(a => a.id === this.selectedId) || null
}
render() {
HStack(() => {
// ── Left: feed list ───────────────────────────────────────
VStack(() => {
// Toolbar
HStack(() => {
p("Announcements")
.fontFamily("Laandbrau")
.margin(0).fontSize(1.8, em).fontWeight("700").color("var(--headertext)")
.flex(1)
if (this.canPost) {
button("+ New")
.paddingHorizontal(0.85, em).paddingVertical(0.42, em)
.background("var(--quillred)").border("none")
.borderRadius(0.45, em).color("white")
.fontSize(0.82, em).fontWeight("600").cursor("pointer")
.onClick((done) => {
// Tell the viewer to open compose mode
if(done) {
this.selectedId = null
this._openCompose = true
this.rerender()
}
})
}
})
.paddingHorizontal(1.1, em).paddingTop(1.1, em).paddingBottom(0.35, em)
.alignItems("center").flexShrink(0)
DesktopAnnouncementsFeed(
this.filtered,
this.selectedId,
this.searchText,
(id) => {
this.selectedId = id
this._openCompose = false
this.rerender()
},
(text) => {
this.searchText = text
this.rerender()
}
)
.flex(1).minHeight(0).overflow("hidden")
})
.width(320, px).minWidth(280, px)
.height(100, pct)
.borderRight("1px solid var(--divider)")
.background("var(--main)")
.flexShrink(0).overflow("hidden")
// ── Right: viewer / composer ──────────────────────────────
VStack(() => {
const viewer = DesktopAnnouncementsViewer(
this.selectedAnnouncement,
this.canPost,
this.canEdit,
this.canDelete,
// onNew
(ann) => {
this.announcements.unshift(ann)
if (global.currentNetwork.data?.announcements) {
global.currentNetwork.data.announcements.unshift(ann)
}
this.selectedId = ann.id
this._openCompose = false
this.rerender()
window.dispatchEvent(new CustomEvent("new-announcement", { detail: { announcement: ann } }))
},
// onEdited
(ann) => {
const i = this.announcements.findIndex(a => a.id === ann.id)
if (i !== -1) this.announcements[i] = ann
if (global.currentNetwork.data?.announcements) {
const gi = global.currentNetwork.data.announcements.findIndex(a => a.id === ann.id)
if (gi !== -1) global.currentNetwork.data.announcements[gi] = ann
}
this.selectedId = ann.id
this.rerender()
window.dispatchEvent(new CustomEvent("edited-announcement", { detail: ann }))
},
// onDeleted
(id) => {
this.announcements = this.announcements.filter(a => a.id !== id)
if (global.currentNetwork.data?.announcements) {
global.currentNetwork.data.announcements = global.currentNetwork.data.announcements.filter(a => a.id !== id)
}
this.selectedId = null
this.rerender()
window.dispatchEvent(new CustomEvent("deleted-announcement", { detail: { id } }))
}
)
// If the "New" button was pressed, trigger compose mode immediately
if (this._openCompose && viewer) {
viewer.composing = true
this._openCompose = false
}
})
.flex(1).height(100, pct).background("var(--main)").overflow("hidden")
})
.height(100, pct).width(100, pct).overflow("hidden")
.onAppear(async () => {
const res = await server.getAnnouncements(global.currentNetwork.id)
const data = Array.isArray(res) ? res : (res?.data || [])
if (data.length !== this.announcements.length) {
this.announcements = data.sort((a, b) => new Date(b.created) - new Date(a.created))
if (global.currentNetwork.data) {
global.currentNetwork.data.announcements = this.announcements
}
if (!this.selectedId && this.announcements.length) {
this.selectedId = this.announcements[0].id
}
this.rerender()
}
})
.onEvent("new-announcement", (e) => {
const ann = e.detail.announcement
if (!this.announcements.find(a => a.id === ann.id)) {
this.announcements.unshift(ann)
this.rerender()
}
})
.onEvent("deleted-announcement", (e) => {
const id = e.detail.id
if (this.selectedId === id) this.selectedId = null
this.announcements = this.announcements.filter(a => a.id !== id)
this.rerender()
})
.onEvent("edited-announcement", (e) => {
const ann = e.detail
const i = this.announcements.findIndex(a => a.id === ann.id)
if (i !== -1) { this.announcements[i] = ann; this.rerender() }
})
}
}
register(Announcements)