| | |
| | | import { CanonicalSlug, canonicalizeServer, resolveRelative } from "../path" |
| | | import { FullSlug, isFolderPath, resolveRelative } from "../util/path" |
| | | import { QuartzPluginData } from "../plugins/vfile" |
| | | import { Date } from "./Date" |
| | | import { QuartzComponentProps } from "./types" |
| | | import { Date, getDate } from "./Date" |
| | | import { QuartzComponent, QuartzComponentProps } from "./types" |
| | | import { GlobalConfiguration } from "../cfg" |
| | | |
| | | function byDateAndAlphabetical(f1: QuartzPluginData, f2: QuartzPluginData): number { |
| | | if (f1.dates && f2.dates) { |
| | | // sort descending by last modified |
| | | return f2.dates.modified.getTime() - f1.dates.modified.getTime() |
| | | } else if (f1.dates && !f2.dates) { |
| | | // prioritize files with dates |
| | | return -1 |
| | | } else if (!f1.dates && f2.dates) { |
| | | return 1 |
| | | export type SortFn = (f1: QuartzPluginData, f2: QuartzPluginData) => number |
| | | |
| | | export function byDateAndAlphabetical(cfg: GlobalConfiguration): SortFn { |
| | | return (f1, f2) => { |
| | | // Sort by date/alphabetical |
| | | if (f1.dates && f2.dates) { |
| | | // sort descending |
| | | return getDate(cfg, f2)!.getTime() - getDate(cfg, f1)!.getTime() |
| | | } else if (f1.dates && !f2.dates) { |
| | | // prioritize files with dates |
| | | return -1 |
| | | } else if (!f1.dates && f2.dates) { |
| | | return 1 |
| | | } |
| | | |
| | | // otherwise, sort lexographically by title |
| | | const f1Title = f1.frontmatter?.title.toLowerCase() ?? "" |
| | | const f2Title = f2.frontmatter?.title.toLowerCase() ?? "" |
| | | return f1Title.localeCompare(f2Title) |
| | | } |
| | | |
| | | // otherwise, sort lexographically by title |
| | | const f1Title = f1.frontmatter?.title.toLowerCase() ?? "" |
| | | const f2Title = f2.frontmatter?.title.toLowerCase() ?? "" |
| | | return f1Title.localeCompare(f2Title) |
| | | } |
| | | |
| | | export function PageList({ fileData, allFiles }: QuartzComponentProps) { |
| | | const slug = canonicalizeServer(fileData.slug!) |
| | | return <ul class="section-ul"> |
| | | {allFiles.sort(byDateAndAlphabetical).map(page => { |
| | | const title = page.frontmatter?.title |
| | | const pageSlug = canonicalizeServer(page.slug!) |
| | | const tags = page.frontmatter?.tags ?? [] |
| | | export function byDateAndAlphabeticalFolderFirst(cfg: GlobalConfiguration): SortFn { |
| | | return (f1, f2) => { |
| | | // Sort folders first |
| | | const f1IsFolder = isFolderPath(f1.slug ?? "") |
| | | const f2IsFolder = isFolderPath(f2.slug ?? "") |
| | | if (f1IsFolder && !f2IsFolder) return -1 |
| | | if (!f1IsFolder && f2IsFolder) return 1 |
| | | |
| | | return <li class="section-li"> |
| | | <div class="section"> |
| | | {page.dates && <p class="meta"> |
| | | <Date date={page.dates.modified} /> |
| | | </p>} |
| | | <div class="desc"> |
| | | <h3><a href={resolveRelative(slug, pageSlug)} class="internal">{title}</a></h3> |
| | | </div> |
| | | <ul class="tags"> |
| | | {tags.map(tag => <li><a class="internal" href={resolveRelative(slug, `tags/${tag}` as CanonicalSlug)}>#{tag}</a></li>)} |
| | | </ul> |
| | | </div> |
| | | </li> |
| | | })} |
| | | </ul> |
| | | // If both are folders or both are files, sort by date/alphabetical |
| | | if (f1.dates && f2.dates) { |
| | | // sort descending |
| | | return getDate(cfg, f2)!.getTime() - getDate(cfg, f1)!.getTime() |
| | | } else if (f1.dates && !f2.dates) { |
| | | // prioritize files with dates |
| | | return -1 |
| | | } else if (!f1.dates && f2.dates) { |
| | | return 1 |
| | | } |
| | | |
| | | // otherwise, sort lexographically by title |
| | | const f1Title = f1.frontmatter?.title.toLowerCase() ?? "" |
| | | const f2Title = f2.frontmatter?.title.toLowerCase() ?? "" |
| | | return f1Title.localeCompare(f2Title) |
| | | } |
| | | } |
| | | |
| | | type Props = { |
| | | limit?: number |
| | | sort?: SortFn |
| | | } & QuartzComponentProps |
| | | |
| | | export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit, sort }: Props) => { |
| | | const sorter = sort ?? byDateAndAlphabeticalFolderFirst(cfg) |
| | | let list = allFiles.sort(sorter) |
| | | if (limit) { |
| | | list = list.slice(0, limit) |
| | | } |
| | | |
| | | return ( |
| | | <ul class="section-ul"> |
| | | {list.map((page) => { |
| | | const title = page.frontmatter?.title |
| | | const tags = page.frontmatter?.tags ?? [] |
| | | |
| | | return ( |
| | | <li class="section-li"> |
| | | <div class="section"> |
| | | <p class="meta"> |
| | | {page.dates && <Date date={getDate(cfg, page)!} locale={cfg.locale} />} |
| | | </p> |
| | | <div class="desc"> |
| | | <h3> |
| | | <a href={resolveRelative(fileData.slug!, page.slug!)} class="internal"> |
| | | {title} |
| | | </a> |
| | | </h3> |
| | | </div> |
| | | <ul class="tags"> |
| | | {tags.map((tag) => ( |
| | | <li> |
| | | <a |
| | | class="internal tag-link" |
| | | href={resolveRelative(fileData.slug!, `tags/${tag}` as FullSlug)} |
| | | > |
| | | {tag} |
| | | </a> |
| | | </li> |
| | | ))} |
| | | </ul> |
| | | </div> |
| | | </li> |
| | | ) |
| | | })} |
| | | </ul> |
| | | ) |
| | | } |
| | | |
| | | PageList.css = ` |
| | | .section h3 { |
| | | margin: 0; |
| | | } |
| | | |
| | | .section > .tags { |
| | | margin: 0; |
| | | } |
| | | ` |