The Trans Directory
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Allow custom sorting of FolderPage and TagPage (#1250)

authored by

Cao Mingjun and committed by
GitHub
ea92ed4f 596e06ab

+110 -99
+4 -2
quartz/components/PageList.tsx
··· 27 27 28 28 type Props = { 29 29 limit?: number 30 + sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number 30 31 } & QuartzComponentProps 31 32 32 - export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit }: Props) => { 33 - let list = allFiles.sort(byDateAndAlphabetical(cfg)) 33 + export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit, sort }: Props) => { 34 + const sorter = sort ?? byDateAndAlphabetical(cfg) 35 + let list = allFiles.sort(sorter) 34 36 if (limit) { 35 37 list = list.slice(0, limit) 36 38 }
+3
quartz/components/pages/FolderContent.tsx
··· 7 7 import { Root } from "hast" 8 8 import { htmlToJsx } from "../../util/jsx" 9 9 import { i18n } from "../../i18n" 10 + import { QuartzPluginData } from "../../plugins/vfile" 10 11 11 12 interface FolderContentOptions { 12 13 /** 13 14 * Whether to display number of folders 14 15 */ 15 16 showFolderCount: boolean 17 + sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number 16 18 } 17 19 18 20 const defaultOptions: FolderContentOptions = { ··· 37 39 const classes = ["popover-hint", ...cssClasses].join(" ") 38 40 const listProps = { 39 41 ...props, 42 + sort: options.sort, 40 43 allFiles: allPagesInFolder, 41 44 } 42 45
+93 -91
quartz/components/pages/TagContent.tsx
··· 7 7 import { htmlToJsx } from "../../util/jsx" 8 8 import { i18n } from "../../i18n" 9 9 10 - const numPages = 10 11 - const TagContent: QuartzComponent = (props: QuartzComponentProps) => { 12 - const { tree, fileData, allFiles, cfg } = props 13 - const slug = fileData.slug 10 + export default ((opts?: { sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number }) => { 11 + const numPages = 10 12 + const TagContent: QuartzComponent = (props: QuartzComponentProps) => { 13 + const { tree, fileData, allFiles, cfg } = props 14 + const slug = fileData.slug 14 15 15 - if (!(slug?.startsWith("tags/") || slug === "tags")) { 16 - throw new Error(`Component "TagContent" tried to render a non-tag page: ${slug}`) 17 - } 16 + if (!(slug?.startsWith("tags/") || slug === "tags")) { 17 + throw new Error(`Component "TagContent" tried to render a non-tag page: ${slug}`) 18 + } 18 19 19 - const tag = simplifySlug(slug.slice("tags/".length) as FullSlug) 20 - const allPagesWithTag = (tag: string) => 21 - allFiles.filter((file) => 22 - (file.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes).includes(tag), 23 - ) 20 + const tag = simplifySlug(slug.slice("tags/".length) as FullSlug) 21 + const allPagesWithTag = (tag: string) => 22 + allFiles.filter((file) => 23 + (file.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes).includes(tag), 24 + ) 24 25 25 - const content = 26 - (tree as Root).children.length === 0 27 - ? fileData.description 28 - : htmlToJsx(fileData.filePath!, tree) 29 - const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] 30 - const classes = ["popover-hint", ...cssClasses].join(" ") 31 - if (tag === "/") { 32 - const tags = [ 33 - ...new Set( 34 - allFiles.flatMap((data) => data.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes), 35 - ), 36 - ].sort((a, b) => a.localeCompare(b)) 37 - const tagItemMap: Map<string, QuartzPluginData[]> = new Map() 38 - for (const tag of tags) { 39 - tagItemMap.set(tag, allPagesWithTag(tag)) 40 - } 41 - return ( 42 - <div class={classes}> 43 - <article> 44 - <p>{content}</p> 45 - </article> 46 - <p>{i18n(cfg.locale).pages.tagContent.totalTags({ count: tags.length })}</p> 47 - <div> 48 - {tags.map((tag) => { 49 - const pages = tagItemMap.get(tag)! 50 - const listProps = { 51 - ...props, 52 - allFiles: pages, 53 - } 26 + const content = 27 + (tree as Root).children.length === 0 28 + ? fileData.description 29 + : htmlToJsx(fileData.filePath!, tree) 30 + const cssClasses: string[] = fileData.frontmatter?.cssclasses ?? [] 31 + const classes = ["popover-hint", ...cssClasses].join(" ") 32 + if (tag === "/") { 33 + const tags = [ 34 + ...new Set( 35 + allFiles.flatMap((data) => data.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes), 36 + ), 37 + ].sort((a, b) => a.localeCompare(b)) 38 + const tagItemMap: Map<string, QuartzPluginData[]> = new Map() 39 + for (const tag of tags) { 40 + tagItemMap.set(tag, allPagesWithTag(tag)) 41 + } 42 + return ( 43 + <div class={classes}> 44 + <article> 45 + <p>{content}</p> 46 + </article> 47 + <p>{i18n(cfg.locale).pages.tagContent.totalTags({ count: tags.length })}</p> 48 + <div> 49 + {tags.map((tag) => { 50 + const pages = tagItemMap.get(tag)! 51 + const listProps = { 52 + ...props, 53 + allFiles: pages, 54 + } 54 55 55 - const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`).at(0) 56 + const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`).at(0) 56 57 57 - const root = contentPage?.htmlAst 58 - const content = 59 - !root || root?.children.length === 0 60 - ? contentPage?.description 61 - : htmlToJsx(contentPage.filePath!, root) 58 + const root = contentPage?.htmlAst 59 + const content = 60 + !root || root?.children.length === 0 61 + ? contentPage?.description 62 + : htmlToJsx(contentPage.filePath!, root) 62 63 63 - return ( 64 - <div> 65 - <h2> 66 - <a class="internal tag-link" href={`../tags/${tag}`}> 67 - {tag} 68 - </a> 69 - </h2> 70 - {content && <p>{content}</p>} 71 - <div class="page-listing"> 72 - <p> 73 - {i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })} 74 - {pages.length > numPages && ( 75 - <> 76 - {" "} 77 - <span> 78 - {i18n(cfg.locale).pages.tagContent.showingFirst({ count: numPages })} 79 - </span> 80 - </> 81 - )} 82 - </p> 83 - <PageList limit={numPages} {...listProps} /> 64 + return ( 65 + <div> 66 + <h2> 67 + <a class="internal tag-link" href={`../tags/${tag}`}> 68 + {tag} 69 + </a> 70 + </h2> 71 + {content && <p>{content}</p>} 72 + <div class="page-listing"> 73 + <p> 74 + {i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })} 75 + {pages.length > numPages && ( 76 + <> 77 + {" "} 78 + <span> 79 + {i18n(cfg.locale).pages.tagContent.showingFirst({ count: numPages })} 80 + </span> 81 + </> 82 + )} 83 + </p> 84 + <PageList limit={numPages} {...listProps} sort={opts?.sort} /> 85 + </div> 84 86 </div> 85 - </div> 86 - ) 87 - })} 87 + ) 88 + })} 89 + </div> 88 90 </div> 89 - </div> 90 - ) 91 - } else { 92 - const pages = allPagesWithTag(tag) 93 - const listProps = { 94 - ...props, 95 - allFiles: pages, 96 - } 91 + ) 92 + } else { 93 + const pages = allPagesWithTag(tag) 94 + const listProps = { 95 + ...props, 96 + allFiles: pages, 97 + } 97 98 98 - return ( 99 - <div class={classes}> 100 - <article>{content}</article> 101 - <div class="page-listing"> 102 - <p>{i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })}</p> 103 - <div> 104 - <PageList {...listProps} /> 99 + return ( 100 + <div class={classes}> 101 + <article>{content}</article> 102 + <div class="page-listing"> 103 + <p>{i18n(cfg.locale).pages.tagContent.itemsUnderTag({ count: pages.length })}</p> 104 + <div> 105 + <PageList {...listProps} /> 106 + </div> 105 107 </div> 106 108 </div> 107 - </div> 108 - ) 109 + ) 110 + } 109 111 } 110 - } 111 112 112 - TagContent.css = style + PageList.css 113 - export default (() => TagContent) satisfies QuartzComponentConstructor 113 + TagContent.css = style + PageList.css 114 + return TagContent 115 + }) satisfies QuartzComponentConstructor
+5 -3
quartz/plugins/emitters/folderPage.tsx
··· 3 3 import HeaderConstructor from "../../components/Header" 4 4 import BodyConstructor from "../../components/Body" 5 5 import { pageResources, renderPage } from "../../components/renderPage" 6 - import { ProcessedContent, defaultProcessedContent } from "../vfile" 6 + import { ProcessedContent, QuartzPluginData, defaultProcessedContent } from "../vfile" 7 7 import { FullPageLayout } from "../../cfg" 8 8 import path from "path" 9 9 import { ··· 21 21 import { i18n } from "../../i18n" 22 22 import DepGraph from "../../depgraph" 23 23 24 - export const FolderPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOpts) => { 24 + export const FolderPage: QuartzEmitterPlugin< 25 + Partial<FullPageLayout> & { sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number } 26 + > = (userOpts) => { 25 27 const opts: FullPageLayout = { 26 28 ...sharedPageComponents, 27 29 ...defaultListPageLayout, 28 - pageBody: FolderContent(), 30 + pageBody: FolderContent({ sort: userOpts?.sort }), 29 31 ...userOpts, 30 32 } 31 33
+5 -3
quartz/plugins/emitters/tagPage.tsx
··· 3 3 import HeaderConstructor from "../../components/Header" 4 4 import BodyConstructor from "../../components/Body" 5 5 import { pageResources, renderPage } from "../../components/renderPage" 6 - import { ProcessedContent, defaultProcessedContent } from "../vfile" 6 + import { ProcessedContent, QuartzPluginData, defaultProcessedContent } from "../vfile" 7 7 import { FullPageLayout } from "../../cfg" 8 8 import { 9 9 FilePath, ··· 18 18 import { i18n } from "../../i18n" 19 19 import DepGraph from "../../depgraph" 20 20 21 - export const TagPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (userOpts) => { 21 + export const TagPage: QuartzEmitterPlugin< 22 + Partial<FullPageLayout> & { sort?: (f1: QuartzPluginData, f2: QuartzPluginData) => number } 23 + > = (userOpts) => { 22 24 const opts: FullPageLayout = { 23 25 ...sharedPageComponents, 24 26 ...defaultListPageLayout, 25 - pageBody: TagContent(), 27 + pageBody: TagContent({ sort: userOpts?.sort }), 26 28 ...userOpts, 27 29 } 28 30