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

133 lines
4.6 KiB
JavaScript

class PeopleCard extends Shadow {
constructor(person) {
super()
this.person = person
}
render() {
const p_ = this.person
const initials = ((p_.first_name?.[0] ?? "") + (p_.last_name?.[0] ?? "")).toUpperCase()
const roles = Array.isArray(p_.roles) ? p_.roles : []
const isOnline = p_._online
HStack(() => {
// Avatar + online dot
ZStack(() => {
VStack(() => {
if (p_.image_path) {
img(`${config.SERVER}${p_.image_path}`, "2.75em", "2.75em")
.borderRadius(50, pct)
.objectFit("cover")
} else {
p(initials)
.margin(0)
.fontSize(0.78, em)
.fontWeight("700")
.color("white")
}
})
.width(2.75, em)
.height(2.75, em)
.borderRadius(50, pct)
.background(p_.image_path ? "transparent" : this.avatarColor(p_.email || p_.first_name))
.justifyContent("center")
.alignItems("center")
.overflow("hidden")
.flexShrink(0)
// Online indicator
if (isOnline) {
VStack(() => {})
.width(0.68, em)
.height(0.68, em)
.borderRadius(50, pct)
.background("#10b981")
.boxSizing("border-box")
.position("absolute")
.bottom(0).right(0)
}
})
.position("relative")
.width(2.75, em)
.height(2.75, em)
.flexShrink(0)
// Info
VStack(() => {
HStack(() => {
p(`${p_.first_name} ${p_.last_name}`)
.margin(0)
.fontSize(0.92, em)
.fontWeight("600")
.color("var(--headertext)")
.flex(1)
.minWidth(0)
.overflow("hidden")
.whiteSpace("nowrap")
.textOverflow("ellipsis")
if (isOnline) {
p("online")
.margin(0)
.fontSize(0.65, em)
.fontWeight("600")
.color("#10b981")
.flexShrink(0)
}
})
.alignItems("center")
.gap(0.5, em)
HStack(() => {
p(p_.email ?? "")
.margin(0)
.fontSize(0.72, em)
.color("var(--headertext)")
.opacity(0.42)
.overflow("hidden")
.whiteSpace("nowrap")
.textOverflow("ellipsis")
.flex(1)
.minWidth(0)
roles.slice(0, 2).forEach(role => {
p(role)
.margin(0)
.fontSize(0.62, em)
.fontWeight("600")
.color("var(--quillred)")
.background("rgba(159,28,41,0.1)")
.paddingHorizontal(0.45, em)
.paddingVertical(0.12, em)
.borderRadius(100, px)
.whiteSpace("nowrap")
.flexShrink(0)
})
})
.gap(0.35, em)
.alignItems("center")
.marginTop(0.2, em)
})
.flex(1)
.minWidth(0)
.gap(0)
})
.gap(0.75, em)
.paddingHorizontal(1, em)
.paddingVertical(0.85, em)
.alignItems("center")
.width(100, pct)
.boxSizing("border-box")
}
avatarColor(seed) {
const colors = ["#3b82f6", "#9E1C29", "#10b981", "#f59e0b", "#8b5cf6", "#ec4899", "#06b6d4", "#84cc16"]
if (!seed) return colors[0]
let hash = 0
for (let i = 0; i < seed.length; i++) hash = seed.charCodeAt(i) + ((hash << 5) - hash)
return colors[Math.abs(hash) % colors.length]
}
}
register(PeopleCard)