@binarynoir/vitepress-blog 0.0.0-stage → 0.1.1
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/LICENSE +21 -0
- package/README.md +491 -2
- package/dist/chunk-DICBXOTS.js +1001 -0
- package/dist/chunk-DICBXOTS.js.map +1 -0
- package/dist/client.cjs +176 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +51 -0
- package/dist/client.d.ts +51 -0
- package/dist/client.js +139 -0
- package/dist/client.js.map +1 -0
- package/dist/index.cjs +930 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin-BjbV6nDK.d.cts +190 -0
- package/dist/plugin-BjbV6nDK.d.ts +190 -0
- package/dist/style.css +418 -0
- package/dist/vitepress.cjs +1243 -0
- package/dist/vitepress.cjs.map +1 -0
- package/dist/vitepress.d.cts +81 -0
- package/dist/vitepress.d.ts +81 -0
- package/dist/vitepress.js +234 -0
- package/dist/vitepress.js.map +1 -0
- package/package.json +108 -4
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { MarkdownIt } from 'markdown-it';
|
|
2
|
+
|
|
3
|
+
interface BlogAuthor {
|
|
4
|
+
name: string;
|
|
5
|
+
/** Linked from the author's name in bylines and cards. */
|
|
6
|
+
url?: string;
|
|
7
|
+
/** Shown in the feed's `<dc:creator>` as `email (name)` when set. */
|
|
8
|
+
email?: string;
|
|
9
|
+
}
|
|
10
|
+
interface BlogOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Absolute URL of the published site, such as `https://example.com`. Feeds
|
|
13
|
+
* and social-card tags need absolute links. Default: VitePress's
|
|
14
|
+
* `sitemap.hostname`. With neither, no feeds or social tags are written.
|
|
15
|
+
*/
|
|
16
|
+
siteUrl?: string;
|
|
17
|
+
/** Locale for dates in bylines and cards. Default: `'en-US'`. */
|
|
18
|
+
locale?: string;
|
|
19
|
+
/** How dates are written. Default: `{ dateStyle: 'long' }`, in UTC. */
|
|
20
|
+
dateFormat?: Intl.DateTimeFormatOptions;
|
|
21
|
+
/** Reading speed for the "5 min read" estimate. `0` hides it. Default: `200`. */
|
|
22
|
+
wordsPerMinute?: number;
|
|
23
|
+
/** Add an author, date and tags line under each post's title. Default: `true`. */
|
|
24
|
+
byline?: boolean;
|
|
25
|
+
/** Show each post's `image` under its byline. Default: `false`. */
|
|
26
|
+
cover?: boolean;
|
|
27
|
+
/** Add newer and older post links to the end of each post. Default: `true`. */
|
|
28
|
+
postNav?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* List `draft: true` posts, marked as drafts. They are never put in a feed.
|
|
31
|
+
* Pass `process.env.NODE_ENV !== 'production'` to see them in `vitepress dev` only.
|
|
32
|
+
* Default: `false`.
|
|
33
|
+
*/
|
|
34
|
+
drafts?: boolean;
|
|
35
|
+
/** Remove markdown-tags syntax (`((tag|draft))`) from titles and summaries. Default: `true`. */
|
|
36
|
+
stripTags?: boolean;
|
|
37
|
+
/** Authors a post can name by key: `author: jane`. */
|
|
38
|
+
authors?: Record<string, BlogAuthor | string>;
|
|
39
|
+
/** Author for posts that don't name one. */
|
|
40
|
+
defaultAuthor?: BlogAuthor | string;
|
|
41
|
+
/** Most posts in each feed, newest first. Default: `20`. */
|
|
42
|
+
feedLimit?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Folder in the build output that post images are copied to, so feeds and
|
|
45
|
+
* social cards can link them at a stable URL. Default: `'blog-images'`.
|
|
46
|
+
*/
|
|
47
|
+
imagesDir?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Posts per page on blog pages, for those that don't set `pageSize`. `0`
|
|
50
|
+
* shows every post on one page. Needs `useBlog()` in the theme. Default: `10`.
|
|
51
|
+
*/
|
|
52
|
+
pageSize?: number;
|
|
53
|
+
/**
|
|
54
|
+
* Most sticky posts pinned to the top of a blog page, for those that don't
|
|
55
|
+
* set `stickyLimit`. Extra sticky posts take their place by date. `0` pins
|
|
56
|
+
* them all. Default: `0`.
|
|
57
|
+
*/
|
|
58
|
+
stickyLimit?: number;
|
|
59
|
+
/**
|
|
60
|
+
* Show a "Subscribe" RSS link on blog pages and `::: blog-posts` blocks,
|
|
61
|
+
* for those that don't set `rssLink`. It only shows for a blog with a feed,
|
|
62
|
+
* on a site with a site URL (without one, no feeds are written). Default: `true`.
|
|
63
|
+
*/
|
|
64
|
+
rssLink?: boolean;
|
|
65
|
+
/** Words the plugin writes on pages, for translating. `{n}`, `{blog}` and `{tag}` are filled in. */
|
|
66
|
+
labels?: Partial<BlogLabels>;
|
|
67
|
+
}
|
|
68
|
+
interface BlogLabels {
|
|
69
|
+
/** Before the author names: "By Jane Doe". */
|
|
70
|
+
by: string;
|
|
71
|
+
/** Before a post's `updated` date. */
|
|
72
|
+
updated: string;
|
|
73
|
+
/** Reading time: "{n} min read". */
|
|
74
|
+
readingTime: string;
|
|
75
|
+
newer: string;
|
|
76
|
+
older: string;
|
|
77
|
+
/** The link back to a post's blog: "All posts in {blog}". */
|
|
78
|
+
allPosts: string;
|
|
79
|
+
draft: string;
|
|
80
|
+
/** Badge on a sticky post. */
|
|
81
|
+
sticky: string;
|
|
82
|
+
noPosts: string;
|
|
83
|
+
/** Year heading for posts without a date, when a blog groups by year. */
|
|
84
|
+
undated: string;
|
|
85
|
+
/** Label of a blog page's keyword list. */
|
|
86
|
+
tags: string;
|
|
87
|
+
/** Above a list filtered by keyword: "Posts tagged {tag}". */
|
|
88
|
+
tagged: string;
|
|
89
|
+
/** Link that clears the keyword filter. */
|
|
90
|
+
showAll: string;
|
|
91
|
+
/** When no post has the keyword: "No posts tagged {tag}." */
|
|
92
|
+
noTagged: string;
|
|
93
|
+
previous: string;
|
|
94
|
+
next: string;
|
|
95
|
+
/** Accessible name of the page links. */
|
|
96
|
+
pages: string;
|
|
97
|
+
/** Text of the RSS link on blog pages and blocks. */
|
|
98
|
+
subscribe: string;
|
|
99
|
+
/** Tooltip of the RSS link: "RSS feed for {blog}". */
|
|
100
|
+
rssFeed: string;
|
|
101
|
+
}
|
|
102
|
+
declare const DEFAULT_LABELS: BlogLabels;
|
|
103
|
+
type BlogScope = 'site' | 'section';
|
|
104
|
+
type BlogLayout = 'list' | 'grid' | 'compact';
|
|
105
|
+
interface BlogFeedConfig {
|
|
106
|
+
title?: string;
|
|
107
|
+
description?: string;
|
|
108
|
+
limit?: number;
|
|
109
|
+
/** Feed file, relative to the blog page's folder. Default: `feed.xml` (`<name>-feed.xml` for a page not named `index.md`). */
|
|
110
|
+
path: string;
|
|
111
|
+
}
|
|
112
|
+
/** What a blog page's `blog-index` frontmatter says, with defaults filled in. */
|
|
113
|
+
interface BlogIndexConfig {
|
|
114
|
+
/** `site` for the main blog; `section` (the default) for a blog of one part of the site. */
|
|
115
|
+
scope: BlogScope;
|
|
116
|
+
/** Folders the blog covers, relative to the source directory. Empty means the whole site. */
|
|
117
|
+
folders: string[];
|
|
118
|
+
/** Only list posts with at least one of these tags. */
|
|
119
|
+
tags: string[];
|
|
120
|
+
/** Most posts to list. `0` lists them all. */
|
|
121
|
+
limit: number;
|
|
122
|
+
layout: BlogLayout;
|
|
123
|
+
/** Put a year heading above each year's posts. */
|
|
124
|
+
groupByYear: boolean;
|
|
125
|
+
/** Show the post's tags on each card. */
|
|
126
|
+
showTags: boolean;
|
|
127
|
+
/** List every keyword above the posts, each one a filter. */
|
|
128
|
+
tagList: boolean;
|
|
129
|
+
/** Posts per page. `0` shows them all on one page. */
|
|
130
|
+
pageSize: number;
|
|
131
|
+
/** Most sticky posts pinned to the top. `0` pins them all. */
|
|
132
|
+
stickyLimit: number;
|
|
133
|
+
/** Show a "Subscribe" link to the blog's feed. */
|
|
134
|
+
rssLink: boolean;
|
|
135
|
+
feed: BlogFeedConfig | null;
|
|
136
|
+
}
|
|
137
|
+
/** A post's frontmatter, normalized. */
|
|
138
|
+
interface BlogPostData {
|
|
139
|
+
title: string;
|
|
140
|
+
summary: string;
|
|
141
|
+
date: Date | null;
|
|
142
|
+
updated: Date | null;
|
|
143
|
+
/** As written: a path relative to the post, a public path (`/x.png`) or a URL. */
|
|
144
|
+
image: string;
|
|
145
|
+
imageAlt: string;
|
|
146
|
+
/** How a card fits the image in its frame: `cover` crops to fill it, `contain` shows all of it. */
|
|
147
|
+
imageFit: 'cover' | 'contain';
|
|
148
|
+
/** Which part of a cropped image stays in view, as CSS `object-position`: `top`, `30% 20%`. `''` is the centre. */
|
|
149
|
+
imagePosition: string;
|
|
150
|
+
authors: BlogAuthor[];
|
|
151
|
+
tags: string[];
|
|
152
|
+
category: string;
|
|
153
|
+
scope: BlogScope;
|
|
154
|
+
sticky: boolean;
|
|
155
|
+
draft: boolean;
|
|
156
|
+
/** Per-post overrides of the `byline`, `cover` and `postNav` options. */
|
|
157
|
+
byline?: boolean;
|
|
158
|
+
cover?: boolean;
|
|
159
|
+
postNav?: boolean;
|
|
160
|
+
readingMinutes: number;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* A markdown-it plugin that turns pages into a blog.
|
|
165
|
+
*
|
|
166
|
+
* ```ts
|
|
167
|
+
* // .vitepress/config.mts
|
|
168
|
+
* import { blogMarkdown } from '@binarynoir/vitepress-blog';
|
|
169
|
+
*
|
|
170
|
+
* export default defineConfig({
|
|
171
|
+
* markdown: {
|
|
172
|
+
* config(md) {
|
|
173
|
+
* md.use(blogMarkdown, { locale: 'en-US' });
|
|
174
|
+
* },
|
|
175
|
+
* },
|
|
176
|
+
* });
|
|
177
|
+
* ```
|
|
178
|
+
*
|
|
179
|
+
* A page with `blog-index` in its frontmatter gets a list of posts; a page
|
|
180
|
+
* with `blog` gets a byline and links to the posts around it; and any page
|
|
181
|
+
* can show a blog's latest posts with a `::: blog-posts` block. Runs on the raw
|
|
182
|
+
* source before markdown-it's `normalize` rule, so the Markdown it writes is
|
|
183
|
+
* parsed like the rest of the page and its links are checked and given the
|
|
184
|
+
* site's base by VitePress. It needs VitePress's `env.path`,
|
|
185
|
+
* `env.relativePath` and `env.frontmatter`, so it does nothing under plain
|
|
186
|
+
* markdown-it.
|
|
187
|
+
*/
|
|
188
|
+
declare function blogMarkdown(md: MarkdownIt, options?: BlogOptions): void;
|
|
189
|
+
|
|
190
|
+
export { type BlogAuthor as B, DEFAULT_LABELS as D, type BlogFeedConfig as a, type BlogIndexConfig as b, type BlogLabels as c, type BlogLayout as d, type BlogOptions as e, type BlogPostData as f, type BlogScope as g, blogMarkdown as h };
|
package/dist/style.css
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Uses VitePress theme variables, so it follows light and dark mode. Override
|
|
3
|
+
* the --vp-blog-* variables to restyle without touching the rules.
|
|
4
|
+
*/
|
|
5
|
+
:root {
|
|
6
|
+
--vp-blog-card-bg: var(--vp-c-bg-soft);
|
|
7
|
+
--vp-blog-card-border: var(--vp-c-divider);
|
|
8
|
+
--vp-blog-card-radius: 12px;
|
|
9
|
+
--vp-blog-meta-color: var(--vp-c-text-2);
|
|
10
|
+
--vp-blog-tag-bg: var(--vp-c-default-soft);
|
|
11
|
+
--vp-blog-tag-color: var(--vp-c-text-2);
|
|
12
|
+
--vp-blog-accent: var(--vp-c-brand-1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Markdown inside the generated blocks is wrapped in <p>; its margins are handled here instead. */
|
|
16
|
+
.vp-blog-card p,
|
|
17
|
+
.vp-blog-byline p,
|
|
18
|
+
.vp-blog-post-nav p {
|
|
19
|
+
margin: 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.vp-blog-list {
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: 20px;
|
|
25
|
+
margin: 24px 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.vp-blog-list--grid {
|
|
29
|
+
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.vp-blog-card {
|
|
33
|
+
display: flex;
|
|
34
|
+
flex-direction: column;
|
|
35
|
+
overflow: hidden;
|
|
36
|
+
border: 1px solid var(--vp-blog-card-border);
|
|
37
|
+
border-radius: var(--vp-blog-card-radius);
|
|
38
|
+
background: var(--vp-blog-card-bg);
|
|
39
|
+
transition: border-color 0.25s;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.vp-blog-card:hover {
|
|
43
|
+
border-color: var(--vp-blog-accent);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.vp-blog-card--sticky {
|
|
47
|
+
border-color: var(--vp-blog-accent);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.vp-blog-card--draft {
|
|
51
|
+
border-style: dashed;
|
|
52
|
+
opacity: 0.8;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.vp-blog-card__image a {
|
|
56
|
+
display: block;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.vp-blog-card__image img {
|
|
60
|
+
display: block;
|
|
61
|
+
width: 100%;
|
|
62
|
+
aspect-ratio: 16 / 9;
|
|
63
|
+
object-fit: cover;
|
|
64
|
+
object-position: var(--vp-blog-image-position, center);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* `imageFit: contain`: the whole image, letterboxed, for logos and diagrams. */
|
|
68
|
+
.vp-blog-card--contain .vp-blog-card__image {
|
|
69
|
+
background: var(--vp-c-bg-alt);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.vp-blog-card--contain .vp-blog-card__image img {
|
|
73
|
+
box-sizing: border-box;
|
|
74
|
+
padding: 12px 16px;
|
|
75
|
+
object-fit: contain;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.vp-blog-card__body {
|
|
79
|
+
display: flex;
|
|
80
|
+
flex: 1;
|
|
81
|
+
flex-direction: column;
|
|
82
|
+
gap: 8px;
|
|
83
|
+
padding: 16px 20px 20px;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.vp-blog-card__title {
|
|
87
|
+
font-size: 18px;
|
|
88
|
+
font-weight: 600;
|
|
89
|
+
line-height: 1.4;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.vp-blog-card__title a {
|
|
93
|
+
color: var(--vp-c-text-1);
|
|
94
|
+
text-decoration: none;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.vp-blog-card__title a:hover {
|
|
98
|
+
color: var(--vp-blog-accent);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.vp-blog-card__meta,
|
|
102
|
+
.vp-blog-byline {
|
|
103
|
+
color: var(--vp-blog-meta-color);
|
|
104
|
+
font-size: 14px;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.vp-blog-card__summary {
|
|
108
|
+
color: var(--vp-c-text-1);
|
|
109
|
+
font-size: 15px;
|
|
110
|
+
line-height: 1.6;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.vp-blog-card__tags {
|
|
114
|
+
margin-top: auto;
|
|
115
|
+
padding-top: 4px;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* List: image beside the text on wide screens. */
|
|
119
|
+
@media (min-width: 640px) {
|
|
120
|
+
.vp-blog-list--list .vp-blog-card--with-image {
|
|
121
|
+
flex-direction: row;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.vp-blog-list--list .vp-blog-card__image {
|
|
125
|
+
flex: 0 0 34%;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.vp-blog-list--list .vp-blog-card__image a,
|
|
129
|
+
.vp-blog-list--list .vp-blog-card__image p {
|
|
130
|
+
height: 100%;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.vp-blog-list--list .vp-blog-card__image img {
|
|
134
|
+
height: 100%;
|
|
135
|
+
aspect-ratio: auto;
|
|
136
|
+
min-height: 160px;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Compact: a dated list of titles. */
|
|
141
|
+
.vp-blog-list--compact {
|
|
142
|
+
display: block;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.vp-blog-list--compact ul {
|
|
146
|
+
padding-left: 0;
|
|
147
|
+
list-style: none;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.vp-blog-list--compact li {
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-wrap: wrap;
|
|
153
|
+
gap: 4px 16px;
|
|
154
|
+
align-items: baseline;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.vp-blog-list--compact time {
|
|
158
|
+
min-width: 10em;
|
|
159
|
+
color: var(--vp-blog-meta-color);
|
|
160
|
+
font-size: 14px;
|
|
161
|
+
font-variant-numeric: tabular-nums;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.vp-blog-tag,
|
|
165
|
+
.vp-blog-badge,
|
|
166
|
+
.vp-blog-tags a,
|
|
167
|
+
.vp-blog-card__tags a,
|
|
168
|
+
.vp-blog-byline__tags a {
|
|
169
|
+
display: inline-block;
|
|
170
|
+
margin: 2px 4px 2px 0;
|
|
171
|
+
padding: 0 10px;
|
|
172
|
+
border-radius: 999px;
|
|
173
|
+
background: var(--vp-blog-tag-bg);
|
|
174
|
+
color: var(--vp-blog-tag-color);
|
|
175
|
+
font-size: 12px;
|
|
176
|
+
font-weight: 500;
|
|
177
|
+
line-height: 22px;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Keyword chips are links that filter their blog. */
|
|
181
|
+
.vp-blog .vp-blog-tags a,
|
|
182
|
+
.vp-blog .vp-blog-card__tags a,
|
|
183
|
+
.vp-blog-byline__tags a {
|
|
184
|
+
text-decoration: none;
|
|
185
|
+
transition:
|
|
186
|
+
background-color 0.25s,
|
|
187
|
+
color 0.25s;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.vp-blog .vp-blog-tags a:hover,
|
|
191
|
+
.vp-blog .vp-blog-card__tags a:hover,
|
|
192
|
+
.vp-blog-byline__tags a:hover,
|
|
193
|
+
.vp-blog-tags a.is-active,
|
|
194
|
+
.vp-blog-card__tags a.is-active {
|
|
195
|
+
background: var(--vp-c-brand-soft);
|
|
196
|
+
color: var(--vp-blog-accent);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.vp-blog-badge--sticky {
|
|
200
|
+
background: var(--vp-c-brand-soft);
|
|
201
|
+
color: var(--vp-c-brand-1);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.vp-blog-badge--draft {
|
|
205
|
+
background: var(--vp-c-warning-soft);
|
|
206
|
+
color: var(--vp-c-warning-1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.vp-blog-empty {
|
|
210
|
+
color: var(--vp-blog-meta-color);
|
|
211
|
+
font-style: italic;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Post pages. */
|
|
215
|
+
.vp-blog-byline {
|
|
216
|
+
display: flex;
|
|
217
|
+
flex-direction: column;
|
|
218
|
+
gap: 8px;
|
|
219
|
+
margin: 12px 0 24px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.vp-blog-cover img {
|
|
223
|
+
width: 100%;
|
|
224
|
+
border-radius: var(--vp-blog-card-radius);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.vp-blog-post-nav {
|
|
228
|
+
display: grid;
|
|
229
|
+
grid-template-columns: 1fr 1fr;
|
|
230
|
+
gap: 16px;
|
|
231
|
+
margin-top: 48px;
|
|
232
|
+
padding-top: 24px;
|
|
233
|
+
border-top: 1px solid var(--vp-c-divider);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.vp-blog-post-nav__older {
|
|
237
|
+
text-align: right;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.vp-blog-post-nav__label {
|
|
241
|
+
color: var(--vp-blog-meta-color);
|
|
242
|
+
font-size: 13px;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.vp-blog-post-nav__all {
|
|
246
|
+
grid-column: 1 / -1;
|
|
247
|
+
text-align: center;
|
|
248
|
+
font-size: 14px;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
@media (max-width: 639px) {
|
|
252
|
+
.vp-blog-post-nav {
|
|
253
|
+
grid-template-columns: 1fr;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.vp-blog-post-nav__older {
|
|
257
|
+
text-align: left;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* The blog: keyword list, filter banner, pinned posts and page links. */
|
|
262
|
+
.vp-blog {
|
|
263
|
+
scroll-margin-top: calc(var(--vp-nav-height, 64px) + 24px);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.vp-blog-tags {
|
|
267
|
+
margin: 16px 0 8px;
|
|
268
|
+
line-height: 2;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.vp-blog-tags p {
|
|
272
|
+
margin: 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.vp-blog-tags__label {
|
|
276
|
+
margin-right: 8px;
|
|
277
|
+
color: var(--vp-blog-meta-color);
|
|
278
|
+
font-size: 14px;
|
|
279
|
+
font-weight: 600;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* The post count in a keyword pill: a small counter badge inside it. */
|
|
283
|
+
.vp-blog-tags__count {
|
|
284
|
+
display: inline-block;
|
|
285
|
+
min-width: 18px;
|
|
286
|
+
margin-left: 6px;
|
|
287
|
+
padding: 0 6px;
|
|
288
|
+
border-radius: 999px;
|
|
289
|
+
background: var(--vp-c-bg);
|
|
290
|
+
color: var(--vp-c-text-2);
|
|
291
|
+
font-size: 11px;
|
|
292
|
+
font-weight: 600;
|
|
293
|
+
font-variant-numeric: tabular-nums;
|
|
294
|
+
line-height: 16px;
|
|
295
|
+
text-align: center;
|
|
296
|
+
vertical-align: 1px;
|
|
297
|
+
transition:
|
|
298
|
+
background-color 0.25s,
|
|
299
|
+
color 0.25s;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.vp-blog-tags a:hover .vp-blog-tags__count,
|
|
303
|
+
.vp-blog-tags a.is-active .vp-blog-tags__count {
|
|
304
|
+
background: var(--vp-blog-accent);
|
|
305
|
+
/* The page background, so the number stays readable on the accent in light and dark mode. */
|
|
306
|
+
color: var(--vp-c-bg);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.vp-blog-filter {
|
|
310
|
+
margin: 16px 0;
|
|
311
|
+
padding: 10px 16px;
|
|
312
|
+
border-radius: 8px;
|
|
313
|
+
background: var(--vp-c-default-soft);
|
|
314
|
+
font-size: 14px;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.vp-blog-filter__clear {
|
|
318
|
+
margin-left: 8px;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.vp-blog-sticky {
|
|
322
|
+
margin: 24px 0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.vp-blog-sticky .vp-blog-list {
|
|
326
|
+
margin: 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.vp-blog-pagination {
|
|
330
|
+
display: flex;
|
|
331
|
+
flex-wrap: wrap;
|
|
332
|
+
gap: 8px;
|
|
333
|
+
justify-content: center;
|
|
334
|
+
margin: 32px 0 8px;
|
|
335
|
+
font-size: 14px;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.vp-blog-pagination a,
|
|
339
|
+
.vp-blog-pagination span {
|
|
340
|
+
min-width: 36px;
|
|
341
|
+
padding: 6px 12px;
|
|
342
|
+
border: 1px solid var(--vp-blog-card-border);
|
|
343
|
+
border-radius: 8px;
|
|
344
|
+
text-align: center;
|
|
345
|
+
text-decoration: none;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.vp-blog-pagination a:hover {
|
|
349
|
+
border-color: var(--vp-blog-accent);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.vp-blog-pagination .is-current {
|
|
353
|
+
border-color: var(--vp-blog-accent);
|
|
354
|
+
background: var(--vp-c-brand-soft);
|
|
355
|
+
color: var(--vp-blog-accent);
|
|
356
|
+
font-weight: 600;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* `hidden` must win over the display rules above. */
|
|
360
|
+
.vp-blog [hidden] {
|
|
361
|
+
display: none !important;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/* A `::: blog-posts` block on any page: a blog's latest posts and a link to the blog. */
|
|
365
|
+
.vp-blog-widget {
|
|
366
|
+
margin: 16px 0 24px;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.vp-blog-widget .vp-blog-list {
|
|
370
|
+
margin: 0;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* A block's footer: the RSS link on the left, the link to the blog on the right. */
|
|
374
|
+
.vp-blog-widget__footer {
|
|
375
|
+
margin-top: 12px;
|
|
376
|
+
font-size: 15px;
|
|
377
|
+
font-weight: 500;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.vp-blog-widget__footer p {
|
|
381
|
+
display: flex;
|
|
382
|
+
flex-wrap: wrap;
|
|
383
|
+
gap: 8px 16px;
|
|
384
|
+
align-items: center;
|
|
385
|
+
justify-content: flex-end;
|
|
386
|
+
margin: 0;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
.vp-blog-widget__footer .vp-blog-rss {
|
|
390
|
+
margin-right: auto;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* The "Subscribe" RSS link on blog pages and blocks. */
|
|
394
|
+
.vp-blog-subscribe {
|
|
395
|
+
margin: 8px 0;
|
|
396
|
+
text-align: right;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.vp-blog-subscribe p {
|
|
400
|
+
margin: 0;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.vp-blog-rss {
|
|
404
|
+
font-size: 14px;
|
|
405
|
+
font-weight: 500;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.vp-blog-rss a {
|
|
409
|
+
display: inline-flex;
|
|
410
|
+
gap: 6px;
|
|
411
|
+
align-items: center;
|
|
412
|
+
text-decoration: none;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
.vp-blog-rss__icon {
|
|
416
|
+
/* The RSS orange, as feed readers expect. */
|
|
417
|
+
color: #f26522;
|
|
418
|
+
}
|