lildocs 0.1.20 → 0.1.22

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.
@@ -193,7 +193,8 @@ html.is-animating .transition-scale {
193
193
  top: 0;
194
194
  align-self: start;
195
195
  max-height: 100vh;
196
- overflow: auto;
196
+ overflow-x: hidden;
197
+ overflow-y: auto;
197
198
  padding-block: 70px 24px;
198
199
  }
199
200
 
@@ -849,9 +850,13 @@ html.mermaidFullscreenOpen {
849
850
  opacity: 1;
850
851
  }
851
852
 
852
- .toc a {
853
+ .tocLinks a {
854
+ display: block;
855
+ overflow: hidden;
853
856
  color: var(--ld-color-muted-text);
854
857
  text-decoration: none;
858
+ text-overflow: ellipsis;
859
+ white-space: nowrap;
855
860
  }
856
861
 
857
862
  .tocDepth3 {
@@ -1042,6 +1047,10 @@ html.mermaidFullscreenOpen {
1042
1047
  text-decoration: none;
1043
1048
  }
1044
1049
 
1050
+ .tocRepoLink:first-child {
1051
+ border-top: 0;
1052
+ }
1053
+
1045
1054
  .tocRepoLink:hover,
1046
1055
  .tocRepoLink:focus-visible {
1047
1056
  color: var(--ld-color-link);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lildocs",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "A lightweight CLI that turns Markdown docs into a static searchable documentation site.",
5
5
  "homepage": "https://aleclarson.github.io/lildocs/",
6
6
  "repository": {
@@ -15,37 +15,34 @@
15
15
  ],
16
16
  "type": "module",
17
17
  "scripts": {
18
- "build": "tsdown",
18
+ "build": "tsdown && node scripts/build-renderers.mjs",
19
19
  "docs:serve": "pnpm run build && node dist/cli.mjs build ./docs --out ./dist/docs && sirv ./dist/docs",
20
- "format": "prettier --write src schemas package.json tsconfig.json tsdown.config.ts vitest.config.ts .oxlintrc.json .prettierrc.json .vscode/settings.json",
21
- "format:check": "prettier --check src schemas package.json tsconfig.json tsdown.config.ts vitest.config.ts .oxlintrc.json .prettierrc.json .vscode/settings.json",
22
- "lint": "oxlint src tsdown.config.ts vitest.config.ts",
20
+ "format": "prettier --write src scripts schemas package.json tsconfig.json tsdown.config.ts vitest.config.ts .oxlintrc.json .prettierrc.json .vscode/settings.json",
21
+ "format:check": "prettier --check src scripts schemas package.json tsconfig.json tsdown.config.ts vitest.config.ts .oxlintrc.json .prettierrc.json .vscode/settings.json",
22
+ "lint": "oxlint src scripts tsdown.config.ts vitest.config.ts",
23
23
  "test": "pnpm run build && vitest run",
24
24
  "typecheck": "tsc --noEmit"
25
25
  },
26
26
  "dependencies": {
27
27
  "beautiful-mermaid": "^1.1.3",
28
+ "shiki": "^4.0.2"
29
+ },
30
+ "devDependencies": {
31
+ "@tsrx/prettier-plugin": "^0.3.93",
32
+ "@types/culori": "^4.0.1",
33
+ "@types/node": "^24.0.0",
28
34
  "cmd-ts": "^0.15.0",
29
35
  "culori": "^4.0.2",
30
36
  "entities": "^8.0.0",
31
- "exports-md": "^0.2.5",
37
+ "exports-md": "^0.2.7",
32
38
  "gray-matter": "^4.0.3",
33
39
  "marked": "^18.0.3",
34
40
  "marked-shiki": "^1.2.1",
35
41
  "octane": "^0.1.3",
36
- "shiki": "^4.0.2",
37
- "swup": "^4.9.0"
38
- },
39
- "peerDependencies": {
40
- "vite": "^8.0.0"
41
- },
42
- "devDependencies": {
43
- "@tsrx/prettier-plugin": "^0.3.93",
44
- "@types/culori": "^4.0.1",
45
- "@types/node": "^24.0.0",
46
42
  "oxlint": "^1.65.0",
47
43
  "prettier": "^3.9.5",
48
44
  "sirv": "^3.0.2",
45
+ "swup": "^4.9.0",
49
46
  "tsdown": "^0.22.0",
50
47
  "typescript": "^5.9.0",
51
48
  "vite": "^8.0.0",
@@ -1,375 +0,0 @@
1
- import type { Heading, Page } from "../core/content.js";
2
- import type { ResolvedLogo } from "../core/logo.js";
3
- import type { NavItem } from "../core/nav.js";
4
- import type { NavigationOptions } from "../core/theme.js";
5
- import { relativeUrl, rootRelativeUrl } from "./paths.js";
6
- import type { PageNavigation } from "./types.js";
7
-
8
- export type LayoutProps = {
9
- page: Page;
10
- nav: NavItem[];
11
- pageNavigation?: PageNavigation;
12
- css: string;
13
- searchIndexJson: string;
14
- logo: ResolvedLogo;
15
- favicon?: string;
16
- repositoryUrl?: string;
17
- projectName?: string;
18
- navigation?: NavigationOptions;
19
- clientScriptPath: string;
20
- clientStylePaths: string[];
21
- };
22
-
23
- export function Layout({
24
- page,
25
- nav,
26
- pageNavigation,
27
- searchIndexJson,
28
- logo,
29
- favicon,
30
- repositoryUrl,
31
- projectName,
32
- navigation,
33
- clientScriptPath,
34
- clientStylePaths,
35
- }: LayoutProps) @{
36
- const transition = navigation?.transition ?? "fade";
37
- const issueUrl = issueUrlForRepository(repositoryUrl);
38
- const repositoryLabel = repositoryLabelForUrl(repositoryUrl);
39
-
40
- <>
41
- <meta charSet="utf-8" />
42
- <meta name="viewport" content="width=device-width, initial-scale=1" />
43
- <title>
44
- {(projectName ? `${page.title} • ${projectName}` : page.title) as string}
45
- </title>
46
- @if (favicon) {
47
- <link rel="icon" href={assetSrc(page.route, favicon)} />
48
- }
49
- <link
50
- rel="stylesheet"
51
- href={rootRelativeUrl(page.route, "assets/tabler-icons.css")}
52
- />
53
- <link
54
- rel="stylesheet"
55
- href={rootRelativeUrl(page.route, "assets/lildocs.css")}
56
- />
57
- @for (const stylePath of clientStylePaths; key stylePath) {
58
- <link rel="stylesheet" href={assetSrc(page.route, stylePath)} />
59
- }
60
- <div class="pageShell">
61
- <aside id="lildocs-sidebar" class="sidebar">
62
- <div class="sidebarContents">
63
- <div class="sidebarHeader">
64
- <a class="brand" href={relativeUrl(page.route, "index.html")}>
65
- @if (logo.image) {
66
- <img
67
- class="brandLogo"
68
- src={assetSrc(page.route, logo.image)}
69
- alt=""
70
- />
71
- }
72
- @if (logo.text) {
73
- <span>
74
- {logo.text as string}
75
- </span>
76
- }
77
- </a>
78
- <button
79
- id="lildocs-sidebar-toggle"
80
- class="sidebarToggle"
81
- type="button"
82
- aria-label="Collapse sidebar"
83
- aria-controls="lildocs-sidebar"
84
- aria-expanded="false"
85
- >
86
- <span
87
- class="sidebarCollapseIcon ti ti-layout-sidebar-left-collapse"
88
- aria-hidden="true"
89
- />
90
- <span class="sidebarMenuIcon ti ti-menu-2" aria-hidden="true" />
91
- </button>
92
- </div>
93
- <div id="lildocs-search-root" class="searchBox">
94
- <span class="searchIcon ti ti-search" aria-hidden="true" />
95
- <input
96
- id="lildocs-search-input"
97
- type="search"
98
- placeholder="Search docs"
99
- aria-label="Search docs"
100
- />
101
- </div>
102
- <nav
103
- id="lildocs-sidebar-navigation"
104
- aria-label="Documentation navigation"
105
- >
106
- <NavList
107
- items={nav}
108
- currentRoute={page.route}
109
- pageRoute={page.route}
110
- />
111
- </nav>
112
- @if (repositoryUrl && repositoryLabel) {
113
- <a
114
- class="sidebarRepoLink"
115
- href={repositoryUrl}
116
- aria-label="View repository on GitHub"
117
- >
118
- <span class="repoIcon" aria-hidden="true" />
119
- <span>
120
- {repositoryLabel as string}
121
- </span>
122
- </a>
123
- }
124
- </div>
125
- </aside>
126
- <div class="sidebarFloatingControls">
127
- <button
128
- id="lildocs-sidebar-expand"
129
- class="sidebarToggle"
130
- type="button"
131
- aria-label="Expand sidebar"
132
- aria-controls="lildocs-sidebar"
133
- >
134
- <span class="ti ti-layout-sidebar-left-expand" aria-hidden="true" />
135
- </button>
136
- <button
137
- id="lildocs-floating-search"
138
- class="sidebarToggle"
139
- type="button"
140
- aria-label="Search docs"
141
- >
142
- <span class="ti ti-search" aria-hidden="true" />
143
- </button>
144
- </div>
145
- <div id="swup" class="contentGrid">
146
- <main class={`content transition-${transition}`}>
147
- <article>
148
- <GroupBreadcrumbs route={page.route} />
149
- <div dangerouslySetInnerHTML={{ __html: page.html ?? "" }} />
150
- </article>
151
- <PageNav pageNavigation={pageNavigation} />
152
- </main>
153
- <aside class={`toc transition-${transition}`}>
154
- <Toc
155
- headings={page.headings}
156
- repositoryUrl={repositoryUrl}
157
- repositoryLabel={repositoryLabel}
158
- />
159
- </aside>
160
- </div>
161
- </div>
162
- <script
163
- dangerouslySetInnerHTML={{
164
- __html: `window.lildocsSearchUrl = ${JSON.stringify(
165
- rootRelativeUrl(page.route, "search-index.json"),
166
- )};${
167
- issueUrl
168
- ? `window.lildocsIssueUrl = ${JSON.stringify(issueUrl)};`
169
- : ""
170
- }`,
171
- }}
172
- />
173
- <script
174
- type="application/json"
175
- id="lildocs-search-index"
176
- dangerouslySetInnerHTML={{ __html: searchIndexJson }}
177
- />
178
- <div id="lildocs-overlay-root" />
179
- <script type="module" src={assetSrc(page.route, clientScriptPath)} />
180
- </>
181
- }
182
-
183
- function issueUrlForRepository(repositoryUrl: string | undefined) {
184
- if (!repositoryUrl) {
185
- return undefined;
186
- }
187
-
188
- let url: URL;
189
- try {
190
- url = new URL(repositoryUrl);
191
- } catch {
192
- return undefined;
193
- }
194
-
195
- if (url.hostname !== "github.com") {
196
- return undefined;
197
- }
198
-
199
- const [owner, repo] = url.pathname.split("/").filter(Boolean);
200
- if (!owner || !repo) {
201
- return undefined;
202
- }
203
-
204
- return `https://github.com/${owner}/${repo}/issues/new`;
205
- }
206
-
207
- function repositoryLabelForUrl(repositoryUrl: string | undefined) {
208
- if (!repositoryUrl) {
209
- return undefined;
210
- }
211
-
212
- try {
213
- const url = new URL(repositoryUrl);
214
- if (url.hostname !== "github.com") {
215
- return undefined;
216
- }
217
-
218
- const [owner, repo] = url.pathname.split("/").filter(Boolean);
219
- return owner && repo ? `${owner}/${repo}` : undefined;
220
- } catch {
221
- return undefined;
222
- }
223
- }
224
-
225
- function assetSrc(pageRoute: string, image: string) {
226
- if (
227
- /^(?:[a-z]+:)?\/\//i.test(image) || image.startsWith("data:") ||
228
- image.startsWith("/")
229
- ) {
230
- return image;
231
- }
232
-
233
- return rootRelativeUrl(pageRoute, image);
234
- }
235
-
236
- function GroupBreadcrumbs({ route }: { route: string }) @{
237
- const dir = route.split("/").slice(0, -1);
238
- if (dir.length === 0) {
239
- return null;
240
- }
241
-
242
- <p class="groupBreadcrumbs">
243
- {dir.map(titleFromDir).join(" / ") as string}
244
- </p>
245
- }
246
-
247
- function titleFromDir(dir: string) {
248
- return dir.replace(/[-_]+/g, " ").replace(
249
- /\S+/g,
250
- (word) => `${word[0]?.toLocaleUpperCase() ?? ""}${word.slice(1)}`,
251
- );
252
- }
253
-
254
- function PageNav({ pageNavigation }: { pageNavigation?: PageNavigation }) @{
255
- if (!pageNavigation?.next) {
256
- return null;
257
- }
258
-
259
- <nav class="pageNav" aria-label="Page navigation">
260
- <p>
261
- {"Next: "}
262
- <a rel="next" href={pageNavigation.next.href}>
263
- {pageNavigation.next.title as string}
264
- </a>
265
- </p>
266
- </nav>
267
- }
268
-
269
- function NavList({
270
- items,
271
- currentRoute,
272
- pageRoute,
273
- }: {
274
- items: NavItem[];
275
- currentRoute: string;
276
- pageRoute: string;
277
- }) @{
278
- <ul class="navList">
279
- @for (const item of items; key item.route) {
280
- <li class={item.children.length > 0 ? "navGroup" : undefined}>
281
- @if (item.children.length > 0 && item.hasPage) {
282
- <details
283
- class="navDisclosure"
284
- open={isActiveBranch(item, currentRoute)}
285
- >
286
- <summary class={item.route === currentRoute ? "active" : undefined}>
287
- {item.title as string}
288
- </summary>
289
- <NavList
290
- items={item.children}
291
- currentRoute={currentRoute}
292
- pageRoute={pageRoute}
293
- />
294
- </details>
295
- } @else if (item.children.length > 0) {
296
- <span class="navFolder">
297
- {item.title as string}
298
- </span>
299
- } @else {
300
- <a
301
- class={item.route === currentRoute ? "active" : undefined}
302
- href={relativeUrl(pageRoute, item.route)}
303
- >
304
- {item.title as string}
305
- </a>
306
- }
307
- @if (item.children.length > 0 && !item.hasPage) {
308
- <NavList
309
- items={item.children}
310
- currentRoute={currentRoute}
311
- pageRoute={pageRoute}
312
- />
313
- }
314
- </li>
315
- }
316
- </ul>
317
- }
318
-
319
- function isActiveBranch(item: NavItem, currentRoute: string): boolean {
320
- return item.route === currentRoute ||
321
- item.children.some((child) => isActiveBranch(child, currentRoute));
322
- }
323
-
324
- function Toc({
325
- headings,
326
- repositoryUrl,
327
- repositoryLabel,
328
- }: {
329
- headings: Heading[];
330
- repositoryUrl?: string;
331
- repositoryLabel?: string;
332
- }) @{
333
- const tocHeadings = headings.filter(
334
- (heading) => heading.depth > 1 && heading.depth < 4,
335
- );
336
- if (tocHeadings.length === 0 && !repositoryLabel) {
337
- return null;
338
- }
339
-
340
- <nav aria-label="Table of contents">
341
- @if (tocHeadings.length > 0) {
342
- <>
343
- <p class="tocTitle">
344
- <span class="ti ti-align-left" aria-hidden="true" />
345
- On this page
346
- </p>
347
- <div class="tocLinks" data-toc-links>
348
- <span class="tocRail" aria-hidden="true" />
349
- <span class="tocVisibility" data-toc-visibility aria-hidden="true" />
350
- <ul>
351
- @for (const heading of tocHeadings; key heading.id) {
352
- <li class={`tocDepth${heading.depth}`}>
353
- <a href={`#${heading.id}`}>
354
- {heading.text as string}
355
- </a>
356
- </li>
357
- }
358
- </ul>
359
- </div>
360
- </>
361
- }
362
- @if (repositoryUrl && repositoryLabel) {
363
- <a
364
- class="tocRepoLink"
365
- href={repositoryUrl}
366
- aria-label="View repository on GitHub"
367
- >
368
- <span class="repoIcon" aria-hidden="true" />
369
- <span>
370
- {repositoryLabel as string}
371
- </span>
372
- </a>
373
- }
374
- </nav>
375
- }