@binarynoir/vitepress-blog 0.4.0 → 0.5.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/dist/index.cjs CHANGED
@@ -288,6 +288,10 @@ var DEFAULT_LABELS = {
288
288
  noMatches: "No posts match these filters.",
289
289
  removeFilter: "Remove filter: {filter}",
290
290
  showAll: "Show all posts",
291
+ more: "+{n} more",
292
+ less: "Show fewer",
293
+ filter: "Filter {row}",
294
+ noFilterMatches: "Nothing matches.",
291
295
  previous: "Previous",
292
296
  next: "Next",
293
297
  pages: "Pages",
@@ -319,7 +323,8 @@ function renderRssLink(index, context, show = index.index.rssLink) {
319
323
  if (!show || !context.feeds || !index.index.feed) return "";
320
324
  const title = fill(context.labels.rssFeed, { blog: index.title }).replace(/"/g, """);
321
325
  const url = toMarkdownUrl(`/${toFeedPath(index)}`);
322
- return `<span class="vp-blog-rss">[${RSS_ICON} ${escapeMarkdown(context.labels.subscribe)}](${url} "${title}")</span>`;
326
+ const text = `<span class="vp-blog-rss__text">${escapeMarkdown(context.labels.subscribe)}</span>`;
327
+ return `<span class="vp-blog-rss">[${RSS_ICON} ${text}](${url} "${title}")</span>`;
323
328
  }
324
329
  function fill(template, values) {
325
330
  return template.replace(/\{(\w+)\}/g, (match, key) => values[key] ?? match);
@@ -514,60 +519,73 @@ function renderChip(name, count, url, title = "") {
514
519
  const tooltip = title ? ` "${title.replace(/"/g, "&quot;")}"` : "";
515
520
  return `[<span class="vp-blog-facet__name">${escapeMarkdown(name)}</span> <span class="vp-blog-facet__count">${count}</span>](${url}${tooltip})`;
516
521
  }
517
- function renderFacet(facet, label, chips, ariaLabel = label, attributes = "") {
522
+ function renderFacet(row) {
523
+ const { facet, label, chips, ariaLabel = label, limit = 0, attributes = "", aside = "" } = row;
524
+ const limited = limit && chips.length > limit ? ` data-limit="${limit}"` : "";
518
525
  return [
519
- `<div class="vp-blog-facet vp-blog-facet--${facet}" role="group" aria-label="${escapeHtml(ariaLabel)}" data-vp-blog-facet="${facet}"${attributes}>`,
526
+ `<div class="vp-blog-facet vp-blog-facet--${facet}" role="group" aria-label="${escapeHtml(ariaLabel)}" data-vp-blog-facet="${facet}"${limited}${attributes}>`,
520
527
  `<span class="vp-blog-facet__label" aria-hidden="true">${escapeTemplateText(label)}</span>`,
521
528
  '<div class="vp-blog-facet__chips">',
522
529
  "",
523
530
  chips.join(" "),
524
531
  "",
525
532
  "</div>",
533
+ ...block("vp-blog-facet__aside", aside),
526
534
  "</div>"
527
535
  ];
528
536
  }
537
+ function canNarrow(values, total) {
538
+ return values.length > 1 || values.length === 1 && values[0].count < total;
539
+ }
540
+ function byUse(a, b) {
541
+ return b.count - a.count || a.value.localeCompare(b.value, void 0, { sensitivity: "base" });
542
+ }
529
543
  function renderBrowse(posts, index, context) {
530
544
  const { labels } = context;
531
545
  const { locale, timeZone } = context.dates;
546
+ const { categoryList, categoryLimit, tagList, tagLimit, tagMinCount, archive: showArchive } = index.index;
532
547
  const blog = index.routePath;
533
548
  const rows = [];
534
- const categories = index.index.categoryList ? collectCategories(posts) : [];
535
- if (categories.length) {
549
+ const categories = categoryList ? collectCategories(posts).sort(byUse) : [];
550
+ if (canNarrow(categories, posts.length)) {
536
551
  const chips = categories.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "category", value)));
537
- rows.push(...renderFacet("category", labels.categories, chips));
552
+ rows.push({ facet: "category", label: labels.categories, chips, limit: categoryLimit });
538
553
  }
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));
554
+ const tags = tagList ? collectTags(posts).map(({ tag, count }) => ({ value: tag, count })).filter(({ count }) => count >= tagMinCount).sort(byUse) : [];
555
+ if (canNarrow(tags, posts.length)) {
556
+ const chips = tags.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "tag", value)));
557
+ rows.push({ facet: "tag", label: labels.tags, chips, limit: tagLimit });
543
558
  }
544
- const archive = index.index.archive ? collectArchive(posts, timeZone) : [];
545
- if (archive.reduce((months, year) => months + year.months.length, 0) > 1) {
559
+ const archive = showArchive ? collectArchive(posts, timeZone) : [];
560
+ const monthChips = (months) => months.map(
561
+ ({ value, count }) => renderChip(
562
+ formatMonth(value, locale, { month: "short" }),
563
+ count,
564
+ toFilterUrl(blog, "month", value),
565
+ formatMonth(value, locale, { month: "long", year: "numeric" })
566
+ )
567
+ );
568
+ if (archive.length === 1 && canNarrow(archive[0].months, posts.length)) {
569
+ const [year] = archive;
570
+ const ariaLabel = `${labels.archive} ${year.value}`;
571
+ const attributes = ` data-year="${year.value}"`;
572
+ rows.push({ facet: "month", label: labels.archive, chips: monthChips(year.months), ariaLabel, attributes });
573
+ } else if (archive.length > 1) {
546
574
  const years = archive.map(({ value, count }) => renderChip(value, count, toFilterUrl(blog, "year", value)));
547
- rows.push(...renderFacet("year", labels.archive, years));
575
+ rows.push({ facet: "year", label: labels.archive, chips: years });
548
576
  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
- );
577
+ const ariaLabel = `${labels.archive} ${year.value}`;
578
+ const attributes = ` data-year="${year.value}" hidden`;
579
+ rows.push({ facet: "month", label: year.value, chips: monthChips(year.months), ariaLabel, attributes });
567
580
  }
568
581
  }
569
582
  if (rows.length === 0) return [];
570
- return [`<nav class="vp-blog-browse" aria-label="${escapeHtml(labels.browse)}">`, ...rows, "</nav>"];
583
+ rows[0].aside = renderRssLink(index, context);
584
+ return [
585
+ `<nav class="vp-blog-browse" aria-label="${escapeHtml(labels.browse)}">`,
586
+ ...rows.flatMap(renderFacet),
587
+ "</nav>"
588
+ ];
571
589
  }
572
590
  function renderClientAttributes(index, context) {
573
591
  const { labels } = context;
@@ -585,7 +603,11 @@ function renderClientAttributes(index, context) {
585
603
  "data-label-post-count": labels.postCount,
586
604
  "data-label-post-count-one": labels.postCountOne,
587
605
  "data-label-no-matches": labels.noMatches,
588
- "data-label-remove-filter": labels.removeFilter
606
+ "data-label-remove-filter": labels.removeFilter,
607
+ "data-label-more": labels.more,
608
+ "data-label-less": labels.less,
609
+ "data-label-filter": labels.filter,
610
+ "data-label-no-filter-matches": labels.noFilterMatches
589
611
  };
590
612
  return Object.entries(attributes).map(([name, value]) => `${name}="${escapeHtml(value)}"`).join(" ");
591
613
  }
@@ -593,10 +615,10 @@ function renderPostList(pinned, rest, index, context) {
593
615
  const all = [...pinned, ...rest];
594
616
  if (all.length === 0) return `<p class="vp-blog-empty">${escapeTemplateText(context.labels.noPosts)}</p>
595
617
  `;
618
+ const browse = renderBrowse(all, index, context);
596
619
  const lines = [
597
620
  `<div class="vp-blog" data-vp-blog ${renderClientAttributes(index, context)}>`,
598
- ...block("vp-blog-subscribe", renderRssLink(index, context)),
599
- ...renderBrowse(all, index, context),
621
+ ...browse.length ? browse : block("vp-blog-subscribe", renderRssLink(index, context)),
600
622
  '<div class="vp-blog-filter" data-vp-blog-filter role="status" hidden></div>'
601
623
  ];
602
624
  if (pinned.length)
@@ -662,6 +684,8 @@ var FENCED_CODE = /^[ \t]*(`{3,}|~{3,})[^\n]*\n[\s\S]*?(?:^[ \t]*\1[`~]*[ \t]*$|
662
684
  var HEADING_1 = /^ {0,3}#[ \t]+(.*?)(?:[ \t]+#+)?[ \t]*$/m;
663
685
  var TAG_SYNTAX = /\(\(<?tag([|/])[^|/)\r\n]*(?:\1[^|/)\r\n]*){0,2}\)\)/g;
664
686
  var MAX_SUMMARY_LENGTH = 200;
687
+ var DEFAULT_CATEGORY_LIMIT = 8;
688
+ var DEFAULT_TAG_LIMIT = 12;
665
689
  function readFrontmatter(raw) {
666
690
  const source = raw.replace(/^/, "");
667
691
  const match = FRONTMATTER.exec(source);
@@ -832,7 +856,10 @@ function resolveIndexConfig(data, relativePath, defaults = {}) {
832
856
  showTags: options.showTags !== false,
833
857
  showCategory: options.showCategory !== false,
834
858
  categoryList: options.categoryList !== false,
859
+ categoryLimit: toCount(options.categoryLimit, DEFAULT_CATEGORY_LIMIT),
835
860
  tagList: options.tagList !== false,
861
+ tagLimit: toCount(options.tagLimit, DEFAULT_TAG_LIMIT),
862
+ tagMinCount: toCount(options.tagMinCount, 1),
836
863
  archive: options.archive !== false,
837
864
  pageSize: toCount(options.pageSize, toCount(defaults.pageSize, 10)),
838
865
  pinLimit: toCount(options.pinLimit ?? options.stickyLimit, toCount(defaults.pinLimit ?? defaults.stickyLimit, 0)),