146 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "../types"
 | |
| 
 | |
| import style from "../styles/listPage.scss"
 | |
| import { PageList, SortFn } from "../PageList"
 | |
| import { Root } from "hast"
 | |
| import { htmlToJsx } from "../../util/jsx"
 | |
| import { i18n } from "../../i18n"
 | |
| import { QuartzPluginData } from "../../plugins/vfile"
 | |
| import { ComponentChildren } from "preact"
 | |
| import { concatenateResources } from "../../util/resources"
 | |
| import { FileTrieNode } from "../../util/fileTrie"
 | |
| interface FolderContentOptions {
 | |
|   /**
 | |
|    * Whether to display number of folders
 | |
|    */
 | |
|   showFolderCount: boolean
 | |
|   showSubfolders: boolean
 | |
|   sort?: SortFn
 | |
| }
 | |
| 
 | |
| const defaultOptions: FolderContentOptions = {
 | |
|   showFolderCount: true,
 | |
|   showSubfolders: true,
 | |
| }
 | |
| 
 | |
| export default ((opts?: Partial<FolderContentOptions>) => {
 | |
|   const options: FolderContentOptions = { ...defaultOptions, ...opts }
 | |
|   let trie: FileTrieNode<
 | |
|     QuartzPluginData & {
 | |
|       slug: string
 | |
|       title: string
 | |
|       filePath: string
 | |
|     }
 | |
|   >
 | |
| 
 | |
|   const FolderContent: QuartzComponent = (props: QuartzComponentProps) => {
 | |
|     const { tree, fileData, allFiles, cfg } = props
 | |
| 
 | |
|     if (!trie) {
 | |
|       trie = new FileTrieNode([])
 | |
|       allFiles.forEach((file) => {
 | |
|         if (file.frontmatter) {
 | |
|           trie.add({
 | |
|             ...file,
 | |
|             slug: file.slug!,
 | |
|             title: file.frontmatter.title,
 | |
|             filePath: file.filePath!,
 | |
|           })
 | |
|         }
 | |
|       })
 | |
|     }
 | |
| 
 | |
|     const folder = trie.findNode(fileData.slug!.split("/"))
 | |
|     if (!folder) {
 | |
|       return null
 | |
|     }
 | |
| 
 | |
|     const allPagesInFolder: QuartzPluginData[] =
 | |
|       folder.children
 | |
|         .map((node) => {
 | |
|           // regular file, proceed
 | |
|           if (node.data) {
 | |
|             return node.data
 | |
|           }
 | |
| 
 | |
|           if (node.isFolder && options.showSubfolders) {
 | |
|             // folders that dont have data need synthetic files
 | |
|             const getMostRecentDates = (): QuartzPluginData["dates"] => {
 | |
|               let maybeDates: QuartzPluginData["dates"] | undefined = undefined
 | |
|               for (const child of node.children) {
 | |
|                 if (child.data?.dates) {
 | |
|                   // compare all dates and assign to maybeDates if its more recent or its not set
 | |
|                   if (!maybeDates) {
 | |
|                     maybeDates = child.data.dates
 | |
|                   } else {
 | |
|                     if (child.data.dates.created > maybeDates.created) {
 | |
|                       maybeDates.created = child.data.dates.created
 | |
|                     }
 | |
| 
 | |
|                     if (child.data.dates.modified > maybeDates.modified) {
 | |
|                       maybeDates.modified = child.data.dates.modified
 | |
|                     }
 | |
| 
 | |
|                     if (child.data.dates.published > maybeDates.published) {
 | |
|                       maybeDates.published = child.data.dates.published
 | |
|                     }
 | |
|                   }
 | |
|                 }
 | |
|               }
 | |
|               return (
 | |
|                 maybeDates ?? {
 | |
|                   created: new Date(),
 | |
|                   modified: new Date(),
 | |
|                   published: new Date(),
 | |
|                 }
 | |
|               )
 | |
|             }
 | |
| 
 | |
|             return {
 | |
|               slug: node.slug,
 | |
|               dates: getMostRecentDates(),
 | |
|               frontmatter: {
 | |
|                 title: node.displayName,
 | |
|                 tags: [],
 | |
|               },
 | |
|             }
 | |
|           }
 | |
|         })
 | |
|         .filter((page) => page !== undefined) ?? []
 | |
|     const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? []
 | |
|     const classes = cssClasses.join(" ")
 | |
|     const listProps = {
 | |
|       ...props,
 | |
|       sort: options.sort,
 | |
|       allFiles: allPagesInFolder,
 | |
|     }
 | |
| 
 | |
|     const content = (
 | |
|       (tree as Root).children.length === 0
 | |
|         ? fileData.description
 | |
|         : htmlToJsx(fileData.filePath!, tree)
 | |
|     ) as ComponentChildren
 | |
| 
 | |
|     return (
 | |
|       <div class="popover-hint">
 | |
|         <article class={classes}>{content}</article>
 | |
|         <div class="page-listing">
 | |
|           {options.showFolderCount && (
 | |
|             <p>
 | |
|               {i18n(cfg.locale).pages.folderContent.itemsUnderFolder({
 | |
|                 count: allPagesInFolder.length,
 | |
|               })}
 | |
|             </p>
 | |
|           )}
 | |
|           <div>
 | |
|             <PageList {...listProps} />
 | |
|           </div>
 | |
|         </div>
 | |
|       </div>
 | |
|     )
 | |
|   }
 | |
| 
 | |
|   FolderContent.css = concatenateResources(style, PageList.css)
 | |
|   return FolderContent
 | |
| }) satisfies QuartzComponentConstructor
 |