mirror of
https://github.com/jackyzha0/quartz.git
synced 2026-02-04 06:25:41 -06:00
Merge 50ce65a2b4 into ec00a40aef
This commit is contained in:
commit
8005a9367f
@ -2,7 +2,15 @@ import { Root } from "hast"
|
|||||||
import { GlobalConfiguration } from "../../cfg"
|
import { GlobalConfiguration } from "../../cfg"
|
||||||
import { getDate } from "../../components/Date"
|
import { getDate } from "../../components/Date"
|
||||||
import { escapeHTML } from "../../util/escape"
|
import { escapeHTML } from "../../util/escape"
|
||||||
import { FilePath, FullSlug, SimpleSlug, joinSegments, simplifySlug } from "../../util/path"
|
import {
|
||||||
|
FilePath,
|
||||||
|
FullSlug,
|
||||||
|
SimpleSlug,
|
||||||
|
getAllSegmentPrefixes,
|
||||||
|
joinSegments,
|
||||||
|
simplifySlug,
|
||||||
|
slugTag,
|
||||||
|
} from "../../util/path"
|
||||||
import { QuartzEmitterPlugin } from "../types"
|
import { QuartzEmitterPlugin } from "../types"
|
||||||
import { toHtml } from "hast-util-to-html"
|
import { toHtml } from "hast-util-to-html"
|
||||||
import { write } from "./helpers"
|
import { write } from "./helpers"
|
||||||
@ -28,6 +36,9 @@ interface Options {
|
|||||||
rssFullHtml: boolean
|
rssFullHtml: boolean
|
||||||
rssSlug: string
|
rssSlug: string
|
||||||
includeEmptyFiles: boolean
|
includeEmptyFiles: boolean
|
||||||
|
includeTags: boolean
|
||||||
|
rssTagsLimit: number
|
||||||
|
rssTags: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions: Options = {
|
const defaultOptions: Options = {
|
||||||
@ -37,6 +48,9 @@ const defaultOptions: Options = {
|
|||||||
rssFullHtml: false,
|
rssFullHtml: false,
|
||||||
rssSlug: "index",
|
rssSlug: "index",
|
||||||
includeEmptyFiles: true,
|
includeEmptyFiles: true,
|
||||||
|
includeTags: false,
|
||||||
|
rssTagsLimit: 15,
|
||||||
|
rssTags: [],
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndexMap): string {
|
function generateSiteMap(cfg: GlobalConfiguration, idx: ContentIndexMap): string {
|
||||||
@ -135,6 +149,62 @@ export const ContentIndex: QuartzEmitterPlugin<Partial<Options>> = (opts) => {
|
|||||||
slug: (opts?.rssSlug ?? "index") as FullSlug,
|
slug: (opts?.rssSlug ?? "index") as FullSlug,
|
||||||
ext: ".xml",
|
ext: ".xml",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (opts?.includeTags) {
|
||||||
|
// Optimization: Build a map of tag -> content list once (reverse index)
|
||||||
|
const tagsInput: Map<string, ContentDetails[]> = new Map()
|
||||||
|
|
||||||
|
// Iterate over the content index once to populate the reverse index
|
||||||
|
for (const [_, content] of linkIndex) {
|
||||||
|
const tags = content.tags.flatMap(getAllSegmentPrefixes)
|
||||||
|
for (const tag of new Set(tags)) {
|
||||||
|
// Use Set to avoid double counting per file
|
||||||
|
if (!tagsInput.has(tag)) {
|
||||||
|
tagsInput.set(tag, [])
|
||||||
|
}
|
||||||
|
tagsInput.get(tag)!.push(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sortedTags: string[] = []
|
||||||
|
|
||||||
|
if (opts.rssTags && opts.rssTags.length > 0) {
|
||||||
|
// Deduplicate and slugify user-provided tags
|
||||||
|
const userTags = new Set(opts.rssTags.map((tag) => slugTag(tag)))
|
||||||
|
|
||||||
|
// Filter user tags to only those that exist in the content
|
||||||
|
sortedTags = Array.from(userTags).filter((tag) => tagsInput.has(tag))
|
||||||
|
} else if ((opts.rssTagsLimit ?? 0) > 0) {
|
||||||
|
// Sort available tags by frequency (number of content items)
|
||||||
|
sortedTags = Array.from(tagsInput.entries())
|
||||||
|
.sort((a, b) => b[1].length - a[1].length) // Sort by frequency descending
|
||||||
|
.slice(0, opts.rssTagsLimit)
|
||||||
|
.map(([tag]) => tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sortedTags.length === 0) {
|
||||||
|
console.warn(
|
||||||
|
"[contentIndex] includeTags is enabled, but no tag-based RSS feeds will be generated. " +
|
||||||
|
"Either provide non-empty `rssTags` matching content tags or set `rssTagsLimit` to a positive number.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const tag of sortedTags) {
|
||||||
|
const tagContent = tagsInput.get(tag)
|
||||||
|
if (!tagContent) continue // Should not happen given logic above
|
||||||
|
|
||||||
|
// Reconstruct a map for generateRSSFeed (it expects a ContentIndexMap)
|
||||||
|
// We can optimize this by making generateRSSFeed accept an array, but for now we conform to the interface
|
||||||
|
const tagFilteredIndex = new Map(tagContent.map((content) => [content.slug, content]))
|
||||||
|
|
||||||
|
yield write({
|
||||||
|
ctx,
|
||||||
|
content: generateRSSFeed(cfg, tagFilteredIndex, opts.rssLimit),
|
||||||
|
slug: joinSegments("tags", tag, "index") as FullSlug,
|
||||||
|
ext: ".xml",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fp = joinSegments("static", "contentIndex") as FullSlug
|
const fp = joinSegments("static", "contentIndex") as FullSlug
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user