@e280/quay
Version:
File-browser and outliner UI for the web
95 lines (78 loc) • 3.06 kB
text/typescript
import {MapG} from "@e280/stz"
import {Content, html} from "@benev/slate"
import Quay from "../../../index.js"
import {Group} from "../../group.js"
import {Codex} from "../../aspects/codex/codex.js"
import {MediaFormat, MediaSchema} from "./schema.js"
import {GroupConfig, SearchFn, SortFn} from "../../types.js"
import {CodexItem} from "../../aspects/codex/parts/codex-item.js"
export class MediaGroup extends Group<MediaSchema> implements Group {
static config = (): GroupConfig<MediaSchema> => {
const formatIcons = new MapG<MediaFormat, Content>()
.set("audio", html`<sl-icon name=music-note-beamed></sl-icon>`)
.set("video", html`<sl-icon name=film></sl-icon>`)
.set("image", html`<sl-icon name=image></sl-icon>`)
.set("other", html`<sl-icon name=file-earmark></sl-icon>`)
const filters = new Map<string, SearchFn<MediaSchema>>()
.set("all", () => true)
.set("video", item => item.isKind("folder") || (item.isKind("file") && item.specimen.format === "video"))
.set("audio", item => item.isKind("folder") || (item.isKind("file") && item.specimen.format === "audio"))
const sorts = new Map<string, SortFn<MediaSchema>>()
.set("label", (a, b) => a.specimen.label.localeCompare(b.specimen.label))
.set("format", (a, b) => {
if (a.isKind("file") && b.isKind("file"))
return a.specimen.format.localeCompare(b.specimen.format)
if (a.isKind("file")) return -1
if (b.isKind("file")) return 1
return 0
})
const search: (terms: string[], item: CodexItem<MediaSchema>) => boolean = (terms, item) => {
const query = terms.join(" ").trim().toLowerCase()
if (query === "") return true
if (item.kind === "folder") {
return item.children.some(child => search(terms, child))
}
return item.specimen.label.toLowerCase().includes(query)
}
const codex = Codex.setup<MediaSchema>({
folder: {icon: html`<sl-icon name="folder"></sl-icon>`},
file: {icon: html`<sl-icon name="file"></sl-icon>`},
})
const root = codex.root(
codex.create("folder", {label: "project"})
)
const renderIcon = (item: CodexItem<MediaSchema>, opened: boolean) => {
return item.isKind("file")
? formatIcons.require(item.specimen.format)
: opened ? html`<sl-icon name="folder2-open"></sl-icon>` : item.taxon.icon
}
return {
codex,
root,
sorts,
filters: filters,
defaultFilter: "all",
defaultSort: "label",
search: (terms, item) => {
return terms.some(term => (
item.kind.includes(term) ||
item.id.includes(term) ||
item.specimen.label.includes(term)
)) || search(terms, item)
},
renderIcon,
renderLabel: item => item.specimen.label,
renderPreview: (item: CodexItem<MediaSchema>) => {
return (item.isKind("file") && item.specimen.previewUrl)
? html`<img src=${item.specimen.previewUrl}>`
: renderIcon(item, false)
// // TODO icons
// : html`<sl-icon name=${item.taxon.icon}></sl-icon>`
},
permissions: item => Quay.permissions.all,
}
}
constructor() {
super(MediaGroup.config())
}
}