sdocs 0.0.57 → 0.0.58

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/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.58] - 2026-07-05
11
+
12
+ ### Added
13
+
14
+ - **Richer page markdown.** GitHub-style alerts (`> [!NOTE]`, `[!TIP]`,
15
+ `[!IMPORTANT]`, `[!WARNING]`, `[!CAUTION]`) render as tinted callouts;
16
+ task lists get proper checkboxes; table columns honor `:---:` alignment;
17
+ external links open in a new tab (internal ones stay in the app); images
18
+ render lazily and Svelte-safe.
19
+ - **`static` config option.** A folder of static assets served at the site
20
+ root in dev and copied into `dist/` by `sdocs build` — `![hero](/hero.png)`
21
+ in a page just works. Powers the standalone CLI flows; embedded apps keep
22
+ using the host's public directory.
23
+ - **Page column alignment.** `content.page.contentX` (config) and
24
+ `contentX` on `[PAGE]` align the content column `left`/`center`/`right`.
25
+ - **A body `#` heading takes over as the page title** — the header no longer
26
+ duplicates it; the entity `title` keeps naming the sidebar entry.
27
+
28
+ ### Changed
29
+
30
+ - **A page's `maxWidth` now bounds the content column together with its
31
+ table of contents**; when the toc is hidden the prose takes its space.
32
+
33
+ ### Fixed
34
+
35
+ - **Code fences can show component tags.** A `<Component />` line inside a
36
+ markdown fence, preceded by a blank line, was treated as a live Svelte
37
+ island and rendered (or crashed the page) instead of staying highlighted
38
+ code. Fences now shield island detection, matching the scanner and the
39
+ editor projection.
40
+
10
41
  ## [0.0.57] - 2026-07-05
11
42
 
12
43
  ### Added
@@ -19,6 +19,8 @@ export async function buildCommand() {
19
19
  await build({
20
20
  configFile: false,
21
21
  root: sdocsDir,
22
+ // The project's static assets (config `static`), copied into dist/
23
+ publicDir: config.static ?? false,
22
24
  resolve: {
23
25
  dedupe: svelteDedupe(cwd),
24
26
  },
@@ -37,6 +37,8 @@ export async function devCommand() {
37
37
  const server = await createServer({
38
38
  configFile: false,
39
39
  root: sdocsDir,
40
+ // The project's static assets (config `static`), served at the site root
41
+ publicDir: config.static ?? false,
40
42
  resolve: {
41
43
  dedupe: svelteDedupe(cwd),
42
44
  },
@@ -40,6 +40,11 @@
40
40
  function scrollToHeading(id: string) {
41
41
  container?.querySelector(`#${CSS.escape(id)}`)?.scrollIntoView({ behavior: 'smooth' });
42
42
  }
43
+
44
+ // contentX aligns the whole column (content + toc) inside the view.
45
+ const columnMargin = $derived(
46
+ doc.contentX === 'center' ? '0 auto' : doc.contentX === 'right' ? '0 0 0 auto' : undefined,
47
+ );
43
48
  </script>
44
49
 
45
50
  {#snippet exampleFrame(index: number)}
@@ -65,52 +70,61 @@
65
70
  {/snippet}
66
71
 
67
72
  <div class="sdocs-page-view" style:padding={doc.padding}>
68
- <div class="sdocs-page-main" style:max-width={doc.maxWidth}>
69
- <!-- Header -->
70
- <div class="sdocs-view-header">
71
- <h1 class="sdocs-view-title">{displayTitle(meta.title)}</h1>
72
- {#if meta.description}
73
- <p class="sdocs-view-description">{meta.description}</p>
73
+ <!-- maxWidth constrains the whole column — content plus toc; contentX
74
+ places it. Without a toc the content takes the toc's space. -->
75
+ <div class="sdocs-page-inner" style:max-width={doc.maxWidth} style:margin={columnMargin}>
76
+ <div class="sdocs-page-main">
77
+ <!-- Header: a body `#` heading takes over as the page title -->
78
+ {#if !doc.bodyTitle}
79
+ <div class="sdocs-view-header">
80
+ <h1 class="sdocs-view-title">{displayTitle(meta.title)}</h1>
81
+ {#if meta.description}
82
+ <p class="sdocs-view-description">{meta.description}</p>
83
+ {/if}
84
+ </div>
74
85
  {/if}
75
- </div>
76
86
 
77
- <!-- Content -->
78
- <div class="sdocs-page-content" bind:this={container}>
79
- {#if PageComponent}
80
- <PageComponent __sdocsExample={exampleFrame} />
81
- {/if}
87
+ <!-- Content -->
88
+ <div class="sdocs-page-content" bind:this={container}>
89
+ {#if PageComponent}
90
+ <PageComponent __sdocsExample={exampleFrame} />
91
+ {/if}
92
+ </div>
82
93
  </div>
83
- </div>
84
94
 
85
- <!-- Table of Contents -->
86
- {#if toc.length > 0 && doc.showToc !== false}
87
- <aside class="sdocs-toc">
88
- <h3 class="sdocs-toc-title">On this page</h3>
89
- <nav>
90
- <ul class="sdocs-toc-list">
91
- {#each toc as heading (heading.id)}
92
- <li class="sdocs-toc-item" style:padding-left="{(heading.level - 2) * 12}px">
93
- <button
94
- class="sdocs-toc-link"
95
- onclick={() => scrollToHeading(heading.id)}
96
- >
97
- {heading.text}
98
- </button>
99
- </li>
100
- {/each}
101
- </ul>
102
- </nav>
103
- </aside>
104
- {/if}
95
+ <!-- Table of Contents -->
96
+ {#if toc.length > 0 && doc.showToc !== false}
97
+ <aside class="sdocs-toc">
98
+ <h3 class="sdocs-toc-title">On this page</h3>
99
+ <nav>
100
+ <ul class="sdocs-toc-list">
101
+ {#each toc as heading (heading.id)}
102
+ <li class="sdocs-toc-item" style:padding-left="{(heading.level - 2) * 12}px">
103
+ <button
104
+ class="sdocs-toc-link"
105
+ onclick={() => scrollToHeading(heading.id)}
106
+ >
107
+ {heading.text}
108
+ </button>
109
+ </li>
110
+ {/each}
111
+ </ul>
112
+ </nav>
113
+ </aside>
114
+ {/if}
115
+ </div>
105
116
  </div>
106
117
 
107
118
  <style>
108
119
  .sdocs-page-view {
109
- display: flex;
110
- gap: 24px;
111
120
  /* padding comes from the doc entry (config/entity cascade) */
112
121
  font-family: var(--sans);
113
122
  }
123
+ .sdocs-page-inner {
124
+ display: flex;
125
+ gap: 24px;
126
+ /* max-width and margin (contentX) come from the doc entry */
127
+ }
114
128
  .sdocs-page-main {
115
129
  flex: 1;
116
130
  min-width: 0;
@@ -207,6 +221,9 @@
207
221
  .sdocs-page-content :global(table) {
208
222
  border-collapse: collapse;
209
223
  margin: 0.9em 0;
224
+ display: block;
225
+ max-width: 100%;
226
+ overflow-x: auto;
210
227
  }
211
228
  .sdocs-page-content :global(th),
212
229
  .sdocs-page-content :global(td) {
@@ -214,12 +231,61 @@
214
231
  padding: 6px 12px;
215
232
  text-align: left;
216
233
  }
234
+ .sdocs-page-content :global(td[align='center']),
235
+ .sdocs-page-content :global(th[align='center']) {
236
+ text-align: center;
237
+ }
238
+ .sdocs-page-content :global(td[align='right']),
239
+ .sdocs-page-content :global(th[align='right']) {
240
+ text-align: right;
241
+ }
217
242
  .sdocs-page-content :global(th) {
218
243
  background: var(--color-base-50);
219
244
  font-weight: 600;
220
245
  }
221
246
  .sdocs-page-content :global(img) {
222
247
  max-width: 100%;
248
+ border-radius: 6px;
249
+ }
250
+
251
+ /* Task lists: GitHub-style checkboxes, no bullet */
252
+ .sdocs-page-content :global(li:has(> input[type='checkbox']:first-child)) {
253
+ list-style: none;
254
+ margin-left: -1.3em;
255
+ }
256
+ .sdocs-page-content :global(li > input[type='checkbox']) {
257
+ margin-right: 6px;
258
+ vertical-align: -2px;
259
+ }
260
+
261
+ /* GitHub-style alerts: > [!NOTE] / [!TIP] / [!IMPORTANT] / [!WARNING] / [!CAUTION] */
262
+ .sdocs-page-content :global(.sdocs-alert) {
263
+ margin: 0.9em 0;
264
+ padding: 8px 16px;
265
+ border-left: 3px solid var(--sdocs-alert-color);
266
+ border-radius: 0 6px 6px 0;
267
+ background: color-mix(in srgb, var(--sdocs-alert-color) 6%, transparent);
268
+ }
269
+ .sdocs-page-content :global(.sdocs-alert-label) {
270
+ font-size: 13px;
271
+ font-weight: 650;
272
+ color: var(--sdocs-alert-color);
273
+ margin: 0.25em 0 0;
274
+ }
275
+ .sdocs-page-content :global(.sdocs-alert-note) {
276
+ --sdocs-alert-color: var(--color-blue-500);
277
+ }
278
+ .sdocs-page-content :global(.sdocs-alert-tip) {
279
+ --sdocs-alert-color: var(--color-green-500);
280
+ }
281
+ .sdocs-page-content :global(.sdocs-alert-important) {
282
+ --sdocs-alert-color: var(--color-purple-500);
283
+ }
284
+ .sdocs-page-content :global(.sdocs-alert-warning) {
285
+ --sdocs-alert-color: var(--color-amber-500);
286
+ }
287
+ .sdocs-page-content :global(.sdocs-alert-caution) {
288
+ --sdocs-alert-color: var(--color-red-500);
223
289
  }
224
290
 
225
291
  /* ── Example stages in the page flow ── */
@@ -65,6 +65,11 @@ export const configSchema = {
65
65
  doc: 'CSS loaded inside preview iframes — a single stylesheet path, or a map of named stylesheets to switch between.',
66
66
  insert: ": '$0'",
67
67
  },
68
+ static: {
69
+ detail: 'string',
70
+ doc: 'Folder of static assets served at the site root — images for pages, files for previews. Standalone CLI flows; embedded apps use the host\'s public directory.',
71
+ insert: ": './${0:static}'",
72
+ },
68
73
  logo: {
69
74
  detail: 'string',
70
75
  doc: 'Sidebar logo text. Default: `sdocs`.',
@@ -101,7 +106,7 @@ export const configSchema = {
101
106
  object: {
102
107
  page: {
103
108
  detail: 'object',
104
- doc: '`[PAGE]` content. Defaults: `maxWidth` `1200px`, `padding` `32px`, `toc` `true`.',
109
+ doc: '`[PAGE]` content. Defaults: `maxWidth` `1200px`, `padding` `32px`, `toc` `true`, `contentX` `left`.',
105
110
  insert: ': {\n\t$0\n}',
106
111
  object: {
107
112
  maxWidth,
@@ -112,6 +117,13 @@ export const configSchema = {
112
117
  insert: ': ${0:true}',
113
118
  values: ['true', 'false'],
114
119
  },
120
+ contentX: {
121
+ detail: "'left' | 'center' | 'right'",
122
+ doc: 'Horizontal alignment of the page content column (with its toc). Default: `left`.',
123
+ insert: ": '${0:center}'",
124
+ values: ['left', 'center', 'right'],
125
+ quoted: true,
126
+ },
115
127
  },
116
128
  },
117
129
  docs: {
@@ -19,5 +19,7 @@ export interface PageSegment {
19
19
  /** Verbatim lines of the segment */
20
20
  lines: string[];
21
21
  }
22
- /** Split a page body into prose and island segments. */
22
+ /** Split a page body into prose and island segments. Lines inside markdown
23
+ * code fences are always prose — a component tag shown in a fence must stay
24
+ * displayed code, never a live island. */
23
25
  export declare function segmentPageBody(body: string): PageSegment[];
@@ -80,7 +80,9 @@ function lineDepths(line) {
80
80
  }
81
81
  return { svelte, html };
82
82
  }
83
- /** Split a page body into prose and island segments. */
83
+ /** Split a page body into prose and island segments. Lines inside markdown
84
+ * code fences are always prose — a component tag shown in a fence must stay
85
+ * displayed code, never a live island. */
84
86
  export function segmentPageBody(body) {
85
87
  const lines = body.split('\n');
86
88
  const segments = [];
@@ -92,9 +94,21 @@ export function segmentPageBody(body) {
92
94
  }
93
95
  current.lines.push(line);
94
96
  };
97
+ let inFence = false;
95
98
  let i = 0;
96
99
  while (i < lines.length) {
97
100
  const line = lines[i];
101
+ if (/^\s*(`{3,}|~{3,})/.test(line)) {
102
+ inFence = !inFence;
103
+ push('prose', line);
104
+ i++;
105
+ continue;
106
+ }
107
+ if (inFence) {
108
+ push('prose', line);
109
+ i++;
110
+ continue;
111
+ }
98
112
  const prevBlank = i === 0 || lines[i - 1].trim() === '';
99
113
  if (prevBlank && line.trim() !== '' && startsIsland(line)) {
100
114
  // Consume the island: until Svelte blocks and HTML tags balance out.
@@ -75,6 +75,8 @@ const ENTITY_ATTR_RULES = {
75
75
  PAGE: {
76
76
  title: { required: true, kind: 'string', hint: 'title="Group / Name"' },
77
77
  ...SIZING_ATTR_RULES,
78
+ // On PAGE, contentX aligns the content column (with its toc), not a stage.
79
+ contentX: { required: false, kind: 'string', hint: 'contentX="center"' },
78
80
  toc: { required: false, kind: 'string', hint: 'toc="false"' },
79
81
  },
80
82
  LAYOUT: {
@@ -7,6 +7,7 @@ const DEFAULTS = {
7
7
  port: 3000,
8
8
  open: false,
9
9
  css: null,
10
+ static: null,
10
11
  logo: 'sdocs',
11
12
  icon: 'sdocs',
12
13
  sidebar: {
@@ -14,7 +15,7 @@ const DEFAULTS = {
14
15
  open: [],
15
16
  },
16
17
  content: {
17
- page: { maxWidth: '1200px', padding: '32px', toc: true },
18
+ page: { maxWidth: '1200px', padding: '32px', toc: true, contentX: 'left' },
18
19
  docs: {
19
20
  maxWidth: '1200px',
20
21
  padding: '16px',
@@ -69,6 +70,8 @@ export function resolveAndFinalize(userConfig, root) {
69
70
  const resolved = resolveConfig(userConfig);
70
71
  resolved.include = resolveIncludePatterns(resolved.include, root);
71
72
  resolved.css = resolveCssPaths(resolved.css, root);
73
+ if (resolved.static)
74
+ resolved.static = resolve(root, resolved.static);
72
75
  return resolved;
73
76
  }
74
77
  /** Import a config file (.js/.mjs; .ts only on Node with native type stripping) */
@@ -89,6 +92,7 @@ export function resolveConfig(userConfig) {
89
92
  port: userConfig.port ?? DEFAULTS.port,
90
93
  open: userConfig.open ?? DEFAULTS.open,
91
94
  css: userConfig.css ?? DEFAULTS.css,
95
+ static: userConfig.static ?? DEFAULTS.static,
92
96
  logo: userConfig.logo ?? DEFAULTS.logo,
93
97
  icon: userConfig.icon ?? DEFAULTS.icon,
94
98
  sidebar: {
@@ -11,6 +11,9 @@ import type { TocHeading } from '../types.js';
11
11
  export interface RenderedPage {
12
12
  html: string;
13
13
  toc: TocHeading[];
14
+ /** Text of the body's first `#` heading, when present — it takes over as
15
+ * the page's displayed title. */
16
+ bodyTitle?: string;
14
17
  }
15
18
  /**
16
19
  * Render a [PAGE] body: Svelte islands (see segmentPageBody) pass through
@@ -97,26 +97,56 @@ function plainText(tokens) {
97
97
  export async function renderPageMarkdown(source) {
98
98
  const toc = [];
99
99
  const usedIds = new Set();
100
+ const state = { toc, usedIds, bodyTitle: undefined };
100
101
  const parts = [];
101
102
  for (const segment of segmentPageBody(source)) {
102
103
  if (segment.kind === 'island') {
103
104
  parts.push(segment.lines.join('\n'));
104
105
  }
105
106
  else {
106
- parts.push(await renderProse(segment.lines.join('\n'), toc, usedIds));
107
+ parts.push(await renderProse(segment.lines.join('\n'), state));
107
108
  }
108
109
  }
109
- return { html: parts.join('\n'), toc };
110
+ return { html: parts.join('\n'), toc, bodyTitle: state.bodyTitle };
110
111
  }
111
- async function renderProse(source, toc, usedIds) {
112
+ /** GitHub-style alert kinds recognized on a blockquote's first line. */
113
+ const ALERT_KINDS = ['NOTE', 'TIP', 'IMPORTANT', 'WARNING', 'CAUTION'];
114
+ const ALERT_RE = new RegExp(`^\\[!(${ALERT_KINDS.join('|')})\\][ \\t]*(?:\\n|$)`);
115
+ async function renderProse(source, state) {
116
+ const { toc, usedIds } = state;
112
117
  const headingIds = new WeakMap();
113
118
  const fenceHtml = new WeakMap();
119
+ const alertKinds = new WeakMap();
114
120
  const marked = new Marked({ gfm: true });
115
121
  const tokens = marked.lexer(source);
122
+ /** Detect a GitHub-style alert marker on a blockquote's first line and
123
+ * strip it from the tokens; the renderer wraps the rest as a callout. */
124
+ const detectAlert = (token) => {
125
+ if (!('tokens' in token) || !token.tokens)
126
+ return;
127
+ const para = token.tokens[0];
128
+ if (para?.type !== 'paragraph' || !para.tokens)
129
+ return;
130
+ const first = para.tokens[0];
131
+ if (first?.type !== 'text')
132
+ return;
133
+ const m = ALERT_RE.exec(first.text ?? '');
134
+ if (!m)
135
+ return;
136
+ alertKinds.set(token, m[1]);
137
+ first.text = first.text.slice(m[0].length);
138
+ if (first.text === '')
139
+ para.tokens.shift();
140
+ if (para.tokens.length === 0)
141
+ token.tokens.shift();
142
+ };
116
143
  const walk = (list) => {
117
144
  for (const token of list) {
118
145
  if (token.type === 'heading') {
119
146
  const text = plainText(token.tokens ?? []);
147
+ if (token.depth === 1 && state.bodyTitle === undefined) {
148
+ state.bodyTitle = text;
149
+ }
120
150
  const baseId = slugify(text);
121
151
  let id = baseId;
122
152
  for (let n = 2; usedIds.has(id); n++)
@@ -127,6 +157,8 @@ async function renderProse(source, toc, usedIds) {
127
157
  toc.push({ text, level: token.depth, id });
128
158
  }
129
159
  }
160
+ if (token.type === 'blockquote')
161
+ detectAlert(token);
130
162
  if ('tokens' in token && token.tokens)
131
163
  walk(token.tokens);
132
164
  if ('items' in token && token.items)
@@ -155,6 +187,31 @@ async function renderProse(source, toc, usedIds) {
155
187
  ? `<h${token.depth} id="${id}">${html}</h${token.depth}>\n`
156
188
  : `<h${token.depth}>${html}</h${token.depth}>\n`;
157
189
  },
190
+ // GitHub-style alerts: `> [!NOTE]` blockquotes become callouts.
191
+ blockquote(token) {
192
+ const body = this.parser.parse(token.tokens ?? []);
193
+ const kind = alertKinds.get(token);
194
+ if (!kind)
195
+ return `<blockquote>\n${body}</blockquote>\n`;
196
+ const label = kind.charAt(0) + kind.slice(1).toLowerCase();
197
+ return `<div class="sdocs-alert sdocs-alert-${kind.toLowerCase()}"><p class="sdocs-alert-label">${label}</p>\n${body}</div>\n`;
198
+ },
199
+ // External links open away from the docs app; hrefs stay inert.
200
+ link(token) {
201
+ const inner = this.parser.parseInline(token.tokens ?? []);
202
+ const href = escapeBraces(escapeHtml(token.href ?? ''));
203
+ const title = token.title ? ` title="${escapeBraces(escapeHtml(token.title))}"` : '';
204
+ const external = /^https?:\/\//i.test(token.href ?? '');
205
+ const attrs = external ? ' target="_blank" rel="noopener noreferrer"' : '';
206
+ return `<a href="${href}"${title}${attrs}>${inner}</a>`;
207
+ },
208
+ // Self-closing and brace-escaped so images are always Svelte-safe.
209
+ image(token) {
210
+ const src = escapeBraces(escapeHtml(token.href ?? ''));
211
+ const alt = escapeBraces(escapeHtml(token.text ?? ''));
212
+ const title = token.title ? ` title="${escapeBraces(escapeHtml(token.title))}"` : '';
213
+ return `<img src="${src}" alt="${alt}"${title} loading="lazy" />`;
214
+ },
158
215
  code(token) {
159
216
  return (fenceHtml.get(token) ??
160
217
  `<pre><code>${escapeBraces(escapeHtml(token.text))}</code></pre>\n`);
package/dist/types.d.ts CHANGED
@@ -8,6 +8,10 @@ export interface SdocsConfig {
8
8
  open?: boolean;
9
9
  /** CSS loaded in preview iframes. Single path or named stylesheets. */
10
10
  css?: string | Record<string, string>;
11
+ /** Folder of static assets served at the site root — images for pages,
12
+ * files for previews. Standalone CLI flows (`sdocs dev`/`build`); when
13
+ * embedding the Vite plugin, use the host app's own public directory. */
14
+ static?: string;
11
15
  /** Sidebar logo text. Default: 'sdocs' */
12
16
  logo?: string;
13
17
  /** Sidebar logo icon: 'sdocs' for the built-in mascot, an image URL, or false to hide. Default: 'sdocs' */
@@ -25,6 +29,9 @@ export interface SdocsConfig {
25
29
  page?: ContentSizing & {
26
30
  /** Show the table of contents. Default: true */
27
31
  toc?: boolean;
32
+ /** Horizontal alignment of the content column (with its toc) inside
33
+ * the view: 'left'|'center'|'right'. Default: 'left' */
34
+ contentX?: string;
28
35
  };
29
36
  /** [DOCS] pages: maxWidth is the content column (default '1200px');
30
37
  * padding/direction/gap are the default preview/example stage layout
@@ -66,6 +73,7 @@ export interface ResolvedSdocsConfig {
66
73
  port: number;
67
74
  open: boolean;
68
75
  css: string | Record<string, string> | null;
76
+ static: string | null;
69
77
  logo: string;
70
78
  icon: string | false;
71
79
  sidebar: {
@@ -75,6 +83,7 @@ export interface ResolvedSdocsConfig {
75
83
  content: {
76
84
  page: Required<ContentSizing> & {
77
85
  toc: boolean;
86
+ contentX: string;
78
87
  };
79
88
  docs: Required<ContentSizing> & {
80
89
  direction: string;
@@ -186,8 +195,13 @@ export interface DocEntry {
186
195
  maxWidth?: string;
187
196
  /** Resolved page padding (pages only) */
188
197
  padding?: string;
198
+ /** Resolved horizontal alignment of the content column (pages only) */
199
+ contentX?: string;
189
200
  /** Resolved table-of-contents visibility (pages only) */
190
201
  showToc?: boolean;
202
+ /** The body's `#` heading, shown as the page title instead of the entity
203
+ * title (pages only) */
204
+ bodyTitle?: string;
191
205
  /** Key into the virtual module's pageModules map (pages only) */
192
206
  contentKey?: string;
193
207
  }
package/dist/vite.js CHANGED
@@ -386,6 +386,8 @@ export function sdocsPlugin(userConfig) {
386
386
  entry.content = snippets[0];
387
387
  entry.toc = rendered.toc;
388
388
  entry.padding = entity.sizing.padding ?? config.content.page.padding;
389
+ entry.contentX = entity.sizing.contentX ?? config.content.page.contentX;
390
+ entry.bodyTitle = rendered.bodyTitle;
389
391
  entry.contentKey = encodeEntityId(filePath, entity.slug);
390
392
  entry.examples = snippets.filter((s) => s.role === 'example');
391
393
  entity.examples.forEach((example, i) => {
@@ -436,7 +438,9 @@ export function sdocsPlugin(userConfig) {
436
438
  toc: e.toc,
437
439
  maxWidth: e.maxWidth,
438
440
  padding: e.padding,
441
+ contentX: e.contentX,
439
442
  showToc: e.showToc,
443
+ bodyTitle: e.bodyTitle,
440
444
  contentKey: e.contentKey,
441
445
  }));
442
446
  // Extract named CSS stylesheet names (empty array if single string or null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdocs",
3
- "version": "0.0.57",
3
+ "version": "0.0.58",
4
4
  "description": "A lightweight documentation tool for Svelte 5 components",
5
5
  "type": "module",
6
6
  "license": "MIT",