diff --git a/.gitignore b/.gitignore index 657842b..ef88793 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ node_modules/ .pnp.js # Build output -dist/ build/ *.tsbuildinfo diff --git a/dist/PageList-DncPcZ4-.d.ts b/dist/PageList-DncPcZ4-.d.ts new file mode 100644 index 0000000..98cb085 --- /dev/null +++ b/dist/PageList-DncPcZ4-.d.ts @@ -0,0 +1,21 @@ +import { QuartzComponent } from '@quartz-community/types'; + +interface PageData { + slug?: string; + frontmatter?: { + title?: string; + tags?: string[]; + }; + dates?: { + created: Date; + modified: Date; + published: Date; + }; + [key: string]: unknown; +} +type SortFn = (f1: PageData, f2: PageData) => number; +declare function byDateAndAlphabetical(cfg: unknown): SortFn; +declare function byDateAndAlphabeticalFolderFirst(cfg: unknown): SortFn; +declare const PageList: QuartzComponent; + +export { PageList as P, type SortFn as S, byDateAndAlphabeticalFolderFirst as a, byDateAndAlphabetical as b }; diff --git a/dist/components/index.d.ts b/dist/components/index.d.ts new file mode 100644 index 0000000..5d341b4 --- /dev/null +++ b/dist/components/index.d.ts @@ -0,0 +1,12 @@ +import { QuartzComponent } from '@quartz-community/types'; +import { S as SortFn } from '../PageList-DncPcZ4-.js'; +export { P as PageList, b as byDateAndAlphabetical, a as byDateAndAlphabeticalFolderFirst } from '../PageList-DncPcZ4-.js'; + +interface FolderContentOptions { + showFolderCount: boolean; + showSubfolders: boolean; + sort?: SortFn; +} +declare const _default: (opts?: Partial) => QuartzComponent; + +export { _default as FolderContent, SortFn }; diff --git a/dist/components/index.js b/dist/components/index.js new file mode 100644 index 0000000..8fcf2b4 --- /dev/null +++ b/dist/components/index.js @@ -0,0 +1,291 @@ +import { jsx, jsxs } from 'preact/jsx-runtime'; +import { htmlToJsx } from '@quartz-community/utils/jsx'; + +// src/util/path.ts +function joinSegments(...args) { + if (args.length === 0) return ""; + let joined = args.filter((segment) => segment !== "" && segment !== "/").map((segment) => stripSlashes(segment)).join("/"); + const first = args[0]; + const last = args[args.length - 1]; + if (first?.startsWith("/")) joined = "/" + joined; + if (last?.endsWith("/")) joined = joined + "/"; + return joined; +} +function stripSlashes(s, onlyStripPrefix) { + if (s.startsWith("/")) s = s.substring(1); + if (!onlyStripPrefix && s.endsWith("/")) s = s.slice(0, -1); + return s; +} +function simplifySlug(fp) { + const res = stripSlashes(trimSuffix(fp, "index"), true); + return res.length === 0 ? "/" : res; +} +function trimSuffix(s, suffix) { + if (endsWith(s, suffix)) s = s.slice(0, -suffix.length); + return s; +} +function endsWith(s, suffix) { + return s === suffix || s.endsWith("/" + suffix); +} +function pathToRoot(slug) { + let rootPath = slug.split("/").filter((x) => x !== "").slice(0, -1).map((_) => "..").join("/"); + if (rootPath.length === 0) rootPath = "."; + return rootPath; +} +function resolveRelative(current, target) { + return joinSegments(pathToRoot(current), simplifySlug(target)); +} +function isFolderPath(fplike) { + return fplike.endsWith("/") || endsWith(fplike, "index") || endsWith(fplike, "index.md") || endsWith(fplike, "index.html"); +} +function getDate(cfg, data) { + const type = cfg?.defaultDateType ?? "created"; + return data.dates?.[type]; +} +function byDateAndAlphabetical(cfg) { + return (f1, f2) => { + if (f1.dates && f2.dates) { + return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0); + } else if (f1.dates && !f2.dates) { + return -1; + } else if (!f1.dates && f2.dates) { + return 1; + } + const f1Title = f1.frontmatter?.title?.toLowerCase() ?? ""; + const f2Title = f2.frontmatter?.title?.toLowerCase() ?? ""; + return f1Title.localeCompare(f2Title); + }; +} +function byDateAndAlphabeticalFolderFirst(cfg) { + return (f1, f2) => { + const f1IsFolder = isFolderPath(f1.slug ?? ""); + const f2IsFolder = isFolderPath(f2.slug ?? ""); + if (f1IsFolder && !f2IsFolder) return -1; + if (!f1IsFolder && f2IsFolder) return 1; + if (f1.dates && f2.dates) { + return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0); + } else if (f1.dates && !f2.dates) { + return -1; + } else if (!f1.dates && f2.dates) { + return 1; + } + const f1Title = f1.frontmatter?.title?.toLowerCase() ?? ""; + const f2Title = f2.frontmatter?.title?.toLowerCase() ?? ""; + return f1Title.localeCompare(f2Title); + }; +} +function DateDisplay({ date, locale }) { + return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date.toLocaleDateString(locale, { + year: "numeric", + month: "short", + day: "2-digit" + }) }); +} +var PageList = ({ + cfg, + fileData, + allFiles, + limit, + sort +}) => { + const sorter = sort ?? byDateAndAlphabeticalFolderFirst(cfg); + let list = [...allFiles].sort(sorter); + if (limit) { + list = list.slice(0, limit); + } + const fileSlug = fileData?.slug; + return /* @__PURE__ */ jsx("ul", { class: "section-ul", children: list.map((page) => { + const title = page.frontmatter?.title; + const tags = page.frontmatter?.tags ?? []; + return /* @__PURE__ */ jsx("li", { class: "section-li", children: /* @__PURE__ */ jsxs("div", { class: "section", children: [ + /* @__PURE__ */ jsx("p", { class: "meta", children: page.dates && /* @__PURE__ */ jsx( + DateDisplay, + { + date: getDate(cfg, page), + locale: cfg?.locale ?? "en-US" + } + ) }), + /* @__PURE__ */ jsx("div", { class: "desc", children: /* @__PURE__ */ jsx("h3", { children: /* @__PURE__ */ jsx( + "a", + { + href: resolveRelative(fileSlug ?? "", page.slug), + class: "internal", + children: title + } + ) }) }), + /* @__PURE__ */ jsx("ul", { class: "tags", children: tags.map((tag) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx( + "a", + { + class: "internal tag-link", + href: resolveRelative( + fileSlug ?? "", + `tags/${tag}` + ), + children: tag + } + ) })) }) + ] }) }); + }) }); +}; +PageList.css = ` +.section h3 { + margin: 0; +} + +.section > .tags { + margin: 0; +} +`; + +// src/i18n/locales/en-US.ts +var en_US_default = { + pages: { + folderContent: { + folder: "Folder", + itemsUnderFolder: ({ count }) => count === 1 ? "1 item under this folder." : `${count} items under this folder.` + } + }, + components: {} +}; + +// src/i18n/index.ts +var locales = { + "en-US": en_US_default +}; +function i18n(locale) { + return locales[locale] || en_US_default; +} + +// src/components/styles/listPage.scss +var listPage_default = "ul.section-ul {\n list-style: none;\n margin-top: 2em;\n padding-left: 0;\n}\n\nli.section-li {\n margin-bottom: 1em;\n}\nli.section-li > .section {\n display: grid;\n grid-template-columns: fit-content(8em) 3fr 1fr;\n}\n@media all and (max-width: 600px) {\n li.section-li > .section > .tags {\n display: none;\n }\n}\nli.section-li > .section > .desc > h3 > a {\n background-color: transparent;\n}\nli.section-li > .section .meta {\n margin: 0 1em 0 0;\n opacity: 0.6;\n}\n\n.popover .section {\n grid-template-columns: fit-content(8em) 1fr !important;\n}\n.popover .section > .tags {\n display: none;\n}"; +var defaultOptions = { + showFolderCount: true, + showSubfolders: true +}; +function concatenateResources(...resources) { + const result = resources.filter((r) => r !== void 0).flat(); + return result.length === 0 ? void 0 : result; +} +function pagesFromTrie(folder, showSubfolders) { + return folder.children.map((node) => { + const nodeData = node.data; + if (nodeData) return nodeData; + if (node.isFolder && showSubfolders) { + return { + slug: node.slug, + dates: mostRecentDatesFromChildren(node.children), + frontmatter: { title: node.displayName, tags: [] } + }; + } + return void 0; + }).filter((page) => page !== void 0); +} +function pagesFromAllFiles(allFiles, folderSlug, showSubfolders) { + const folderPrefix = folderSlug.endsWith("/index") ? folderSlug.slice(0, -"index".length) : folderSlug.endsWith("/") ? folderSlug : folderSlug + "/"; + const directChildren = []; + const subfolderFiles = /* @__PURE__ */ new Map(); + for (const file of allFiles) { + const fileSlug = file.slug; + if (!fileSlug || !fileSlug.startsWith(folderPrefix)) continue; + const relativePath = fileSlug.slice(folderPrefix.length); + if (!relativePath || relativePath === "index") continue; + const segments = relativePath.split("/"); + if (segments.length === 1) { + directChildren.push(file); + } else if (showSubfolders) { + const subfolderName = segments[0]; + if (!subfolderFiles.has(subfolderName)) { + subfolderFiles.set(subfolderName, []); + } + subfolderFiles.get(subfolderName).push(file); + } + } + for (const [subfolderName, files] of subfolderFiles) { + const indexFile = files.find((f) => f.slug === `${folderPrefix}${subfolderName}/index`); + if (indexFile) continue; + directChildren.push({ + slug: `${folderPrefix}${subfolderName}/index`, + dates: mostRecentDatesFromEntries(files), + frontmatter: { title: subfolderName, tags: [] } + }); + } + return directChildren; +} +function mostRecentDatesFromChildren(children) { + let maybeDates; + for (const child of children) { + const childDates = child.data?.dates; + if (childDates) { + if (!maybeDates) { + maybeDates = { ...childDates }; + } else { + if (childDates.created > maybeDates.created) maybeDates.created = childDates.created; + if (childDates.modified > maybeDates.modified) maybeDates.modified = childDates.modified; + if (childDates.published > maybeDates.published) + maybeDates.published = childDates.published; + } + } + } + return maybeDates ?? { created: /* @__PURE__ */ new Date(), modified: /* @__PURE__ */ new Date(), published: /* @__PURE__ */ new Date() }; +} +function mostRecentDatesFromEntries(entries) { + let maybeDates; + for (const entry of entries) { + if (entry.dates) { + if (!maybeDates) { + maybeDates = { ...entry.dates }; + } else { + if (entry.dates.created > maybeDates.created) maybeDates.created = entry.dates.created; + if (entry.dates.modified > maybeDates.modified) maybeDates.modified = entry.dates.modified; + if (entry.dates.published > maybeDates.published) + maybeDates.published = entry.dates.published; + } + } + } + return maybeDates ?? { created: /* @__PURE__ */ new Date(), modified: /* @__PURE__ */ new Date(), published: /* @__PURE__ */ new Date() }; +} +var FolderContent_default = ((opts) => { + const options = { ...defaultOptions, ...opts }; + const FolderContent = (props) => { + const { tree, fileData, allFiles, cfg } = props; + const ctx = props.ctx; + const slug = fileData?.slug; + if (!slug) return null; + const trie = ctx?.trie; + let allPagesInFolder; + if (trie) { + const folder = trie.findNode(slug.split("/")); + if (!folder) return null; + allPagesInFolder = pagesFromTrie(folder, options.showSubfolders); + } else { + allPagesInFolder = pagesFromAllFiles(allFiles ?? [], slug, options.showSubfolders); + } + const cssClasses = fileData?.frontmatter?.cssclasses ?? []; + const classes = cssClasses.join(" "); + const listProps = { + ...props, + sort: options.sort, + allFiles: allPagesInFolder + }; + const hastRoot = tree; + const content = hastRoot.children.length === 0 ? fileData?.description : htmlToJsx(hastRoot); + const pageListContent = PageList(listProps); + return /* @__PURE__ */ jsxs("div", { class: "popover-hint", children: [ + /* @__PURE__ */ jsx("article", { class: classes, children: content }), + /* @__PURE__ */ jsxs("div", { class: "page-listing", children: [ + options.showFolderCount && /* @__PURE__ */ jsx("p", { children: i18n( + cfg?.locale ?? "en-US" + ).pages.folderContent.itemsUnderFolder({ + count: allPagesInFolder.length + }) }), + /* @__PURE__ */ jsx("div", { children: pageListContent }) + ] }) + ] }); + }; + FolderContent.css = concatenateResources(listPage_default, PageList.css); + return FolderContent; +}); + +export { FolderContent_default as FolderContent, PageList, byDateAndAlphabetical, byDateAndAlphabeticalFolderFirst }; +//# sourceMappingURL=index.js.map +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/components/index.js.map b/dist/components/index.js.map new file mode 100644 index 0000000..c113526 --- /dev/null +++ b/dist/components/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/util/path.ts","../../src/components/PageList.tsx","../../src/i18n/locales/en-US.ts","../../src/i18n/index.ts","../../src/components/styles/listPage.scss","../../src/components/FolderContent.tsx"],"names":["jsxs","jsx"],"mappings":"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","file":"index.js","sourcesContent":["export type FullSlug = string & { __brand: \"FullSlug\" };\nexport type SimpleSlug = string & { __brand: \"SimpleSlug\" };\nexport type RelativeURL = string & { __brand: \"relative\" };\n\nexport function joinSegments(...args: string[]): string {\n if (args.length === 0) return \"\";\n let joined = args\n .filter((segment) => segment !== \"\" && segment !== \"/\")\n .map((segment) => stripSlashes(segment))\n .join(\"/\");\n const first = args[0];\n const last = args[args.length - 1];\n if (first?.startsWith(\"/\")) joined = \"/\" + joined;\n if (last?.endsWith(\"/\")) joined = joined + \"/\";\n return joined;\n}\n\nexport function stripSlashes(s: string, onlyStripPrefix?: boolean): string {\n if (s.startsWith(\"/\")) s = s.substring(1);\n if (!onlyStripPrefix && s.endsWith(\"/\")) s = s.slice(0, -1);\n return s;\n}\n\nexport function simplifySlug(fp: FullSlug): SimpleSlug {\n const res = stripSlashes(trimSuffix(fp, \"index\"), true);\n return (res.length === 0 ? \"/\" : res) as SimpleSlug;\n}\n\nexport function trimSuffix(s: string, suffix: string): string {\n if (endsWith(s, suffix)) s = s.slice(0, -suffix.length);\n return s;\n}\n\nexport function endsWith(s: string, suffix: string): boolean {\n return s === suffix || s.endsWith(\"/\" + suffix);\n}\n\nexport function pathToRoot(slug: FullSlug): RelativeURL {\n let rootPath = slug\n .split(\"/\")\n .filter((x) => x !== \"\")\n .slice(0, -1)\n .map((_) => \"..\")\n .join(\"/\");\n if (rootPath.length === 0) rootPath = \".\";\n return rootPath as RelativeURL;\n}\n\nexport function resolveRelative(current: FullSlug, target: FullSlug | SimpleSlug): RelativeURL {\n return joinSegments(pathToRoot(current), simplifySlug(target as FullSlug)) as RelativeURL;\n}\n\nexport function isFolderPath(fplike: string): boolean {\n return (\n fplike.endsWith(\"/\") ||\n endsWith(fplike, \"index\") ||\n endsWith(fplike, \"index.md\") ||\n endsWith(fplike, \"index.html\")\n );\n}\n","import type { QuartzComponent, QuartzComponentProps } from \"@quartz-community/types\";\nimport { resolveRelative, isFolderPath } from \"../util/path\";\nimport type { FullSlug } from \"../util/path\";\n\ninterface PageData {\n slug?: string;\n frontmatter?: { title?: string; tags?: string[] };\n dates?: {\n created: Date;\n modified: Date;\n published: Date;\n };\n [key: string]: unknown;\n}\n\nexport type SortFn = (f1: PageData, f2: PageData) => number;\n\nfunction getDate(cfg: unknown, data: PageData): Date | undefined {\n const type = (cfg as { defaultDateType?: string } | undefined)?.defaultDateType ?? \"created\";\n return data.dates?.[type as keyof typeof data.dates] as Date | undefined;\n}\n\nexport function byDateAndAlphabetical(cfg: unknown): SortFn {\n return (f1, f2) => {\n if (f1.dates && f2.dates) {\n return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0);\n } else if (f1.dates && !f2.dates) {\n return -1;\n } else if (!f1.dates && f2.dates) {\n return 1;\n }\n const f1Title = f1.frontmatter?.title?.toLowerCase() ?? \"\";\n const f2Title = f2.frontmatter?.title?.toLowerCase() ?? \"\";\n return f1Title.localeCompare(f2Title);\n };\n}\n\nexport function byDateAndAlphabeticalFolderFirst(cfg: unknown): SortFn {\n return (f1, f2) => {\n const f1IsFolder = isFolderPath(f1.slug ?? \"\");\n const f2IsFolder = isFolderPath(f2.slug ?? \"\");\n if (f1IsFolder && !f2IsFolder) return -1;\n if (!f1IsFolder && f2IsFolder) return 1;\n\n if (f1.dates && f2.dates) {\n return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0);\n } else if (f1.dates && !f2.dates) {\n return -1;\n } else if (!f1.dates && f2.dates) {\n return 1;\n }\n const f1Title = f1.frontmatter?.title?.toLowerCase() ?? \"\";\n const f2Title = f2.frontmatter?.title?.toLowerCase() ?? \"\";\n return f1Title.localeCompare(f2Title);\n };\n}\n\ntype DateComponentProps = {\n date: Date;\n locale: string;\n};\n\nfunction DateDisplay({ date, locale }: DateComponentProps) {\n return (\n \n );\n}\n\ntype PageListProps = {\n limit?: number;\n sort?: SortFn;\n} & QuartzComponentProps;\n\nexport const PageList: QuartzComponent = ({\n cfg,\n fileData,\n allFiles,\n limit,\n sort,\n}: PageListProps) => {\n const sorter = sort ?? byDateAndAlphabeticalFolderFirst(cfg);\n let list = [...(allFiles as PageData[])].sort(sorter);\n if (limit) {\n list = list.slice(0, limit);\n }\n\n const fileSlug = (fileData as { slug?: string } | undefined)?.slug as FullSlug | undefined;\n\n return (\n \n );\n};\n\nPageList.css = `\n.section h3 {\n margin: 0;\n}\n\n.section > .tags {\n margin: 0;\n}\n`;\n","export default {\n pages: {\n folderContent: {\n folder: \"Folder\",\n itemsUnderFolder: ({ count }: { count: number }) =>\n count === 1 ? \"1 item under this folder.\" : `${count} items under this folder.`,\n },\n },\n components: {},\n};\n","import enUS from \"./locales/en-US\";\n\nconst locales: Record = {\n \"en-US\": enUS,\n};\n\nexport function i18n(locale: string) {\n return locales[locale] || enUS;\n}\n","ul.section-ul {\n list-style: none;\n margin-top: 2em;\n padding-left: 0;\n}\n\nli.section-li {\n margin-bottom: 1em;\n}\nli.section-li > .section {\n display: grid;\n grid-template-columns: fit-content(8em) 3fr 1fr;\n}\n@media all and (max-width: 600px) {\n li.section-li > .section > .tags {\n display: none;\n }\n}\nli.section-li > .section > .desc > h3 > a {\n background-color: transparent;\n}\nli.section-li > .section .meta {\n margin: 0 1em 0 0;\n opacity: 0.6;\n}\n\n.popover .section {\n grid-template-columns: fit-content(8em) 1fr !important;\n}\n.popover .section > .tags {\n display: none;\n}","import type {\n QuartzComponent,\n QuartzComponentConstructor,\n QuartzComponentProps,\n} from \"@quartz-community/types\";\nimport { PageList } from \"./PageList\";\nimport type { SortFn } from \"./PageList\";\nimport { htmlToJsx } from \"@quartz-community/utils/jsx\";\nimport type { ComponentChildren } from \"preact\";\nimport type { Root } from \"hast\";\nimport { i18n } from \"../i18n\";\nimport style from \"./styles/listPage.scss\";\n\ninterface FolderContentOptions {\n showFolderCount: boolean;\n showSubfolders: boolean;\n sort?: SortFn;\n}\n\nconst defaultOptions: FolderContentOptions = {\n showFolderCount: true,\n showSubfolders: true,\n};\n\ninterface TrieNode {\n isFolder: boolean;\n children: TrieNode[];\n data: unknown;\n slug: string;\n displayName: string;\n findNode(path: string[]): TrieNode | undefined;\n}\n\ntype PageEntry = {\n slug?: string;\n dates?: { created: Date; modified: Date; published: Date };\n frontmatter?: { title?: string; tags?: string[] };\n};\n\nfunction concatenateResources(\n ...resources: (string | string[] | undefined)[]\n): string | string[] | undefined {\n const result = resources.filter((r): r is string | string[] => r !== undefined).flat();\n return result.length === 0 ? undefined : result;\n}\n\nfunction pagesFromTrie(folder: TrieNode, showSubfolders: boolean): PageEntry[] {\n return folder.children\n .map((node) => {\n const nodeData = node.data as PageEntry | null;\n if (nodeData) return nodeData;\n\n if (node.isFolder && showSubfolders) {\n return {\n slug: node.slug,\n dates: mostRecentDatesFromChildren(node.children),\n frontmatter: { title: node.displayName, tags: [] },\n };\n }\n return undefined;\n })\n .filter((page): page is PageEntry => page !== undefined);\n}\n\nfunction pagesFromAllFiles(\n allFiles: unknown[],\n folderSlug: string,\n showSubfolders: boolean,\n): PageEntry[] {\n const folderPrefix = folderSlug.endsWith(\"/index\")\n ? folderSlug.slice(0, -\"index\".length)\n : folderSlug.endsWith(\"/\")\n ? folderSlug\n : folderSlug + \"/\";\n\n const directChildren: PageEntry[] = [];\n const subfolderFiles = new Map();\n\n for (const file of allFiles as PageEntry[]) {\n const fileSlug = file.slug;\n if (!fileSlug || !fileSlug.startsWith(folderPrefix)) continue;\n\n const relativePath = fileSlug.slice(folderPrefix.length);\n if (!relativePath || relativePath === \"index\") continue;\n\n const segments = relativePath.split(\"/\");\n\n if (segments.length === 1) {\n directChildren.push(file);\n } else if (showSubfolders) {\n const subfolderName = segments[0]!;\n if (!subfolderFiles.has(subfolderName)) {\n subfolderFiles.set(subfolderName, []);\n }\n subfolderFiles.get(subfolderName)!.push(file);\n }\n }\n\n for (const [subfolderName, files] of subfolderFiles) {\n const indexFile = files.find((f) => f.slug === `${folderPrefix}${subfolderName}/index`);\n if (indexFile) continue;\n\n directChildren.push({\n slug: `${folderPrefix}${subfolderName}/index`,\n dates: mostRecentDatesFromEntries(files),\n frontmatter: { title: subfolderName, tags: [] },\n });\n }\n\n return directChildren;\n}\n\nfunction mostRecentDatesFromChildren(children: TrieNode[]): PageEntry[\"dates\"] {\n let maybeDates: PageEntry[\"dates\"] | undefined;\n for (const child of children) {\n const childDates = (child.data as { dates?: PageEntry[\"dates\"] } | null)?.dates;\n if (childDates) {\n if (!maybeDates) {\n maybeDates = { ...childDates };\n } else {\n if (childDates.created > maybeDates.created) maybeDates.created = childDates.created;\n if (childDates.modified > maybeDates.modified) maybeDates.modified = childDates.modified;\n if (childDates.published > maybeDates.published)\n maybeDates.published = childDates.published;\n }\n }\n }\n return maybeDates ?? { created: new Date(), modified: new Date(), published: new Date() };\n}\n\nfunction mostRecentDatesFromEntries(entries: PageEntry[]): PageEntry[\"dates\"] {\n let maybeDates: PageEntry[\"dates\"] | undefined;\n for (const entry of entries) {\n if (entry.dates) {\n if (!maybeDates) {\n maybeDates = { ...entry.dates };\n } else {\n if (entry.dates.created > maybeDates.created) maybeDates.created = entry.dates.created;\n if (entry.dates.modified > maybeDates.modified) maybeDates.modified = entry.dates.modified;\n if (entry.dates.published > maybeDates.published)\n maybeDates.published = entry.dates.published;\n }\n }\n }\n return maybeDates ?? { created: new Date(), modified: new Date(), published: new Date() };\n}\n\nexport default ((opts?: Partial) => {\n const options: FolderContentOptions = { ...defaultOptions, ...opts };\n\n const FolderContent: QuartzComponent = (props: QuartzComponentProps) => {\n const { tree, fileData, allFiles, cfg } = props;\n const ctx = props.ctx as { trie?: TrieNode } | undefined;\n const slug = (fileData as { slug?: string } | undefined)?.slug;\n\n if (!slug) return null;\n\n const trie = ctx?.trie;\n let allPagesInFolder: PageEntry[];\n\n if (trie) {\n const folder = trie.findNode(slug.split(\"/\"));\n if (!folder) return null;\n allPagesInFolder = pagesFromTrie(folder, options.showSubfolders);\n } else {\n allPagesInFolder = pagesFromAllFiles(allFiles ?? [], slug, options.showSubfolders);\n }\n\n const cssClasses =\n ((fileData as { frontmatter?: { cssclasses?: string[] } } | undefined)?.frontmatter\n ?.cssclasses as string[] | undefined) ?? [];\n const classes = cssClasses.join(\" \");\n const listProps = {\n ...props,\n sort: options.sort,\n allFiles: allPagesInFolder,\n };\n\n const hastRoot = tree as Root;\n const content =\n hastRoot.children.length === 0\n ? (fileData as { description?: unknown } | undefined)?.description\n : htmlToJsx(hastRoot);\n\n const pageListContent = PageList(listProps) as unknown as ComponentChildren;\n\n return (\n
\n
{content}
\n
\n {options.showFolderCount && (\n

\n {i18n(\n (cfg as { locale?: string } | undefined)?.locale ?? \"en-US\",\n ).pages.folderContent.itemsUnderFolder({\n count: allPagesInFolder.length,\n })}\n

\n )}\n
{pageListContent}
\n
\n
\n );\n };\n\n FolderContent.css = concatenateResources(style, PageList.css);\n return FolderContent;\n}) satisfies QuartzComponentConstructor;\n"]} \ No newline at end of file diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..d857875 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,4 @@ +export { F as FolderPage, a as FolderPageOptions } from './types-DjXd6K7r.js'; +export { FolderContent } from './components/index.js'; +export { PageGenerator, PageMatcher, QuartzComponent, QuartzComponentConstructor, QuartzComponentProps, QuartzPageTypePlugin, QuartzPageTypePluginInstance, VirtualPage } from '@quartz-community/types'; +import './PageList-DncPcZ4-.js'; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..1f0eabd --- /dev/null +++ b/dist/index.js @@ -0,0 +1,333 @@ +import { jsxs, jsx } from 'preact/jsx-runtime'; +import { htmlToJsx } from '@quartz-community/utils/jsx'; +import path from 'path'; + +// src/util/path.ts +function joinSegments(...args) { + if (args.length === 0) return ""; + let joined = args.filter((segment) => segment !== "" && segment !== "/").map((segment) => stripSlashes(segment)).join("/"); + const first = args[0]; + const last = args[args.length - 1]; + if (first?.startsWith("/")) joined = "/" + joined; + if (last?.endsWith("/")) joined = joined + "/"; + return joined; +} +function stripSlashes(s, onlyStripPrefix) { + if (s.startsWith("/")) s = s.substring(1); + if (!onlyStripPrefix && s.endsWith("/")) s = s.slice(0, -1); + return s; +} +function simplifySlug(fp) { + const res = stripSlashes(trimSuffix(fp, "index"), true); + return res.length === 0 ? "/" : res; +} +function trimSuffix(s, suffix) { + if (endsWith(s, suffix)) s = s.slice(0, -suffix.length); + return s; +} +function endsWith(s, suffix) { + return s === suffix || s.endsWith("/" + suffix); +} +function pathToRoot(slug) { + let rootPath = slug.split("/").filter((x) => x !== "").slice(0, -1).map((_) => "..").join("/"); + if (rootPath.length === 0) rootPath = "."; + return rootPath; +} +function resolveRelative(current, target) { + return joinSegments(pathToRoot(current), simplifySlug(target)); +} +function isFolderPath(fplike) { + return fplike.endsWith("/") || endsWith(fplike, "index") || endsWith(fplike, "index.md") || endsWith(fplike, "index.html"); +} +function getDate(cfg, data) { + const type = cfg?.defaultDateType ?? "created"; + return data.dates?.[type]; +} +function byDateAndAlphabeticalFolderFirst(cfg) { + return (f1, f2) => { + const f1IsFolder = isFolderPath(f1.slug ?? ""); + const f2IsFolder = isFolderPath(f2.slug ?? ""); + if (f1IsFolder && !f2IsFolder) return -1; + if (!f1IsFolder && f2IsFolder) return 1; + if (f1.dates && f2.dates) { + return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0); + } else if (f1.dates && !f2.dates) { + return -1; + } else if (!f1.dates && f2.dates) { + return 1; + } + const f1Title = f1.frontmatter?.title?.toLowerCase() ?? ""; + const f2Title = f2.frontmatter?.title?.toLowerCase() ?? ""; + return f1Title.localeCompare(f2Title); + }; +} +function DateDisplay({ date, locale }) { + return /* @__PURE__ */ jsx("time", { dateTime: date.toISOString(), children: date.toLocaleDateString(locale, { + year: "numeric", + month: "short", + day: "2-digit" + }) }); +} +var PageList = ({ + cfg, + fileData, + allFiles, + limit, + sort +}) => { + const sorter = sort ?? byDateAndAlphabeticalFolderFirst(cfg); + let list = [...allFiles].sort(sorter); + if (limit) { + list = list.slice(0, limit); + } + const fileSlug = fileData?.slug; + return /* @__PURE__ */ jsx("ul", { class: "section-ul", children: list.map((page) => { + const title = page.frontmatter?.title; + const tags = page.frontmatter?.tags ?? []; + return /* @__PURE__ */ jsx("li", { class: "section-li", children: /* @__PURE__ */ jsxs("div", { class: "section", children: [ + /* @__PURE__ */ jsx("p", { class: "meta", children: page.dates && /* @__PURE__ */ jsx( + DateDisplay, + { + date: getDate(cfg, page), + locale: cfg?.locale ?? "en-US" + } + ) }), + /* @__PURE__ */ jsx("div", { class: "desc", children: /* @__PURE__ */ jsx("h3", { children: /* @__PURE__ */ jsx( + "a", + { + href: resolveRelative(fileSlug ?? "", page.slug), + class: "internal", + children: title + } + ) }) }), + /* @__PURE__ */ jsx("ul", { class: "tags", children: tags.map((tag) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx( + "a", + { + class: "internal tag-link", + href: resolveRelative( + fileSlug ?? "", + `tags/${tag}` + ), + children: tag + } + ) })) }) + ] }) }); + }) }); +}; +PageList.css = ` +.section h3 { + margin: 0; +} + +.section > .tags { + margin: 0; +} +`; + +// src/i18n/locales/en-US.ts +var en_US_default = { + pages: { + folderContent: { + folder: "Folder", + itemsUnderFolder: ({ count }) => count === 1 ? "1 item under this folder." : `${count} items under this folder.` + } + }, + components: {} +}; + +// src/i18n/index.ts +var locales = { + "en-US": en_US_default +}; +function i18n(locale) { + return locales[locale] || en_US_default; +} + +// src/components/styles/listPage.scss +var listPage_default = "ul.section-ul {\n list-style: none;\n margin-top: 2em;\n padding-left: 0;\n}\n\nli.section-li {\n margin-bottom: 1em;\n}\nli.section-li > .section {\n display: grid;\n grid-template-columns: fit-content(8em) 3fr 1fr;\n}\n@media all and (max-width: 600px) {\n li.section-li > .section > .tags {\n display: none;\n }\n}\nli.section-li > .section > .desc > h3 > a {\n background-color: transparent;\n}\nli.section-li > .section .meta {\n margin: 0 1em 0 0;\n opacity: 0.6;\n}\n\n.popover .section {\n grid-template-columns: fit-content(8em) 1fr !important;\n}\n.popover .section > .tags {\n display: none;\n}"; +var defaultOptions = { + showFolderCount: true, + showSubfolders: true +}; +function concatenateResources(...resources) { + const result = resources.filter((r) => r !== void 0).flat(); + return result.length === 0 ? void 0 : result; +} +function pagesFromTrie(folder, showSubfolders) { + return folder.children.map((node) => { + const nodeData = node.data; + if (nodeData) return nodeData; + if (node.isFolder && showSubfolders) { + return { + slug: node.slug, + dates: mostRecentDatesFromChildren(node.children), + frontmatter: { title: node.displayName, tags: [] } + }; + } + return void 0; + }).filter((page) => page !== void 0); +} +function pagesFromAllFiles(allFiles, folderSlug, showSubfolders) { + const folderPrefix = folderSlug.endsWith("/index") ? folderSlug.slice(0, -"index".length) : folderSlug.endsWith("/") ? folderSlug : folderSlug + "/"; + const directChildren = []; + const subfolderFiles = /* @__PURE__ */ new Map(); + for (const file of allFiles) { + const fileSlug = file.slug; + if (!fileSlug || !fileSlug.startsWith(folderPrefix)) continue; + const relativePath = fileSlug.slice(folderPrefix.length); + if (!relativePath || relativePath === "index") continue; + const segments = relativePath.split("/"); + if (segments.length === 1) { + directChildren.push(file); + } else if (showSubfolders) { + const subfolderName = segments[0]; + if (!subfolderFiles.has(subfolderName)) { + subfolderFiles.set(subfolderName, []); + } + subfolderFiles.get(subfolderName).push(file); + } + } + for (const [subfolderName, files] of subfolderFiles) { + const indexFile = files.find((f) => f.slug === `${folderPrefix}${subfolderName}/index`); + if (indexFile) continue; + directChildren.push({ + slug: `${folderPrefix}${subfolderName}/index`, + dates: mostRecentDatesFromEntries(files), + frontmatter: { title: subfolderName, tags: [] } + }); + } + return directChildren; +} +function mostRecentDatesFromChildren(children) { + let maybeDates; + for (const child of children) { + const childDates = child.data?.dates; + if (childDates) { + if (!maybeDates) { + maybeDates = { ...childDates }; + } else { + if (childDates.created > maybeDates.created) maybeDates.created = childDates.created; + if (childDates.modified > maybeDates.modified) maybeDates.modified = childDates.modified; + if (childDates.published > maybeDates.published) + maybeDates.published = childDates.published; + } + } + } + return maybeDates ?? { created: /* @__PURE__ */ new Date(), modified: /* @__PURE__ */ new Date(), published: /* @__PURE__ */ new Date() }; +} +function mostRecentDatesFromEntries(entries) { + let maybeDates; + for (const entry of entries) { + if (entry.dates) { + if (!maybeDates) { + maybeDates = { ...entry.dates }; + } else { + if (entry.dates.created > maybeDates.created) maybeDates.created = entry.dates.created; + if (entry.dates.modified > maybeDates.modified) maybeDates.modified = entry.dates.modified; + if (entry.dates.published > maybeDates.published) + maybeDates.published = entry.dates.published; + } + } + } + return maybeDates ?? { created: /* @__PURE__ */ new Date(), modified: /* @__PURE__ */ new Date(), published: /* @__PURE__ */ new Date() }; +} +var FolderContent_default = ((opts) => { + const options = { ...defaultOptions, ...opts }; + const FolderContent = (props) => { + const { tree, fileData, allFiles, cfg } = props; + const ctx = props.ctx; + const slug = fileData?.slug; + if (!slug) return null; + const trie = ctx?.trie; + let allPagesInFolder; + if (trie) { + const folder = trie.findNode(slug.split("/")); + if (!folder) return null; + allPagesInFolder = pagesFromTrie(folder, options.showSubfolders); + } else { + allPagesInFolder = pagesFromAllFiles(allFiles ?? [], slug, options.showSubfolders); + } + const cssClasses = fileData?.frontmatter?.cssclasses ?? []; + const classes = cssClasses.join(" "); + const listProps = { + ...props, + sort: options.sort, + allFiles: allPagesInFolder + }; + const hastRoot = tree; + const content = hastRoot.children.length === 0 ? fileData?.description : htmlToJsx(hastRoot); + const pageListContent = PageList(listProps); + return /* @__PURE__ */ jsxs("div", { class: "popover-hint", children: [ + /* @__PURE__ */ jsx("article", { class: classes, children: content }), + /* @__PURE__ */ jsxs("div", { class: "page-listing", children: [ + options.showFolderCount && /* @__PURE__ */ jsx("p", { children: i18n( + cfg?.locale ?? "en-US" + ).pages.folderContent.itemsUnderFolder({ + count: allPagesInFolder.length + }) }), + /* @__PURE__ */ jsx("div", { children: pageListContent }) + ] }) + ] }); + }; + FolderContent.css = concatenateResources(listPage_default, PageList.css); + return FolderContent; +}); +var folderMatcher = ({ slug }) => { + return slug.endsWith("/index"); +}; +function getFolders(slug) { + let folderName = path.dirname(slug ?? ""); + const parentFolderNames = [folderName]; + while (folderName !== ".") { + folderName = path.dirname(folderName ?? ""); + parentFolderNames.push(folderName); + } + return parentFolderNames; +} +var FolderPage = (opts) => { + const body = () => FolderContent_default(opts); + return { + name: "FolderPage", + priority: 10, + match: folderMatcher, + generate({ content, cfg }) { + const allFiles = content.map((c) => c[1].data); + const locale = cfg?.locale ?? "en-US"; + const folders = /* @__PURE__ */ new Set(); + for (const file of allFiles) { + const slug = file?.slug; + if (!slug) continue; + const fileFolders = getFolders(slug).filter((f) => f !== "." && f !== "tags"); + for (const f of fileFolders) { + folders.add(f); + } + } + const foldersWithIndex = /* @__PURE__ */ new Set(); + for (const [, file] of content) { + const slug = file.data?.slug; + if (slug && slug.endsWith("/index")) { + const folder = slug.slice(0, -"/index".length); + foldersWithIndex.add(folder); + } + } + const virtualPages = []; + for (const folder of folders) { + if (foldersWithIndex.has(folder)) continue; + const slug = joinSegments(folder, "index"); + const title = `${i18n(locale).pages.folderContent.folder}: ${folder}`; + virtualPages.push({ + slug, + title, + data: {} + }); + } + return virtualPages; + }, + layout: "folder", + body + }; +}; + +export { FolderContent_default as FolderContent, FolderPage }; +//# sourceMappingURL=index.js.map +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/dist/index.js.map b/dist/index.js.map new file mode 100644 index 0000000..1933b8a --- /dev/null +++ b/dist/index.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/util/path.ts","../src/components/PageList.tsx","../src/i18n/locales/en-US.ts","../src/i18n/index.ts","../src/components/styles/listPage.scss","../src/components/FolderContent.tsx","../src/pageType.ts"],"names":["jsxs","jsx"],"mappings":"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","file":"index.js","sourcesContent":["export type FullSlug = string & { __brand: \"FullSlug\" };\nexport type SimpleSlug = string & { __brand: \"SimpleSlug\" };\nexport type RelativeURL = string & { __brand: \"relative\" };\n\nexport function joinSegments(...args: string[]): string {\n if (args.length === 0) return \"\";\n let joined = args\n .filter((segment) => segment !== \"\" && segment !== \"/\")\n .map((segment) => stripSlashes(segment))\n .join(\"/\");\n const first = args[0];\n const last = args[args.length - 1];\n if (first?.startsWith(\"/\")) joined = \"/\" + joined;\n if (last?.endsWith(\"/\")) joined = joined + \"/\";\n return joined;\n}\n\nexport function stripSlashes(s: string, onlyStripPrefix?: boolean): string {\n if (s.startsWith(\"/\")) s = s.substring(1);\n if (!onlyStripPrefix && s.endsWith(\"/\")) s = s.slice(0, -1);\n return s;\n}\n\nexport function simplifySlug(fp: FullSlug): SimpleSlug {\n const res = stripSlashes(trimSuffix(fp, \"index\"), true);\n return (res.length === 0 ? \"/\" : res) as SimpleSlug;\n}\n\nexport function trimSuffix(s: string, suffix: string): string {\n if (endsWith(s, suffix)) s = s.slice(0, -suffix.length);\n return s;\n}\n\nexport function endsWith(s: string, suffix: string): boolean {\n return s === suffix || s.endsWith(\"/\" + suffix);\n}\n\nexport function pathToRoot(slug: FullSlug): RelativeURL {\n let rootPath = slug\n .split(\"/\")\n .filter((x) => x !== \"\")\n .slice(0, -1)\n .map((_) => \"..\")\n .join(\"/\");\n if (rootPath.length === 0) rootPath = \".\";\n return rootPath as RelativeURL;\n}\n\nexport function resolveRelative(current: FullSlug, target: FullSlug | SimpleSlug): RelativeURL {\n return joinSegments(pathToRoot(current), simplifySlug(target as FullSlug)) as RelativeURL;\n}\n\nexport function isFolderPath(fplike: string): boolean {\n return (\n fplike.endsWith(\"/\") ||\n endsWith(fplike, \"index\") ||\n endsWith(fplike, \"index.md\") ||\n endsWith(fplike, \"index.html\")\n );\n}\n","import type { QuartzComponent, QuartzComponentProps } from \"@quartz-community/types\";\nimport { resolveRelative, isFolderPath } from \"../util/path\";\nimport type { FullSlug } from \"../util/path\";\n\ninterface PageData {\n slug?: string;\n frontmatter?: { title?: string; tags?: string[] };\n dates?: {\n created: Date;\n modified: Date;\n published: Date;\n };\n [key: string]: unknown;\n}\n\nexport type SortFn = (f1: PageData, f2: PageData) => number;\n\nfunction getDate(cfg: unknown, data: PageData): Date | undefined {\n const type = (cfg as { defaultDateType?: string } | undefined)?.defaultDateType ?? \"created\";\n return data.dates?.[type as keyof typeof data.dates] as Date | undefined;\n}\n\nexport function byDateAndAlphabetical(cfg: unknown): SortFn {\n return (f1, f2) => {\n if (f1.dates && f2.dates) {\n return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0);\n } else if (f1.dates && !f2.dates) {\n return -1;\n } else if (!f1.dates && f2.dates) {\n return 1;\n }\n const f1Title = f1.frontmatter?.title?.toLowerCase() ?? \"\";\n const f2Title = f2.frontmatter?.title?.toLowerCase() ?? \"\";\n return f1Title.localeCompare(f2Title);\n };\n}\n\nexport function byDateAndAlphabeticalFolderFirst(cfg: unknown): SortFn {\n return (f1, f2) => {\n const f1IsFolder = isFolderPath(f1.slug ?? \"\");\n const f2IsFolder = isFolderPath(f2.slug ?? \"\");\n if (f1IsFolder && !f2IsFolder) return -1;\n if (!f1IsFolder && f2IsFolder) return 1;\n\n if (f1.dates && f2.dates) {\n return (getDate(cfg, f2)?.getTime() ?? 0) - (getDate(cfg, f1)?.getTime() ?? 0);\n } else if (f1.dates && !f2.dates) {\n return -1;\n } else if (!f1.dates && f2.dates) {\n return 1;\n }\n const f1Title = f1.frontmatter?.title?.toLowerCase() ?? \"\";\n const f2Title = f2.frontmatter?.title?.toLowerCase() ?? \"\";\n return f1Title.localeCompare(f2Title);\n };\n}\n\ntype DateComponentProps = {\n date: Date;\n locale: string;\n};\n\nfunction DateDisplay({ date, locale }: DateComponentProps) {\n return (\n \n );\n}\n\ntype PageListProps = {\n limit?: number;\n sort?: SortFn;\n} & QuartzComponentProps;\n\nexport const PageList: QuartzComponent = ({\n cfg,\n fileData,\n allFiles,\n limit,\n sort,\n}: PageListProps) => {\n const sorter = sort ?? byDateAndAlphabeticalFolderFirst(cfg);\n let list = [...(allFiles as PageData[])].sort(sorter);\n if (limit) {\n list = list.slice(0, limit);\n }\n\n const fileSlug = (fileData as { slug?: string } | undefined)?.slug as FullSlug | undefined;\n\n return (\n
    \n {list.map((page) => {\n const title = page.frontmatter?.title;\n const tags = page.frontmatter?.tags ?? [];\n\n return (\n
  • \n
    \n

    \n {page.dates && (\n \n )}\n

    \n
    \n

    \n \n {title}\n \n

    \n
    \n
      \n {tags.map((tag) => (\n
    • \n \n {tag}\n \n
    • \n ))}\n
    \n
    \n
  • \n );\n })}\n
\n );\n};\n\nPageList.css = `\n.section h3 {\n margin: 0;\n}\n\n.section > .tags {\n margin: 0;\n}\n`;\n","export default {\n pages: {\n folderContent: {\n folder: \"Folder\",\n itemsUnderFolder: ({ count }: { count: number }) =>\n count === 1 ? \"1 item under this folder.\" : `${count} items under this folder.`,\n },\n },\n components: {},\n};\n","import enUS from \"./locales/en-US\";\n\nconst locales: Record = {\n \"en-US\": enUS,\n};\n\nexport function i18n(locale: string) {\n return locales[locale] || enUS;\n}\n","ul.section-ul {\n list-style: none;\n margin-top: 2em;\n padding-left: 0;\n}\n\nli.section-li {\n margin-bottom: 1em;\n}\nli.section-li > .section {\n display: grid;\n grid-template-columns: fit-content(8em) 3fr 1fr;\n}\n@media all and (max-width: 600px) {\n li.section-li > .section > .tags {\n display: none;\n }\n}\nli.section-li > .section > .desc > h3 > a {\n background-color: transparent;\n}\nli.section-li > .section .meta {\n margin: 0 1em 0 0;\n opacity: 0.6;\n}\n\n.popover .section {\n grid-template-columns: fit-content(8em) 1fr !important;\n}\n.popover .section > .tags {\n display: none;\n}","import type {\n QuartzComponent,\n QuartzComponentConstructor,\n QuartzComponentProps,\n} from \"@quartz-community/types\";\nimport { PageList } from \"./PageList\";\nimport type { SortFn } from \"./PageList\";\nimport { htmlToJsx } from \"@quartz-community/utils/jsx\";\nimport type { ComponentChildren } from \"preact\";\nimport type { Root } from \"hast\";\nimport { i18n } from \"../i18n\";\nimport style from \"./styles/listPage.scss\";\n\ninterface FolderContentOptions {\n showFolderCount: boolean;\n showSubfolders: boolean;\n sort?: SortFn;\n}\n\nconst defaultOptions: FolderContentOptions = {\n showFolderCount: true,\n showSubfolders: true,\n};\n\ninterface TrieNode {\n isFolder: boolean;\n children: TrieNode[];\n data: unknown;\n slug: string;\n displayName: string;\n findNode(path: string[]): TrieNode | undefined;\n}\n\ntype PageEntry = {\n slug?: string;\n dates?: { created: Date; modified: Date; published: Date };\n frontmatter?: { title?: string; tags?: string[] };\n};\n\nfunction concatenateResources(\n ...resources: (string | string[] | undefined)[]\n): string | string[] | undefined {\n const result = resources.filter((r): r is string | string[] => r !== undefined).flat();\n return result.length === 0 ? undefined : result;\n}\n\nfunction pagesFromTrie(folder: TrieNode, showSubfolders: boolean): PageEntry[] {\n return folder.children\n .map((node) => {\n const nodeData = node.data as PageEntry | null;\n if (nodeData) return nodeData;\n\n if (node.isFolder && showSubfolders) {\n return {\n slug: node.slug,\n dates: mostRecentDatesFromChildren(node.children),\n frontmatter: { title: node.displayName, tags: [] },\n };\n }\n return undefined;\n })\n .filter((page): page is PageEntry => page !== undefined);\n}\n\nfunction pagesFromAllFiles(\n allFiles: unknown[],\n folderSlug: string,\n showSubfolders: boolean,\n): PageEntry[] {\n const folderPrefix = folderSlug.endsWith(\"/index\")\n ? folderSlug.slice(0, -\"index\".length)\n : folderSlug.endsWith(\"/\")\n ? folderSlug\n : folderSlug + \"/\";\n\n const directChildren: PageEntry[] = [];\n const subfolderFiles = new Map();\n\n for (const file of allFiles as PageEntry[]) {\n const fileSlug = file.slug;\n if (!fileSlug || !fileSlug.startsWith(folderPrefix)) continue;\n\n const relativePath = fileSlug.slice(folderPrefix.length);\n if (!relativePath || relativePath === \"index\") continue;\n\n const segments = relativePath.split(\"/\");\n\n if (segments.length === 1) {\n directChildren.push(file);\n } else if (showSubfolders) {\n const subfolderName = segments[0]!;\n if (!subfolderFiles.has(subfolderName)) {\n subfolderFiles.set(subfolderName, []);\n }\n subfolderFiles.get(subfolderName)!.push(file);\n }\n }\n\n for (const [subfolderName, files] of subfolderFiles) {\n const indexFile = files.find((f) => f.slug === `${folderPrefix}${subfolderName}/index`);\n if (indexFile) continue;\n\n directChildren.push({\n slug: `${folderPrefix}${subfolderName}/index`,\n dates: mostRecentDatesFromEntries(files),\n frontmatter: { title: subfolderName, tags: [] },\n });\n }\n\n return directChildren;\n}\n\nfunction mostRecentDatesFromChildren(children: TrieNode[]): PageEntry[\"dates\"] {\n let maybeDates: PageEntry[\"dates\"] | undefined;\n for (const child of children) {\n const childDates = (child.data as { dates?: PageEntry[\"dates\"] } | null)?.dates;\n if (childDates) {\n if (!maybeDates) {\n maybeDates = { ...childDates };\n } else {\n if (childDates.created > maybeDates.created) maybeDates.created = childDates.created;\n if (childDates.modified > maybeDates.modified) maybeDates.modified = childDates.modified;\n if (childDates.published > maybeDates.published)\n maybeDates.published = childDates.published;\n }\n }\n }\n return maybeDates ?? { created: new Date(), modified: new Date(), published: new Date() };\n}\n\nfunction mostRecentDatesFromEntries(entries: PageEntry[]): PageEntry[\"dates\"] {\n let maybeDates: PageEntry[\"dates\"] | undefined;\n for (const entry of entries) {\n if (entry.dates) {\n if (!maybeDates) {\n maybeDates = { ...entry.dates };\n } else {\n if (entry.dates.created > maybeDates.created) maybeDates.created = entry.dates.created;\n if (entry.dates.modified > maybeDates.modified) maybeDates.modified = entry.dates.modified;\n if (entry.dates.published > maybeDates.published)\n maybeDates.published = entry.dates.published;\n }\n }\n }\n return maybeDates ?? { created: new Date(), modified: new Date(), published: new Date() };\n}\n\nexport default ((opts?: Partial) => {\n const options: FolderContentOptions = { ...defaultOptions, ...opts };\n\n const FolderContent: QuartzComponent = (props: QuartzComponentProps) => {\n const { tree, fileData, allFiles, cfg } = props;\n const ctx = props.ctx as { trie?: TrieNode } | undefined;\n const slug = (fileData as { slug?: string } | undefined)?.slug;\n\n if (!slug) return null;\n\n const trie = ctx?.trie;\n let allPagesInFolder: PageEntry[];\n\n if (trie) {\n const folder = trie.findNode(slug.split(\"/\"));\n if (!folder) return null;\n allPagesInFolder = pagesFromTrie(folder, options.showSubfolders);\n } else {\n allPagesInFolder = pagesFromAllFiles(allFiles ?? [], slug, options.showSubfolders);\n }\n\n const cssClasses =\n ((fileData as { frontmatter?: { cssclasses?: string[] } } | undefined)?.frontmatter\n ?.cssclasses as string[] | undefined) ?? [];\n const classes = cssClasses.join(\" \");\n const listProps = {\n ...props,\n sort: options.sort,\n allFiles: allPagesInFolder,\n };\n\n const hastRoot = tree as Root;\n const content =\n hastRoot.children.length === 0\n ? (fileData as { description?: unknown } | undefined)?.description\n : htmlToJsx(hastRoot);\n\n const pageListContent = PageList(listProps) as unknown as ComponentChildren;\n\n return (\n
\n
{content}
\n
\n {options.showFolderCount && (\n

\n {i18n(\n (cfg as { locale?: string } | undefined)?.locale ?? \"en-US\",\n ).pages.folderContent.itemsUnderFolder({\n count: allPagesInFolder.length,\n })}\n

\n )}\n
{pageListContent}
\n
\n
\n );\n };\n\n FolderContent.css = concatenateResources(style, PageList.css);\n return FolderContent;\n}) satisfies QuartzComponentConstructor;\n","import type {\n QuartzPageTypePlugin,\n QuartzComponentConstructor,\n PageMatcher,\n FullSlug,\n VirtualPage,\n} from \"@quartz-community/types\";\nimport FolderContentComponent from \"./components/FolderContent\";\nimport { i18n } from \"./i18n\";\nimport { joinSegments } from \"./util/path\";\nimport type { SortFn } from \"./components/PageList\";\nimport path from \"path\";\n\nexport interface FolderPageOptions {\n showFolderCount?: boolean;\n showSubfolders?: boolean;\n sort?: SortFn;\n}\n\nconst folderMatcher: PageMatcher = ({ slug }) => {\n return slug.endsWith(\"/index\");\n};\n\nfunction getFolders(slug: string): string[] {\n let folderName = path.dirname(slug ?? \"\");\n const parentFolderNames = [folderName];\n while (folderName !== \".\") {\n folderName = path.dirname(folderName ?? \"\");\n parentFolderNames.push(folderName);\n }\n return parentFolderNames;\n}\n\nexport const FolderPage: QuartzPageTypePlugin = (opts) => {\n const body: QuartzComponentConstructor = () => FolderContentComponent(opts);\n\n return {\n name: \"FolderPage\",\n priority: 10,\n match: folderMatcher,\n generate({ content, cfg }) {\n const allFiles = content.map((c) => c[1].data);\n const locale = (cfg as { locale?: string } | undefined)?.locale ?? \"en-US\";\n\n const folders = new Set();\n for (const file of allFiles) {\n const slug = (file as { slug?: string } | undefined)?.slug;\n if (!slug) continue;\n const fileFolders = getFolders(slug).filter((f) => f !== \".\" && f !== \"tags\");\n for (const f of fileFolders) {\n folders.add(f);\n }\n }\n\n const foldersWithIndex = new Set();\n for (const [, file] of content) {\n const slug = (file.data as { slug?: string } | undefined)?.slug;\n if (slug && slug.endsWith(\"/index\")) {\n const folder = slug.slice(0, -\"/index\".length);\n foldersWithIndex.add(folder);\n }\n }\n\n const virtualPages: VirtualPage[] = [];\n for (const folder of folders) {\n if (foldersWithIndex.has(folder)) continue;\n\n const slug = joinSegments(folder, \"index\") as unknown as FullSlug;\n const title = `${i18n(locale).pages.folderContent.folder}: ${folder}`;\n\n virtualPages.push({\n slug,\n title,\n data: {},\n });\n }\n\n return virtualPages;\n },\n layout: \"folder\",\n body,\n };\n};\n"]} \ No newline at end of file diff --git a/dist/types-DjXd6K7r.d.ts b/dist/types-DjXd6K7r.d.ts new file mode 100644 index 0000000..5787259 --- /dev/null +++ b/dist/types-DjXd6K7r.d.ts @@ -0,0 +1,11 @@ +import { QuartzPageTypePlugin } from '@quartz-community/types'; +import { S as SortFn } from './PageList-DncPcZ4-.js'; + +interface FolderPageOptions { + showFolderCount?: boolean; + showSubfolders?: boolean; + sort?: SortFn; +} +declare const FolderPage: QuartzPageTypePlugin; + +export { FolderPage as F, type FolderPageOptions as a }; diff --git a/dist/types.d.ts b/dist/types.d.ts new file mode 100644 index 0000000..be33444 --- /dev/null +++ b/dist/types.d.ts @@ -0,0 +1,3 @@ +export { BuildCtx, PageGenerator, PageMatcher, ProcessedContent, QuartzPageTypePlugin, QuartzPageTypePluginInstance, QuartzPluginData, StaticResources, VirtualPage } from '@quartz-community/types'; +export { a as FolderPageOptions } from './types-DjXd6K7r.js'; +export { S as SortFn } from './PageList-DncPcZ4-.js'; diff --git a/dist/types.js b/dist/types.js new file mode 100644 index 0000000..6bd95cc --- /dev/null +++ b/dist/types.js @@ -0,0 +1,3 @@ + +//# sourceMappingURL=types.js.map +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/dist/types.js.map b/dist/types.js.map new file mode 100644 index 0000000..efc9e48 --- /dev/null +++ b/dist/types.js.map @@ -0,0 +1 @@ +{"version":3,"sources":[],"names":[],"mappings":"","file":"types.js"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 56e88ae..be8ab11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,7 @@ "license": "MIT", "dependencies": { "@quartz-community/types": "github:quartz-community/types", - "@quartz-community/utils": "github:quartz-community/utils", - "tsup": "^8.5.0", - "typescript": "^5.9.3", - "vfile": "^6.0.3" + "@quartz-community/utils": "github:quartz-community/utils" }, "devDependencies": { "@types/hast": "^3.0.4", @@ -26,6 +23,8 @@ "preact": "^10.28.2", "prettier": "^3.6.2", "sass": "^1.97.3", + "tsup": "^8.5.0", + "typescript": "^5.9.3", "vitest": "^2.1.9" }, "engines": { @@ -34,7 +33,8 @@ }, "peerDependencies": { "@jackyzha0/quartz": "^4.5.2", - "preact": "^10.0.0" + "preact": "^10.0.0", + "vfile": "^6.0.3" }, "peerDependenciesMeta": { "@jackyzha0/quartz": { @@ -42,6 +42,9 @@ }, "preact": { "optional": false + }, + "vfile": { + "optional": true } } }, @@ -4046,7 +4049,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", diff --git a/package.json b/package.json index eeb0047..07b3bb3 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ "sideEffects": false, "scripts": { "build": "tsup", - "prepare": "npm run build", "dev": "tsup --watch", "lint": "eslint . --max-warnings=0", "format": "prettier . --check",