@binarynoir/vitepress-blog 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -83
- package/dist/{chunk-LYTJBMVK.js → chunk-ZM5FOUT4.js} +188 -74
- package/dist/chunk-ZM5FOUT4.js.map +1 -0
- package/dist/client.cjs +160 -56
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +26 -14
- package/dist/client.d.ts +26 -14
- package/dist/client.js +159 -56
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +185 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/{plugin-Bb4rRwO8.d.cts → plugin-DUTUA_t4.d.cts} +46 -22
- package/dist/{plugin-Bb4rRwO8.d.ts → plugin-DUTUA_t4.d.ts} +46 -22
- package/dist/style.css +157 -25
- package/dist/vitepress.cjs +188 -74
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.d.cts +2 -2
- package/dist/vitepress.d.ts +2 -2
- package/dist/vitepress.js +2 -2
- package/dist/vitepress.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-LYTJBMVK.js.map +0 -1
package/dist/vitepress.cjs
CHANGED
|
@@ -64,6 +64,11 @@ function hasAnyTag(post, tags) {
|
|
|
64
64
|
const wanted = new Set(tags.map((tag) => tag.toLowerCase()));
|
|
65
65
|
return post.post.tags.some((tag) => wanted.has(tag.toLowerCase()));
|
|
66
66
|
}
|
|
67
|
+
function inAnyCategory(post, categories) {
|
|
68
|
+
if (categories.length === 0) return true;
|
|
69
|
+
const category = post.post.category.toLowerCase();
|
|
70
|
+
return !!category && categories.some((wanted) => wanted.toLowerCase() === category);
|
|
71
|
+
}
|
|
67
72
|
function blogCoversPost(index, post, sections) {
|
|
68
73
|
if (index.index.scope === "section") return isInFolders(post.relativePath, index.index.folders);
|
|
69
74
|
if (!isInFolders(post.relativePath, index.index.folders)) return false;
|
|
@@ -77,22 +82,22 @@ function compareDates(a, b) {
|
|
|
77
82
|
function compareByDate(a, b) {
|
|
78
83
|
return compareDates(a.post.date, b.post.date) || a.post.title.localeCompare(b.post.title);
|
|
79
84
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
const pinned = new Set(limit ?
|
|
85
|
+
function pinPosts(posts, limit) {
|
|
86
|
+
const candidates = posts.filter((post) => post.post.pinned);
|
|
87
|
+
const pinned = new Set(limit ? candidates.slice(0, limit) : candidates);
|
|
83
88
|
return { pinned: [...pinned], rest: posts.filter((post) => !pinned.has(post)) };
|
|
84
89
|
}
|
|
85
90
|
function listBlogPosts(pages, index, options) {
|
|
86
91
|
const sections = pages.filter(isIndex).filter((page) => page.index.scope === "section");
|
|
87
|
-
let posts = pages.filter(isPost).filter((post) => options.drafts || !post.post.draft).filter((post) => blogCoversPost(index, post, sections) && hasAnyTag(post, index.index.tags)).sort(compareByDate);
|
|
88
|
-
if (options.
|
|
89
|
-
const { pinned, rest } =
|
|
92
|
+
let posts = pages.filter(isPost).filter((post) => options.drafts || !post.post.draft).filter((post) => blogCoversPost(index, post, sections) && hasAnyTag(post, index.index.tags)).filter((post) => inAnyCategory(post, index.index.categories)).sort(compareByDate);
|
|
93
|
+
if (options.pinnedFirst) {
|
|
94
|
+
const { pinned, rest } = pinPosts(posts, index.index.pinLimit);
|
|
90
95
|
posts = [...pinned, ...rest];
|
|
91
96
|
}
|
|
92
97
|
return options.applyLimit && index.index.limit ? posts.slice(0, index.index.limit) : posts;
|
|
93
98
|
}
|
|
94
99
|
function findHomeBlog(pages, post, drafts) {
|
|
95
|
-
const listing = pages.filter(isIndex).filter((index) => listBlogPosts(pages, index, { drafts,
|
|
100
|
+
const listing = pages.filter(isIndex).filter((index) => listBlogPosts(pages, index, { drafts, pinnedFirst: false, applyLimit: false }).includes(post));
|
|
96
101
|
const sections = listing.filter((index) => index.index.scope === "section");
|
|
97
102
|
if (sections.length) return deepestFirst(sections, post.relativePath)[0];
|
|
98
103
|
return listing[0] ?? null;
|
|
@@ -111,7 +116,7 @@ function findBlogForPage(pages, relativePath) {
|
|
|
111
116
|
}
|
|
112
117
|
function findBlogsListing(pages, post) {
|
|
113
118
|
return pages.filter(isIndex).filter(
|
|
114
|
-
(index) => listBlogPosts(pages, index, { drafts: false,
|
|
119
|
+
(index) => listBlogPosts(pages, index, { drafts: false, pinnedFirst: false, applyLimit: false }).includes(post)
|
|
115
120
|
);
|
|
116
121
|
}
|
|
117
122
|
function listAnnouncements(pages, drafts) {
|
|
@@ -120,7 +125,7 @@ function listAnnouncements(pages, drafts) {
|
|
|
120
125
|
function findAnnouncementBlog(pages, announcements, drafts) {
|
|
121
126
|
if (announcements.length === 0) return null;
|
|
122
127
|
const listingAll = pages.filter(isIndex).filter((index) => {
|
|
123
|
-
const listed = listBlogPosts(pages, index, { drafts,
|
|
128
|
+
const listed = listBlogPosts(pages, index, { drafts, pinnedFirst: false, applyLimit: false });
|
|
124
129
|
return announcements.every((post) => listed.includes(post));
|
|
125
130
|
});
|
|
126
131
|
return listingAll.find((index) => index.index.scope === "site") ?? listingAll[0] ?? findHomeBlog(pages, announcements[0], drafts);
|
|
@@ -137,18 +142,24 @@ var DEFAULT_LABELS = {
|
|
|
137
142
|
older: "Older post",
|
|
138
143
|
allPosts: "All posts in {blog}",
|
|
139
144
|
draft: "Draft",
|
|
140
|
-
|
|
145
|
+
pinned: "Pinned",
|
|
141
146
|
announcement: "Announcement",
|
|
142
147
|
announcements: "Announcements",
|
|
143
|
-
noAnnouncements: "No announcements.",
|
|
144
148
|
announcementCount: "{n} announcements",
|
|
145
149
|
dismiss: "Dismiss",
|
|
146
150
|
noPosts: "No posts yet.",
|
|
147
151
|
undated: "Undated",
|
|
152
|
+
browse: "Browse posts",
|
|
153
|
+
categories: "Categories",
|
|
148
154
|
tags: "Keywords",
|
|
149
|
-
|
|
155
|
+
archive: "Archive",
|
|
156
|
+
category: "Category",
|
|
157
|
+
tag: "Keyword",
|
|
158
|
+
postCount: "{n} posts",
|
|
159
|
+
postCountOne: "{n} post",
|
|
160
|
+
noMatches: "No posts match these filters.",
|
|
161
|
+
removeFilter: "Remove filter: {filter}",
|
|
150
162
|
showAll: "Show all posts",
|
|
151
|
-
noTagged: "No posts tagged {tag}.",
|
|
152
163
|
previous: "Previous",
|
|
153
164
|
next: "Next",
|
|
154
165
|
pages: "Pages",
|
|
@@ -319,6 +330,13 @@ function toDateTimeAttribute({ date, hasTime }, timeZone) {
|
|
|
319
330
|
function yearIn(date, timeZone) {
|
|
320
331
|
return Number(toZonedIsoDate(date, timeZone).slice(0, 4));
|
|
321
332
|
}
|
|
333
|
+
function monthIn(date, timeZone) {
|
|
334
|
+
return toZonedIsoDate(date, timeZone).slice(0, 7);
|
|
335
|
+
}
|
|
336
|
+
function formatMonth(month, locale, format) {
|
|
337
|
+
const [year, number] = month.split("-").map(Number);
|
|
338
|
+
return new Intl.DateTimeFormat(locale, { timeZone: "UTC", ...format }).format(Date.UTC(year, number - 1, 1, 12));
|
|
339
|
+
}
|
|
322
340
|
|
|
323
341
|
// src/frontmatter.ts
|
|
324
342
|
var POST_FRONTMATTER_KEY = "blog";
|
|
@@ -442,7 +460,8 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
442
460
|
tags: toStringList(pick("tags")),
|
|
443
461
|
category: toText(pick("category")),
|
|
444
462
|
scope: toScope(post.scope),
|
|
445
|
-
|
|
463
|
+
// `sticky` is this setting's old name.
|
|
464
|
+
pinned: (post.pinned ?? post.sticky) === true,
|
|
446
465
|
draft: post.draft === true,
|
|
447
466
|
announcement: post.announcement === true || !!announcementText,
|
|
448
467
|
announcementText,
|
|
@@ -455,6 +474,9 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
455
474
|
function toLayout(value) {
|
|
456
475
|
return value === "grid" || value === "compact" ? value : "list";
|
|
457
476
|
}
|
|
477
|
+
function toGroupBy(value) {
|
|
478
|
+
return value === "year" || value === "month" ? value : "";
|
|
479
|
+
}
|
|
458
480
|
function defaultFeedPath(relativePath) {
|
|
459
481
|
const name = import_node_path.default.posix.basename(relativePath, ".md");
|
|
460
482
|
return name === "index" ? "feed.xml" : `${name}-feed.xml`;
|
|
@@ -488,13 +510,17 @@ function resolveIndexConfig(data, relativePath, defaults = {}) {
|
|
|
488
510
|
scope,
|
|
489
511
|
folders: folders.length ? resolveFolders(folders, relativePath) : scope === "section" ? [ownFolder] : [],
|
|
490
512
|
tags: toStringList(options.tags),
|
|
513
|
+
categories: toStringList(options.categories),
|
|
491
514
|
limit: typeof options.limit === "number" && options.limit > 0 ? Math.floor(options.limit) : 0,
|
|
492
515
|
layout: toLayout(options.layout),
|
|
493
|
-
|
|
516
|
+
groupBy: toGroupBy(options.groupBy),
|
|
494
517
|
showTags: options.showTags !== false,
|
|
518
|
+
showCategory: options.showCategory !== false,
|
|
519
|
+
categoryList: options.categoryList !== false,
|
|
495
520
|
tagList: options.tagList !== false,
|
|
521
|
+
archive: options.archive !== false,
|
|
496
522
|
pageSize: toCount(options.pageSize, toCount(defaults.pageSize, 10)),
|
|
497
|
-
|
|
523
|
+
pinLimit: toCount(options.pinLimit ?? options.stickyLimit, toCount(defaults.pinLimit ?? defaults.stickyLimit, 0)),
|
|
498
524
|
rssLink: typeof options.rssLink === "boolean" ? options.rssLink : defaults.rssLink ?? true,
|
|
499
525
|
feed: toFeed(options.feed, relativePath)
|
|
500
526
|
};
|
|
@@ -652,27 +678,33 @@ function renderAuthors(authors, context) {
|
|
|
652
678
|
function renderBadge(kind, context) {
|
|
653
679
|
return `<span class="vp-blog-badge vp-blog-badge--${kind}">${escapeTemplateText(context.labels[kind])}</span>`;
|
|
654
680
|
}
|
|
655
|
-
function
|
|
656
|
-
const
|
|
681
|
+
function toFilterUrl(blogRoutePath, param, value) {
|
|
682
|
+
const encoded = encodeURIComponent(value.toLowerCase()).replace(/[()]/g, (c) => c === "(" ? "%28" : "%29");
|
|
657
683
|
const page = blogRoutePath.replace(/(^|\/)index\.md$/, "$1");
|
|
658
|
-
return `${toMarkdownUrl(`/${page}`)}
|
|
684
|
+
return `${toMarkdownUrl(`/${page}`)}?${param}=${encoded}`;
|
|
685
|
+
}
|
|
686
|
+
function renderFilterLink(text, param, blogRoutePath, className) {
|
|
687
|
+
return blogRoutePath ? `[${escapeMarkdown(text)}](${toFilterUrl(blogRoutePath, param, text)})` : `<span class="${className}">${escapeTemplateText(text)}</span>`;
|
|
659
688
|
}
|
|
660
689
|
function renderTags(tags, blogRoutePath) {
|
|
661
|
-
return tags.map(
|
|
662
|
-
(tag) => blogRoutePath ? `[${escapeMarkdown(tag)}](${toTagUrl(blogRoutePath, tag)})` : `<span class="vp-blog-tag">${escapeTemplateText(tag)}</span>`
|
|
663
|
-
).join(" ");
|
|
690
|
+
return tags.map((tag) => renderFilterLink(tag, "tag", blogRoutePath, "vp-blog-tag")).join(" ");
|
|
664
691
|
}
|
|
665
692
|
function toTagsAttribute(post) {
|
|
666
693
|
return escapeHtml(post.post.tags.map((tag) => tag.toLowerCase()).join("|"));
|
|
667
694
|
}
|
|
668
|
-
function toItemAttributes(post) {
|
|
669
|
-
|
|
695
|
+
function toItemAttributes(post, context) {
|
|
696
|
+
const { category, date, announcement } = post.post;
|
|
697
|
+
const attributes = [`data-vp-blog-item data-tags="${toTagsAttribute(post)}"`];
|
|
698
|
+
if (category) attributes.push(`data-category="${escapeHtml(category.toLowerCase())}"`);
|
|
699
|
+
if (date) attributes.push(`data-month="${monthIn(date, context.dates.timeZone)}"`);
|
|
700
|
+
if (announcement) attributes.push("data-announcement");
|
|
701
|
+
return attributes.join(" ");
|
|
670
702
|
}
|
|
671
703
|
function renderBadges(post, context) {
|
|
672
|
-
const { draft,
|
|
704
|
+
const { draft, pinned, announcement } = post.post;
|
|
673
705
|
return [
|
|
674
706
|
draft && renderBadge("draft", context),
|
|
675
|
-
|
|
707
|
+
pinned && renderBadge("pinned", context),
|
|
676
708
|
announcement && renderBadge("announcement", context)
|
|
677
709
|
].filter(Boolean).join(" ");
|
|
678
710
|
}
|
|
@@ -707,7 +739,7 @@ function renderCard(post, context, index) {
|
|
|
707
739
|
const link = `/${post.routePath}`;
|
|
708
740
|
const image = toImageSource(post, context.pageDirectory);
|
|
709
741
|
const modifiers = [
|
|
710
|
-
post.post.
|
|
742
|
+
post.post.pinned && "pinned",
|
|
711
743
|
post.post.draft && "draft",
|
|
712
744
|
post.post.announcement && "announcement",
|
|
713
745
|
image && "with-image",
|
|
@@ -715,9 +747,10 @@ function renderCard(post, context, index) {
|
|
|
715
747
|
].filter(Boolean).map((modifier) => ` vp-blog-card--${modifier}`).join("");
|
|
716
748
|
const alt = escapeMarkdown(post.post.imageAlt);
|
|
717
749
|
return [
|
|
718
|
-
`<article class="vp-blog-card${modifiers}"${imageStyle(post)} ${toItemAttributes(post)}>`,
|
|
750
|
+
`<article class="vp-blog-card${modifiers}"${imageStyle(post)} ${toItemAttributes(post, context)}>`,
|
|
719
751
|
...image ? block("vp-blog-card__image", `[})](${toMarkdownUrl(link)})`) : [],
|
|
720
752
|
'<div class="vp-blog-card__body">',
|
|
753
|
+
...index.index.showCategory && post.post.category ? block("vp-blog-card__category", renderFilterLink(post.post.category, "category", index.routePath, "")) : [],
|
|
721
754
|
...block("vp-blog-card__title", toPageLink(post.post.title, post.routePath)),
|
|
722
755
|
...block("vp-blog-card__meta", renderMeta(post, context, { authors: true, updated: false, badges: true })),
|
|
723
756
|
...block("vp-blog-card__summary", escapeMarkdown(post.post.summary)),
|
|
@@ -729,7 +762,7 @@ function renderCard(post, context, index) {
|
|
|
729
762
|
function renderCompactItem(post, context) {
|
|
730
763
|
const date = post.post.date ? `${renderTime(post.post.date, post.post.dateHasTime, context)} ` : "";
|
|
731
764
|
const badges = renderBadges(post, context);
|
|
732
|
-
const marker = `<span hidden ${toItemAttributes(post)}></span>`;
|
|
765
|
+
const marker = `<span hidden ${toItemAttributes(post, context)}></span>`;
|
|
733
766
|
return `- ${marker}${date}${toPageLink(post.post.title, post.routePath)}${badges ? ` ${badges}` : ""}`;
|
|
734
767
|
}
|
|
735
768
|
function renderGroup(posts, index, context) {
|
|
@@ -749,18 +782,23 @@ function renderGroup(posts, index, context) {
|
|
|
749
782
|
"</div>"
|
|
750
783
|
];
|
|
751
784
|
}
|
|
752
|
-
function
|
|
753
|
-
const
|
|
785
|
+
function renderGroups(posts, index, context) {
|
|
786
|
+
const { groupBy } = index.index;
|
|
787
|
+
if (!groupBy) return renderGroup(posts, index, context);
|
|
788
|
+
const { timeZone, locale } = context.dates;
|
|
789
|
+
const groups = /* @__PURE__ */ new Map();
|
|
754
790
|
for (const post of posts) {
|
|
755
|
-
const
|
|
756
|
-
|
|
791
|
+
const { date } = post.post;
|
|
792
|
+
const key = !date ? "" : groupBy === "year" ? String(yearIn(date, timeZone)) : monthIn(date, timeZone);
|
|
793
|
+
groups.set(key, [...groups.get(key) ?? [], post]);
|
|
757
794
|
}
|
|
758
795
|
const lines = [];
|
|
759
|
-
for (const [
|
|
796
|
+
for (const [key, group] of groups) {
|
|
797
|
+
const heading = !key ? context.labels.undated : groupBy === "year" ? key : formatMonth(key, locale, { month: "long", year: "numeric" });
|
|
760
798
|
lines.push(
|
|
761
|
-
|
|
799
|
+
`<section class="vp-blog-group vp-blog-${groupBy}">`,
|
|
762
800
|
"",
|
|
763
|
-
`## ${escapeMarkdown(
|
|
801
|
+
`## ${escapeMarkdown(heading)}`,
|
|
764
802
|
"",
|
|
765
803
|
...renderGroup(group, index, context),
|
|
766
804
|
"",
|
|
@@ -769,44 +807,114 @@ function renderYears(posts, index, context) {
|
|
|
769
807
|
}
|
|
770
808
|
return lines;
|
|
771
809
|
}
|
|
772
|
-
function
|
|
773
|
-
const
|
|
810
|
+
function collectValues(posts, pick) {
|
|
811
|
+
const values = /* @__PURE__ */ new Map();
|
|
774
812
|
for (const post of posts) {
|
|
775
|
-
for (const
|
|
776
|
-
const entry =
|
|
813
|
+
for (const value of new Set(pick(post))) {
|
|
814
|
+
const entry = values.get(value.toLowerCase()) ?? { value, count: 0 };
|
|
777
815
|
entry.count++;
|
|
778
|
-
|
|
816
|
+
values.set(value.toLowerCase(), entry);
|
|
779
817
|
}
|
|
780
818
|
}
|
|
781
|
-
return [...
|
|
819
|
+
return [...values.values()].sort((a, b) => a.value.localeCompare(b.value, void 0, { sensitivity: "base" }));
|
|
782
820
|
}
|
|
783
|
-
function
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
821
|
+
function collectTags(posts) {
|
|
822
|
+
return collectValues(posts, (post) => post.post.tags).map(({ value, count }) => ({ tag: value, count }));
|
|
823
|
+
}
|
|
824
|
+
function collectCategories(posts) {
|
|
825
|
+
return collectValues(posts, (post) => post.post.category ? [post.post.category] : []);
|
|
826
|
+
}
|
|
827
|
+
function collectArchive(posts, timeZone) {
|
|
828
|
+
const years = /* @__PURE__ */ new Map();
|
|
829
|
+
for (const post of posts) {
|
|
830
|
+
if (!post.post.date) continue;
|
|
831
|
+
const month = monthIn(post.post.date, timeZone);
|
|
832
|
+
const year = years.get(month.slice(0, 4)) ?? { value: month.slice(0, 4), count: 0, months: [] };
|
|
833
|
+
year.count++;
|
|
834
|
+
const entry = year.months.find((candidate) => candidate.value === month);
|
|
835
|
+
if (entry) entry.count++;
|
|
836
|
+
else year.months.push({ value: month, count: 1 });
|
|
837
|
+
years.set(year.value, year);
|
|
838
|
+
}
|
|
839
|
+
const newestFirst = (a, b) => b.value.localeCompare(a.value);
|
|
840
|
+
return [...years.values()].sort(newestFirst).map((year) => ({ ...year, months: [...year.months].sort(newestFirst) }));
|
|
841
|
+
}
|
|
842
|
+
function renderChip(name, count, url, title = "") {
|
|
843
|
+
const tooltip = title ? ` "${title.replace(/"/g, """)}"` : "";
|
|
844
|
+
return `[<span class="vp-blog-facet__name">${escapeMarkdown(name)}</span> <span class="vp-blog-facet__count">${count}</span>](${url}${tooltip})`;
|
|
845
|
+
}
|
|
846
|
+
function renderFacet(facet, label, chips, ariaLabel = label, attributes = "") {
|
|
790
847
|
return [
|
|
791
|
-
`<
|
|
848
|
+
`<div class="vp-blog-facet vp-blog-facet--${facet}" role="group" aria-label="${escapeHtml(ariaLabel)}" data-vp-blog-facet="${facet}"${attributes}>`,
|
|
849
|
+
`<span class="vp-blog-facet__label" aria-hidden="true">${escapeTemplateText(label)}</span>`,
|
|
850
|
+
'<div class="vp-blog-facet__chips">',
|
|
792
851
|
"",
|
|
793
|
-
|
|
852
|
+
chips.join(" "),
|
|
794
853
|
"",
|
|
795
|
-
"</
|
|
854
|
+
"</div>",
|
|
855
|
+
"</div>"
|
|
796
856
|
];
|
|
797
857
|
}
|
|
858
|
+
function renderBrowse(posts, index, context) {
|
|
859
|
+
const { labels } = context;
|
|
860
|
+
const { locale, timeZone } = context.dates;
|
|
861
|
+
const blog = index.routePath;
|
|
862
|
+
const rows = [];
|
|
863
|
+
const categories = index.index.categoryList ? collectCategories(posts) : [];
|
|
864
|
+
if (categories.length) {
|
|
865
|
+
const chips = categories.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "category", value)));
|
|
866
|
+
rows.push(...renderFacet("category", labels.categories, chips));
|
|
867
|
+
}
|
|
868
|
+
const tags = index.index.tagList ? collectTags(posts) : [];
|
|
869
|
+
if (tags.length) {
|
|
870
|
+
const chips = tags.map(({ tag, count }) => renderChip(tag, count, toFilterUrl(blog, "tag", tag)));
|
|
871
|
+
rows.push(...renderFacet("tag", labels.tags, chips));
|
|
872
|
+
}
|
|
873
|
+
const archive = index.index.archive ? collectArchive(posts, timeZone) : [];
|
|
874
|
+
if (archive.reduce((months, year) => months + year.months.length, 0) > 1) {
|
|
875
|
+
const years = archive.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "year", value)));
|
|
876
|
+
rows.push(...renderFacet("year", labels.archive, years));
|
|
877
|
+
for (const year of archive) {
|
|
878
|
+
const months = year.months.map(
|
|
879
|
+
({ value, count }) => renderChip(
|
|
880
|
+
formatMonth(value, locale, { month: "short" }),
|
|
881
|
+
count,
|
|
882
|
+
toFilterUrl(blog, "month", value),
|
|
883
|
+
formatMonth(value, locale, { month: "long", year: "numeric" })
|
|
884
|
+
)
|
|
885
|
+
);
|
|
886
|
+
const shown = archive.length === 1 ? "" : " hidden";
|
|
887
|
+
rows.push(
|
|
888
|
+
...renderFacet(
|
|
889
|
+
"month",
|
|
890
|
+
year.value,
|
|
891
|
+
months,
|
|
892
|
+
`${labels.archive} ${year.value}`,
|
|
893
|
+
` data-year="${year.value}"${shown}`
|
|
894
|
+
)
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (rows.length === 0) return [];
|
|
899
|
+
return [`<nav class="vp-blog-browse" aria-label="${escapeHtml(labels.browse)}">`, ...rows, "</nav>"];
|
|
900
|
+
}
|
|
798
901
|
function renderClientAttributes(index, context) {
|
|
799
902
|
const { labels } = context;
|
|
800
903
|
const attributes = {
|
|
801
904
|
"data-page-size": String(index.index.pageSize),
|
|
802
|
-
"
|
|
905
|
+
// For writing a `?month=` filter's name: "October 2026".
|
|
906
|
+
"data-locale": context.locale,
|
|
803
907
|
"data-label-show-all": labels.showAll,
|
|
804
|
-
"data-label-no-tagged": labels.noTagged,
|
|
805
908
|
"data-label-previous": labels.previous,
|
|
806
909
|
"data-label-next": labels.next,
|
|
807
910
|
"data-label-pages": labels.pages,
|
|
808
911
|
"data-label-announcements": labels.announcements,
|
|
809
|
-
"data-label-
|
|
912
|
+
"data-label-category": labels.category,
|
|
913
|
+
"data-label-tag": labels.tag,
|
|
914
|
+
"data-label-post-count": labels.postCount,
|
|
915
|
+
"data-label-post-count-one": labels.postCountOne,
|
|
916
|
+
"data-label-no-matches": labels.noMatches,
|
|
917
|
+
"data-label-remove-filter": labels.removeFilter
|
|
810
918
|
};
|
|
811
919
|
return Object.entries(attributes).map(([name, value]) => `${name}="${escapeHtml(value)}"`).join(" ");
|
|
812
920
|
}
|
|
@@ -817,17 +925,16 @@ function renderPostList(pinned, rest, index, context) {
|
|
|
817
925
|
const lines = [
|
|
818
926
|
`<div class="vp-blog" data-vp-blog ${renderClientAttributes(index, context)}>`,
|
|
819
927
|
...block("vp-blog-subscribe", renderRssLink(index, context)),
|
|
820
|
-
...
|
|
821
|
-
'<div class="vp-blog-filter" data-vp-blog-filter hidden></div>'
|
|
928
|
+
...renderBrowse(all, index, context),
|
|
929
|
+
'<div class="vp-blog-filter" data-vp-blog-filter role="status" hidden></div>'
|
|
822
930
|
];
|
|
823
931
|
if (pinned.length)
|
|
824
932
|
lines.push(
|
|
825
|
-
'<section class="vp-blog-
|
|
933
|
+
'<section class="vp-blog-pinned" data-vp-blog-pinned>',
|
|
826
934
|
...renderGroup(pinned, index, context),
|
|
827
935
|
"</section>"
|
|
828
936
|
);
|
|
829
|
-
if (rest.length)
|
|
830
|
-
lines.push(...index.index.groupByYear ? renderYears(rest, index, context) : renderGroup(rest, index, context));
|
|
937
|
+
if (rest.length) lines.push(...renderGroups(rest, index, context));
|
|
831
938
|
lines.push(`<nav class="vp-blog-pagination" data-vp-blog-pagination hidden></nav>`, "</div>");
|
|
832
939
|
return `${lines.join("\n")}
|
|
833
940
|
`;
|
|
@@ -836,8 +943,12 @@ function renderPostHeader(post, context, show, blogRoutePath = null) {
|
|
|
836
943
|
const lines = [];
|
|
837
944
|
if (show.byline) {
|
|
838
945
|
const meta = renderMeta(post, context, { authors: true, updated: true, badges: true });
|
|
839
|
-
const
|
|
840
|
-
|
|
946
|
+
const { category, tags } = post.post;
|
|
947
|
+
const chips = [
|
|
948
|
+
category && `<span class="vp-blog-byline__category">${renderFilterLink(category, "category", blogRoutePath, "vp-blog-category")}</span>`,
|
|
949
|
+
tags.length && `<span class="vp-blog-byline__tags">${renderTags(tags, blogRoutePath)}</span>`
|
|
950
|
+
].filter(Boolean).join(" ");
|
|
951
|
+
lines.push(...block("vp-blog-byline", [meta, chips].filter(Boolean).join("\n\n")));
|
|
841
952
|
}
|
|
842
953
|
if (show.cover && post.post.image) {
|
|
843
954
|
const image = /^[./@~]/.test(post.post.image) || isExternalUrl(post.post.image) ? post.post.image : `./${post.post.image}`;
|
|
@@ -928,7 +1039,7 @@ function toOptionsKey(options) {
|
|
|
928
1039
|
options.wordsPerMinute,
|
|
929
1040
|
options.stripTags,
|
|
930
1041
|
options.pageSize,
|
|
931
|
-
options.stickyLimit,
|
|
1042
|
+
options.pinLimit ?? options.stickyLimit,
|
|
932
1043
|
options.rssLink,
|
|
933
1044
|
options.timeZone
|
|
934
1045
|
]);
|
|
@@ -1017,10 +1128,13 @@ function resolveWidgetConfig(body) {
|
|
|
1017
1128
|
config: {
|
|
1018
1129
|
blog: typeof data.blog === "string" ? data.blog.trim() : "",
|
|
1019
1130
|
limit: toCount2(data.limit) ?? DEFAULT_LIMIT,
|
|
1020
|
-
stickyLimit
|
|
1131
|
+
// `stickyLimit` is this setting's old name.
|
|
1132
|
+
pinLimit: toCount2(data.pinLimit ?? data.stickyLimit),
|
|
1021
1133
|
layout,
|
|
1022
1134
|
showTags: typeof data.showTags === "boolean" ? data.showTags : void 0,
|
|
1135
|
+
showCategory: typeof data.showCategory === "boolean" ? data.showCategory : void 0,
|
|
1023
1136
|
tags: toStringList(data.tags),
|
|
1137
|
+
categories: toStringList(data.categories),
|
|
1024
1138
|
more: data.more === false ? null : typeof data.more === "string" && data.more.trim() ? data.more.trim() : "",
|
|
1025
1139
|
rssLink: typeof data.rssLink === "boolean" ? data.rssLink : void 0
|
|
1026
1140
|
},
|
|
@@ -1036,19 +1150,19 @@ function renderWidget(body, environment) {
|
|
|
1036
1150
|
warn(config.blog ? `no blog page found at "${config.blog}"` : 'no blog covers this page: name one with "blog:"');
|
|
1037
1151
|
return "";
|
|
1038
1152
|
}
|
|
1039
|
-
const
|
|
1040
|
-
const
|
|
1041
|
-
|
|
1042
|
-
(post) => wanted.size === 0 || post.post.tags.some((tag) => wanted.has(tag.toLowerCase()))
|
|
1153
|
+
const pinLimit = config.pinLimit ?? blog.index.pinLimit;
|
|
1154
|
+
const posts = listBlogPosts(pages, blog, { drafts, pinnedFirst: false, applyLimit: false }).filter(
|
|
1155
|
+
(post) => hasAnyTag(post, config.tags) && inAnyCategory(post, config.categories)
|
|
1043
1156
|
);
|
|
1044
|
-
const { pinned, rest } =
|
|
1157
|
+
const { pinned, rest } = pinPosts(posts, pinLimit);
|
|
1045
1158
|
const shown = [...pinned, ...rest].slice(0, config.limit || void 0);
|
|
1046
1159
|
const view = {
|
|
1047
1160
|
...blog,
|
|
1048
1161
|
index: {
|
|
1049
1162
|
...blog.index,
|
|
1050
1163
|
layout: config.layout ?? blog.index.layout,
|
|
1051
|
-
showTags: config.showTags ?? blog.index.showTags
|
|
1164
|
+
showTags: config.showTags ?? blog.index.showTags,
|
|
1165
|
+
showCategory: config.showCategory ?? blog.index.showCategory
|
|
1052
1166
|
}
|
|
1053
1167
|
};
|
|
1054
1168
|
const lines = [`<div class="vp-blog-widget">`];
|
|
@@ -1121,8 +1235,8 @@ function hasFeeds(options) {
|
|
|
1121
1235
|
}
|
|
1122
1236
|
function withPostList(source, page, pages, options) {
|
|
1123
1237
|
if (!isIndex(page)) return source;
|
|
1124
|
-
const posts = listBlogPosts(pages, page, { drafts: options.drafts ?? false,
|
|
1125
|
-
const { pinned, rest } =
|
|
1238
|
+
const posts = listBlogPosts(pages, page, { drafts: options.drafts ?? false, pinnedFirst: true, applyLimit: true });
|
|
1239
|
+
const { pinned, rest } = pinPosts(posts, page.index.pinLimit);
|
|
1126
1240
|
const context = createRenderContext(options, import_node_path6.default.dirname(page.absolutePath), hasFeeds(options));
|
|
1127
1241
|
const generated = renderPostList(pinned, rest, page, context);
|
|
1128
1242
|
return source.includes(BLOG_POSTS_PLACEHOLDER) ? source.replace(BLOG_POSTS_PLACEHOLDER, () => `
|
|
@@ -1145,7 +1259,7 @@ function withPostDecorations(source, page, pages, options) {
|
|
|
1145
1259
|
let result = header ? insertAfterTitle(source, header) : source;
|
|
1146
1260
|
if (page.post.postNav ?? options.postNav ?? true) {
|
|
1147
1261
|
if (blog) {
|
|
1148
|
-
const posts = listBlogPosts(pages, blog, { drafts,
|
|
1262
|
+
const posts = listBlogPosts(pages, blog, { drafts, pinnedFirst: false, applyLimit: false });
|
|
1149
1263
|
result = `${result.replace(/\s*$/, "")}
|
|
1150
1264
|
|
|
1151
1265
|
${renderPostNav(page, posts, blog, context)}
|
|
@@ -1222,7 +1336,7 @@ function attachAnnouncements(siteConfig, options = {}) {
|
|
|
1222
1336
|
}
|
|
1223
1337
|
function listFeedPosts(pages, index, options) {
|
|
1224
1338
|
const limit = index.index.feed?.limit ?? options.feedLimit ?? DEFAULT_FEED_LIMIT;
|
|
1225
|
-
return listBlogPosts(pages, index, { drafts: false,
|
|
1339
|
+
return listBlogPosts(pages, index, { drafts: false, pinnedFirst: false, applyLimit: false }).slice(0, limit);
|
|
1226
1340
|
}
|
|
1227
1341
|
function renderIndexFeed(pages, index, site, siteConfig, options) {
|
|
1228
1342
|
return renderFeed({
|