Skip to content

Commit d91eb92

Browse files
committed
feat(docs): add vitepress-blog plugin page, blog and config
- docs: add the BinaryNoir blog with three posts, the blog plugin page and its scopes demo; document Auto Sidebar and Auto Navbar's .sort, .limit and .more, and the glossary's {.off} and first-mention options - config: wire up vitepress-blog (Markdown, head tags, page data, feeds, dev server and useBlog in the theme), add the RSS icon to the navbar and set the site URL to binarynoir.tech - deps: vitepress-blog 0.1.1, auto-sidebar 0.9.0, auto-navbar 0.7.0, image-fallback 0.4.2, markdown-it-glossary 0.7.0
1 parent 784f242 commit d91eb92

28 files changed

Lines changed: 813 additions & 90 deletions

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ It documents BinaryNoir's open-source VitePress plugins, Vite plugins and comman
2020
| [`@binarynoir/vitepress-broken-links`](https://github.com/binarynoir/vitepress-broken-links) | Dead links render as text with a fix-it popover instead of failing the build |
2121
| [`@binarynoir/vitepress-exclude`](https://github.com/binarynoir/vitepress-exclude) | `.exclude` files keep pages out of the build (a draft in `docs/plugins/exclude/` on purpose) |
2222
| [`@binarynoir/vitepress-readme-index`](https://github.com/binarynoir/vitepress-readme-index) | `README.md` served as a folder's index page, for VuePress migrations |
23+
| [`@binarynoir/vitepress-blog`](https://github.com/binarynoir/vitepress-blog) | The official [blog](https://binarynoir.tech/blog/) and its RSS feed, plus a scopes demo |
2324
| [`@binarynoir/vite-plugin-optimize-images`](https://github.com/binarynoir/vite-plugin-optimize-images) | Re-compresses images in the build output |
2425
| [`@binarynoir/vite-plugin-image-fallback`](https://github.com/binarynoir/vite-plugin-image-fallback) | Placeholder for missing images (one is missing on purpose) |
2526

‎docs/.nav‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ plugins
33
apps
44
guide
55
reference
6+
blog
67
-legal.md
78
-privacy.md
89
-terms.md

‎docs/.vitepress/config.mts‎

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,21 @@ import { markdownBrokenLinks } from '@binarynoir/vitepress-broken-links';
1515
import { excludeSrc, excludeVitePlugin } from '@binarynoir/vitepress-exclude';
1616
import { readmeLinks, readmeRewrites } from '@binarynoir/vitepress-readme-index';
1717
import { markdownTextStyle } from '@binarynoir/vitepress-text-style';
18+
import { blogMarkdown } from '@binarynoir/vitepress-blog';
19+
import {
20+
blogHead,
21+
blogPageData,
22+
blogVitePlugin,
23+
writeBlogFeeds,
24+
} from '@binarynoir/vitepress-blog/vitepress';
1825

1926
// import.meta.dirname, not __dirname: VitePress configs are ESM.
2027
const docsRoot = path.resolve(import.meta.dirname, '..');
2128

22-
const SITE_URL = 'https://binarynoir.github.io';
29+
// The address the site is served at; binarynoir.github.io redirects here. Used by the sitemap,
30+
// Open Graph tags and blog feeds. Feed readers use each post's URL as its permanent ID, so
31+
// this must not change once the feed is public.
32+
const SITE_URL = 'https://binarynoir.tech';
2333

2434
// @binarynoir/vitepress-auto-sidebar and -auto-navbar: how titles are written in both
2535
// menus. Markdown Tags syntax is stripped from titles by default (`stripTags`).
@@ -34,6 +44,15 @@ const menuTitleOptions = {
3444
// @binarynoir/vitepress-downloads: the same options go to all three pieces below.
3545
const downloadsOptions = { folders: ['downloads', 'files'] };
3646

47+
// @binarynoir/vitepress-blog: the same options go to all five pieces below.
48+
const blogOptions = {
49+
siteUrl: SITE_URL,
50+
authors: { binarynoir: { name: 'BinaryNoir', url: 'https://github.com/binarynoir' } },
51+
defaultAuthor: 'binarynoir',
52+
// Posts marked `draft: true` are listed (with a Draft badge) in `docs:dev` only.
53+
drafts: process.env.NODE_ENV !== 'production',
54+
};
55+
3756
export default defineConfig({
3857
title: 'BinaryNoir',
3958
description: 'Open-source tools and VitePress plugins by BinaryNoir, with live demos.',
@@ -105,7 +124,11 @@ export default defineConfig({
105124
collapsed: true,
106125
}),
107126

108-
socialLinks: [{ icon: 'github', link: 'https://github.com/binarynoir' }],
127+
socialLinks: [
128+
{ icon: 'github', link: 'https://github.com/binarynoir' },
129+
// The blog's RSS feed. `_self`, so the router doesn't try to open it as a page.
130+
{ icon: 'rss', link: '/blog/feed.xml', ariaLabel: 'Blog RSS feed', target: '_self' },
131+
],
109132

110133
search: { provider: 'local' },
111134

@@ -139,6 +162,9 @@ export default defineConfig({
139162
md.use(markdownTags);
140163
// @binarynoir/vitepress-text-style: [t:red:1.2em]text[/t] becomes colored, sized text.
141164
md.use(markdownTextStyle);
165+
// @binarynoir/vitepress-blog: `blog-index` pages list posts; `blog` pages get a byline
166+
// and newer / older links.
167+
md.use(blogMarkdown, blogOptions);
142168
// @binarynoir/vitepress-downloads: links into a `downloads` or `files` folder become file downloads.
143169
md.use(downloadsMarkdown, downloadsOptions);
144170
// @binarynoir/vitepress-readme-index: a link to README.md goes to the page it is served as.
@@ -153,16 +179,24 @@ export default defineConfig({
153179
},
154180
},
155181

156-
// Keep ((tag|...)) syntax out of <title>, search results and the page outline.
157-
transformPageData(pageData) {
182+
transformPageData(pageData, context) {
183+
// Keep ((tag|...)) syntax out of <title>, search results and the page outline.
158184
if (typeof pageData.title === 'string') {
159185
pageData.title = stripTags(pageData.title);
160186
}
161187
if (typeof pageData.frontmatter?.title === 'string') {
162188
pageData.frontmatter.title = stripTags(pageData.frontmatter.title);
163189
}
190+
// @binarynoir/vitepress-blog: a post's summary becomes its <meta name="description">.
191+
blogPageData(pageData, context, blogOptions);
164192
},
165193

194+
// @binarynoir/vitepress-blog: social-card tags on posts, and RSS links on blogs and their posts.
195+
transformHead: (context) => blogHead(context, blogOptions),
196+
197+
// @binarynoir/vitepress-blog: writes each blog's feed.xml once the pages are built.
198+
buildEnd: (siteConfig) => writeBlogFeeds(siteConfig, blogOptions),
199+
166200
vite: {
167201
plugins: [
168202
// Missing image imports become a placeholder plus a console warning
@@ -176,6 +210,8 @@ export default defineConfig({
176210
downloadsVitePlugin(downloadsOptions),
177211
// Restarts `vitepress dev` when an `.exclude` file changes, so new rules apply right away.
178212
excludeVitePlugin(),
213+
// Keeps blog lists current while running `vitepress dev`, and serves the feeds there.
214+
blogVitePlugin(blogOptions),
179215
],
180216
},
181217
});

‎docs/.vitepress/theme/index.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { enableHtmlEscapeHints } from '@binarynoir/vitepress-html-escape/client'
77
import { enableBrokenLinkHints } from '@binarynoir/vitepress-broken-links/client';
88
import { enableImageFallbackHints } from '@binarynoir/vite-plugin-image-fallback/client';
99
import { useSidebarAccordion } from '@binarynoir/vitepress-sidebar-accordion';
10+
import { useBlog } from '@binarynoir/vitepress-blog/client';
11+
import '@binarynoir/vitepress-blog/style.css';
1012
import './custom.css';
1113

1214
export default {
@@ -28,5 +30,7 @@ export default {
2830
// The filter field only appears on sidebars with 20 or more links: the Plugins
2931
// sidebar (nearly 40, with the demo pages) gets one; Guide, Apps and Reference don't.
3032
useSidebarAccordion({ filter: { minItems: 20 } });
33+
// Blog pages: one page of posts at a time (?page=2), and keyword filters (?tag=release).
34+
useBlog();
3135
},
3236
} satisfies Theme;

‎docs/blog/.sidebar‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# The overview stays first; sticky posts come next, then every other post, newest first.
2+
index.md:All posts
3+
.sort: blog.sticky desc, date desc
4+
# Only the 10 newest posts are listed here; the blog page has them all.
5+
.limit: 10
6+
# In the navbar, Blog is one link to the blog page rather than a dropdown of every post.
7+
.link
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
title: 'Glossary Tooltips 0.6: exact-case terms'
3+
blog:
4+
date: 2026-10-16
5+
summary: markdown-it-glossary 0.6.0 lets a single term match in exact case, or in any case, whatever the rest of the site does.
6+
tags: [release, glossary]
7+
category: Plugins
8+
---
9+
10+
# Glossary Tooltips 0.6: exact-case terms
11+
12+
[Glossary Tooltips](/plugins/glossary/) (`markdown-it-glossary`) 0.6.0 adds case flags for single terms.
13+
14+
End a term's heading with `{.exact}` and it only matches in exact case. End it with `{.anycase}` and it matches in any case. Either flag wins over the site, section and page settings, and covers the term's aliases too.
15+
16+
```md
17+
### IT, Information Technology {.exact}
18+
19+
The people and systems that keep the computers running.
20+
```
21+
22+
This is for short acronyms that collide with ordinary words when case is ignored: `IT` would otherwise match "it". See [Case sensitivity](/plugins/glossary/#case-sensitivity) for every level the setting can be made at.
23+
24+
This release also fixes headings with an attribute block, such as a custom anchor (`### CI {#ci}`): the block is no longer read as part of the term.

‎docs/blog/index.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
title: Blog
3+
description: News and release notes for BinaryNoir's VitePress plugins, Vite plugins and command-line apps.
4+
blog-index:
5+
scope: site
6+
folders: ./
7+
feed:
8+
title: BinaryNoir
9+
description: News and release notes for BinaryNoir's VitePress plugins, Vite plugins and command-line apps.
10+
---
11+
12+
# Blog
13+
14+
News and release notes for BinaryNoir's [plugins](/plugins/) and [apps](/apps/). Subscribe with the [RSS feed](/blog/feed.xml){target="_self"} to hear about new releases.
15+
16+
<!-- blog-posts -->
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
title: Introducing the Blog plugin
3+
blog:
4+
date: 2026-10-20
5+
summary: Any page can now be a blog post, with a main blog, folder-scoped section blogs and an RSS feed for each.
6+
image: /logo-wide-dark.png
7+
imageAlt: The BinaryNoir logo
8+
# A wide logo, not a photo: show all of it rather than cropping it to fill the card.
9+
imageFit: contain
10+
tags: [release, vitepress]
11+
category: Plugins
12+
sticky: true
13+
---
14+
15+
# Introducing the Blog plugin
16+
17+
[`@binarynoir/vitepress-blog`](/plugins/blog/) is the newest BinaryNoir plugin. It turns any VitePress page into a blog post.
18+
19+
It works like the [Glossary](/plugins/glossary/) and [Markdown Tags](/plugins/markdown-tags/) plugins: you mark pages in their frontmatter, and the build does the rest.
20+
21+
- **`blog`** turns a page into a post, with a date, summary, image, authors and tags.
22+
- **`blog-index`** turns a page into a blog that lists posts: the main blog for the whole site, or a section blog for one folder.
23+
- **Every blog gets an RSS feed**, and every post gets a byline, newer and older links, and social-card tags.
24+
25+
This blog is the first to use it. See the [plugin page](/plugins/blog/) for everything it can do, and the [Scopes Demo](/plugins/blog/demo/) for a main blog and a section blog side by side.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
title: 'Sidebar Accordion 0.3: filter long sidebars'
3+
blog:
4+
date: 2026-10-16
5+
summary: Sidebar Accordion 0.3.0 adds a filter field that narrows a long sidebar to the pages that match.
6+
tags: [release, sidebar-accordion]
7+
category: Plugins
8+
---
9+
10+
# Sidebar Accordion 0.3: filter long sidebars
11+
12+
[Sidebar Accordion](/plugins/sidebar-accordion) 0.3.0 adds a filter field at the top of the sidebar.
13+
14+
Type in it and the sidebar narrows to the pages that match, with the groups above each match held open. Clear it and every group goes back to how it was.
15+
16+
- Words can match the groups above a page, not just the page's own title.
17+
- Case and accents are ignored, and matches are highlighted.
18+
- The field only appears on sidebars with at least 20 links. Change that with `minItems`, and its wording with `labels`.
19+
20+
Turn it on with the `filter` option:
21+
22+
```ts
23+
useSidebarAccordion({ filter: { minItems: 20 } });
24+
```
25+
26+
Or use `useSidebarFilter()` to add the filter without the accordion. The Plugins sidebar on this site has it: try it there.

‎docs/guide/how-this-site-works.md‎

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ title: How this site works
66

77
[[readingTime]]
88

9-
This site is plain VitePress 2 plus fourteen plugins. There is no hand-written navigation anywhere: add a Markdown file in the right folder and it shows up in the sidebar, the navbar, search and the sitemap.
9+
This site is plain VitePress 2 plus fifteen plugins. There is no hand-written navigation anywhere: add a Markdown file in the right folder and it shows up in the sidebar, the navbar, search and the sitemap.
1010

1111
## Folder layout
1212

@@ -22,6 +22,7 @@ docs/
2222
exclude/ a .exclude file and the draft it keeps out of the build
2323
readme-index/ pages served from README.md, as in VuePress
2424
apps/ user docs for the CLI apps
25+
blog/ the BinaryNoir blog: news and release notes
2526
guide/ this section
2627
reference/ glossary terms and the generated list of every tag
2728
assets/ images imported by pages
@@ -33,30 +34,31 @@ docs/
3334

3435
## Which plugin does what
3536

36-
| You see | Plugin | Where it is wired |
37-
| ------------------------------------------------------------------ | ----------------------------------------------- | ------------------------------------------------ |
38-
| Top navbar | [Auto Navbar](/plugins/auto-navbar) | `themeConfig.nav` in `config.mts` |
39-
| One open sidebar group per level, and the Plugins sidebar's filter | [Sidebar Accordion](/plugins/sidebar-accordion) | The theme, plus `collapsed: true` on the sidebar |
40-
| Left sidebar | [Auto Sidebar](/plugins/auto-sidebar/) | `themeConfig.sidebar` in `config.mts` |
41-
| Status badges | [Markdown Tags](/plugins/markdown-tags/) | `markdown.config`, plus the theme |
42-
| "Reading time" box | [Reading Time Tag](/plugins/reading-time-tag) | `markdown.config` |
43-
| Dotted-underline hovers | [Glossary Tooltips](/plugins/glossary/) | `markdown.config` |
44-
| Colored and sized text | [Text Style](/plugins/text-style) | `markdown.config` |
45-
| File download links | [Downloads](/plugins/downloads) | `markdown.config` and `vite.plugins` |
46-
| Stray `<tags>` shown as text | [HTML Escape](/plugins/html-escape/) | `markdown.config`, plus the theme |
47-
| Dead links shown as text | [Broken Links](/plugins/broken-links) | `markdown.config`, plus the theme |
48-
| Pages left out by `.exclude` | [Exclude](/plugins/exclude/) | `srcExclude` and `vite.plugins` |
49-
| `README.md` as a folder's index | [README Index](/plugins/readme-index/) | `rewrites` and `markdown.config` |
50-
| Smaller images | [Optimize Images](/plugins/optimize-images) | `vite.plugins` |
51-
| Placeholder for a missing image | [Image Fallback](/plugins/image-fallback) | `vite.plugins`, plus the theme |
37+
| You see | Plugin | Where it is wired |
38+
| ------------------------------------------------------------------ | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
39+
| Top navbar | [Auto Navbar](/plugins/auto-navbar) | `themeConfig.nav` in `config.mts` |
40+
| One open sidebar group per level, and the Plugins sidebar's filter | [Sidebar Accordion](/plugins/sidebar-accordion) | The theme, plus `collapsed: true` on the sidebar |
41+
| Left sidebar | [Auto Sidebar](/plugins/auto-sidebar/) | `themeConfig.sidebar` in `config.mts` |
42+
| Status badges | [Markdown Tags](/plugins/markdown-tags/) | `markdown.config`, plus the theme |
43+
| "Reading time" box | [Reading Time Tag](/plugins/reading-time-tag) | `markdown.config` |
44+
| Dotted-underline hovers | [Glossary Tooltips](/plugins/glossary/) | `markdown.config` |
45+
| Colored and sized text | [Text Style](/plugins/text-style) | `markdown.config` |
46+
| File download links | [Downloads](/plugins/downloads) | `markdown.config` and `vite.plugins` |
47+
| Stray `<tags>` shown as text | [HTML Escape](/plugins/html-escape/) | `markdown.config`, plus the theme |
48+
| Dead links shown as text | [Broken Links](/plugins/broken-links) | `markdown.config`, plus the theme |
49+
| Pages left out by `.exclude` | [Exclude](/plugins/exclude/) | `srcExclude` and `vite.plugins` |
50+
| `README.md` as a folder's index | [README Index](/plugins/readme-index/) | `rewrites` and `markdown.config` |
51+
| The blog, its post lists, bylines and RSS feeds | [Blog](/plugins/blog/) | `markdown.config`, `transformHead`, `transformPageData`, `buildEnd` and `vite.plugins`, plus the theme |
52+
| Smaller images | [Optimize Images](/plugins/optimize-images) | `vite.plugins` |
53+
| Placeholder for a missing image | [Image Fallback](/plugins/image-fallback) | `vite.plugins`, plus the theme |
5254

5355
## The config
5456

5557
<<< @/.vitepress/config.mts{ts}
5658

5759
## The theme
5860

59-
The theme registers the badge component and loads its stylesheet, and turns on the four popovers: glossary definitions, the HTML Escape hints that explain broken markup, the Broken Links hints that explain dead links, and the Image Fallback hints that explain missing images:
61+
The theme registers the badge component, loads the badge and blog stylesheets, and turns on the four popovers: glossary definitions, the HTML Escape hints that explain broken markup, the Broken Links hints that explain dead links, and the Image Fallback hints that explain missing images:
6062

6163
<<< @/.vitepress/theme/index.ts{ts}
6264

0 commit comments

Comments
 (0)