@raystack/chronicle 0.6.1 → 0.7.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/cli/index.js CHANGED
@@ -1,5 +1,35 @@
1
1
  import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
2
4
  var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
3
33
  var __returnValue = (v) => v;
4
34
  function __exportSetter(name, newValue) {
5
35
  this[name] = __returnValue.bind(null, newValue);
@@ -33,11 +63,146 @@ var init_remark_strip_md_extensions = __esm(() => {
33
63
  remark_strip_md_extensions_default = remarkStripMdExtensions;
34
64
  });
35
65
 
36
- // src/lib/remark-unused-directives.ts
66
+ // ../../node_modules/.bun/reading-time@1.5.0/node_modules/reading-time/lib/reading-time.js
67
+ var require_reading_time = __commonJS((exports, module) => {
68
+ /*!
69
+ * reading-time
70
+ * Copyright (c) Nicolas Gryman <ngryman@gmail.com>
71
+ * MIT Licensed
72
+ */
73
+ function codeIsInRanges(number, arrayOfRanges) {
74
+ return arrayOfRanges.some(([lowerBound, upperBound]) => lowerBound <= number && number <= upperBound);
75
+ }
76
+ function isCJK(c) {
77
+ if (typeof c !== "string") {
78
+ return false;
79
+ }
80
+ const charCode = c.charCodeAt(0);
81
+ return codeIsInRanges(charCode, [
82
+ [12352, 12447],
83
+ [19968, 40959],
84
+ [44032, 55203],
85
+ [131072, 191456]
86
+ ]);
87
+ }
88
+ function isAnsiWordBound(c) {
89
+ return `
90
+ \r `.includes(c);
91
+ }
92
+ function isPunctuation(c) {
93
+ if (typeof c !== "string") {
94
+ return false;
95
+ }
96
+ const charCode = c.charCodeAt(0);
97
+ return codeIsInRanges(charCode, [
98
+ [33, 47],
99
+ [58, 64],
100
+ [91, 96],
101
+ [123, 126],
102
+ [12288, 12351],
103
+ [65280, 65519]
104
+ ]);
105
+ }
106
+ function readingTime(text, options = {}) {
107
+ let words = 0, start = 0, end = text.length - 1;
108
+ const wordsPerMinute = options.wordsPerMinute || 200;
109
+ const isWordBound = options.wordBound || isAnsiWordBound;
110
+ while (isWordBound(text[start]))
111
+ start++;
112
+ while (isWordBound(text[end]))
113
+ end--;
114
+ const normalizedText = `${text}
115
+ `;
116
+ for (let i = start;i <= end; i++) {
117
+ if (isCJK(normalizedText[i]) || !isWordBound(normalizedText[i]) && (isWordBound(normalizedText[i + 1]) || isCJK(normalizedText[i + 1]))) {
118
+ words++;
119
+ }
120
+ if (isCJK(normalizedText[i])) {
121
+ while (i <= end && (isPunctuation(normalizedText[i + 1]) || isWordBound(normalizedText[i + 1]))) {
122
+ i++;
123
+ }
124
+ }
125
+ }
126
+ const minutes = words / wordsPerMinute;
127
+ const time = Math.round(minutes * 60 * 1000);
128
+ const displayed = Math.ceil(minutes.toFixed(2));
129
+ return {
130
+ text: displayed + " min read",
131
+ minutes,
132
+ time,
133
+ words
134
+ };
135
+ }
136
+ module.exports = readingTime;
137
+ });
138
+
139
+ // ../../node_modules/.bun/reading-time@1.5.0/node_modules/reading-time/lib/stream.js
140
+ var require_stream = __commonJS((exports, module) => {
141
+ /*!
142
+ * reading-time
143
+ * Copyright (c) Nicolas Gryman <ngryman@gmail.com>
144
+ * MIT Licensed
145
+ */
146
+ var readingTime = require_reading_time();
147
+ var Transform = __require("stream").Transform;
148
+ var util = __require("util");
149
+ function ReadingTimeStream(options) {
150
+ if (!(this instanceof ReadingTimeStream)) {
151
+ return new ReadingTimeStream(options);
152
+ }
153
+ Transform.call(this, { objectMode: true });
154
+ this.options = options || {};
155
+ this.stats = {
156
+ minutes: 0,
157
+ time: 0,
158
+ words: 0
159
+ };
160
+ }
161
+ util.inherits(ReadingTimeStream, Transform);
162
+ ReadingTimeStream.prototype._transform = function(chunk, encoding, callback) {
163
+ const stats = readingTime(chunk.toString(encoding), this.options);
164
+ this.stats.minutes += stats.minutes;
165
+ this.stats.time += stats.time;
166
+ this.stats.words += stats.words;
167
+ callback();
168
+ };
169
+ ReadingTimeStream.prototype._flush = function(callback) {
170
+ this.stats.text = Math.ceil(this.stats.minutes.toFixed(2)) + " min read";
171
+ this.push(this.stats);
172
+ callback();
173
+ };
174
+ module.exports = ReadingTimeStream;
175
+ });
176
+
177
+ // ../../node_modules/.bun/reading-time@1.5.0/node_modules/reading-time/index.js
178
+ var require_reading_time2 = __commonJS((exports, module) => {
179
+ exports.default = module.exports = require_reading_time();
180
+ module.exports.readingTimeStream = require_stream();
181
+ });
182
+
183
+ // ../../node_modules/.bun/remark-reading-time@2.1.0/node_modules/remark-reading-time/index.js
37
184
  import { visit as visit2 } from "unist-util-visit";
185
+ function readingTime({
186
+ attribute = "readingTime"
187
+ } = {}) {
188
+ return function(info, file) {
189
+ let text = "";
190
+ visit2(info, ["text", "code"], (node) => {
191
+ text += node.value;
192
+ });
193
+ file.data[attribute] = import_reading_time.default(text);
194
+ };
195
+ }
196
+ var import_reading_time;
197
+ var init_remark_reading_time = __esm(() => {
198
+ import_reading_time = __toESM(require_reading_time2(), 1);
199
+ });
200
+
201
+ // src/lib/remark-unused-directives.ts
202
+ import { visit as visit3 } from "unist-util-visit";
38
203
  var remarkUnusedDirectives = () => {
39
204
  return (tree) => {
40
- visit2(tree, ["textDirective"], (node) => {
205
+ visit3(tree, ["textDirective"], (node) => {
41
206
  const directive = node;
42
207
  if (!directive.data) {
43
208
  const hasAttributes = directive.attributes && Object.keys(directive.attributes).length > 0;
@@ -105,6 +270,7 @@ async function createViteConfig(options) {
105
270
  mdx({
106
271
  default: defineFumadocsConfig({
107
272
  mdxOptions: {
273
+ valueToExport: ["readingTime"],
108
274
  remarkPlugins: [
109
275
  remarkDirective,
110
276
  [remarkDirectiveAdmonition, {
@@ -126,7 +292,8 @@ async function createViteConfig(options) {
126
292
  }],
127
293
  remark_unused_directives_default,
128
294
  remark_strip_md_extensions_default,
129
- remarkMdxMermaid
295
+ remarkMdxMermaid,
296
+ readingTime
130
297
  ]
131
298
  }
132
299
  })
@@ -183,6 +350,7 @@ async function createViteConfig(options) {
183
350
  }
184
351
  var init_vite_config = __esm(() => {
185
352
  init_remark_strip_md_extensions();
353
+ init_remark_reading_time();
186
354
  init_remark_unused_directives();
187
355
  });
188
356
 
@@ -266,6 +434,7 @@ var dirNameSchema = z.string().min(1).refine((s) => DIR_NAME_PATTERN.test(s) &&
266
434
  var contentEntrySchema = z.object({
267
435
  dir: dirNameSchema,
268
436
  label: z.string().min(1),
437
+ description: z.string().optional(),
269
438
  icon: z.string().optional()
270
439
  });
271
440
  var badgeVariantSchema = z.enum([
@@ -428,6 +597,7 @@ function getLatestContentRoots(config2) {
428
597
  versionLabel: config2.latest?.label ?? null,
429
598
  contentDir: c.dir,
430
599
  contentLabel: c.label,
600
+ contentDescription: c.description,
431
601
  contentIcon: c.icon,
432
602
  fsPath: `content/${c.dir}`,
433
603
  urlPrefix: `/${c.dir}`
@@ -442,6 +612,7 @@ function getVersionContentRoots(config2, versionDir) {
442
612
  versionLabel: version.label,
443
613
  contentDir: c.dir,
444
614
  contentLabel: c.label,
615
+ contentDescription: c.description,
445
616
  contentIcon: c.icon,
446
617
  fsPath: `versions/${version.dir}/${c.dir}`,
447
618
  urlPrefix: `/${version.dir}/${c.dir}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raystack/chronicle",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Config-driven documentation framework",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
package/src/lib/config.ts CHANGED
@@ -35,6 +35,7 @@ export interface ContentRoot {
35
35
  versionLabel: string | null
36
36
  contentDir: string
37
37
  contentLabel: string
38
+ contentDescription?: string
38
39
  contentIcon?: string
39
40
  fsPath: string
40
41
  urlPrefix: string
@@ -46,6 +47,7 @@ export function getLatestContentRoots(config: ChronicleConfig): ContentRoot[] {
46
47
  versionLabel: config.latest?.label ?? null,
47
48
  contentDir: c.dir,
48
49
  contentLabel: c.label,
50
+ contentDescription: c.description,
49
51
  contentIcon: c.icon,
50
52
  fsPath: `content/${c.dir}`,
51
53
  urlPrefix: `/${c.dir}`,
@@ -64,6 +66,7 @@ export function getVersionContentRoots(
64
66
  versionLabel: version.label,
65
67
  contentDir: c.dir,
66
68
  contentLabel: c.label,
69
+ contentDescription: c.description,
67
70
  contentIcon: c.icon,
68
71
  fsPath: `versions/${version.dir}/${c.dir}`,
69
72
  urlPrefix: `/${version.dir}/${c.dir}`,
@@ -79,6 +82,7 @@ export interface VersionDescriptor {
79
82
 
80
83
  export interface LandingEntry {
81
84
  label: string
85
+ description?: string
82
86
  href: string
83
87
  contentDir: string
84
88
  icon?: string
@@ -95,6 +99,7 @@ export function getLandingEntries(
95
99
 
96
100
  return roots.map((r) => ({
97
101
  label: r.contentLabel,
102
+ description: r.contentDescription,
98
103
  href: r.urlPrefix,
99
104
  contentDir: r.contentDir,
100
105
  icon: r.contentIcon,
package/src/lib/source.ts CHANGED
@@ -206,6 +206,7 @@ export function extractFrontmatter(page: { data: unknown }, fallbackTitle?: stri
206
206
  order: d.order as number | undefined,
207
207
  icon: d.icon as string | undefined,
208
208
  lastModified: d.lastModified as string | undefined,
209
+ _readingTime: d._readingTime as number | undefined,
209
210
  };
210
211
  }
211
212
 
@@ -217,13 +218,20 @@ export function getOriginalPath(page: { data: unknown }): string {
217
218
  return ((page.data as Record<string, unknown>)._originalPath as string) ?? '';
218
219
  }
219
220
 
220
- const ssrModules = import.meta.glob<{ default?: MDXContent; toc?: TableOfContents }>(
221
+ interface ReadingTime {
222
+ text: string;
223
+ minutes: number;
224
+ words: number;
225
+ time: number;
226
+ }
227
+
228
+ const ssrModules = import.meta.glob<{ default?: MDXContent; toc?: TableOfContents; readingTime?: ReadingTime }>(
221
229
  '../../.content/**/*.{mdx,md}'
222
230
  );
223
231
 
224
232
  export async function loadPageModule(
225
233
  relativePath: string
226
- ): Promise<{ default: MDXContent | null; toc: TableOfContents }> {
234
+ ): Promise<{ default: MDXContent | null; toc: TableOfContents; _readingTime?: number }> {
227
235
  if (!relativePath || relativePath.includes('..')) return { default: null, toc: [] };
228
236
  const withoutExt = relativePath.replace(/\.(mdx|md)$/, '');
229
237
  const key = relativePath.endsWith('.md')
@@ -232,5 +240,6 @@ export async function loadPageModule(
232
240
  const loader = ssrModules[key];
233
241
  if (!loader) return { default: null, toc: [] };
234
242
  const mod = await loader();
235
- return { default: mod.default ?? null, toc: mod.toc ?? [] };
243
+ const minutes = mod.readingTime?.minutes;
244
+ return { default: mod.default ?? null, toc: mod.toc ?? [], _readingTime: minutes != null ? Math.max(1, Math.round(minutes)) : undefined };
236
245
  }
@@ -1,56 +1,169 @@
1
1
  .root {
2
2
  display: flex;
3
3
  flex-direction: column;
4
- gap: var(--rs-space-8);
5
- padding: var(--rs-space-9) var(--rs-space-7);
6
- max-width: 960px;
7
- margin: 0 auto;
4
+ padding: var(--rs-space-12) var(--rs-space-9);
5
+ width: 100%;
6
+ }
7
+
8
+ .header {
9
+ display: flex;
10
+ align-items: center;
11
+ padding-bottom: var(--rs-space-10);
12
+ border-bottom: 0.5px solid var(--rs-color-border-base-primary);
8
13
  }
9
14
 
10
15
  .title {
11
- font-size: var(--rs-font-size-h3);
12
- font-weight: 600;
13
- color: var(--rs-color-foreground-base-primary);
16
+ flex: 1;
17
+ font-family: var(--paper-font-mono, inherit);
18
+ font-size: 64px;
19
+ line-height: 1.1;
20
+ color: var(--rs-color-foreground-accent-primary);
21
+ text-transform: uppercase;
14
22
  margin: 0;
23
+ font-weight: var(--rs-font-weight-regular);
15
24
  }
16
25
 
17
26
  .description {
27
+ width: 385px;
28
+ flex-shrink: 0;
29
+ font-family: var(--paper-font-body, inherit);
18
30
  font-size: var(--rs-font-size-regular);
19
- color: var(--rs-color-foreground-base-secondary);
31
+ line-height: 1.4;
32
+ color: var(--rs-color-foreground-base-primary);
20
33
  margin: 0;
21
34
  }
22
35
 
23
36
  .grid {
24
- display: grid;
25
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
26
- gap: var(--rs-space-6);
37
+ display: flex;
38
+ flex-wrap: wrap;
39
+ gap: var(--rs-space-7);
40
+ margin-top: var(--rs-space-9);
27
41
  }
28
42
 
29
43
  .card {
30
44
  display: flex;
31
45
  flex-direction: column;
32
- gap: var(--rs-space-3);
33
- padding: var(--rs-space-6);
34
- border: 1px solid var(--rs-color-border-base-primary);
35
- border-radius: var(--rs-radius-3);
46
+ gap: var(--rs-space-7);
47
+ padding: var(--rs-space-2);
36
48
  text-decoration: none;
37
49
  color: inherit;
38
- background: var(--rs-color-background-base-primary);
39
- transition: border-color 0.15s ease, background 0.15s ease;
50
+ width: 360px;
51
+ }
52
+
53
+ .card:hover .cardImage {
54
+ border-color: var(--rs-color-foreground-accent-primary);
55
+ }
56
+
57
+ .cardImage {
58
+ position: relative;
59
+ display: flex;
60
+ align-items: center;
61
+ justify-content: center;
62
+ width: 100%;
63
+ aspect-ratio: 1.05;
64
+ min-height: 280px;
65
+ max-width: 360px;
66
+ background: var(--rs-color-background-accent-secondary);
67
+ border: 1px solid var(--rs-color-foreground-accent-primary);
68
+ overflow: hidden;
69
+ transition: border-color 0.15s ease;
70
+ }
71
+
72
+ .cardImage::before {
73
+ content: "";
74
+ position: absolute;
75
+ inset: 0;
76
+ background-image:
77
+ radial-gradient(circle, var(--rs-color-foreground-accent-primary) 1px, transparent 1px);
78
+ background-size: 10px 10px;
79
+ opacity: 0.3;
80
+ pointer-events: none;
81
+ }
82
+
83
+ .cardImageLabel {
84
+ position: absolute;
85
+ font-family: var(--paper-font-mono, monospace);
86
+ font-size: var(--rs-font-size-micro);
87
+ text-transform: uppercase;
88
+ color: var(--rs-color-foreground-base-secondary);
89
+ background: var(--rs-color-background-accent-secondary);
90
+ padding: var(--rs-space-1);
91
+ white-space: nowrap;
92
+ }
93
+
94
+ .cardImageLabelTop {
95
+ top: 19px;
96
+ left: -1px;
97
+ writing-mode: vertical-rl;
98
+ transform: rotate(180deg);
40
99
  }
41
100
 
42
- .card:hover {
43
- border-color: var(--rs-color-border-accent-primary);
44
- background: var(--rs-color-background-neutral-secondary);
101
+ .cardImageLabelRight {
102
+ bottom: 19px;
103
+ right: -1px;
104
+ writing-mode: vertical-rl;
105
+ }
106
+
107
+ .cardIcon {
108
+ width: 90%;
109
+ height: 90%;
110
+ min-width: 64px;
111
+ min-height: 64px;
112
+ color: var(--rs-color-foreground-accent-primary);
113
+ opacity: 0.3;
114
+ transition: opacity 0.2s ease, transform 0.2s ease;
115
+ }
116
+
117
+ .card:hover .cardIcon {
118
+ opacity: 0.5;
119
+ transform: scale(1.05);
120
+ }
121
+
122
+ .card:hover .cardImage {
123
+ background: var(--rs-color-background-accent-primary);
124
+ }
125
+
126
+ .cardBody {
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: var(--rs-space-3);
130
+ padding-bottom: var(--rs-space-4);
45
131
  }
46
132
 
47
133
  .cardLabel {
134
+ font-family: var(--paper-font-mono, inherit);
48
135
  font-size: var(--rs-font-size-large);
49
- font-weight: 500;
136
+ line-height: 1.4;
137
+ text-transform: uppercase;
138
+ color: var(--rs-color-foreground-base-primary);
50
139
  }
51
140
 
52
- .cardHref {
141
+ .cardDescription {
142
+ font-family: var(--paper-font-body, inherit);
53
143
  font-size: var(--rs-font-size-small);
54
- color: var(--rs-color-foreground-base-secondary);
55
- font-family: var(--rs-font-family-mono);
144
+ line-height: 1.4;
145
+ color: var(--rs-color-foreground-base-primary);
146
+ }
147
+
148
+ @media (max-width: 768px) {
149
+ .header {
150
+ flex-direction: column;
151
+ gap: var(--rs-space-5);
152
+ }
153
+
154
+ .title {
155
+ font-size: var(--rs-font-size-t4);
156
+ }
157
+
158
+ .description {
159
+ width: 100%;
160
+ }
161
+
162
+ .card {
163
+ width: 100%;
164
+ }
165
+
166
+ .cardImage {
167
+ max-width: 100%;
168
+ }
56
169
  }
@@ -1,3 +1,4 @@
1
+ import { FolderIcon } from '@heroicons/react/24/outline';
1
2
  import { Link as RouterLink } from 'react-router';
2
3
  import { getLandingEntries } from '@/lib/config';
3
4
  import { usePageContext } from '@/lib/page-context';
@@ -13,15 +14,30 @@ export function LandingPage() {
13
14
 
14
15
  return (
15
16
  <div className={styles.root}>
16
- <h1 className={styles.title}>{heading}</h1>
17
- {config.site.description ? (
18
- <p className={styles.description}>{config.site.description}</p>
19
- ) : null}
17
+ <div className={styles.header}>
18
+ <h1 className={styles.title}>{heading}</h1>
19
+ {config.site.description ? (
20
+ <p className={styles.description}>{config.site.description}</p>
21
+ ) : null}
22
+ </div>
20
23
  <div className={styles.grid}>
21
- {entries.map((entry) => (
24
+ {entries.map((entry, i) => (
22
25
  <RouterLink key={entry.href} to={entry.href} className={styles.card}>
23
- <span className={styles.cardLabel}>{entry.label}</span>
24
- <span className={styles.cardHref}>{entry.href}</span>
26
+ <div className={styles.cardImage} aria-hidden='true'>
27
+ <span className={`${styles.cardImageLabel} ${styles.cardImageLabelTop}`}>
28
+ Fig_{String(i + 1).padStart(3, '0')}
29
+ </span>
30
+ <span className={`${styles.cardImageLabel} ${styles.cardImageLabelRight}`}>
31
+ [ {entry.label} ]
32
+ </span>
33
+ <FolderIcon className={styles.cardIcon} />
34
+ </div>
35
+ <div className={styles.cardBody}>
36
+ <span className={styles.cardLabel}>{entry.label}</span>
37
+ {entry.description ? (
38
+ <span className={styles.cardDescription}>{entry.description}</span>
39
+ ) : null}
40
+ </div>
25
41
  </RouterLink>
26
42
  ))}
27
43
  </div>
@@ -54,7 +54,10 @@ export default {
54
54
  const pageData = page
55
55
  ? {
56
56
  slug: pageSlug,
57
- frontmatter: extractFrontmatter(page, pageSlug[pageSlug.length - 1]),
57
+ frontmatter: {
58
+ ...extractFrontmatter(page, pageSlug[pageSlug.length - 1]),
59
+ _readingTime: mdxModule?._readingTime,
60
+ },
58
61
  content: mdxModule?.default
59
62
  ? React.createElement(mdxModule.default, { components: mdxComponents })
60
63
  : null,
@@ -8,6 +8,7 @@ import path from 'node:path';
8
8
  import remarkDirective from 'remark-directive';
9
9
  import { type InlineConfig } from 'vite';
10
10
  import remarkStripMdExtensions from '../lib/remark-strip-md-extensions';
11
+ import remarkReadingTime from 'remark-reading-time';
11
12
  import remarkUnusedDirectives from '../lib/remark-unused-directives';
12
13
 
13
14
  function resolveOutputDir(projectRoot: string, preset?: string): string {
@@ -55,6 +56,7 @@ export async function createViteConfig(
55
56
  mdx({
56
57
  default: defineFumadocsConfig({
57
58
  mdxOptions: {
59
+ valueToExport: ['readingTime'],
58
60
  remarkPlugins: [
59
61
  remarkDirective,
60
62
  [remarkDirectiveAdmonition, {
@@ -77,6 +79,7 @@ export async function createViteConfig(
77
79
  remarkUnusedDirectives,
78
80
  remarkStripMdExtensions,
79
81
  remarkMdxMermaid,
82
+ remarkReadingTime,
80
83
  ],
81
84
  },
82
85
  }),
@@ -1,21 +1,25 @@
1
1
  .nav {
2
2
  display: flex;
3
3
  flex-direction: column;
4
- gap: var(--rs-space-5);
4
+ gap: var(--rs-space-8);
5
5
  }
6
6
 
7
7
  .chapter {
8
8
  display: flex;
9
9
  flex-direction: column;
10
10
  gap: var(--rs-space-2);
11
+ margin-top: var(--rs-space-8);
11
12
  }
12
13
 
13
14
  .chapterLabel {
15
+ font-family: var(--paper-font-mono);
14
16
  font-size: var(--rs-font-size-small);
15
- font-weight: 600;
17
+ font-weight: var(--rs-font-weight-medium);
18
+ line-height: var(--rs-line-height-small);
19
+ letter-spacing: var(--rs-letter-spacing-small);
16
20
  text-transform: uppercase;
17
- letter-spacing: 0.05em;
18
- color: var(--rs-color-foreground-base-primary);
21
+ color: var(--rs-color-foreground-base-secondary);
22
+ padding: 0 var(--rs-space-3);
19
23
  white-space: nowrap;
20
24
  overflow: hidden;
21
25
  text-overflow: ellipsis;
@@ -27,30 +31,32 @@
27
31
  margin: 0;
28
32
  display: flex;
29
33
  flex-direction: column;
30
- gap: var(--rs-space-1);
31
- padding-left: var(--rs-space-4);
32
34
  }
33
35
 
34
36
  .link {
35
37
  display: flex;
36
38
  align-items: center;
37
- gap: var(--rs-space-2);
39
+ gap: var(--rs-space-3);
40
+ font-family: var(--paper-font-body);
38
41
  font-size: var(--rs-font-size-small);
39
- color: var(--rs-color-foreground-base-tertiary);
42
+ font-weight: var(--rs-font-weight-regular);
43
+ line-height: var(--rs-line-height-small);
44
+ letter-spacing: var(--rs-letter-spacing-small);
45
+ color: var(--rs-color-foreground-base-primary);
40
46
  text-decoration: none;
41
- padding: var(--rs-space-1) 0;
47
+ padding: var(--rs-space-3);
48
+ border-radius: var(--rs-radius-2);
42
49
  white-space: nowrap;
43
50
  overflow: hidden;
44
51
  text-overflow: ellipsis;
45
52
  }
46
53
 
47
54
  .link:hover {
48
- color: var(--rs-color-foreground-base-primary);
55
+ color: var(--rs-color-foreground-accent-primary);
49
56
  }
50
57
 
51
58
  .active {
52
59
  color: var(--rs-color-foreground-accent-primary);
53
- font-weight: 500;
54
60
  }
55
61
 
56
62
  .icon {
@@ -60,9 +66,14 @@
60
66
  }
61
67
 
62
68
  .subLabel {
69
+ font-family: var(--paper-font-mono);
63
70
  font-size: var(--rs-font-size-small);
64
- font-weight: 500;
71
+ font-weight: var(--rs-font-weight-medium);
72
+ line-height: var(--rs-line-height-small);
73
+ letter-spacing: var(--rs-letter-spacing-small);
74
+ text-transform: uppercase;
65
75
  color: var(--rs-color-foreground-base-secondary);
76
+ padding: 0 var(--rs-space-3);
66
77
  margin-top: var(--rs-space-3);
67
78
  display: block;
68
79
  white-space: nowrap;