@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/index.cjs
CHANGED
|
@@ -63,6 +63,11 @@ function hasAnyTag(post, tags) {
|
|
|
63
63
|
const wanted = new Set(tags.map((tag) => tag.toLowerCase()));
|
|
64
64
|
return post.post.tags.some((tag) => wanted.has(tag.toLowerCase()));
|
|
65
65
|
}
|
|
66
|
+
function inAnyCategory(post, categories) {
|
|
67
|
+
if (categories.length === 0) return true;
|
|
68
|
+
const category = post.post.category.toLowerCase();
|
|
69
|
+
return !!category && categories.some((wanted) => wanted.toLowerCase() === category);
|
|
70
|
+
}
|
|
66
71
|
function blogCoversPost(index, post, sections) {
|
|
67
72
|
if (index.index.scope === "section") return isInFolders(post.relativePath, index.index.folders);
|
|
68
73
|
if (!isInFolders(post.relativePath, index.index.folders)) return false;
|
|
@@ -76,22 +81,22 @@ function compareDates(a, b) {
|
|
|
76
81
|
function compareByDate(a, b) {
|
|
77
82
|
return compareDates(a.post.date, b.post.date) || a.post.title.localeCompare(b.post.title);
|
|
78
83
|
}
|
|
79
|
-
function
|
|
80
|
-
const
|
|
81
|
-
const pinned = new Set(limit ?
|
|
84
|
+
function pinPosts(posts, limit) {
|
|
85
|
+
const candidates = posts.filter((post) => post.post.pinned);
|
|
86
|
+
const pinned = new Set(limit ? candidates.slice(0, limit) : candidates);
|
|
82
87
|
return { pinned: [...pinned], rest: posts.filter((post) => !pinned.has(post)) };
|
|
83
88
|
}
|
|
84
89
|
function listBlogPosts(pages, index, options) {
|
|
85
90
|
const sections = pages.filter(isIndex).filter((page) => page.index.scope === "section");
|
|
86
|
-
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);
|
|
87
|
-
if (options.
|
|
88
|
-
const { pinned, rest } =
|
|
91
|
+
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);
|
|
92
|
+
if (options.pinnedFirst) {
|
|
93
|
+
const { pinned, rest } = pinPosts(posts, index.index.pinLimit);
|
|
89
94
|
posts = [...pinned, ...rest];
|
|
90
95
|
}
|
|
91
96
|
return options.applyLimit && index.index.limit ? posts.slice(0, index.index.limit) : posts;
|
|
92
97
|
}
|
|
93
98
|
function findHomeBlog(pages, post, drafts) {
|
|
94
|
-
const listing = pages.filter(isIndex).filter((index) => listBlogPosts(pages, index, { drafts,
|
|
99
|
+
const listing = pages.filter(isIndex).filter((index) => listBlogPosts(pages, index, { drafts, pinnedFirst: false, applyLimit: false }).includes(post));
|
|
95
100
|
const sections = listing.filter((index) => index.index.scope === "section");
|
|
96
101
|
if (sections.length) return deepestFirst(sections, post.relativePath)[0];
|
|
97
102
|
return listing[0] ?? null;
|
|
@@ -207,6 +212,13 @@ function toDateTimeAttribute({ date, hasTime }, timeZone) {
|
|
|
207
212
|
function yearIn(date, timeZone) {
|
|
208
213
|
return Number(toZonedIsoDate(date, timeZone).slice(0, 4));
|
|
209
214
|
}
|
|
215
|
+
function monthIn(date, timeZone) {
|
|
216
|
+
return toZonedIsoDate(date, timeZone).slice(0, 7);
|
|
217
|
+
}
|
|
218
|
+
function formatMonth(month, locale, format) {
|
|
219
|
+
const [year, number] = month.split("-").map(Number);
|
|
220
|
+
return new Intl.DateTimeFormat(locale, { timeZone: "UTC", ...format }).format(Date.UTC(year, number - 1, 1, 12));
|
|
221
|
+
}
|
|
210
222
|
|
|
211
223
|
// src/feed.ts
|
|
212
224
|
var import_node_crypto = require("crypto");
|
|
@@ -258,18 +270,24 @@ var DEFAULT_LABELS = {
|
|
|
258
270
|
older: "Older post",
|
|
259
271
|
allPosts: "All posts in {blog}",
|
|
260
272
|
draft: "Draft",
|
|
261
|
-
|
|
273
|
+
pinned: "Pinned",
|
|
262
274
|
announcement: "Announcement",
|
|
263
275
|
announcements: "Announcements",
|
|
264
|
-
noAnnouncements: "No announcements.",
|
|
265
276
|
announcementCount: "{n} announcements",
|
|
266
277
|
dismiss: "Dismiss",
|
|
267
278
|
noPosts: "No posts yet.",
|
|
268
279
|
undated: "Undated",
|
|
280
|
+
browse: "Browse posts",
|
|
281
|
+
categories: "Categories",
|
|
269
282
|
tags: "Keywords",
|
|
270
|
-
|
|
283
|
+
archive: "Archive",
|
|
284
|
+
category: "Category",
|
|
285
|
+
tag: "Keyword",
|
|
286
|
+
postCount: "{n} posts",
|
|
287
|
+
postCountOne: "{n} post",
|
|
288
|
+
noMatches: "No posts match these filters.",
|
|
289
|
+
removeFilter: "Remove filter: {filter}",
|
|
271
290
|
showAll: "Show all posts",
|
|
272
|
-
noTagged: "No posts tagged {tag}.",
|
|
273
291
|
previous: "Previous",
|
|
274
292
|
next: "Next",
|
|
275
293
|
pages: "Pages",
|
|
@@ -331,27 +349,33 @@ function renderAuthors(authors, context) {
|
|
|
331
349
|
function renderBadge(kind, context) {
|
|
332
350
|
return `<span class="vp-blog-badge vp-blog-badge--${kind}">${escapeTemplateText(context.labels[kind])}</span>`;
|
|
333
351
|
}
|
|
334
|
-
function
|
|
335
|
-
const
|
|
352
|
+
function toFilterUrl(blogRoutePath, param, value) {
|
|
353
|
+
const encoded = encodeURIComponent(value.toLowerCase()).replace(/[()]/g, (c) => c === "(" ? "%28" : "%29");
|
|
336
354
|
const page = blogRoutePath.replace(/(^|\/)index\.md$/, "$1");
|
|
337
|
-
return `${toMarkdownUrl(`/${page}`)}
|
|
355
|
+
return `${toMarkdownUrl(`/${page}`)}?${param}=${encoded}`;
|
|
356
|
+
}
|
|
357
|
+
function renderFilterLink(text, param, blogRoutePath, className) {
|
|
358
|
+
return blogRoutePath ? `[${escapeMarkdown(text)}](${toFilterUrl(blogRoutePath, param, text)})` : `<span class="${className}">${escapeTemplateText(text)}</span>`;
|
|
338
359
|
}
|
|
339
360
|
function renderTags(tags, blogRoutePath) {
|
|
340
|
-
return tags.map(
|
|
341
|
-
(tag) => blogRoutePath ? `[${escapeMarkdown(tag)}](${toTagUrl(blogRoutePath, tag)})` : `<span class="vp-blog-tag">${escapeTemplateText(tag)}</span>`
|
|
342
|
-
).join(" ");
|
|
361
|
+
return tags.map((tag) => renderFilterLink(tag, "tag", blogRoutePath, "vp-blog-tag")).join(" ");
|
|
343
362
|
}
|
|
344
363
|
function toTagsAttribute(post) {
|
|
345
364
|
return escapeHtml(post.post.tags.map((tag) => tag.toLowerCase()).join("|"));
|
|
346
365
|
}
|
|
347
|
-
function toItemAttributes(post) {
|
|
348
|
-
|
|
366
|
+
function toItemAttributes(post, context) {
|
|
367
|
+
const { category, date, announcement } = post.post;
|
|
368
|
+
const attributes = [`data-vp-blog-item data-tags="${toTagsAttribute(post)}"`];
|
|
369
|
+
if (category) attributes.push(`data-category="${escapeHtml(category.toLowerCase())}"`);
|
|
370
|
+
if (date) attributes.push(`data-month="${monthIn(date, context.dates.timeZone)}"`);
|
|
371
|
+
if (announcement) attributes.push("data-announcement");
|
|
372
|
+
return attributes.join(" ");
|
|
349
373
|
}
|
|
350
374
|
function renderBadges(post, context) {
|
|
351
|
-
const { draft,
|
|
375
|
+
const { draft, pinned, announcement } = post.post;
|
|
352
376
|
return [
|
|
353
377
|
draft && renderBadge("draft", context),
|
|
354
|
-
|
|
378
|
+
pinned && renderBadge("pinned", context),
|
|
355
379
|
announcement && renderBadge("announcement", context)
|
|
356
380
|
].filter(Boolean).join(" ");
|
|
357
381
|
}
|
|
@@ -386,7 +410,7 @@ function renderCard(post, context, index) {
|
|
|
386
410
|
const link = `/${post.routePath}`;
|
|
387
411
|
const image = toImageSource(post, context.pageDirectory);
|
|
388
412
|
const modifiers = [
|
|
389
|
-
post.post.
|
|
413
|
+
post.post.pinned && "pinned",
|
|
390
414
|
post.post.draft && "draft",
|
|
391
415
|
post.post.announcement && "announcement",
|
|
392
416
|
image && "with-image",
|
|
@@ -394,9 +418,10 @@ function renderCard(post, context, index) {
|
|
|
394
418
|
].filter(Boolean).map((modifier) => ` vp-blog-card--${modifier}`).join("");
|
|
395
419
|
const alt = escapeMarkdown(post.post.imageAlt);
|
|
396
420
|
return [
|
|
397
|
-
`<article class="vp-blog-card${modifiers}"${imageStyle(post)} ${toItemAttributes(post)}>`,
|
|
421
|
+
`<article class="vp-blog-card${modifiers}"${imageStyle(post)} ${toItemAttributes(post, context)}>`,
|
|
398
422
|
...image ? block("vp-blog-card__image", `[})](${toMarkdownUrl(link)})`) : [],
|
|
399
423
|
'<div class="vp-blog-card__body">',
|
|
424
|
+
...index.index.showCategory && post.post.category ? block("vp-blog-card__category", renderFilterLink(post.post.category, "category", index.routePath, "")) : [],
|
|
400
425
|
...block("vp-blog-card__title", toPageLink(post.post.title, post.routePath)),
|
|
401
426
|
...block("vp-blog-card__meta", renderMeta(post, context, { authors: true, updated: false, badges: true })),
|
|
402
427
|
...block("vp-blog-card__summary", escapeMarkdown(post.post.summary)),
|
|
@@ -408,7 +433,7 @@ function renderCard(post, context, index) {
|
|
|
408
433
|
function renderCompactItem(post, context) {
|
|
409
434
|
const date = post.post.date ? `${renderTime(post.post.date, post.post.dateHasTime, context)} ` : "";
|
|
410
435
|
const badges = renderBadges(post, context);
|
|
411
|
-
const marker = `<span hidden ${toItemAttributes(post)}></span>`;
|
|
436
|
+
const marker = `<span hidden ${toItemAttributes(post, context)}></span>`;
|
|
412
437
|
return `- ${marker}${date}${toPageLink(post.post.title, post.routePath)}${badges ? ` ${badges}` : ""}`;
|
|
413
438
|
}
|
|
414
439
|
function renderGroup(posts, index, context) {
|
|
@@ -428,18 +453,23 @@ function renderGroup(posts, index, context) {
|
|
|
428
453
|
"</div>"
|
|
429
454
|
];
|
|
430
455
|
}
|
|
431
|
-
function
|
|
432
|
-
const
|
|
456
|
+
function renderGroups(posts, index, context) {
|
|
457
|
+
const { groupBy } = index.index;
|
|
458
|
+
if (!groupBy) return renderGroup(posts, index, context);
|
|
459
|
+
const { timeZone, locale } = context.dates;
|
|
460
|
+
const groups = /* @__PURE__ */ new Map();
|
|
433
461
|
for (const post of posts) {
|
|
434
|
-
const
|
|
435
|
-
|
|
462
|
+
const { date } = post.post;
|
|
463
|
+
const key = !date ? "" : groupBy === "year" ? String(yearIn(date, timeZone)) : monthIn(date, timeZone);
|
|
464
|
+
groups.set(key, [...groups.get(key) ?? [], post]);
|
|
436
465
|
}
|
|
437
466
|
const lines = [];
|
|
438
|
-
for (const [
|
|
467
|
+
for (const [key, group] of groups) {
|
|
468
|
+
const heading = !key ? context.labels.undated : groupBy === "year" ? key : formatMonth(key, locale, { month: "long", year: "numeric" });
|
|
439
469
|
lines.push(
|
|
440
|
-
|
|
470
|
+
`<section class="vp-blog-group vp-blog-${groupBy}">`,
|
|
441
471
|
"",
|
|
442
|
-
`## ${escapeMarkdown(
|
|
472
|
+
`## ${escapeMarkdown(heading)}`,
|
|
443
473
|
"",
|
|
444
474
|
...renderGroup(group, index, context),
|
|
445
475
|
"",
|
|
@@ -448,44 +478,114 @@ function renderYears(posts, index, context) {
|
|
|
448
478
|
}
|
|
449
479
|
return lines;
|
|
450
480
|
}
|
|
451
|
-
function
|
|
452
|
-
const
|
|
481
|
+
function collectValues(posts, pick) {
|
|
482
|
+
const values = /* @__PURE__ */ new Map();
|
|
453
483
|
for (const post of posts) {
|
|
454
|
-
for (const
|
|
455
|
-
const entry =
|
|
484
|
+
for (const value of new Set(pick(post))) {
|
|
485
|
+
const entry = values.get(value.toLowerCase()) ?? { value, count: 0 };
|
|
456
486
|
entry.count++;
|
|
457
|
-
|
|
487
|
+
values.set(value.toLowerCase(), entry);
|
|
458
488
|
}
|
|
459
489
|
}
|
|
460
|
-
return [...
|
|
490
|
+
return [...values.values()].sort((a, b) => a.value.localeCompare(b.value, void 0, { sensitivity: "base" }));
|
|
461
491
|
}
|
|
462
|
-
function
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
492
|
+
function collectTags(posts) {
|
|
493
|
+
return collectValues(posts, (post) => post.post.tags).map(({ value, count }) => ({ tag: value, count }));
|
|
494
|
+
}
|
|
495
|
+
function collectCategories(posts) {
|
|
496
|
+
return collectValues(posts, (post) => post.post.category ? [post.post.category] : []);
|
|
497
|
+
}
|
|
498
|
+
function collectArchive(posts, timeZone) {
|
|
499
|
+
const years = /* @__PURE__ */ new Map();
|
|
500
|
+
for (const post of posts) {
|
|
501
|
+
if (!post.post.date) continue;
|
|
502
|
+
const month = monthIn(post.post.date, timeZone);
|
|
503
|
+
const year = years.get(month.slice(0, 4)) ?? { value: month.slice(0, 4), count: 0, months: [] };
|
|
504
|
+
year.count++;
|
|
505
|
+
const entry = year.months.find((candidate) => candidate.value === month);
|
|
506
|
+
if (entry) entry.count++;
|
|
507
|
+
else year.months.push({ value: month, count: 1 });
|
|
508
|
+
years.set(year.value, year);
|
|
509
|
+
}
|
|
510
|
+
const newestFirst = (a, b) => b.value.localeCompare(a.value);
|
|
511
|
+
return [...years.values()].sort(newestFirst).map((year) => ({ ...year, months: [...year.months].sort(newestFirst) }));
|
|
512
|
+
}
|
|
513
|
+
function renderChip(name, count, url, title = "") {
|
|
514
|
+
const tooltip = title ? ` "${title.replace(/"/g, """)}"` : "";
|
|
515
|
+
return `[<span class="vp-blog-facet__name">${escapeMarkdown(name)}</span> <span class="vp-blog-facet__count">${count}</span>](${url}${tooltip})`;
|
|
516
|
+
}
|
|
517
|
+
function renderFacet(facet, label, chips, ariaLabel = label, attributes = "") {
|
|
469
518
|
return [
|
|
470
|
-
`<
|
|
519
|
+
`<div class="vp-blog-facet vp-blog-facet--${facet}" role="group" aria-label="${escapeHtml(ariaLabel)}" data-vp-blog-facet="${facet}"${attributes}>`,
|
|
520
|
+
`<span class="vp-blog-facet__label" aria-hidden="true">${escapeTemplateText(label)}</span>`,
|
|
521
|
+
'<div class="vp-blog-facet__chips">',
|
|
471
522
|
"",
|
|
472
|
-
|
|
523
|
+
chips.join(" "),
|
|
473
524
|
"",
|
|
474
|
-
"</
|
|
525
|
+
"</div>",
|
|
526
|
+
"</div>"
|
|
475
527
|
];
|
|
476
528
|
}
|
|
529
|
+
function renderBrowse(posts, index, context) {
|
|
530
|
+
const { labels } = context;
|
|
531
|
+
const { locale, timeZone } = context.dates;
|
|
532
|
+
const blog = index.routePath;
|
|
533
|
+
const rows = [];
|
|
534
|
+
const categories = index.index.categoryList ? collectCategories(posts) : [];
|
|
535
|
+
if (categories.length) {
|
|
536
|
+
const chips = categories.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "category", value)));
|
|
537
|
+
rows.push(...renderFacet("category", labels.categories, chips));
|
|
538
|
+
}
|
|
539
|
+
const tags = index.index.tagList ? collectTags(posts) : [];
|
|
540
|
+
if (tags.length) {
|
|
541
|
+
const chips = tags.map(({ tag, count }) => renderChip(tag, count, toFilterUrl(blog, "tag", tag)));
|
|
542
|
+
rows.push(...renderFacet("tag", labels.tags, chips));
|
|
543
|
+
}
|
|
544
|
+
const archive = index.index.archive ? collectArchive(posts, timeZone) : [];
|
|
545
|
+
if (archive.reduce((months, year) => months + year.months.length, 0) > 1) {
|
|
546
|
+
const years = archive.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "year", value)));
|
|
547
|
+
rows.push(...renderFacet("year", labels.archive, years));
|
|
548
|
+
for (const year of archive) {
|
|
549
|
+
const months = year.months.map(
|
|
550
|
+
({ value, count }) => renderChip(
|
|
551
|
+
formatMonth(value, locale, { month: "short" }),
|
|
552
|
+
count,
|
|
553
|
+
toFilterUrl(blog, "month", value),
|
|
554
|
+
formatMonth(value, locale, { month: "long", year: "numeric" })
|
|
555
|
+
)
|
|
556
|
+
);
|
|
557
|
+
const shown = archive.length === 1 ? "" : " hidden";
|
|
558
|
+
rows.push(
|
|
559
|
+
...renderFacet(
|
|
560
|
+
"month",
|
|
561
|
+
year.value,
|
|
562
|
+
months,
|
|
563
|
+
`${labels.archive} ${year.value}`,
|
|
564
|
+
` data-year="${year.value}"${shown}`
|
|
565
|
+
)
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (rows.length === 0) return [];
|
|
570
|
+
return [`<nav class="vp-blog-browse" aria-label="${escapeHtml(labels.browse)}">`, ...rows, "</nav>"];
|
|
571
|
+
}
|
|
477
572
|
function renderClientAttributes(index, context) {
|
|
478
573
|
const { labels } = context;
|
|
479
574
|
const attributes = {
|
|
480
575
|
"data-page-size": String(index.index.pageSize),
|
|
481
|
-
"
|
|
576
|
+
// For writing a `?month=` filter's name: "October 2026".
|
|
577
|
+
"data-locale": context.locale,
|
|
482
578
|
"data-label-show-all": labels.showAll,
|
|
483
|
-
"data-label-no-tagged": labels.noTagged,
|
|
484
579
|
"data-label-previous": labels.previous,
|
|
485
580
|
"data-label-next": labels.next,
|
|
486
581
|
"data-label-pages": labels.pages,
|
|
487
582
|
"data-label-announcements": labels.announcements,
|
|
488
|
-
"data-label-
|
|
583
|
+
"data-label-category": labels.category,
|
|
584
|
+
"data-label-tag": labels.tag,
|
|
585
|
+
"data-label-post-count": labels.postCount,
|
|
586
|
+
"data-label-post-count-one": labels.postCountOne,
|
|
587
|
+
"data-label-no-matches": labels.noMatches,
|
|
588
|
+
"data-label-remove-filter": labels.removeFilter
|
|
489
589
|
};
|
|
490
590
|
return Object.entries(attributes).map(([name, value]) => `${name}="${escapeHtml(value)}"`).join(" ");
|
|
491
591
|
}
|
|
@@ -496,17 +596,16 @@ function renderPostList(pinned, rest, index, context) {
|
|
|
496
596
|
const lines = [
|
|
497
597
|
`<div class="vp-blog" data-vp-blog ${renderClientAttributes(index, context)}>`,
|
|
498
598
|
...block("vp-blog-subscribe", renderRssLink(index, context)),
|
|
499
|
-
...
|
|
500
|
-
'<div class="vp-blog-filter" data-vp-blog-filter hidden></div>'
|
|
599
|
+
...renderBrowse(all, index, context),
|
|
600
|
+
'<div class="vp-blog-filter" data-vp-blog-filter role="status" hidden></div>'
|
|
501
601
|
];
|
|
502
602
|
if (pinned.length)
|
|
503
603
|
lines.push(
|
|
504
|
-
'<section class="vp-blog-
|
|
604
|
+
'<section class="vp-blog-pinned" data-vp-blog-pinned>',
|
|
505
605
|
...renderGroup(pinned, index, context),
|
|
506
606
|
"</section>"
|
|
507
607
|
);
|
|
508
|
-
if (rest.length)
|
|
509
|
-
lines.push(...index.index.groupByYear ? renderYears(rest, index, context) : renderGroup(rest, index, context));
|
|
608
|
+
if (rest.length) lines.push(...renderGroups(rest, index, context));
|
|
510
609
|
lines.push(`<nav class="vp-blog-pagination" data-vp-blog-pagination hidden></nav>`, "</div>");
|
|
511
610
|
return `${lines.join("\n")}
|
|
512
611
|
`;
|
|
@@ -515,8 +614,12 @@ function renderPostHeader(post, context, show, blogRoutePath = null) {
|
|
|
515
614
|
const lines = [];
|
|
516
615
|
if (show.byline) {
|
|
517
616
|
const meta = renderMeta(post, context, { authors: true, updated: true, badges: true });
|
|
518
|
-
const
|
|
519
|
-
|
|
617
|
+
const { category, tags } = post.post;
|
|
618
|
+
const chips = [
|
|
619
|
+
category && `<span class="vp-blog-byline__category">${renderFilterLink(category, "category", blogRoutePath, "vp-blog-category")}</span>`,
|
|
620
|
+
tags.length && `<span class="vp-blog-byline__tags">${renderTags(tags, blogRoutePath)}</span>`
|
|
621
|
+
].filter(Boolean).join(" ");
|
|
622
|
+
lines.push(...block("vp-blog-byline", [meta, chips].filter(Boolean).join("\n\n")));
|
|
520
623
|
}
|
|
521
624
|
if (show.cover && post.post.image) {
|
|
522
625
|
const image = /^[./@~]/.test(post.post.image) || isExternalUrl(post.post.image) ? post.post.image : `./${post.post.image}`;
|
|
@@ -672,7 +775,8 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
672
775
|
tags: toStringList(pick("tags")),
|
|
673
776
|
category: toText(pick("category")),
|
|
674
777
|
scope: toScope(post.scope),
|
|
675
|
-
|
|
778
|
+
// `sticky` is this setting's old name.
|
|
779
|
+
pinned: (post.pinned ?? post.sticky) === true,
|
|
676
780
|
draft: post.draft === true,
|
|
677
781
|
announcement: post.announcement === true || !!announcementText,
|
|
678
782
|
announcementText,
|
|
@@ -685,6 +789,9 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
685
789
|
function toLayout(value) {
|
|
686
790
|
return value === "grid" || value === "compact" ? value : "list";
|
|
687
791
|
}
|
|
792
|
+
function toGroupBy(value) {
|
|
793
|
+
return value === "year" || value === "month" ? value : "";
|
|
794
|
+
}
|
|
688
795
|
function defaultFeedPath(relativePath) {
|
|
689
796
|
const name = import_node_path3.default.posix.basename(relativePath, ".md");
|
|
690
797
|
return name === "index" ? "feed.xml" : `${name}-feed.xml`;
|
|
@@ -718,13 +825,17 @@ function resolveIndexConfig(data, relativePath, defaults = {}) {
|
|
|
718
825
|
scope,
|
|
719
826
|
folders: folders.length ? resolveFolders(folders, relativePath) : scope === "section" ? [ownFolder] : [],
|
|
720
827
|
tags: toStringList(options.tags),
|
|
828
|
+
categories: toStringList(options.categories),
|
|
721
829
|
limit: typeof options.limit === "number" && options.limit > 0 ? Math.floor(options.limit) : 0,
|
|
722
830
|
layout: toLayout(options.layout),
|
|
723
|
-
|
|
831
|
+
groupBy: toGroupBy(options.groupBy),
|
|
724
832
|
showTags: options.showTags !== false,
|
|
833
|
+
showCategory: options.showCategory !== false,
|
|
834
|
+
categoryList: options.categoryList !== false,
|
|
725
835
|
tagList: options.tagList !== false,
|
|
836
|
+
archive: options.archive !== false,
|
|
726
837
|
pageSize: toCount(options.pageSize, toCount(defaults.pageSize, 10)),
|
|
727
|
-
|
|
838
|
+
pinLimit: toCount(options.pinLimit ?? options.stickyLimit, toCount(defaults.pinLimit ?? defaults.stickyLimit, 0)),
|
|
728
839
|
rssLink: typeof options.rssLink === "boolean" ? options.rssLink : defaults.rssLink ?? true,
|
|
729
840
|
feed: toFeed(options.feed, relativePath)
|
|
730
841
|
};
|
|
@@ -791,7 +902,7 @@ function toOptionsKey(options) {
|
|
|
791
902
|
options.wordsPerMinute,
|
|
792
903
|
options.stripTags,
|
|
793
904
|
options.pageSize,
|
|
794
|
-
options.stickyLimit,
|
|
905
|
+
options.pinLimit ?? options.stickyLimit,
|
|
795
906
|
options.rssLink,
|
|
796
907
|
options.timeZone
|
|
797
908
|
]);
|
|
@@ -871,10 +982,13 @@ function resolveWidgetConfig(body) {
|
|
|
871
982
|
config: {
|
|
872
983
|
blog: typeof data.blog === "string" ? data.blog.trim() : "",
|
|
873
984
|
limit: toCount2(data.limit) ?? DEFAULT_LIMIT,
|
|
874
|
-
stickyLimit
|
|
985
|
+
// `stickyLimit` is this setting's old name.
|
|
986
|
+
pinLimit: toCount2(data.pinLimit ?? data.stickyLimit),
|
|
875
987
|
layout,
|
|
876
988
|
showTags: typeof data.showTags === "boolean" ? data.showTags : void 0,
|
|
989
|
+
showCategory: typeof data.showCategory === "boolean" ? data.showCategory : void 0,
|
|
877
990
|
tags: toStringList(data.tags),
|
|
991
|
+
categories: toStringList(data.categories),
|
|
878
992
|
more: data.more === false ? null : typeof data.more === "string" && data.more.trim() ? data.more.trim() : "",
|
|
879
993
|
rssLink: typeof data.rssLink === "boolean" ? data.rssLink : void 0
|
|
880
994
|
},
|
|
@@ -890,19 +1004,19 @@ function renderWidget(body, environment) {
|
|
|
890
1004
|
warn(config.blog ? `no blog page found at "${config.blog}"` : 'no blog covers this page: name one with "blog:"');
|
|
891
1005
|
return "";
|
|
892
1006
|
}
|
|
893
|
-
const
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
(post) => wanted.size === 0 || post.post.tags.some((tag) => wanted.has(tag.toLowerCase()))
|
|
1007
|
+
const pinLimit = config.pinLimit ?? blog.index.pinLimit;
|
|
1008
|
+
const posts = listBlogPosts(pages, blog, { drafts, pinnedFirst: false, applyLimit: false }).filter(
|
|
1009
|
+
(post) => hasAnyTag(post, config.tags) && inAnyCategory(post, config.categories)
|
|
897
1010
|
);
|
|
898
|
-
const { pinned, rest } =
|
|
1011
|
+
const { pinned, rest } = pinPosts(posts, pinLimit);
|
|
899
1012
|
const shown = [...pinned, ...rest].slice(0, config.limit || void 0);
|
|
900
1013
|
const view = {
|
|
901
1014
|
...blog,
|
|
902
1015
|
index: {
|
|
903
1016
|
...blog.index,
|
|
904
1017
|
layout: config.layout ?? blog.index.layout,
|
|
905
|
-
showTags: config.showTags ?? blog.index.showTags
|
|
1018
|
+
showTags: config.showTags ?? blog.index.showTags,
|
|
1019
|
+
showCategory: config.showCategory ?? blog.index.showCategory
|
|
906
1020
|
}
|
|
907
1021
|
};
|
|
908
1022
|
const lines = [`<div class="vp-blog-widget">`];
|
|
@@ -975,8 +1089,8 @@ function hasFeeds(options) {
|
|
|
975
1089
|
}
|
|
976
1090
|
function withPostList(source, page, pages, options) {
|
|
977
1091
|
if (!isIndex(page)) return source;
|
|
978
|
-
const posts = listBlogPosts(pages, page, { drafts: options.drafts ?? false,
|
|
979
|
-
const { pinned, rest } =
|
|
1092
|
+
const posts = listBlogPosts(pages, page, { drafts: options.drafts ?? false, pinnedFirst: true, applyLimit: true });
|
|
1093
|
+
const { pinned, rest } = pinPosts(posts, page.index.pinLimit);
|
|
980
1094
|
const context = createRenderContext(options, import_node_path6.default.dirname(page.absolutePath), hasFeeds(options));
|
|
981
1095
|
const generated = renderPostList(pinned, rest, page, context);
|
|
982
1096
|
return source.includes(BLOG_POSTS_PLACEHOLDER) ? source.replace(BLOG_POSTS_PLACEHOLDER, () => `
|
|
@@ -999,7 +1113,7 @@ function withPostDecorations(source, page, pages, options) {
|
|
|
999
1113
|
let result = header ? insertAfterTitle(source, header) : source;
|
|
1000
1114
|
if (page.post.postNav ?? options.postNav ?? true) {
|
|
1001
1115
|
if (blog) {
|
|
1002
|
-
const posts = listBlogPosts(pages, blog, { drafts,
|
|
1116
|
+
const posts = listBlogPosts(pages, blog, { drafts, pinnedFirst: false, applyLimit: false });
|
|
1003
1117
|
result = `${result.replace(/\s*$/, "")}
|
|
1004
1118
|
|
|
1005
1119
|
${renderPostNav(page, posts, blog, context)}
|