@binarynoir/vitepress-blog 0.1.0 → 0.2.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 +59 -23
- package/dist/{chunk-DICBXOTS.js → chunk-PWNWSYI4.js} +133 -26
- package/dist/chunk-PWNWSYI4.js.map +1 -0
- package/dist/client.cjs +14 -3
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +1 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.js +4 -3
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +130 -25
- 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-BjbV6nDK.d.cts → plugin-BlfpqyX4.d.cts} +24 -1
- package/dist/{plugin-BjbV6nDK.d.ts → plugin-BlfpqyX4.d.ts} +24 -1
- package/dist/vitepress.cjs +132 -25
- 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 +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,7 +250,9 @@ 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",
|
|
@@ -183,10 +275,18 @@ var DEFAULT_LABELS = {
|
|
|
183
275
|
// src/render.ts
|
|
184
276
|
var BLOG_POSTS_PLACEHOLDER = "<!-- blog-posts -->";
|
|
185
277
|
function createRenderContext(options, pageDirectory, feeds = !!options.siteUrl) {
|
|
278
|
+
const locale = options.locale ?? "en-US";
|
|
279
|
+
const labels = { ...DEFAULT_LABELS, ...options.labels };
|
|
186
280
|
return {
|
|
187
|
-
locale
|
|
188
|
-
|
|
189
|
-
|
|
281
|
+
locale,
|
|
282
|
+
dates: {
|
|
283
|
+
locale,
|
|
284
|
+
timeZone: resolveTimeZone(options.timeZone),
|
|
285
|
+
dateFormat: options.dateFormat ?? { dateStyle: "long" },
|
|
286
|
+
timeFormat: options.timeFormat ?? { hour: "numeric", minute: "2-digit", timeZoneName: "short" },
|
|
287
|
+
dateTime: labels.dateTime
|
|
288
|
+
},
|
|
289
|
+
labels,
|
|
190
290
|
pageDirectory,
|
|
191
291
|
feeds
|
|
192
292
|
};
|
|
@@ -208,8 +308,10 @@ function toImageSource(post, pageDirectory) {
|
|
|
208
308
|
const relative = import_node_path2.default.relative(pageDirectory, absolute).split(import_node_path2.default.sep).join("/");
|
|
209
309
|
return relative.startsWith(".") ? relative : `./${relative}`;
|
|
210
310
|
}
|
|
211
|
-
function renderTime(date, context) {
|
|
212
|
-
|
|
311
|
+
function renderTime(date, hasTime, context) {
|
|
312
|
+
const value = { date, hasTime };
|
|
313
|
+
const attribute = toDateTimeAttribute(value, context.dates.timeZone);
|
|
314
|
+
return `<time datetime="${attribute}">${escapeTemplateText(formatPostDate(value, context.dates))}</time>`;
|
|
213
315
|
}
|
|
214
316
|
function renderAuthor(author) {
|
|
215
317
|
return author.url ? `[${escapeMarkdown(author.name)}](${toMarkdownUrl(author.url)})` : escapeMarkdown(author.name);
|
|
@@ -238,16 +340,19 @@ function toTagsAttribute(post) {
|
|
|
238
340
|
return escapeHtml(post.post.tags.map((tag) => tag.toLowerCase()).join("|"));
|
|
239
341
|
}
|
|
240
342
|
function renderMeta(post, context, include) {
|
|
241
|
-
const { date, updated, readingMinutes, authors, draft, sticky } = post.post;
|
|
343
|
+
const { date, dateHasTime, updated, updatedHasTime, readingMinutes, authors, draft, sticky } = post.post;
|
|
242
344
|
const parts = [];
|
|
243
345
|
if (include.badges) {
|
|
244
346
|
const badges = [draft && renderBadge("draft", context), sticky && renderBadge("sticky", context)];
|
|
245
347
|
const shown = badges.filter(Boolean).join(" ");
|
|
246
348
|
if (shown) parts.push(shown);
|
|
247
349
|
}
|
|
248
|
-
if (date)
|
|
350
|
+
if (date) {
|
|
351
|
+
const time = renderTime(date, dateHasTime, context);
|
|
352
|
+
parts.push(include.updated ? `${escapeMarkdown(context.labels.published)} ${time}` : time);
|
|
353
|
+
}
|
|
249
354
|
if (include.updated && updated && (!date || updated.getTime() !== date.getTime())) {
|
|
250
|
-
parts.push(`${escapeMarkdown(context.labels.updated)} ${renderTime(updated, context)}`);
|
|
355
|
+
parts.push(`${escapeMarkdown(context.labels.updated)} ${renderTime(updated, updatedHasTime, context)}`);
|
|
251
356
|
}
|
|
252
357
|
if (readingMinutes) parts.push(escapeMarkdown(fill(context.labels.readingTime, { n: String(readingMinutes) })));
|
|
253
358
|
if (include.authors) {
|
|
@@ -285,7 +390,7 @@ function renderCard(post, context, index) {
|
|
|
285
390
|
];
|
|
286
391
|
}
|
|
287
392
|
function renderCompactItem(post, context) {
|
|
288
|
-
const date = post.post.date ? `${renderTime(post.post.date, context)} ` : "";
|
|
393
|
+
const date = post.post.date ? `${renderTime(post.post.date, post.post.dateHasTime, context)} ` : "";
|
|
289
394
|
const badges = [post.post.draft && renderBadge("draft", context), post.post.sticky && renderBadge("sticky", context)].filter(Boolean).join(" ");
|
|
290
395
|
const marker = `<span hidden data-vp-blog-item data-tags="${toTagsAttribute(post)}"></span>`;
|
|
291
396
|
return `- ${marker}${date}${toPageLink(post.post.title, post.routePath)}${badges ? ` ${badges}` : ""}`;
|
|
@@ -310,7 +415,7 @@ function renderGroup(posts, index, context) {
|
|
|
310
415
|
function renderYears(posts, index, context) {
|
|
311
416
|
const years = /* @__PURE__ */ new Map();
|
|
312
417
|
for (const post of posts) {
|
|
313
|
-
const year = post.post.date ? String(post.post.date.
|
|
418
|
+
const year = post.post.date ? String(yearIn(post.post.date, context.dates.timeZone)) : context.labels.undated;
|
|
314
419
|
years.set(year, [...years.get(year) ?? [], post]);
|
|
315
420
|
}
|
|
316
421
|
const lines = [];
|
|
@@ -466,12 +571,6 @@ function toStringList(value) {
|
|
|
466
571
|
const values = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
|
|
467
572
|
return values.map(toText).filter(Boolean);
|
|
468
573
|
}
|
|
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
574
|
function toAuthor(value, options) {
|
|
476
575
|
if (typeof value === "string") {
|
|
477
576
|
const name2 = value.trim();
|
|
@@ -536,11 +635,16 @@ function resolvePostData(data, content, fallbackTitle, options = {}) {
|
|
|
536
635
|
const stripTags = options.stripTags ?? true;
|
|
537
636
|
const clean = (text) => stripTags ? stripTagSyntax(text) : text;
|
|
538
637
|
const image = toRecord(pick("image"));
|
|
638
|
+
const timeZone = resolveTimeZone(options.timeZone);
|
|
639
|
+
const date = parsePostDate(pick("date"), timeZone);
|
|
640
|
+
const updated = parsePostDate(pick("updated"), timeZone);
|
|
539
641
|
return {
|
|
540
642
|
title: clean(toText(post.title) || toText(data.title) || readHeading(content)) || fallbackTitle,
|
|
541
643
|
summary: clean(toText(post.summary) || toText(data.description) || readExcerpt(content)),
|
|
542
|
-
date:
|
|
543
|
-
|
|
644
|
+
date: date?.date ?? null,
|
|
645
|
+
dateHasTime: date?.hasTime ?? false,
|
|
646
|
+
updated: updated?.date ?? null,
|
|
647
|
+
updatedHasTime: updated?.hasTime ?? false,
|
|
544
648
|
image: toText(image.src) || toText(pick("image")),
|
|
545
649
|
imageAlt: toText(image.alt) || toText(post.imageAlt) || toText(data.imageAlt),
|
|
546
650
|
imageFit: (toText(image.fit) || toText(post.imageFit)) === "contain" ? "contain" : "cover",
|
|
@@ -667,7 +771,8 @@ function toOptionsKey(options) {
|
|
|
667
771
|
options.stripTags,
|
|
668
772
|
options.pageSize,
|
|
669
773
|
options.stickyLimit,
|
|
670
|
-
options.rssLink
|
|
774
|
+
options.rssLink,
|
|
775
|
+
options.timeZone
|
|
671
776
|
]);
|
|
672
777
|
}
|
|
673
778
|
function indexBlogSource(sourceDirectory, options = {}, rewrites = {}) {
|