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

155 lines
5.7 KiB
JavaScript

class FilePreview extends Window {
_visible = false
_file = null
_url = null
open(file, url) {
this._file = file
this._url = url
this._visible = true
this.rerender()
}
close() {
this._visible = false
this.rerender()
}
render() {
this.style.position = "fixed"
this.style.inset = "0"
this.style.zIndex = "300"
this.style.pointerEvents = this._visible ? "all" : "none"
if (!this._visible) return
const x = this.getX()
const y = this.getY()
const w = this.getWidth()
const h = this.getHeight()
const type = this._file?.type ?? ""
const isImage = type.startsWith("image/")
const isPDF = type === "application/pdf"
const isOffice = [
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'application/msword',
'application/vnd.ms-excel',
'application/vnd.ms-powerpoint',
'text/plain',
].includes(type)
const displayName = this._file?.original_name ?? this._file?.name ?? "File"
VStack(() => {
const panel = VStack(() => {
// Header
HStack(() => {
HStack(() => {
div().attr({ class: "tl tl-close" }).onClick((done) => { if (done) this.close() })
div().attr({ class: "tl tl-min" })
div().attr({ class: "tl tl-max" })
})
.attr({ class: "traffic-lights" })
.flexShrink(0)
p(displayName)
.margin(0)
.fontSize(0.88, em)
.fontWeight("600")
.color("var(--headertext)")
.overflow("hidden")
.whiteSpace("nowrap")
.textOverflow("ellipsis")
.flex(1)
.textAlign("center")
div().width("52px").flexShrink(0)
})
.paddingHorizontal(1, em)
.paddingVertical(0.75, em)
.alignItems("center")
.gap(1, em)
.background("var(--darkaccent)")
.borderBottom("1px solid var(--divider)")
.width(100, pct)
.boxSizing("border-box")
.flexShrink(0)
// Content
if (isImage) {
img(this._url, "auto", "auto")
.display("block")
.maxWidth(100, pct)
.maxHeight(h - 48, px)
.margin("0 auto")
} else if (isPDF) {
const wrap = div()
.flex(1)
.width(100, pct)
.overflow("hidden")
wrap.innerHTML = `<iframe src="${this._url}" style="width:100%;height:100%;border:none;display:block;"></iframe>`
} else {
const icon = {
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': "📄",
'application/msword': "📄",
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': "📊",
'application/vnd.ms-excel': "📊",
'application/vnd.openxmlformats-officedocument.presentationml.presentation': "📋",
'application/vnd.ms-powerpoint': "📋",
'text/plain': "📄",
}[type] ?? "📎"
VStack(() => {
p(icon).fontSize(3, em).margin(0)
p(displayName)
.margin(0)
.fontSize(0.9, em)
.color("var(--headertext)")
.textAlign("center")
a(this._url, "Download")
.attr({ download: displayName })
.fontSize(0.85, em)
.color("var(--quillred)")
.fontWeight("600")
.fontFamily("Arial")
.textDecoration("none")
.cursor("pointer")
.marginTop(0.25, em)
.onHover(function(hovering) {
this.style.textDecoration = hovering ? "underline" : "none"
})
})
.gap(0.5, em)
.alignItems("center")
.padding(2, em)
}
})
.background("var(--window)")
.backdropFilter("blur(18px)")
.border("0.5px solid var(--window-border)")
.borderRadius(12, px)
.overflow("hidden")
.width(100, pct)
.boxSizing("border-box")
if (isPDF) panel.height(h, px)
else panel.maxHeight(h, px)
panel.onClick((done, e) => { e.stopPropagation() })
})
.position("fixed")
.x(x, px)
.y(y, px)
.width(w, px)
.height(h, px)
.justifyContent(isPDF ? "flex-start" : "center")
.alignItems("center")
.onClick((done) => { if (done) this.close() })
.onEvent("resize", () => this.rerender())
}
}
register(FilePreview)