import { QuartzComponentConstructor, QuartzComponentProps } from "./types" import explorerStyle from "./styles/explorer.scss" // @ts-ignore import script from "./scripts/explorer.inline" import { ExplorerNode, FileNode, Options } from "./ExplorerNode" // Options interface defined in `ExplorerNode` to avoid circular dependency const defaultOptions = { title: "Explorer", folderClickBehavior: "collapse", folderDefaultState: "collapsed", useSavedState: true, // Sort order: folders first, then files. Sort folders and files alphabetically sortFn: (a, b) => { if ((!a.file && !b.file) || (a.file && b.file)) { return a.name.localeCompare(b.name) } if (a.file && !b.file) { return 1 } else { return -1 } }, order: ["filter", "map", "sort"], } satisfies Options export default ((userOpts?: Partial) => { function Explorer({ allFiles, displayClass, fileData }: QuartzComponentProps) { // Parse config const opts: Options = { ...defaultOptions, ...userOpts } // Construct tree from allFiles const fileTree = new FileNode("") allFiles.forEach((file) => fileTree.add(file, 1)) /** * Keys of this object must match corresponding function name of `FileNode`, * while values must be the argument that will be passed to the function. * * e.g. entry for FileNode.sort: `sort: opts.sortFn` (value is sort function from options) */ const functions = { map: opts.mapFn, sort: opts.sortFn, filter: opts.filterFn, } // Execute all functions (sort, filter, map) that were provided (if none were provided, only default "sort" is applied) if (opts.order) { // Order is important, use loop with index instead of order.map() for (let i = 0; i < opts.order.length; i++) { const functionName = opts.order[i] if (functions[functionName]) { // for every entry in order, call matching function in FileNode and pass matching argument // e.g. i = 0; functionName = "filter" // converted to: (if opts.filterFn) => fileTree.filter(opts.filterFn) // @ts-ignore // typescript cant statically check these dynamic references, so manually make sure reference is valid and ignore warning fileTree[functionName].call(fileTree, functions[functionName]) } } } // Get all folders of tree. Initialize with collapsed state const folders = fileTree.getFolderPaths(opts.folderDefaultState === "collapsed") // Stringify to pass json tree as data attribute ([data-tree]) const jsonTree = JSON.stringify(folders) return (
) } Explorer.css = explorerStyle Explorer.afterDOMLoaded = script return Explorer }) satisfies QuartzComponentConstructor