@binarynoir/vitepress-blog 0.3.0 → 0.4.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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { B as BlogAnnouncementData, a as BlogAnnouncementItem, b as BlogAuthor, c as BlogFeedConfig, d as BlogIndexConfig, e as BlogLabels, f as BlogLayout, g as BlogOptions, h as BlogPostData, i as BlogScope, D as DEFAULT_LABELS, j as blogMarkdown } from './plugin-Bb4rRwO8.cjs';
1
+ export { B as BlogAnnouncementData, a as BlogAnnouncementItem, b as BlogAuthor, c as BlogFeedConfig, d as BlogGroupBy, e as BlogIndexConfig, f as BlogLabels, g as BlogLayout, h as BlogOptions, i as BlogPostData, j as BlogScope, D as DEFAULT_LABELS, k as blogMarkdown } from './plugin-DUTUA_t4.cjs';
2
2
  import 'markdown-it';
3
3
 
4
4
  /** Marker a blog page can use to say where its list of posts goes. Without it the list is appended. */
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { B as BlogAnnouncementData, a as BlogAnnouncementItem, b as BlogAuthor, c as BlogFeedConfig, d as BlogIndexConfig, e as BlogLabels, f as BlogLayout, g as BlogOptions, h as BlogPostData, i as BlogScope, D as DEFAULT_LABELS, j as blogMarkdown } from './plugin-Bb4rRwO8.js';
1
+ export { B as BlogAnnouncementData, a as BlogAnnouncementItem, b as BlogAuthor, c as BlogFeedConfig, d as BlogGroupBy, e as BlogIndexConfig, f as BlogLabels, g as BlogLayout, h as BlogOptions, i as BlogPostData, j as BlogScope, D as DEFAULT_LABELS, k as blogMarkdown } from './plugin-DUTUA_t4.js';
2
2
  import 'markdown-it';
3
3
 
4
4
  /** Marker a blog page can use to say where its list of posts goes. Without it the list is appended. */
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  POST_FRONTMATTER_KEY,
6
6
  WIDGET_NAME,
7
7
  blogMarkdown
8
- } from "./chunk-LYTJBMVK.js";
8
+ } from "./chunk-ZM5FOUT4.js";
9
9
  import "./chunk-42Z6H7IN.js";
10
10
  export {
11
11
  BLOG_POSTS_PLACEHOLDER,
@@ -64,10 +64,12 @@ interface BlogOptions {
64
64
  */
65
65
  pageSize?: number;
66
66
  /**
67
- * Most sticky posts pinned to the top of a blog page, for those that don't
68
- * set `stickyLimit`. Extra sticky posts take their place by date. `0` pins
69
- * them all. Default: `0`.
67
+ * Most `pinned: true` posts kept at the top of a blog page, for those that
68
+ * don't set `pinLimit`. Extra pinned posts take their place by date. `0`
69
+ * pins them all. Default: `0`.
70
70
  */
71
+ pinLimit?: number;
72
+ /** @deprecated Renamed `pinLimit`; still read when `pinLimit` isn't set. */
71
73
  stickyLimit?: number;
72
74
  /**
73
75
  * Show a "Subscribe" RSS link on blog pages and `::: blog-posts` blocks,
@@ -75,7 +77,7 @@ interface BlogOptions {
75
77
  * on a site with a site URL (without one, no feeds are written). Default: `true`.
76
78
  */
77
79
  rssLink?: boolean;
78
- /** Words the plugin writes on pages, for translating. `{n}`, `{blog}` and `{tag}` are filled in. */
80
+ /** Words the plugin writes on pages, for translating. `{n}`, `{blog}` and `{filter}` are filled in. */
79
81
  labels?: Partial<BlogLabels>;
80
82
  }
81
83
  interface BlogLabels {
@@ -94,29 +96,41 @@ interface BlogLabels {
94
96
  /** The link back to a post's blog: "All posts in {blog}". */
95
97
  allPosts: string;
96
98
  draft: string;
97
- /** Badge on a sticky post. */
98
- sticky: string;
99
+ /** Badge on a pinned post. */
100
+ pinned: string;
99
101
  /** Badge on an announcement, and the accessible name of the announcement banner. */
100
102
  announcement: string;
101
- /** Above a blog page filtered to announcements (`?announcements`). */
103
+ /** A blog page's announcements filter (`?announcements`), in the active filters. */
102
104
  announcements: string;
103
- /** When the blog page has no announcements to show. */
104
- noAnnouncements: string;
105
105
  /** Tooltip of the banner's count badge: "{n} announcements". */
106
106
  announcementCount: string;
107
107
  /** Accessible name of the banner's close button. */
108
108
  dismiss: string;
109
109
  noPosts: string;
110
- /** Year heading for posts without a date, when a blog groups by year. */
110
+ /** Group heading for posts without a date, when a blog groups by year or month. */
111
111
  undated: string;
112
- /** Label of a blog page's keyword list. */
112
+ /** Accessible name of the browse panel above a blog page's posts. */
113
+ browse: string;
114
+ /** Label of the browse panel's category row. */
115
+ categories: string;
116
+ /** Label of the browse panel's keyword row. */
113
117
  tags: string;
114
- /** Above a list filtered by keyword: "Posts tagged {tag}". */
115
- tagged: string;
116
- /** Link that clears the keyword filter. */
118
+ /** Label of the browse panel's year row. */
119
+ archive: string;
120
+ /** Names a category filter among the active filters: "Category". */
121
+ category: string;
122
+ /** Names a keyword filter among the active filters: "Keyword". */
123
+ tag: string;
124
+ /** How many posts the active filters match: "{n} posts". */
125
+ postCount: string;
126
+ /** The same, for one post: "{n} post". */
127
+ postCountOne: string;
128
+ /** When no post matches the active filters. */
129
+ noMatches: string;
130
+ /** Accessible name of an active filter's remove link: "Remove filter: {filter}". */
131
+ removeFilter: string;
132
+ /** Link that clears every filter. */
117
133
  showAll: string;
118
- /** When no post has the keyword: "No posts tagged {tag}." */
119
- noTagged: string;
120
134
  previous: string;
121
135
  next: string;
122
136
  /** Accessible name of the page links. */
@@ -129,6 +143,8 @@ interface BlogLabels {
129
143
  declare const DEFAULT_LABELS: BlogLabels;
130
144
  type BlogScope = 'site' | 'section';
131
145
  type BlogLayout = 'list' | 'grid' | 'compact';
146
+ /** How a blog page groups its posts under headings: by year, by month, or not at all (`''`). */
147
+ type BlogGroupBy = 'year' | 'month' | '';
132
148
  interface BlogFeedConfig {
133
149
  title?: string;
134
150
  description?: string;
@@ -144,19 +160,27 @@ interface BlogIndexConfig {
144
160
  folders: string[];
145
161
  /** Only list posts with at least one of these tags. */
146
162
  tags: string[];
163
+ /** Only list posts in one of these categories. */
164
+ categories: string[];
147
165
  /** Most posts to list. `0` lists them all. */
148
166
  limit: number;
149
167
  layout: BlogLayout;
150
- /** Put a year heading above each year's posts. */
151
- groupByYear: boolean;
168
+ /** Put a heading above each year's or month's posts. */
169
+ groupBy: BlogGroupBy;
152
170
  /** Show the post's tags on each card. */
153
171
  showTags: boolean;
172
+ /** Show the post's category above its title on each card. */
173
+ showCategory: boolean;
174
+ /** List every category above the posts, each one a filter. */
175
+ categoryList: boolean;
154
176
  /** List every keyword above the posts, each one a filter. */
155
177
  tagList: boolean;
178
+ /** List the years and months that have posts above the posts, each one a filter. */
179
+ archive: boolean;
156
180
  /** Posts per page. `0` shows them all on one page. */
157
181
  pageSize: number;
158
- /** Most sticky posts pinned to the top. `0` pins them all. */
159
- stickyLimit: number;
182
+ /** Most pinned posts kept at the top. `0` pins them all. */
183
+ pinLimit: number;
160
184
  /** Show a "Subscribe" link to the blog's feed. */
161
185
  rssLink: boolean;
162
186
  feed: BlogFeedConfig | null;
@@ -184,7 +208,7 @@ interface BlogPostData {
184
208
  tags: string[];
185
209
  category: string;
186
210
  scope: BlogScope;
187
- sticky: boolean;
211
+ pinned: boolean;
188
212
  draft: boolean;
189
213
  /** Shown in the announcement banner above the nav bar. */
190
214
  announcement: boolean;
@@ -240,4 +264,4 @@ interface BlogAnnouncementData {
240
264
  */
241
265
  declare function blogMarkdown(md: MarkdownIt, options?: BlogOptions): void;
242
266
 
243
- export { type BlogAnnouncementData as B, DEFAULT_LABELS as D, type BlogAnnouncementItem as a, type BlogAuthor as b, type BlogFeedConfig as c, type BlogIndexConfig as d, type BlogLabels as e, type BlogLayout as f, type BlogOptions as g, type BlogPostData as h, type BlogScope as i, blogMarkdown as j };
267
+ export { type BlogAnnouncementData as B, DEFAULT_LABELS as D, type BlogAnnouncementItem as a, type BlogAuthor as b, type BlogFeedConfig as c, type BlogGroupBy as d, type BlogIndexConfig as e, type BlogLabels as f, type BlogLayout as g, type BlogOptions as h, type BlogPostData as i, type BlogScope as j, blogMarkdown as k };
@@ -64,10 +64,12 @@ interface BlogOptions {
64
64
  */
65
65
  pageSize?: number;
66
66
  /**
67
- * Most sticky posts pinned to the top of a blog page, for those that don't
68
- * set `stickyLimit`. Extra sticky posts take their place by date. `0` pins
69
- * them all. Default: `0`.
67
+ * Most `pinned: true` posts kept at the top of a blog page, for those that
68
+ * don't set `pinLimit`. Extra pinned posts take their place by date. `0`
69
+ * pins them all. Default: `0`.
70
70
  */
71
+ pinLimit?: number;
72
+ /** @deprecated Renamed `pinLimit`; still read when `pinLimit` isn't set. */
71
73
  stickyLimit?: number;
72
74
  /**
73
75
  * Show a "Subscribe" RSS link on blog pages and `::: blog-posts` blocks,
@@ -75,7 +77,7 @@ interface BlogOptions {
75
77
  * on a site with a site URL (without one, no feeds are written). Default: `true`.
76
78
  */
77
79
  rssLink?: boolean;
78
- /** Words the plugin writes on pages, for translating. `{n}`, `{blog}` and `{tag}` are filled in. */
80
+ /** Words the plugin writes on pages, for translating. `{n}`, `{blog}` and `{filter}` are filled in. */
79
81
  labels?: Partial<BlogLabels>;
80
82
  }
81
83
  interface BlogLabels {
@@ -94,29 +96,41 @@ interface BlogLabels {
94
96
  /** The link back to a post's blog: "All posts in {blog}". */
95
97
  allPosts: string;
96
98
  draft: string;
97
- /** Badge on a sticky post. */
98
- sticky: string;
99
+ /** Badge on a pinned post. */
100
+ pinned: string;
99
101
  /** Badge on an announcement, and the accessible name of the announcement banner. */
100
102
  announcement: string;
101
- /** Above a blog page filtered to announcements (`?announcements`). */
103
+ /** A blog page's announcements filter (`?announcements`), in the active filters. */
102
104
  announcements: string;
103
- /** When the blog page has no announcements to show. */
104
- noAnnouncements: string;
105
105
  /** Tooltip of the banner's count badge: "{n} announcements". */
106
106
  announcementCount: string;
107
107
  /** Accessible name of the banner's close button. */
108
108
  dismiss: string;
109
109
  noPosts: string;
110
- /** Year heading for posts without a date, when a blog groups by year. */
110
+ /** Group heading for posts without a date, when a blog groups by year or month. */
111
111
  undated: string;
112
- /** Label of a blog page's keyword list. */
112
+ /** Accessible name of the browse panel above a blog page's posts. */
113
+ browse: string;
114
+ /** Label of the browse panel's category row. */
115
+ categories: string;
116
+ /** Label of the browse panel's keyword row. */
113
117
  tags: string;
114
- /** Above a list filtered by keyword: "Posts tagged {tag}". */
115
- tagged: string;
116
- /** Link that clears the keyword filter. */
118
+ /** Label of the browse panel's year row. */
119
+ archive: string;
120
+ /** Names a category filter among the active filters: "Category". */
121
+ category: string;
122
+ /** Names a keyword filter among the active filters: "Keyword". */
123
+ tag: string;
124
+ /** How many posts the active filters match: "{n} posts". */
125
+ postCount: string;
126
+ /** The same, for one post: "{n} post". */
127
+ postCountOne: string;
128
+ /** When no post matches the active filters. */
129
+ noMatches: string;
130
+ /** Accessible name of an active filter's remove link: "Remove filter: {filter}". */
131
+ removeFilter: string;
132
+ /** Link that clears every filter. */
117
133
  showAll: string;
118
- /** When no post has the keyword: "No posts tagged {tag}." */
119
- noTagged: string;
120
134
  previous: string;
121
135
  next: string;
122
136
  /** Accessible name of the page links. */
@@ -129,6 +143,8 @@ interface BlogLabels {
129
143
  declare const DEFAULT_LABELS: BlogLabels;
130
144
  type BlogScope = 'site' | 'section';
131
145
  type BlogLayout = 'list' | 'grid' | 'compact';
146
+ /** How a blog page groups its posts under headings: by year, by month, or not at all (`''`). */
147
+ type BlogGroupBy = 'year' | 'month' | '';
132
148
  interface BlogFeedConfig {
133
149
  title?: string;
134
150
  description?: string;
@@ -144,19 +160,27 @@ interface BlogIndexConfig {
144
160
  folders: string[];
145
161
  /** Only list posts with at least one of these tags. */
146
162
  tags: string[];
163
+ /** Only list posts in one of these categories. */
164
+ categories: string[];
147
165
  /** Most posts to list. `0` lists them all. */
148
166
  limit: number;
149
167
  layout: BlogLayout;
150
- /** Put a year heading above each year's posts. */
151
- groupByYear: boolean;
168
+ /** Put a heading above each year's or month's posts. */
169
+ groupBy: BlogGroupBy;
152
170
  /** Show the post's tags on each card. */
153
171
  showTags: boolean;
172
+ /** Show the post's category above its title on each card. */
173
+ showCategory: boolean;
174
+ /** List every category above the posts, each one a filter. */
175
+ categoryList: boolean;
154
176
  /** List every keyword above the posts, each one a filter. */
155
177
  tagList: boolean;
178
+ /** List the years and months that have posts above the posts, each one a filter. */
179
+ archive: boolean;
156
180
  /** Posts per page. `0` shows them all on one page. */
157
181
  pageSize: number;
158
- /** Most sticky posts pinned to the top. `0` pins them all. */
159
- stickyLimit: number;
182
+ /** Most pinned posts kept at the top. `0` pins them all. */
183
+ pinLimit: number;
160
184
  /** Show a "Subscribe" link to the blog's feed. */
161
185
  rssLink: boolean;
162
186
  feed: BlogFeedConfig | null;
@@ -184,7 +208,7 @@ interface BlogPostData {
184
208
  tags: string[];
185
209
  category: string;
186
210
  scope: BlogScope;
187
- sticky: boolean;
211
+ pinned: boolean;
188
212
  draft: boolean;
189
213
  /** Shown in the announcement banner above the nav bar. */
190
214
  announcement: boolean;
@@ -240,4 +264,4 @@ interface BlogAnnouncementData {
240
264
  */
241
265
  declare function blogMarkdown(md: MarkdownIt, options?: BlogOptions): void;
242
266
 
243
- export { type BlogAnnouncementData as B, DEFAULT_LABELS as D, type BlogAnnouncementItem as a, type BlogAuthor as b, type BlogFeedConfig as c, type BlogIndexConfig as d, type BlogLabels as e, type BlogLayout as f, type BlogOptions as g, type BlogPostData as h, type BlogScope as i, blogMarkdown as j };
267
+ export { type BlogAnnouncementData as B, DEFAULT_LABELS as D, type BlogAnnouncementItem as a, type BlogAuthor as b, type BlogFeedConfig as c, type BlogGroupBy as d, type BlogIndexConfig as e, type BlogLabels as f, type BlogLayout as g, type BlogOptions as h, type BlogPostData as i, type BlogScope as j, blogMarkdown as k };
package/dist/style.css CHANGED
@@ -10,6 +10,9 @@
10
10
  --vp-blog-tag-bg: var(--vp-c-default-soft);
11
11
  --vp-blog-tag-color: var(--vp-c-text-2);
12
12
  --vp-blog-accent: var(--vp-c-brand-1);
13
+ --vp-blog-browse-bg: var(--vp-c-bg-soft);
14
+ /* Width of the label column in the browse panel, so every row's chips line up. */
15
+ --vp-blog-facet-label-width: 6.5rem;
13
16
  --vp-blog-announcement-height: 40px;
14
17
  --vp-blog-announcement-bg: var(--vp-button-brand-bg);
15
18
  --vp-blog-announcement-color: var(--vp-button-brand-text);
@@ -46,7 +49,7 @@
46
49
  border-color: var(--vp-blog-accent);
47
50
  }
48
51
 
49
- .vp-blog-card--sticky {
52
+ .vp-blog-card--pinned {
50
53
  border-color: var(--vp-blog-accent);
51
54
  }
52
55
 
@@ -86,6 +89,28 @@
86
89
  padding: 16px 20px 20px;
87
90
  }
88
91
 
92
+ /* The category, above the title: a small linked eyebrow. */
93
+ .vp-blog-card__category {
94
+ margin-bottom: -4px;
95
+ font-size: 12px;
96
+ font-weight: 600;
97
+ letter-spacing: 0.06em;
98
+ line-height: 1.4;
99
+ text-transform: uppercase;
100
+ }
101
+
102
+ .vp-blog-card .vp-blog-card__category a {
103
+ color: var(--vp-blog-accent);
104
+ font-weight: 600;
105
+ text-decoration: none;
106
+ }
107
+
108
+ .vp-blog-card .vp-blog-card__category a:hover,
109
+ .vp-blog-card .vp-blog-card__category a.is-active {
110
+ text-decoration: underline;
111
+ text-underline-offset: 3px;
112
+ }
113
+
89
114
  .vp-blog-card__title {
90
115
  font-size: 18px;
91
116
  font-weight: 600;
@@ -165,9 +190,11 @@
165
190
  }
166
191
 
167
192
  .vp-blog-tag,
193
+ .vp-blog-category,
168
194
  .vp-blog-badge,
169
- .vp-blog-tags a,
195
+ .vp-blog-facet a,
170
196
  .vp-blog-card__tags a,
197
+ .vp-blog-byline__category a,
171
198
  .vp-blog-byline__tags a {
172
199
  display: inline-block;
173
200
  margin: 2px 4px 2px 0;
@@ -180,26 +207,37 @@
180
207
  line-height: 22px;
181
208
  }
182
209
 
183
- /* Keyword chips are links that filter their blog. */
184
- .vp-blog .vp-blog-tags a,
210
+ /* Chips are links that filter their blog. */
211
+ .vp-blog .vp-blog-facet a,
185
212
  .vp-blog .vp-blog-card__tags a,
213
+ .vp-blog-byline__category a,
186
214
  .vp-blog-byline__tags a {
187
215
  text-decoration: none;
188
216
  transition:
189
217
  background-color 0.25s,
190
- color 0.25s;
218
+ color 0.25s,
219
+ opacity 0.25s;
191
220
  }
192
221
 
193
- .vp-blog .vp-blog-tags a:hover,
222
+ .vp-blog .vp-blog-facet a:hover,
194
223
  .vp-blog .vp-blog-card__tags a:hover,
224
+ .vp-blog-byline__category a:hover,
195
225
  .vp-blog-byline__tags a:hover,
196
- .vp-blog-tags a.is-active,
197
- .vp-blog-card__tags a.is-active {
226
+ .vp-blog .vp-blog-facet a.is-active,
227
+ .vp-blog .vp-blog-card__tags a.is-active {
198
228
  background: var(--vp-c-brand-soft);
199
229
  color: var(--vp-blog-accent);
200
230
  }
201
231
 
202
- .vp-blog-badge--sticky {
232
+ /* A post's category in its byline: a chip in the accent, ahead of its keywords. */
233
+ .vp-blog-category,
234
+ .vp-blog-byline__category a {
235
+ background: var(--vp-c-brand-soft);
236
+ color: var(--vp-blog-accent);
237
+ font-weight: 600;
238
+ }
239
+
240
+ .vp-blog-badge--pinned {
203
241
  background: var(--vp-c-brand-soft);
204
242
  color: var(--vp-c-brand-1);
205
243
  }
@@ -266,29 +304,53 @@
266
304
  }
267
305
  }
268
306
 
269
- /* The blog: keyword list, filter banner, pinned posts and page links. */
307
+ /* The blog: browse panel, active filters, pinned posts and page links. */
270
308
  .vp-blog {
271
309
  scroll-margin-top: calc(var(--vp-nav-height, 64px) + 24px);
272
310
  }
273
311
 
274
- .vp-blog-tags {
275
- margin: 16px 0 8px;
276
- line-height: 2;
312
+ /*
313
+ * The browse panel: one row each for categories, keywords and years, and the
314
+ * months of the year in view below the years. Labels sit in a column of their
315
+ * own on wide screens, above their chips on narrow ones.
316
+ */
317
+ .vp-blog-browse {
318
+ display: flex;
319
+ flex-direction: column;
320
+ gap: 10px;
321
+ margin: 16px 0;
322
+ padding: 14px 16px;
323
+ border: 1px solid var(--vp-blog-card-border);
324
+ border-radius: var(--vp-blog-card-radius);
325
+ background: var(--vp-blog-browse-bg);
277
326
  }
278
327
 
279
- .vp-blog-tags p {
280
- margin: 0;
328
+ .vp-blog-facet {
329
+ display: grid;
330
+ grid-template-columns: var(--vp-blog-facet-label-width) minmax(0, 1fr);
331
+ gap: 2px 12px;
332
+ align-items: baseline;
281
333
  }
282
334
 
283
- .vp-blog-tags__label {
284
- margin-right: 8px;
335
+ .vp-blog-facet__label {
285
336
  color: var(--vp-blog-meta-color);
286
- font-size: 14px;
337
+ font-size: 13px;
287
338
  font-weight: 600;
339
+ line-height: 26px;
340
+ }
341
+
342
+ /* A year's months: tucked under the years, their label the year. */
343
+ .vp-blog-facet--month .vp-blog-facet__label {
344
+ font-variant-numeric: tabular-nums;
345
+ font-weight: 500;
288
346
  }
289
347
 
290
- /* The post count in a keyword pill: a small counter badge inside it. */
291
- .vp-blog-tags__count {
348
+ .vp-blog-facet__chips p {
349
+ margin: 0;
350
+ }
351
+
352
+ /* The post count in a chip: a small counter badge inside it. */
353
+ .vp-blog-facet__count {
292
354
  display: inline-block;
293
355
  min-width: 18px;
294
356
  margin-left: 6px;
@@ -307,14 +369,38 @@
307
369
  color 0.25s;
308
370
  }
309
371
 
310
- .vp-blog-tags a:hover .vp-blog-tags__count,
311
- .vp-blog-tags a.is-active .vp-blog-tags__count {
372
+ .vp-blog-facet a:hover .vp-blog-facet__count,
373
+ .vp-blog-facet a.is-active .vp-blog-facet__count {
312
374
  background: var(--vp-blog-accent);
313
375
  /* The page background, so the number stays readable on the accent in light and dark mode. */
314
376
  color: var(--vp-c-bg);
315
377
  }
316
378
 
379
+ /* A chip that would show no posts with the other filters kept. */
380
+ .vp-blog .vp-blog-facet a.is-empty {
381
+ opacity: 0.45;
382
+ }
383
+
384
+ .vp-blog .vp-blog-facet a.is-empty:hover {
385
+ opacity: 0.8;
386
+ }
387
+
388
+ @media (max-width: 639px) {
389
+ .vp-blog-facet {
390
+ grid-template-columns: minmax(0, 1fr);
391
+ }
392
+
393
+ .vp-blog-facet__label {
394
+ line-height: 20px;
395
+ }
396
+ }
397
+
398
+ /* The active filters: how many posts match, a removable chip for each filter, and a link to clear them all. */
317
399
  .vp-blog-filter {
400
+ display: flex;
401
+ flex-wrap: wrap;
402
+ gap: 8px;
403
+ align-items: center;
318
404
  margin: 16px 0;
319
405
  padding: 10px 16px;
320
406
  border-radius: 8px;
@@ -322,15 +408,61 @@
322
408
  font-size: 14px;
323
409
  }
324
410
 
411
+ .vp-blog-filter__count {
412
+ margin-right: 4px;
413
+ color: var(--vp-c-text-1);
414
+ font-weight: 600;
415
+ }
416
+
417
+ .vp-blog .vp-blog-filter__chip {
418
+ display: inline-flex;
419
+ gap: 4px;
420
+ align-items: center;
421
+ padding: 0 4px 0 10px;
422
+ border: 1px solid var(--vp-blog-accent);
423
+ border-radius: 999px;
424
+ background: var(--vp-c-bg);
425
+ color: var(--vp-c-text-1);
426
+ font-size: 13px;
427
+ font-weight: 500;
428
+ line-height: 24px;
429
+ text-decoration: none;
430
+ }
431
+
432
+ .vp-blog-filter__kind {
433
+ color: var(--vp-blog-meta-color);
434
+ font-weight: 400;
435
+ }
436
+
437
+ .vp-blog-filter__remove {
438
+ display: inline-flex;
439
+ align-items: center;
440
+ justify-content: center;
441
+ width: 18px;
442
+ height: 18px;
443
+ border-radius: 50%;
444
+ color: var(--vp-blog-meta-color);
445
+ font-size: 14px;
446
+ line-height: 1;
447
+ transition:
448
+ background-color 0.25s,
449
+ color 0.25s;
450
+ }
451
+
452
+ .vp-blog .vp-blog-filter__chip:hover .vp-blog-filter__remove {
453
+ background: var(--vp-c-brand-soft);
454
+ color: var(--vp-blog-accent);
455
+ }
456
+
325
457
  .vp-blog-filter__clear {
326
- margin-left: 8px;
458
+ margin-left: auto;
327
459
  }
328
460
 
329
- .vp-blog-sticky {
461
+ .vp-blog-pinned {
330
462
  margin: 24px 0;
331
463
  }
332
464
 
333
- .vp-blog-sticky .vp-blog-list {
465
+ .vp-blog-pinned .vp-blog-list {
334
466
  margin: 0;
335
467
  }
336
468