@binarynoir/vitepress-blog 0.1.1 → 0.3.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 +158 -33
- package/dist/chunk-42Z6H7IN.js +52 -0
- package/dist/chunk-42Z6H7IN.js.map +1 -0
- package/dist/{chunk-DICBXOTS.js → chunk-LYTJBMVK.js} +182 -66
- package/dist/chunk-LYTJBMVK.js.map +1 -0
- package/dist/client.cjs +140 -28
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +35 -4
- package/dist/client.d.ts +35 -4
- package/dist/client.js +136 -26
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +157 -31
- 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 +2 -1
- package/dist/{plugin-BjbV6nDK.d.cts → plugin-Bb4rRwO8.d.cts} +55 -2
- package/dist/{plugin-BjbV6nDK.d.ts → plugin-Bb4rRwO8.d.ts} +55 -2
- package/dist/style.css +113 -0
- package/dist/vitepress.cjs +294 -98
- package/dist/vitepress.cjs.map +1 -1
- package/dist/vitepress.d.cts +17 -7
- package/dist/vitepress.d.ts +17 -7
- package/dist/vitepress.js +75 -7
- package/dist/vitepress.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-DICBXOTS.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -112,6 +112,102 @@ function findBlogForPage(pages, relativePath) {
|
|
|
112
112
|
// src/render.ts
|
|
113
113
|
var import_node_path2 = __toESM(require("path"), 1);
|
|
114
114
|
|
|
115
|
+
// src/dates.ts
|
|
116
|
+
var DATE_TIME = /^(\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{1,3})\d*)?)?)?\s*(Z|[+-]\d{2}:?\d{2})?$/i;
|
|
117
|
+
function isTimeZone(timeZone) {
|
|
118
|
+
try {
|
|
119
|
+
new Intl.DateTimeFormat("en-US", { timeZone });
|
|
120
|
+
return true;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
var warnedZones = /* @__PURE__ */ new Set();
|
|
126
|
+
function resolveTimeZone(timeZone) {
|
|
127
|
+
if (!timeZone) return "UTC";
|
|
128
|
+
if (isTimeZone(timeZone)) return timeZone;
|
|
129
|
+
if (!warnedZones.has(timeZone)) {
|
|
130
|
+
warnedZones.add(timeZone);
|
|
131
|
+
console.warn(
|
|
132
|
+
`[vitepress-blog] "${timeZone}" is not a time zone; using UTC. Use an IANA name such as "America/New_York".`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return "UTC";
|
|
136
|
+
}
|
|
137
|
+
var offsetFormats = /* @__PURE__ */ new Map();
|
|
138
|
+
function zoneOffset(instant, timeZone) {
|
|
139
|
+
let format = offsetFormats.get(timeZone);
|
|
140
|
+
if (!format) {
|
|
141
|
+
format = new Intl.DateTimeFormat("en-US", {
|
|
142
|
+
timeZone,
|
|
143
|
+
hourCycle: "h23",
|
|
144
|
+
year: "numeric",
|
|
145
|
+
month: "2-digit",
|
|
146
|
+
day: "2-digit",
|
|
147
|
+
hour: "2-digit",
|
|
148
|
+
minute: "2-digit",
|
|
149
|
+
second: "2-digit"
|
|
150
|
+
});
|
|
151
|
+
offsetFormats.set(timeZone, format);
|
|
152
|
+
}
|
|
153
|
+
const parts = Object.fromEntries(format.formatToParts(instant).map(({ type, value }) => [type, Number(value)]));
|
|
154
|
+
const wall = Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);
|
|
155
|
+
return wall - Math.floor(instant / 1e3) * 1e3;
|
|
156
|
+
}
|
|
157
|
+
function fromZonedTime(wall, timeZone) {
|
|
158
|
+
const first = wall - zoneOffset(wall, timeZone);
|
|
159
|
+
const second = wall - zoneOffset(first, timeZone);
|
|
160
|
+
return second;
|
|
161
|
+
}
|
|
162
|
+
function parsePostDate(value, timeZone = "UTC") {
|
|
163
|
+
if (value instanceof Date) {
|
|
164
|
+
if (Number.isNaN(value.getTime())) return null;
|
|
165
|
+
const midnight = value.getUTCHours() === 0 && value.getUTCMinutes() === 0 && value.getUTCSeconds() === 0;
|
|
166
|
+
return { date: value, hasTime: !midnight };
|
|
167
|
+
}
|
|
168
|
+
if (typeof value !== "string") return null;
|
|
169
|
+
const match = DATE_TIME.exec(value.trim());
|
|
170
|
+
if (!match) return null;
|
|
171
|
+
const [, year, month, day, hour, minute, second = "0", millisecond = "0", offset] = match;
|
|
172
|
+
const hasTime = hour !== void 0;
|
|
173
|
+
const wall = Date.UTC(
|
|
174
|
+
Number(year),
|
|
175
|
+
Number(month) - 1,
|
|
176
|
+
Number(day),
|
|
177
|
+
hasTime ? Number(hour) : 0,
|
|
178
|
+
hasTime ? Number(minute) : 0,
|
|
179
|
+
Number(second),
|
|
180
|
+
Number(millisecond.padEnd(3, "0"))
|
|
181
|
+
);
|
|
182
|
+
const check = new Date(wall);
|
|
183
|
+
if (check.getUTCMonth() !== Number(month) - 1 || check.getUTCDate() !== Number(day)) return null;
|
|
184
|
+
if (!offset) return { date: new Date(fromZonedTime(wall, timeZone)), hasTime };
|
|
185
|
+
if (offset.toUpperCase() === "Z") return { date: new Date(wall), hasTime };
|
|
186
|
+
const sign = offset.startsWith("-") ? -1 : 1;
|
|
187
|
+
const digits = offset.slice(1).replace(":", "");
|
|
188
|
+
const minutes = Number(digits.slice(0, 2)) * 60 + Number(digits.slice(2));
|
|
189
|
+
return { date: new Date(wall - sign * minutes * 6e4), hasTime };
|
|
190
|
+
}
|
|
191
|
+
function formatPostDate({ date, hasTime }, display) {
|
|
192
|
+
const { locale, timeZone } = display;
|
|
193
|
+
const day = new Intl.DateTimeFormat(locale, { timeZone, ...display.dateFormat }).format(date);
|
|
194
|
+
if (!hasTime) return day;
|
|
195
|
+
const time = new Intl.DateTimeFormat(locale, { timeZone, ...display.timeFormat }).format(date);
|
|
196
|
+
return display.dateTime.replace("{date}", day).replace("{time}", time);
|
|
197
|
+
}
|
|
198
|
+
function toZonedIsoDate(date, timeZone) {
|
|
199
|
+
const parts = Object.fromEntries(
|
|
200
|
+
new Intl.DateTimeFormat("en-US", { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).formatToParts(date).map(({ type, value }) => [type, value])
|
|
201
|
+
);
|
|
202
|
+
return `${parts.year}-${parts.month}-${parts.day}`;
|
|
203
|
+
}
|
|
204
|
+
function toDateTimeAttribute({ date, hasTime }, timeZone) {
|
|
205
|
+
return hasTime ? date.toISOString() : toZonedIsoDate(date, timeZone);
|
|
206
|
+
}
|
|
207
|
+
function yearIn(date, timeZone) {
|
|
208
|
+
return Number(toZonedIsoDate(date, timeZone).slice(0, 4));
|
|
209
|
+
}
|
|
210
|
+
|
|
115
211
|
// src/feed.ts
|
|
116
212
|
var import_node_crypto = require("crypto");
|
|
117
213
|
var import_node_fs = require("fs");
|
|
@@ -145,12 +241,6 @@ function toMarkdownUrl(url) {
|
|
|
145
241
|
function toPageLink(text, routePath) {
|
|
146
242
|
return `[${escapeMarkdown(text)}](${toMarkdownUrl(`/${routePath}`)})`;
|
|
147
243
|
}
|
|
148
|
-
function toIsoDate(date) {
|
|
149
|
-
return date.toISOString().slice(0, 10);
|
|
150
|
-
}
|
|
151
|
-
function formatDate(date, locale, format) {
|
|
152
|
-
return new Intl.DateTimeFormat(locale, { timeZone: "UTC", ...format }).format(date);
|
|
153
|
-
}
|
|
154
244
|
|
|
155
245
|
// src/feed.ts
|
|
156
246
|
function toFeedPath(index) {
|
|
@@ -160,13 +250,20 @@ function toFeedPath(index) {
|
|
|
160
250
|
// src/types.ts
|
|
161
251
|
var DEFAULT_LABELS = {
|
|
162
252
|
by: "By",
|
|
253
|
+
published: "Published",
|
|
163
254
|
updated: "Updated",
|
|
255
|
+
dateTime: "{date} at {time}",
|
|
164
256
|
readingTime: "{n} min read",
|
|
165
257
|
newer: "Newer post",
|
|
166
258
|
older: "Older post",
|
|
167
259
|
allPosts: "All posts in {blog}",
|
|
168
260
|
draft: "Draft",
|
|
169
261
|
sticky: "Pinned",
|
|
262
|
+
announcement: "Announcement",
|
|
263
|
+
announcements: "Announcements",
|
|
264
|
+
noAnnouncements: "No announcements.",
|
|
265
|
+
announcementCount: "{n} announcements",
|
|
266
|
+
dismiss: "Dismiss",
|
|
170
267
|
noPosts: "No posts yet.",
|
|
171
268
|
undated: "Undated",
|
|
172
269
|
tags: "Keywords",
|
|
@@ -183,10 +280,18 @@ var DEFAULT_LABELS = {
|
|
|
183
280
|
// src/render.ts
|
|
184
281
|
var BLOG_POSTS_PLACEHOLDER = "<!-- blog-posts -->";
|
|
185
282
|
function createRenderContext(options, pageDirectory, feeds = !!options.siteUrl) {
|
|
283
|
+
const locale = options.locale ?? "en-US";
|
|
284
|
+
const labels = { ...DEFAULT_LABELS, ...options.labels };
|
|
186
285
|
return {
|
|
187
|
-
locale
|
|
188
|
-
|
|
189
|
-
|
|
286
|
+
locale,
|
|
287
|
+
dates: {
|
|
288
|
+
locale,
|
|
289
|
+
timeZone: resolveTimeZone(options.timeZone),
|
|
290
|
+
dateFormat: options.dateFormat ?? { dateStyle: "long" },
|
|
291
|
+
timeFormat: options.timeFormat ?? { hour: "numeric", minute: "2-digit", timeZoneName: "short" },
|
|
292
|
+
dateTime: labels.dateTime
|
|
293
|
+
},
|
|
294
|
+
labels,
|
|
190
295
|
pageDirectory,
|
|
191
296
|
feeds
|
|
192
297
|
};
|
|
@@ -208,8 +313,10 @@ function toImageSource(post, pageDirectory) {
|
|
|
208
313
|
const relative = import_node_path2.default.relative(pageDirectory, absolute).split(import_node_path2.default.sep).join("/");
|
|
209
314
|
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
210
315
|
}
|
|
211
|
-
function renderTime(date, context) {
|
|
212
|
-
|
|
316
|
+
function renderTime(date, hasTime, context) {
|
|
317
|
+
const value = { date, hasTime };
|
|
318
|
+
const attribute = toDateTimeAttribute(value, context.dates.timeZone);
|
|
319
|
+
return `<time datetime="${attribute}">${escapeTemplateText(formatPostDate(value, context.dates))}</time>`;
|
|
213
320
|
}
|
|
214
321
|
function renderAuthor(author) {
|
|
215
322
|
return author.url ? `[${escapeMarkdown(author.name)}](${toMarkdownUrl(author.url)})` : escapeMarkdown(author.name);
|
|
@@ -237,17 +344,30 @@ function renderTags(tags, blogRoutePath) {
|
|
|
237
344
|
function toTagsAttribute(post) {
|
|
238
345
|
return escapeHtml(post.post.tags.map((tag) => tag.toLowerCase()).join("|"));
|
|
239
346
|
}
|
|
347
|
+
function toItemAttributes(post) {
|
|
348
|
+
return `data-vp-blog-item data-tags="${toTagsAttribute(post)}"${post.post.announcement ? " data-announcement" : ""}`;
|
|
349
|
+
}
|
|
350
|
+
function renderBadges(post, context) {
|
|
351
|
+
const { draft, sticky, announcement } = post.post;
|
|
352
|
+
return [
|
|
353
|
+
draft && renderBadge("draft", context),
|
|
354
|
+
sticky && renderBadge("sticky", context),
|
|
355
|
+
announcement && renderBadge("announcement", context)
|
|
356
|
+
].filter(Boolean).join(" ");
|
|
357
|
+
}
|
|
240
358
|
function renderMeta(post, context, include) {
|
|
241
|
-
const { date,
|
|
359
|
+
const { date, dateHasTime, updated, updatedHasTime, readingMinutes, authors } = post.post;
|
|
242
360
|
const parts = [];
|
|
243
361
|
if (include.badges) {
|
|
244
|
-
const
|
|
245
|
-
const shown = badges.filter(Boolean).join(" ");
|
|
362
|
+
const shown = renderBadges(post, context);
|
|
246
363
|
if (shown) parts.push(shown);
|
|
247
364
|
}
|
|
248
|
-
if (date)
|
|
365
|
+
if (date) {
|
|
366
|
+
const time = renderTime(date, dateHasTime, context);
|
|
367
|
+
parts.push(include.updated ? `${escapeMarkdown(context.labels.published)} ${time}` : time);
|
|
368
|
+
}
|
|
249
369
|
if (include.updated && updated && (!date || updated.getTime() !== date.getTime())) {
|
|
250
|
-
parts.push(`${escapeMarkdown(context.labels.updated)} ${renderTime(updated, context)}`);
|
|
370
|
+
parts.push(`${escapeMarkdown(context.labels.updated)} ${renderTime(updated, updatedHasTime, context)}`);
|
|
251
371
|
}
|
|
252
372
|
if (readingMinutes) parts.push(escapeMarkdown(fill(context.labels.readingTime, { n: String(readingMinutes) })));
|
|
253
373
|
if (include.authors) {
|
|
@@ -268,12 +388,13 @@ function renderCard(post, context, index) {
|
|
|
268
388
|
const modifiers = [
|
|
269
389
|
post.post.sticky && "sticky",
|
|
270
390
|
post.post.draft && "draft",
|
|
391
|
+
post.post.announcement && "announcement",
|
|
271
392
|
image && "with-image",
|
|
272
393
|
image && post.post.imageFit === "contain" && "contain"
|
|
273
394
|
].filter(Boolean).map((modifier) => ` vp-blog-card--${modifier}`).join("");
|
|
274
395
|
const alt = escapeMarkdown(post.post.imageAlt);
|
|
275
396
|
return [
|
|
276
|
-
`<article class="vp-blog-card${modifiers}"${imageStyle(post)}
|
|
397
|
+
`<article class="vp-blog-card${modifiers}"${imageStyle(post)} ${toItemAttributes(post)}>`,
|
|
277
398
|
...image ? block("vp-blog-card__image", `[})](${toMarkdownUrl(link)})`) : [],
|
|
278
399
|
'<div class="vp-blog-card__body">',
|
|
279
400
|
...block("vp-blog-card__title", toPageLink(post.post.title, post.routePath)),
|
|
@@ -285,9 +406,9 @@ function renderCard(post, context, index) {
|
|
|
285
406
|
];
|
|
286
407
|
}
|
|
287
408
|
function renderCompactItem(post, context) {
|
|
288
|
-
const date = post.post.date ? `${renderTime(post.post.date, context)} ` : "";
|
|
289
|
-
const badges =
|
|
290
|
-
const marker = `<span hidden
|
|
409
|
+
const date = post.post.date ? `${renderTime(post.post.date, post.post.dateHasTime, context)} ` : "";
|
|
410
|
+
const badges = renderBadges(post, context);
|
|
411
|
+
const marker = `<span hidden ${toItemAttributes(post)}></span>`;
|
|
291
412
|
return `- ${marker}${date}${toPageLink(post.post.title, post.routePath)}${badges ? ` ${badges}` : ""}`;
|
|
292
413
|
}
|
|
293
414
|
function renderGroup(posts, index, context) {
|
|
@@ -310,7 +431,7 @@ function renderGroup(posts, index, context) {
|
|
|
310
431
|
function renderYears(posts, index, context) {
|
|
311
432
|
const years = /* @__PURE__ */ new Map();
|
|
312
433
|
for (const post of posts) {
|
|
313
|
-
const year = post.post.date ? String(post.post.date.
|
|
434
|
+
const year = post.post.date ? String(yearIn(post.post.date, context.dates.timeZone)) : context.labels.undated;
|
|
314
435
|
years.set(year, [...years.get(year) ?? [], post]);
|
|
315
436
|
}
|
|
316
437
|
const lines = [];
|
|
@@ -362,7 +483,9 @@ function renderClientAttributes(index, context) {
|
|
|
362
483
|
"data-label-no-tagged": labels.noTagged,
|
|
363
484
|
"data-label-previous": labels.previous,
|
|
364
485
|
"data-label-next": labels.next,
|
|
365
|
-
"data-label-pages": labels.pages
|
|
486
|
+
"data-label-pages": labels.pages,
|
|
487
|
+
"data-label-announcements": labels.announcements,
|
|
488
|
+
"data-label-no-announcements": labels.noAnnouncements
|
|
366
489
|
};
|
|
367
490
|
return Object.entries(attributes).map(([name, value]) => `${name}="${escapeHtml(value)}"`).join(" ");
|
|
368
491
|
}
|
|
@@ -466,12 +589,6 @@ function toStringList(value) {
|
|
|
466
589
|
const values = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
|
|
467
590
|
return values.map(toText).filter(Boolean);
|
|
468
591
|
}
|
|
469
|
-
function toDate(value) {
|
|
470
|
-
if (value instanceof Date) return Number.isNaN(value.getTime()) ? null : value;
|
|
471
|
-
if (typeof value !== "string" && typeof value !== "number") return null;
|
|
472
|
-
const date = new Date(value);
|
|
473
|
-
return Number.isNaN(date.getTime()) ? null : date;
|
|
474
|
-
}
|
|
475
592
|
function toAuthor(value, options) {
|
|
476
593
|
if (typeof value === "string") {
|
|
477
594
|
const name2 = value.trim();
|
|
@@ -536,11 +653,17 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
536
653
|
const stripTags = options.stripTags ?? true;
|
|
537
654
|
const clean = (text) => stripTags ? stripTagSyntax(text) : text;
|
|
538
655
|
const image = toRecord(pick("image"));
|
|
656
|
+
const timeZone = resolveTimeZone(options.timeZone);
|
|
657
|
+
const date = parsePostDate(pick("date"), timeZone);
|
|
658
|
+
const updated = parsePostDate(pick("updated"), timeZone);
|
|
659
|
+
const announcementText = typeof post.announcement === "string" ? clean(post.announcement.trim()) : "";
|
|
539
660
|
return {
|
|
540
661
|
title: clean(toText(post.title) || toText(data.title) || readHeading(content)) || fallbackTitle,
|
|
541
662
|
summary: clean(toText(post.summary) || toText(data.description) || readExcerpt(content)),
|
|
542
|
-
date:
|
|
543
|
-
|
|
663
|
+
date: date?.date ?? null,
|
|
664
|
+
dateHasTime: date?.hasTime ?? false,
|
|
665
|
+
updated: updated?.date ?? null,
|
|
666
|
+
updatedHasTime: updated?.hasTime ?? false,
|
|
544
667
|
image: toText(image.src) || toText(pick("image")),
|
|
545
668
|
imageAlt: toText(image.alt) || toText(post.imageAlt) || toText(data.imageAlt),
|
|
546
669
|
imageFit: (toText(image.fit) || toText(post.imageFit)) === "contain" ? "contain" : "cover",
|
|
@@ -551,6 +674,8 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
551
674
|
scope: toScope(post.scope),
|
|
552
675
|
sticky: post.sticky === true,
|
|
553
676
|
draft: post.draft === true,
|
|
677
|
+
announcement: post.announcement === true || !!announcementText,
|
|
678
|
+
announcementText,
|
|
554
679
|
byline: toBoolean(post.byline),
|
|
555
680
|
cover: toBoolean(post.cover),
|
|
556
681
|
postNav: toBoolean(post.postNav),
|
|
@@ -667,7 +792,8 @@ function toOptionsKey(options) {
|
|
|
667
792
|
options.stripTags,
|
|
668
793
|
options.pageSize,
|
|
669
794
|
options.stickyLimit,
|
|
670
|
-
options.rssLink
|
|
795
|
+
options.rssLink,
|
|
796
|
+
options.timeZone
|
|
671
797
|
]);
|
|
672
798
|
}
|
|
673
799
|
function indexBlogSource(sourceDirectory, options = {}, rewrites = {}) {
|