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

166 lines
6.6 KiB
JavaScript

import server from "/people/@server/index.js"
import "./PeopleList.js"
class People extends Shadow {
searchText = ""
filterOnline = false
listEl = null
get people() { return this._people }
set people(val) {
this._people = val
global.currentNetwork.data.members = val
}
constructor() {
super()
this._people = (global.currentNetwork.data.members || []).map(p => ({ ...p, _online: this.isOnline(p) }))
}
isOnline(member) {
return global.socket.connectedUsers.includes(member.email)
}
get filtered() {
let list = this.people
if (this.filterOnline) list = list.filter(p => p._online)
if (this.searchText) {
const q = this.searchText.toLowerCase()
list = list.filter(p =>
[p.first_name, p.last_name, p.email]
.some(v => v?.toLowerCase().includes(q))
)
}
return list
}
get onlineCount() {
return this.people.filter(p => p._online).length
}
render() {
VStack(() => {
// ── Header ────────────────────────────────────────────────
VStack(() => {
HStack(() => {
VStack(() => {
HStack(() => {
p(`${this.people.length} total`)
.margin(0)
.fontSize(0.72, em)
.color("var(--headertext)")
.opacity(0.4)
if (this.onlineCount > 0) {
HStack(() => {
VStack(() => {})
.width(6, px)
.height(6, px)
.borderRadius(50, pct)
.background("#10b981")
.flexShrink(0)
p(`${this.onlineCount} online`)
.margin(0)
.fontSize(0.72, em)
.color("#10b981")
.fontWeight("600")
})
.gap(0.3, em)
.alignItems("center")
}
})
.gap(0.65, em)
.alignItems("center")
.marginTop(0.2, em)
})
.gap(0)
.flex(1)
// Online filter pill
if (this.people.length > 0) {
HStack(() => {
VStack(() => {})
.width(7, px)
.height(7, px)
.borderRadius(50, pct)
.background(this.filterOnline ? "#10b981" : "var(--headertext)")
.opacity(this.filterOnline ? 1 : 0.3)
.flexShrink(0)
p("Online")
.margin(0)
.fontSize(0.75, em)
.fontWeight(this.filterOnline ? "600" : "400")
.color("var(--headertext)")
.opacity(this.filterOnline ? 1 : 0.45)
})
.gap(0.35, em)
.alignItems("center")
.paddingHorizontal(0.75, em)
.paddingVertical(0.35, em)
.background(this.filterOnline ? "rgba(16,185,129,0.12)" : "var(--darkaccent)")
.border(`1px solid ${this.filterOnline ? "rgba(16,185,129,0.4)" : "var(--divider)"}`)
.borderRadius(100, px)
.cursor("pointer")
.onTap(() => { this.filterOnline = !this.filterOnline; this.rerender() })
}
})
.alignItems("flex-start")
.marginBottom(0.75, em)
// Search bar
HStack(() => {
p("🔍")
.margin(0)
.fontSize(0.75, em)
.opacity(0.4)
.flexShrink(0)
input("Search members…", "100%")
.border("none")
.background("transparent")
.color("var(--headertext)")
.fontSize(0.88, em)
.outline("none")
.flex(1)
.attr({ value: this.searchText })
.onInput(e => {
this.searchText = e.target.value
this.listEl._members = this.filtered
this.listEl.rerender()
})
})
.gap(0.5, em)
.paddingHorizontal(0.75, em)
.paddingVertical(0.55, em)
.background("var(--darkaccent)")
.border("1px solid var(--divider)")
.borderRadius(0.55, em)
.alignItems("center")
})
.paddingHorizontal(1, em)
.paddingTop(1.25, em)
.paddingBottom(0.85, em)
.flexShrink(0)
// ── Divider ───────────────────────────────────────────────
VStack(() => {}).height(1, px).background("var(--divider)").flexShrink(0)
// ── List ──────────────────────────────────────────────────
this.listEl = PeopleList(this.filtered, global.appRefreshing || this.people.length === 0)
})
.height(100, pct)
.width(100, pct)
.boxSizing("border-box")
.overflow("hidden")
.onAppear(async () => {
const res = await server.getPeople(global.currentNetwork.id)
if (!res.error && res.length > 0 && this.people.length !== res.length) {
this.people = res.map(p => ({ ...p, _online: this.isOnline(p) }))
this.rerender()
}
})
}
}
register(People)