@riebeckite/plugin-series 0.0.15 → 0.0.17
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 +33 -3
- package/README_ja.md +24 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +130 -8
- package/dist/src/series.d.ts +4 -0
- package/dist/src/types.d.ts +2 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -14,6 +14,10 @@ to each note in the series. Links use the permalinks resolved by Core, so
|
|
|
14
14
|
plugins such as `permalink` are respected. A single-note series renders no
|
|
15
15
|
navigation block.
|
|
16
16
|
|
|
17
|
+
The plugin also declares page types, so it exposes a list page at `/series`
|
|
18
|
+
and one landing page per series at `/series/<name>`. Both are built from the
|
|
19
|
+
discoverable manifest, so unlisted, draft, and scheduled notes never appear.
|
|
20
|
+
|
|
17
21
|
The plugin is build-time only: it ships a stylesheet asset and no client
|
|
18
22
|
runtime.
|
|
19
23
|
|
|
@@ -59,6 +63,7 @@ the numbered parts, using `date`/`created`/`published`, then `title`, then
|
|
|
59
63
|
| `heading` | `boolean` | `true` | Render the series heading above the list. |
|
|
60
64
|
| `className` | `string` | `"rb-series"` | Base CSS class for generated markup. |
|
|
61
65
|
| `positionLabel` | `boolean` | `false` | Add a `Part N of M` label for the current note. |
|
|
66
|
+
| `basePath` | `string` | `"/series"` | Base path for the generated pages. An empty string disables them. |
|
|
62
67
|
|
|
63
68
|
## Output
|
|
64
69
|
|
|
@@ -91,6 +96,20 @@ All text and attributes are escaped. The injected HTML is written back to both
|
|
|
91
96
|
the manifest entry and the processed content object so the page route, feeds,
|
|
92
97
|
and search see the same markup.
|
|
93
98
|
|
|
99
|
+
## Page types
|
|
100
|
+
|
|
101
|
+
The plugin registers two page types. Both derive their output from
|
|
102
|
+
`manifest.discoverableEntries`, so non-public notes are excluded.
|
|
103
|
+
|
|
104
|
+
| Page type | Path | Output |
|
|
105
|
+
| --------- | ---- | ------ |
|
|
106
|
+
| `series-list` | `<basePath>` (`/series`) | `<section class="rb-series rb-series--list">` listing each series with a link to its landing page. Generated only when at least one series exists. |
|
|
107
|
+
| `series-index` | `<basePath>/<name>` (`/series/<name>`) | The `renderSeriesIndex()` section for one series, in the existing order. |
|
|
108
|
+
|
|
109
|
+
The `<name>` segment is a lowercase, hyphenated slug; non-ASCII names fall back
|
|
110
|
+
to percent-encoding. Set `basePath` to match a custom routing scheme, or pass
|
|
111
|
+
`basePath: ""` to disable the pages and render them yourself.
|
|
112
|
+
|
|
94
113
|
## Exports
|
|
95
114
|
|
|
96
115
|
- `series(options?)` / `seriesPlugin(options?)` — plugin factory
|
|
@@ -98,14 +117,23 @@ and search see the same markup.
|
|
|
98
117
|
(`SeriesIndex | null`); useful for landing pages
|
|
99
118
|
- `renderSeriesIndex(manifest, name, options?)` — standalone `<section>` block
|
|
100
119
|
for a whole series
|
|
120
|
+
- `renderSeriesList(manifest, options?, label?)` — standalone `<section>` block
|
|
121
|
+
listing every series; returns `""` when there are none
|
|
122
|
+
- `seriesLandingPath(name, options?)` — landing path for a series, or `""` when
|
|
123
|
+
the pages are disabled
|
|
124
|
+
- `seriesSlug(name)` — URL segment used by a series landing page
|
|
101
125
|
- `renderSeriesNavigation(index, currentSlug, options?)` — a single navigation
|
|
102
126
|
block
|
|
103
127
|
- `collectSeriesIndexes(manifest, options?)` — every series in first-seen order
|
|
104
128
|
- `resolveSeriesOptions(options?)` — options with defaults applied
|
|
129
|
+
- `DEFAULT_SERIES_BASE_PATH` — default `basePath` (`"/series"`)
|
|
105
130
|
- Types: `SeriesOptions`, `ResolvedSeriesOptions`, `SeriesMember`, `SeriesIndex`
|
|
106
131
|
|
|
107
132
|
### Series landing page
|
|
108
133
|
|
|
134
|
+
The plugin generates these pages automatically. To render them yourself, or to
|
|
135
|
+
reuse the markup elsewhere, combine the exported helpers:
|
|
136
|
+
|
|
109
137
|
```ts
|
|
110
138
|
import { buildSeriesIndex, renderSeriesIndex } from "@riebeckite/plugin-series";
|
|
111
139
|
|
|
@@ -134,10 +162,12 @@ matched with `.rb-series__item a[aria-current="page"]`.
|
|
|
134
162
|
## Limitations
|
|
135
163
|
|
|
136
164
|
- A note belongs to exactly one series.
|
|
137
|
-
- A series of one note produces no navigation block
|
|
165
|
+
- A series of one note produces no navigation block on the note, but it still
|
|
166
|
+
gets a list entry and a landing page.
|
|
138
167
|
- `series_order` must be a finite number; numeric strings are not coerced.
|
|
139
|
-
-
|
|
140
|
-
|
|
168
|
+
- Series names that slugify to the same segment share the first landing page.
|
|
169
|
+
- Generated pages use `/series` by default; change `basePath` to avoid clashes
|
|
170
|
+
with existing routes.
|
|
141
171
|
|
|
142
172
|
## See also
|
|
143
173
|
|
package/README_ja.md
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
`series()` は frontmatter からシリーズ情報を読み取り、該当するノートをグループ化して並べ替えたうえで、各ノートの HTML に `<nav class="rb-series">` ブロックを追加します。リンクには Core が解決したパーマリンクを使うため、`permalink` プラグインなどとも併用できます。1 件だけのシリーズにはナビゲーションを出力しません。
|
|
10
10
|
|
|
11
|
+
また page type を登録し、一覧ページを `/series`、シリーズごとのランディングページを `/series/<name>` に生成します。どちらも公開対象(discoverable)の manifest から組み立てるため、非公開・下書き・予約投稿のノートは現れません。
|
|
12
|
+
|
|
11
13
|
このプラグインはビルド時のみ動作し、クライアント用のランタイムは持ちません(スタイルシートのみを登録します)。
|
|
12
14
|
|
|
13
15
|
## 設定する
|
|
@@ -50,6 +52,7 @@ series_order: 2
|
|
|
50
52
|
| `heading` | `boolean` | `true` | リストの上に見出しを表示する。 |
|
|
51
53
|
| `className` | `string` | `"rb-series"` | 生成する HTML の基準クラス名。 |
|
|
52
54
|
| `positionLabel` | `boolean` | `false` | 現在の記事に「Part N of M」を付ける。 |
|
|
55
|
+
| `basePath` | `string` | `"/series"` | 生成するページの基準パス。空文字にすると生成しない。 |
|
|
53
56
|
|
|
54
57
|
## 出力
|
|
55
58
|
|
|
@@ -79,18 +82,36 @@ series_order: 2
|
|
|
79
82
|
|
|
80
83
|
テキストと属性はすべてエスケープします。生成した HTML は manifest の entry と処理済みコンテンツの両方へ書き戻すため、ページのルート表示・フィード・検索でも同じマークアップになります。
|
|
81
84
|
|
|
85
|
+
## ページタイプ
|
|
86
|
+
|
|
87
|
+
プラグインは 2 つの page type を登録します。どちらも `manifest.discoverableEntries` から組み立てるため、非公開のノートは含まれません。
|
|
88
|
+
|
|
89
|
+
| page type | パス | 出力 |
|
|
90
|
+
| --------- | ---- | ---- |
|
|
91
|
+
| `series-list` | `<basePath>`(`/series`) | 各シリーズをランディングページへのリンク付きで並べた `<section class="rb-series rb-series--list">`。シリーズが 1 つ以上あるときだけ生成。 |
|
|
92
|
+
| `series-index` | `<basePath>/<name>`(`/series/<name>`) | 1 つのシリーズの `renderSeriesIndex()` セクション。既存の並び順をそのまま使う。 |
|
|
93
|
+
|
|
94
|
+
`<name>` は小文字化・ハイフン化したスラッグです。ASCII 以外の名前はパーセントエンコードにフォールバックします。`basePath` をカスタムルーティングに合わせて変更でき、`basePath: ""` で生成を止めて自前で描画できます。
|
|
95
|
+
|
|
82
96
|
## 公開 API
|
|
83
97
|
|
|
84
98
|
- `series(options?)` / `seriesPlugin(options?)` — プラグインファクトリ
|
|
85
99
|
- `buildSeriesIndex(manifest, name, options?)` — 1 つのシリーズの並び順付きメンバー(`SeriesIndex | null`)。ランディングページ向け
|
|
86
100
|
- `renderSeriesIndex(manifest, name, options?)` — シリーズ全体の `<section>` ブロック
|
|
101
|
+
- `renderSeriesList(manifest, options?, label?)` — 全シリーズを並べた `<section>` ブロック。無ければ `""`
|
|
102
|
+
- `seriesLandingPath(name, options?)` — シリーズのランディングパス。生成無効時は `""`
|
|
103
|
+
- `seriesSlug(name)` — ランディングページの URL セグメント
|
|
87
104
|
- `renderSeriesNavigation(index, currentSlug, options?)` — ナビゲーション 1 つ分
|
|
88
105
|
- `collectSeriesIndexes(manifest, options?)` — 全シリーズを出現順で取得
|
|
89
106
|
- `resolveSeriesOptions(options?)` — 既定値を適用したオプション
|
|
107
|
+
- `DEFAULT_SERIES_BASE_PATH` — 既定の `basePath`(`"/series"`)
|
|
90
108
|
- 型: `SeriesOptions`, `ResolvedSeriesOptions`, `SeriesMember`, `SeriesIndex`
|
|
91
109
|
|
|
92
110
|
### シリーズのランディングページ
|
|
93
111
|
|
|
112
|
+
これらのページはプラグインが自動生成します。自前で描画したい場合や別の場所で
|
|
113
|
+
マークアップを再利用したい場合は、公開ヘルパーを組み合わせます。
|
|
114
|
+
|
|
94
115
|
```ts
|
|
95
116
|
import { buildSeriesIndex, renderSeriesIndex } from "@riebeckite/plugin-series";
|
|
96
117
|
|
|
@@ -116,9 +137,10 @@ const html = renderSeriesIndex(manifest, "何かを作る");
|
|
|
116
137
|
## 制限
|
|
117
138
|
|
|
118
139
|
- 1 つのノートが所属できるシリーズは 1 つだけです。
|
|
119
|
-
- 1
|
|
140
|
+
- 1 件だけのシリーズにはナビゲーションを出力しませんが、一覧の項目とランディングページは生成します。
|
|
120
141
|
- `series_order` は有限の数値である必要があります。数値文字列は変換しません。
|
|
121
|
-
-
|
|
142
|
+
- スラッグが同じになるシリーズ名は、最初のランディングページを共有します。
|
|
143
|
+
- 生成ページは既定で `/series` を使います。既存ルートと衝突する場合は `basePath` を変更してください。
|
|
122
144
|
|
|
123
145
|
## 関連
|
|
124
146
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolveSeriesOptions } from "./src/series.js";
|
|
2
2
|
import type { SeriesOptions } from "./src/types.js";
|
|
3
|
-
export { buildSeriesIndex, collectSeriesIndexes, renderSeriesIndex, renderSeriesNavigation, } from "./src/series.js";
|
|
3
|
+
export { buildSeriesIndex, collectSeriesIndexes, DEFAULT_SERIES_BASE_PATH, renderSeriesIndex, renderSeriesList, renderSeriesNavigation, seriesLandingPath, seriesSlug, } from "./src/series.js";
|
|
4
4
|
export type { ResolvedSeriesOptions, SeriesIndex, SeriesMember, SeriesOptions, } from "./src/types.js";
|
|
5
5
|
/**
|
|
6
6
|
* Series (ordered multi-part posts) for Riebeckite.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// index.ts
|
|
2
2
|
import {
|
|
3
|
+
appendContentBodySlot,
|
|
3
4
|
createStyleAsset,
|
|
4
5
|
definePlugin
|
|
5
6
|
} from "@riebeckite/core";
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
escapeHtmlAttribute
|
|
11
12
|
} from "@riebeckite/core";
|
|
12
13
|
var DEFAULT_SERIES_CLASS_NAME = "rb-series";
|
|
14
|
+
var DEFAULT_SERIES_BASE_PATH = "/series";
|
|
13
15
|
function resolveSeriesOptions(options = {}) {
|
|
14
16
|
return {
|
|
15
17
|
key: options.key ?? "series",
|
|
@@ -17,7 +19,8 @@ function resolveSeriesOptions(options = {}) {
|
|
|
17
19
|
titleKey: options.titleKey ?? "series_title",
|
|
18
20
|
heading: options.heading ?? true,
|
|
19
21
|
className: options.className ?? DEFAULT_SERIES_CLASS_NAME,
|
|
20
|
-
positionLabel: options.positionLabel ?? false
|
|
22
|
+
positionLabel: options.positionLabel ?? false,
|
|
23
|
+
basePath: normalizeBasePath(options.basePath ?? DEFAULT_SERIES_BASE_PATH)
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
26
|
function collectSeriesIndexes(manifest, options = {}) {
|
|
@@ -47,6 +50,18 @@ function buildSeriesIndex(manifest, name, options = {}) {
|
|
|
47
50
|
(index) => index.name === name
|
|
48
51
|
) ?? null;
|
|
49
52
|
}
|
|
53
|
+
function seriesSlug(name) {
|
|
54
|
+
return name.split("/").map((segment) => {
|
|
55
|
+
const normalized = segment.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
56
|
+
return normalized === "" ? encodeURIComponent(segment.trim()) : normalized;
|
|
57
|
+
}).join("/");
|
|
58
|
+
}
|
|
59
|
+
function seriesLandingPath(name, options = {}) {
|
|
60
|
+
const resolved = resolveSeriesOptions(options);
|
|
61
|
+
if (resolved.basePath === "") return "";
|
|
62
|
+
const slug = seriesSlug(name);
|
|
63
|
+
return slug === "" ? "" : `${resolved.basePath}/${slug}`;
|
|
64
|
+
}
|
|
50
65
|
function renderSeriesNavigation(index, currentSlug, options = {}) {
|
|
51
66
|
const resolved = resolveSeriesOptions(options);
|
|
52
67
|
const cls = resolved.className;
|
|
@@ -143,6 +158,21 @@ function renderSeriesIndex(manifest, name, options = {}) {
|
|
|
143
158
|
parts.push("</ol></section>");
|
|
144
159
|
return parts.join("");
|
|
145
160
|
}
|
|
161
|
+
function renderSeriesList(manifest, options = {}, label = "Series") {
|
|
162
|
+
const indexes = collectSeriesIndexes(manifest, options);
|
|
163
|
+
if (indexes.length === 0) return "";
|
|
164
|
+
const resolved = resolveSeriesOptions(options);
|
|
165
|
+
const cls = escapeHtmlAttribute(resolved.className);
|
|
166
|
+
const items = indexes.map((index) => {
|
|
167
|
+
const path = seriesLandingPath(index.name, options);
|
|
168
|
+
const title = escapeHtml(index.title);
|
|
169
|
+
const link = path === "" ? `<span class="${cls}__link">${title}</span>` : `<a class="${cls}__link" href="${escapeHtmlAttribute(path)}">${title}</a>`;
|
|
170
|
+
return `<li class="${cls}__item" data-series-count="${index.members.length}">${link}</li>`;
|
|
171
|
+
}).join("");
|
|
172
|
+
return `<section class="${cls} ${cls}--list" data-series-list><h1 class="${cls}__title">${escapeHtml(
|
|
173
|
+
label
|
|
174
|
+
)}</h1><ol class="${cls}__list">${items}</ol></section>`;
|
|
175
|
+
}
|
|
146
176
|
function collectSeriesDiagnostics(manifest, options = {}) {
|
|
147
177
|
const resolved = resolveSeriesOptions(options);
|
|
148
178
|
const diagnostics = [];
|
|
@@ -247,9 +277,44 @@ function hasFrontmatterKey(entry, key) {
|
|
|
247
277
|
function formatPosition(position, total) {
|
|
248
278
|
return `Part ${position} of ${total}`;
|
|
249
279
|
}
|
|
280
|
+
function normalizeBasePath(value) {
|
|
281
|
+
const trimmed = value.trim();
|
|
282
|
+
if (trimmed === "") return "";
|
|
283
|
+
const prefixed = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
|
|
284
|
+
return prefixed.length > 1 ? prefixed.replace(/\/+$/, "") : prefixed;
|
|
285
|
+
}
|
|
250
286
|
|
|
251
287
|
// index.ts
|
|
252
288
|
function series(options = {}) {
|
|
289
|
+
const models = /* @__PURE__ */ new WeakMap();
|
|
290
|
+
const modelFor = (manifest) => {
|
|
291
|
+
const cached = models.get(manifest);
|
|
292
|
+
if (cached) return cached;
|
|
293
|
+
const resolved = resolveSeriesOptions(options);
|
|
294
|
+
const view = {
|
|
295
|
+
...manifest,
|
|
296
|
+
entries: manifest.discoverableEntries
|
|
297
|
+
};
|
|
298
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
299
|
+
const landingPaths = [];
|
|
300
|
+
if (resolved.basePath !== "") {
|
|
301
|
+
for (const index of collectSeriesIndexes(view, options)) {
|
|
302
|
+
const path = seriesLandingPath(index.name, options);
|
|
303
|
+
if (path === "" || byPath.has(path)) continue;
|
|
304
|
+
byPath.set(path, index);
|
|
305
|
+
landingPaths.push(path);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const model = {
|
|
309
|
+
resolved,
|
|
310
|
+
view,
|
|
311
|
+
listPath: resolved.basePath !== "" && landingPaths.length > 0 ? resolved.basePath : "",
|
|
312
|
+
landingPaths,
|
|
313
|
+
byPath
|
|
314
|
+
};
|
|
315
|
+
models.set(manifest, model);
|
|
316
|
+
return model;
|
|
317
|
+
};
|
|
253
318
|
return definePlugin({
|
|
254
319
|
name: "series",
|
|
255
320
|
processedContentCache: {
|
|
@@ -261,12 +326,13 @@ function series(options = {}) {
|
|
|
261
326
|
validateOptions: validateSeriesOptions,
|
|
262
327
|
onManifestCreated: ({ manifest, diagnostics }) => {
|
|
263
328
|
diagnostics.push(...collectSeriesDiagnostics(manifest, options));
|
|
329
|
+
const view = modelFor(manifest).view;
|
|
264
330
|
const injected = /* @__PURE__ */ new Set();
|
|
265
|
-
for (const index of collectSeriesIndexes(
|
|
331
|
+
for (const index of collectSeriesIndexes(view, options)) {
|
|
266
332
|
if (index.members.length < 2) continue;
|
|
267
333
|
for (const member of index.members) {
|
|
268
334
|
if (injected.has(member.slug)) continue;
|
|
269
|
-
const entry =
|
|
335
|
+
const entry = view.bySlug.get(member.slug);
|
|
270
336
|
if (!entry) continue;
|
|
271
337
|
injected.add(member.slug);
|
|
272
338
|
const navigation = renderSeriesNavigation(
|
|
@@ -274,21 +340,73 @@ function series(options = {}) {
|
|
|
274
340
|
member.slug,
|
|
275
341
|
options
|
|
276
342
|
);
|
|
277
|
-
if (!entry.
|
|
278
|
-
entry.
|
|
279
|
-
${navigation}`;
|
|
343
|
+
if (!hasSlotFragment(entry.bodySlots?.["article.footer"], navigation)) {
|
|
344
|
+
appendContentBodySlot(entry, "article.footer", navigation);
|
|
280
345
|
}
|
|
281
346
|
}
|
|
282
347
|
}
|
|
283
348
|
},
|
|
349
|
+
pageTypes: [
|
|
350
|
+
{
|
|
351
|
+
id: "series-list",
|
|
352
|
+
paths: ({ manifest }) => {
|
|
353
|
+
const listPath = modelFor(manifest).listPath;
|
|
354
|
+
return listPath === "" ? [] : [listPath];
|
|
355
|
+
},
|
|
356
|
+
outputDependencies: [{ type: "global" }],
|
|
357
|
+
resolve: ({ manifest, pathname }) => {
|
|
358
|
+
const model = modelFor(manifest);
|
|
359
|
+
if (model.listPath === "" || pathname !== model.listPath) return null;
|
|
360
|
+
const body = renderSeriesList(model.view, options);
|
|
361
|
+
if (body === "") return null;
|
|
362
|
+
return {
|
|
363
|
+
type: "series-list",
|
|
364
|
+
pathname,
|
|
365
|
+
title: "Series",
|
|
366
|
+
body
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
id: "series-index",
|
|
372
|
+
paths: ({ manifest }) => modelFor(manifest).landingPaths,
|
|
373
|
+
outputDependencies: [{ type: "global" }],
|
|
374
|
+
resolve: ({ manifest, pathname }) => {
|
|
375
|
+
const model = modelFor(manifest);
|
|
376
|
+
const index = model.byPath.get(pathname);
|
|
377
|
+
if (!index) return null;
|
|
378
|
+
const body = renderSeriesIndex(model.view, index.name, options);
|
|
379
|
+
if (body === "") return null;
|
|
380
|
+
return {
|
|
381
|
+
type: "series-index",
|
|
382
|
+
pathname,
|
|
383
|
+
title: index.title,
|
|
384
|
+
body
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
],
|
|
284
389
|
assets: [createStyleAsset("series")]
|
|
285
390
|
});
|
|
286
391
|
}
|
|
287
392
|
var seriesPlugin = series;
|
|
393
|
+
function hasSlotFragment(slot, fragment) {
|
|
394
|
+
return slot === fragment || slot?.startsWith(`${fragment}
|
|
395
|
+
`) || slot?.endsWith(`
|
|
396
|
+
${fragment}`) || slot?.includes(`
|
|
397
|
+
${fragment}
|
|
398
|
+
`) || false;
|
|
399
|
+
}
|
|
288
400
|
function validateSeriesOptions(options) {
|
|
289
401
|
if (!options) return [];
|
|
290
402
|
const issues = [];
|
|
291
|
-
for (const key of [
|
|
403
|
+
for (const key of [
|
|
404
|
+
"key",
|
|
405
|
+
"orderKey",
|
|
406
|
+
"titleKey",
|
|
407
|
+
"className",
|
|
408
|
+
"basePath"
|
|
409
|
+
]) {
|
|
292
410
|
const value = options[key];
|
|
293
411
|
if (value !== void 0 && (typeof value !== "string" || value.trim() === "")) {
|
|
294
412
|
issues.push({ path: key, message: "Expected a non-empty string." });
|
|
@@ -304,11 +422,15 @@ function validateSeriesOptions(options) {
|
|
|
304
422
|
var DEFAULT_CLASS_NAME = resolveSeriesOptions({}).className;
|
|
305
423
|
export {
|
|
306
424
|
DEFAULT_CLASS_NAME,
|
|
425
|
+
DEFAULT_SERIES_BASE_PATH,
|
|
307
426
|
buildSeriesIndex,
|
|
308
427
|
collectSeriesIndexes,
|
|
309
428
|
renderSeriesIndex,
|
|
429
|
+
renderSeriesList,
|
|
310
430
|
renderSeriesNavigation,
|
|
311
431
|
resolveSeriesOptions,
|
|
312
432
|
series,
|
|
313
|
-
|
|
433
|
+
seriesLandingPath,
|
|
434
|
+
seriesPlugin,
|
|
435
|
+
seriesSlug
|
|
314
436
|
};
|
package/dist/src/series.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type ContentManifest, type Diagnostic } from "@riebeckite/core";
|
|
|
2
2
|
import type { ResolvedSeriesOptions, SeriesIndex, SeriesOptions } from "./types.js";
|
|
3
3
|
/** Base class applied when `options.className` is not set. */
|
|
4
4
|
export declare const DEFAULT_SERIES_CLASS_NAME = "rb-series";
|
|
5
|
+
export declare const DEFAULT_SERIES_BASE_PATH = "/series";
|
|
5
6
|
/** Applies defaults to the user-supplied options. */
|
|
6
7
|
export declare function resolveSeriesOptions(options?: SeriesOptions): ResolvedSeriesOptions;
|
|
7
8
|
/**
|
|
@@ -13,6 +14,8 @@ export declare function resolveSeriesOptions(options?: SeriesOptions): ResolvedS
|
|
|
13
14
|
export declare function collectSeriesIndexes(manifest: ContentManifest, options?: SeriesOptions): SeriesIndex[];
|
|
14
15
|
/** Returns a single series index, or `null` when no note declares `name`. */
|
|
15
16
|
export declare function buildSeriesIndex(manifest: ContentManifest, name: string, options?: SeriesOptions): SeriesIndex | null;
|
|
17
|
+
export declare function seriesSlug(name: string): string;
|
|
18
|
+
export declare function seriesLandingPath(name: string, options?: SeriesOptions): string;
|
|
16
19
|
/**
|
|
17
20
|
* Renders the navigation block that is appended to each note in a series.
|
|
18
21
|
* `currentSlug` marks the active part with `aria-current="page"` and drives the
|
|
@@ -24,6 +27,7 @@ export declare function renderSeriesNavigation(index: SeriesIndex, currentSlug:
|
|
|
24
27
|
* Returns an empty string when the manifest has no member for `name`.
|
|
25
28
|
*/
|
|
26
29
|
export declare function renderSeriesIndex(manifest: ContentManifest, name: string, options?: SeriesOptions): string;
|
|
30
|
+
export declare function renderSeriesList(manifest: ContentManifest, options?: SeriesOptions, label?: string): string;
|
|
27
31
|
/**
|
|
28
32
|
* Reports notes whose series metadata cannot be ordered reliably. Emitted
|
|
29
33
|
* diagnostics use `pluginName: "series"` and `severity: "warning"`.
|
package/dist/src/types.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type SeriesOptions = {
|
|
|
12
12
|
className?: string;
|
|
13
13
|
/** Render a `Part N of M` label for the current note. Defaults to `false`. */
|
|
14
14
|
positionLabel?: boolean;
|
|
15
|
+
basePath?: string;
|
|
15
16
|
};
|
|
16
17
|
/** Options after defaults have been applied. */
|
|
17
18
|
export type ResolvedSeriesOptions = {
|
|
@@ -21,6 +22,7 @@ export type ResolvedSeriesOptions = {
|
|
|
21
22
|
heading: boolean;
|
|
22
23
|
className: string;
|
|
23
24
|
positionLabel: boolean;
|
|
25
|
+
basePath: string;
|
|
24
26
|
};
|
|
25
27
|
/** A single note that belongs to a series. */
|
|
26
28
|
export type SeriesMember = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@riebeckite/plugin-series",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"./style.css": "./style.css"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@riebeckite/core": "0.0.
|
|
18
|
+
"@riebeckite/core": "0.0.17"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"tsx": "^4.22.4",
|
|
22
|
-
"@riebeckite/test": "0.0.
|
|
22
|
+
"@riebeckite/test": "0.0.17"
|
|
23
23
|
},
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|