radiant-docs 0.1.69 → 0.1.70

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "radiant-docs",
3
- "version": "0.1.69",
3
+ "version": "0.1.70",
4
4
  "description": "CLI tool for previewing Radiant documentation locally",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,6 +32,7 @@
32
32
  "@iconify/react": "^6.0.2",
33
33
  "@paper-design/shaders": "^0.0.76",
34
34
  "@preact/preset-vite": "^2.10.3",
35
+ "@radiant-docs/assistant-shiki": "file:../packages/assistant-shiki",
35
36
  "@readme/oas-to-snippet": "^29.3.0",
36
37
  "@shikijs/core": "4.2.0",
37
38
  "@shikijs/engine-javascript": "4.2.0",
@@ -3222,6 +3223,10 @@
3222
3223
  "url": "https://github.com/sponsors/jonschlinkert"
3223
3224
  }
3224
3225
  },
3226
+ "node_modules/@radiant-docs/assistant-shiki": {
3227
+ "resolved": "../packages/assistant-shiki",
3228
+ "link": true
3229
+ },
3225
3230
  "node_modules/@readme/better-ajv-errors": {
3226
3231
  "version": "2.4.0",
3227
3232
  "resolved": "https://registry.npmjs.org/@readme/better-ajv-errors/-/better-ajv-errors-2.4.0.tgz",
@@ -7,6 +7,7 @@
7
7
  "astro": "astro"
8
8
  },
9
9
  "dependencies": {
10
+ "@radiant-docs/assistant-shiki": "file:../packages/assistant-shiki",
10
11
  "@alpinejs/collapse": "^3.15.2",
11
12
  "@alpinejs/focus": "^3.15.3",
12
13
  "@alpinejs/persist": "^3.15.2",
@@ -131,42 +131,24 @@ const navbarPrimaryHref = config.navbar?.primary
131
131
  "sm:bg-background/85 sm:backdrop-blur-[18px] sm:backdrop-saturate-50 sm:border-b-neutral-100/85 sm:dark:border-neutral-800/85 sm:bg-clip-padding",
132
132
  ]}
133
133
  data-pagefind-ignore
134
+ data-rd-navbar-header
134
135
  >
135
- <div class="flex h-full">
136
- <div class="lg:w-[283px] h-full">
137
- <div class="flex gap-3 lg:block h-full lg:border-r border-border-light">
138
- <button
139
- x-on:click="open = ! open"
140
- class="lg:hidden cursor-pointer pl-4 sm:pl-6 pr-2"
141
- >
142
- <div
143
- class="flex flex-col items-center justify-center gap-1 h-full transition"
144
- x-bind:class="open ? 'rotate-90': ''"
145
- >
146
- <div
147
- class="w-[14px] h-0.5 bg-neutral-900 dark:bg-white rounded-full origin-[20%_50%] transition"
148
- x-bind:class="open ? 'rotate-45': ''"
149
- >
150
- </div>
151
- <div
152
- class="w-[14px] h-0.5 bg-neutral-900 dark:bg-white rounded-full origin-[20%_50%] transition"
153
- x-bind:class="open ? '-rotate-45': ''"
154
- >
155
- </div>
156
- </div>
157
- </button>
136
+ <div class="flex h-full items-stretch">
137
+ <div class="h-full min-w-0 shrink lg:w-[283px] lg:shrink-0">
138
+ <div
139
+ class="flex h-full items-center justify-start pl-4 sm:pl-6 lg:justify-center lg:border-r lg:border-border-light lg:pl-0"
140
+ >
158
141
  <LogoLink />
159
142
  </div>
160
143
  </div>
161
- <div class="flex-1 flex">
144
+ <div class="flex min-w-0 flex-1">
162
145
  <div
163
- class="min-w-0 w-full flex items-center justify-end md:justify-between gap-3 px-4 sm:px-6"
146
+ class="flex w-full min-w-0 items-center justify-end pr-2 sm:pr-4 lg:justify-between lg:gap-8 lg:px-6"
147
+ data-rd-navbar-content
164
148
  >
165
149
  <div
166
- class:list={[
167
- "flex items-center gap-2 mx-0",
168
- "md:mx-auto lg:mx-0",
169
- ]}
150
+ class="flex min-w-0 flex-1 items-center justify-end gap-2 md:justify-center lg:flex-none lg:justify-start"
151
+ data-rd-navbar-search
170
152
  >
171
153
  <Search />
172
154
  {
@@ -193,24 +175,23 @@ const navbarPrimaryHref = config.navbar?.primary
193
175
  </div>
194
176
  {
195
177
  config.navbar && (
196
- <nav class="hidden xs:flex items-center gap-3">
178
+ <nav
179
+ class="hidden lg:flex items-center gap-3"
180
+ data-rd-navbar-desktop-nav
181
+ >
197
182
  {navbarLinks.length > 0 && (
198
183
  <div
199
184
  class:list={[
200
- "space-x-1",
185
+ "flex shrink-0 items-center gap-1",
201
186
  config.navbar.primary || config.navbar.secondary
202
- ? "pr-2 hidden xl:flex"
203
- : "hidden lg:flex",
187
+ ? "pr-2"
188
+ : "",
204
189
  ]}
190
+ data-rd-navbar-links
205
191
  >
206
- {navbarLinks.map((l, i, a) => (
192
+ {navbarLinks.map((l) => (
207
193
  <a
208
- class:list={[
209
- "items-center gap-1 text-[13px] font-medium dark:font-normal text-neutral-600/85 hover:text-neutral-600 dark:text-neutral-200/90 dark:hover:text-neutral-200 duration-200 px-1.5 py-[5px] whitespace-nowrap",
210
- showAssistantNavbarButton && a.length === 3 && i === 2
211
- ? "hidden 2xl:flex"
212
- : "flex",
213
- ]}
194
+ class="flex items-center gap-1 px-1.5 py-[5px] text-[13px] font-medium text-neutral-600/85 whitespace-nowrap duration-200 hover:text-neutral-600 dark:font-normal dark:text-neutral-200/90 dark:hover:text-neutral-200"
214
195
  href={l.href}
215
196
  >
216
197
  {l.icon && (
@@ -226,52 +207,134 @@ const navbarPrimaryHref = config.navbar?.primary
226
207
  ))}
227
208
  </div>
228
209
  )}
229
- {config.navbar.secondary && (
230
- <a
231
- class:list={[
232
- "h-[33px] items-center gap-1.5 px-[11px] text-[13px] bg-linear-to-br from-neutral-100/70 to-neutral-100/90 dark:bg-none dark:bg-neutral-800/80 text-neutral-900/85 hover:text-neutral-600 dark:text-neutral-200/95 dark:hover:text-neutral-200 rounded-lg [corner-shape:superellipse(1.2)] border-[0.5px] border-neutral-900/10 dark:border-white/5 transition-all whitespace-nowrap",
233
- config.navbar.primary ? "hidden lg:flex" : "flex",
234
- ]}
235
- href={navbarSecondaryHref}
210
+ {navbarLinks.length > 0 && (
211
+ <div
212
+ class="relative shrink-0"
213
+ data-rd-navbar-overflow
214
+ hidden
236
215
  >
237
- {config.navbar.secondary.icon && (
216
+ <button
217
+ type="button"
218
+ class="flex size-8 cursor-pointer items-center justify-center rounded-lg text-neutral-600 transition-colors hover:bg-neutral-100/70 hover:text-neutral-900 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-500 dark:text-neutral-300 dark:hover:bg-neutral-800/70 dark:hover:text-white dark:focus-visible:outline-neutral-400"
219
+ aria-label="Show more navbar links"
220
+ aria-haspopup="true"
221
+ aria-expanded="false"
222
+ aria-controls="navbar-overflow-menu"
223
+ data-rd-navbar-overflow-trigger
224
+ >
238
225
  <Icon
239
- name={config.navbar.secondary.icon}
240
- width="14"
241
- height="14"
242
- class="-ml-px"
226
+ name="lucide:ellipsis-vertical"
227
+ class="size-4"
228
+ aria-hidden="true"
243
229
  />
244
- )}
245
- {config.navbar.secondary.text}
246
- </a>
230
+ </button>
231
+ </div>
247
232
  )}
248
- {config.navbar.primary && (
249
- <a
250
- class:list={[
251
- "navbar-primary-trigger h-8 flex items-center gap-2 px-3 text-[13px] font-normal dark:font-medium rounded-lg [corner-shape:superellipse(1.2)] duration-200 transition-all whitespace-nowrap hover:opacity-95",
252
- ]}
253
- style={navbarPrimaryButtonStyle}
254
- href={navbarPrimaryHref}
233
+ {(config.navbar.secondary || config.navbar.primary) && (
234
+ <div
235
+ class="flex shrink-0 items-center gap-3"
236
+ data-rd-navbar-actions
255
237
  >
256
- {config.navbar.primary.icon && (
257
- <Icon
258
- name={config.navbar.primary.icon}
259
- width="14"
260
- height="14"
261
- class="-ml-px"
262
- />
238
+ {config.navbar.secondary && (
239
+ <a
240
+ class="flex h-[33px] items-center gap-1.5 rounded-lg [corner-shape:superellipse(1.2)] border-[0.5px] border-neutral-900/10 bg-linear-to-br from-neutral-100/70 to-neutral-100/90 px-[11px] text-[13px] text-neutral-900/85 whitespace-nowrap transition-all hover:text-neutral-600 dark:border-white/5 dark:bg-none dark:bg-neutral-800/80 dark:text-neutral-200/95 dark:hover:text-neutral-200"
241
+ href={navbarSecondaryHref}
242
+ >
243
+ {config.navbar.secondary.icon && (
244
+ <Icon
245
+ name={config.navbar.secondary.icon}
246
+ width="14"
247
+ height="14"
248
+ class="-ml-px"
249
+ />
250
+ )}
251
+ {config.navbar.secondary.text}
252
+ </a>
263
253
  )}
264
- {config.navbar.primary.text}
265
- </a>
254
+ {config.navbar.primary && (
255
+ <a
256
+ class="navbar-primary-trigger flex h-8 items-center gap-2 rounded-lg [corner-shape:superellipse(1.2)] px-3 text-[13px] font-normal whitespace-nowrap transition-all duration-200 hover:opacity-95 dark:font-medium"
257
+ style={navbarPrimaryButtonStyle}
258
+ href={navbarPrimaryHref}
259
+ >
260
+ {config.navbar.primary.icon && (
261
+ <Icon
262
+ name={config.navbar.primary.icon}
263
+ width="14"
264
+ height="14"
265
+ class="-ml-px"
266
+ />
267
+ )}
268
+ {config.navbar.primary.text}
269
+ </a>
270
+ )}
271
+ </div>
266
272
  )}
267
273
  </nav>
268
274
  )
269
275
  }
276
+ <button
277
+ type="button"
278
+ x-on:click="open = !open"
279
+ x-bind:aria-expanded="open"
280
+ x-bind:aria-label="open ? 'Close navigation menu' : 'Open navigation menu'"
281
+ aria-controls="mobile-navigation"
282
+ class="flex size-10 shrink-0 cursor-pointer items-center justify-center rounded-lg text-neutral-900 transition-colors hover:bg-neutral-100/70 dark:text-white dark:hover:bg-neutral-800/70 lg:hidden"
283
+ >
284
+ <span class="sr-only">Toggle navigation menu</span>
285
+ <span
286
+ aria-hidden="true"
287
+ class="flex flex-col items-center justify-center gap-1 transition"
288
+ x-bind:class="open ? 'rotate-90': ''"
289
+ >
290
+ <span
291
+ class="h-0.5 w-[14px] origin-[20%_50%] rounded-full bg-current transition"
292
+ x-bind:class="open ? 'rotate-45': ''"
293
+ >
294
+ </span>
295
+ <span
296
+ class="h-0.5 w-[14px] origin-[20%_50%] rounded-full bg-current transition"
297
+ x-bind:class="open ? '-rotate-45': ''"
298
+ >
299
+ </span>
300
+ </span>
301
+ </button>
270
302
  </div>
271
303
  </div>
272
304
  </div>
273
305
  </header>
274
306
 
307
+ {
308
+ navbarLinks.length > 0 && (
309
+ <nav
310
+ id="navbar-overflow-menu"
311
+ aria-label="More navbar links"
312
+ class="fixed z-50 w-56 max-w-[calc(100vw-1rem)] overflow-y-auto rounded-xl border-[0.5px] border-neutral-200 bg-white p-1 shadow-2xl shadow-neutral-900/12 dark:border-neutral-800 dark:bg-neutral-800 dark:shadow-black/40"
313
+ data-rd-navbar-overflow-menu
314
+ data-pagefind-ignore
315
+ hidden
316
+ >
317
+ {navbarLinks.map((link) => (
318
+ <a
319
+ class="flex min-h-9 items-center gap-2 rounded-lg px-2.5 py-2 text-[13px] font-medium text-neutral-700 transition-colors hover:bg-neutral-100/70 hover:text-neutral-950 focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-neutral-500 dark:font-normal dark:text-neutral-200 dark:hover:bg-neutral-700/70 dark:hover:text-white dark:focus-visible:outline-neutral-400"
320
+ href={link.href}
321
+ data-rd-navbar-overflow-link
322
+ >
323
+ {link.icon && (
324
+ <Icon
325
+ name={link.icon}
326
+ width="14"
327
+ height="14"
328
+ class="shrink-0"
329
+ />
330
+ )}
331
+ <span class="min-w-0 break-words">{link.text}</span>
332
+ </a>
333
+ ))}
334
+ </nav>
335
+ )
336
+ }
337
+
275
338
  <style>
276
339
  .assistant-header-trigger {
277
340
  --assistant-header-theme: var(--assistant-header-theme-light);
@@ -305,3 +368,215 @@ const navbarPrimaryHref = config.navbar?.primary
305
368
  --navbar-primary-foreground: var(--navbar-primary-foreground-dark);
306
369
  }
307
370
  </style>
371
+
372
+ <script is:inline>
373
+ (() => {
374
+ const cleanupKey = "__radiantDocsNavbarFitCleanup";
375
+ const previousCleanup = window[cleanupKey];
376
+
377
+ if (typeof previousCleanup === "function") previousCleanup();
378
+
379
+ const header = document.querySelector("[data-rd-navbar-header]");
380
+ const content = header?.querySelector("[data-rd-navbar-content]");
381
+ const search = header?.querySelector("[data-rd-navbar-search]");
382
+ const nav = header?.querySelector("[data-rd-navbar-desktop-nav]");
383
+ const links = header?.querySelector("[data-rd-navbar-links]");
384
+ const actions = header?.querySelector("[data-rd-navbar-actions]");
385
+ const overflow = header?.querySelector("[data-rd-navbar-overflow]");
386
+ const overflowTrigger = header?.querySelector(
387
+ "[data-rd-navbar-overflow-trigger]",
388
+ );
389
+ const overflowMenu = document.querySelector(
390
+ "[data-rd-navbar-overflow-menu]",
391
+ );
392
+
393
+ if (
394
+ !(header instanceof HTMLElement) ||
395
+ !(content instanceof HTMLElement) ||
396
+ !(search instanceof HTMLElement) ||
397
+ !(nav instanceof HTMLElement) ||
398
+ !(links instanceof HTMLElement) ||
399
+ !(overflow instanceof HTMLElement) ||
400
+ !(overflowTrigger instanceof HTMLButtonElement) ||
401
+ !(overflowMenu instanceof HTMLElement)
402
+ ) {
403
+ return;
404
+ }
405
+
406
+ const desktopQuery = window.matchMedia("(min-width: 64rem)");
407
+ let linksWidth = 0;
408
+ let frameId = 0;
409
+
410
+ const positionOverflowMenu = () => {
411
+ const triggerRect = overflowTrigger.getBoundingClientRect();
412
+ const menuWidth = overflowMenu.getBoundingClientRect().width;
413
+ const viewportPadding = 8;
414
+ const left = Math.min(
415
+ Math.max(viewportPadding, triggerRect.right - menuWidth),
416
+ window.innerWidth - menuWidth - viewportPadding,
417
+ );
418
+
419
+ overflowMenu.style.left = `${Math.max(viewportPadding, left)}px`;
420
+ overflowMenu.style.top = `${triggerRect.bottom + 8}px`;
421
+ overflowMenu.style.maxHeight = `${Math.max(
422
+ 120,
423
+ window.innerHeight - triggerRect.bottom - 16,
424
+ )}px`;
425
+ };
426
+
427
+ const setOverflowMenuOpen = (nextOpen, focusFirstLink = false) => {
428
+ const canOpen =
429
+ nextOpen && desktopQuery.matches && !overflow.hasAttribute("hidden");
430
+
431
+ overflowMenu.hidden = !canOpen;
432
+ overflowTrigger.setAttribute("aria-expanded", String(canOpen));
433
+
434
+ if (!canOpen) return;
435
+
436
+ positionOverflowMenu();
437
+ if (focusFirstLink) {
438
+ const firstLink = overflowMenu.querySelector(
439
+ "[data-rd-navbar-overflow-link]",
440
+ );
441
+ if (firstLink instanceof HTMLElement) firstLink.focus();
442
+ }
443
+ };
444
+
445
+ const measureLinksWidth = () => {
446
+ const clone = links.cloneNode(true);
447
+ if (!(clone instanceof HTMLElement)) return linksWidth;
448
+
449
+ clone.removeAttribute("hidden");
450
+ clone.removeAttribute("data-rd-navbar-links");
451
+ clone.setAttribute("aria-hidden", "true");
452
+ clone.style.position = "fixed";
453
+ clone.style.inset = "0 auto auto -10000px";
454
+ clone.style.display = "flex";
455
+ clone.style.width = "max-content";
456
+ clone.style.visibility = "hidden";
457
+ clone.style.pointerEvents = "none";
458
+ document.body.append(clone);
459
+
460
+ const width = clone.getBoundingClientRect().width;
461
+ clone.remove();
462
+ return width;
463
+ };
464
+
465
+ const updateLinksVisibility = () => {
466
+ frameId = 0;
467
+
468
+ if (!desktopQuery.matches) {
469
+ links.removeAttribute("hidden");
470
+ overflow.setAttribute("hidden", "");
471
+ setOverflowMenuOpen(false);
472
+ return;
473
+ }
474
+
475
+ const contentStyle = getComputedStyle(content);
476
+ const navStyle = getComputedStyle(nav);
477
+ const availableWidth =
478
+ content.clientWidth -
479
+ (Number.parseFloat(contentStyle.paddingLeft) || 0) -
480
+ (Number.parseFloat(contentStyle.paddingRight) || 0);
481
+ const searchWidth = search.getBoundingClientRect().width;
482
+ const actionsWidth =
483
+ actions instanceof HTMLElement
484
+ ? actions.getBoundingClientRect().width
485
+ : 0;
486
+ const contentGap = Number.parseFloat(contentStyle.columnGap) || 0;
487
+ const navGap =
488
+ actions instanceof HTMLElement
489
+ ? Number.parseFloat(navStyle.columnGap) || 0
490
+ : 0;
491
+ const requiredWidth =
492
+ searchWidth +
493
+ contentGap +
494
+ linksWidth +
495
+ navGap +
496
+ actionsWidth;
497
+
498
+ const linksDoNotFit = requiredWidth > availableWidth;
499
+ links.toggleAttribute("hidden", linksDoNotFit);
500
+ overflow.toggleAttribute("hidden", !linksDoNotFit);
501
+
502
+ if (!linksDoNotFit) {
503
+ setOverflowMenuOpen(false);
504
+ } else if (!overflowMenu.hidden) {
505
+ positionOverflowMenu();
506
+ }
507
+ };
508
+
509
+ const scheduleUpdate = () => {
510
+ if (frameId !== 0) return;
511
+ frameId = requestAnimationFrame(updateLinksVisibility);
512
+ };
513
+
514
+ const onOverflowTriggerClick = () => {
515
+ setOverflowMenuOpen(overflowMenu.hidden);
516
+ };
517
+
518
+ const onOverflowTriggerKeydown = (event) => {
519
+ if (event.key !== "ArrowDown") return;
520
+ event.preventDefault();
521
+ setOverflowMenuOpen(true, true);
522
+ };
523
+
524
+ const onDocumentPointerDown = (event) => {
525
+ if (overflowMenu.hidden || !(event.target instanceof Node)) return;
526
+ if (
527
+ overflowTrigger.contains(event.target) ||
528
+ overflowMenu.contains(event.target)
529
+ ) {
530
+ return;
531
+ }
532
+ setOverflowMenuOpen(false);
533
+ };
534
+
535
+ const onDocumentKeydown = (event) => {
536
+ if (event.key !== "Escape" || overflowMenu.hidden) return;
537
+ setOverflowMenuOpen(false);
538
+ overflowTrigger.focus();
539
+ };
540
+
541
+ const onOverflowMenuClick = (event) => {
542
+ if (
543
+ event.target instanceof Element &&
544
+ event.target.closest("[data-rd-navbar-overflow-link]")
545
+ ) {
546
+ setOverflowMenuOpen(false);
547
+ }
548
+ };
549
+
550
+ linksWidth = measureLinksWidth();
551
+ updateLinksVisibility();
552
+
553
+ const resizeObserver = new ResizeObserver(scheduleUpdate);
554
+ resizeObserver.observe(content);
555
+ resizeObserver.observe(search);
556
+ if (actions instanceof HTMLElement) resizeObserver.observe(actions);
557
+ desktopQuery.addEventListener("change", scheduleUpdate);
558
+ overflowTrigger.addEventListener("click", onOverflowTriggerClick);
559
+ overflowTrigger.addEventListener("keydown", onOverflowTriggerKeydown);
560
+ overflowMenu.addEventListener("click", onOverflowMenuClick);
561
+ document.addEventListener("pointerdown", onDocumentPointerDown);
562
+ document.addEventListener("keydown", onDocumentKeydown);
563
+
564
+ document.fonts?.ready.then(() => {
565
+ if (!header.isConnected) return;
566
+ linksWidth = measureLinksWidth();
567
+ scheduleUpdate();
568
+ });
569
+
570
+ window[cleanupKey] = () => {
571
+ if (frameId !== 0) cancelAnimationFrame(frameId);
572
+ resizeObserver.disconnect();
573
+ desktopQuery.removeEventListener("change", scheduleUpdate);
574
+ overflowTrigger.removeEventListener("click", onOverflowTriggerClick);
575
+ overflowTrigger.removeEventListener("keydown", onOverflowTriggerKeydown);
576
+ overflowMenu.removeEventListener("click", onOverflowMenuClick);
577
+ document.removeEventListener("pointerdown", onDocumentPointerDown);
578
+ document.removeEventListener("keydown", onDocumentKeydown);
579
+ overflowMenu.hidden = true;
580
+ };
581
+ })();
582
+ </script>
@@ -130,15 +130,23 @@ const tocHeadings = headings.filter(
130
130
  <article class="prose-rules">
131
131
  <Content components={components} />
132
132
  </article>
133
+ </div>
134
+ <aside class="hidden xl:block w-48 shrink-0" data-rd-toc-column>
135
+ <TableOfContents headings={tocHeadings} />
136
+ </aside>
137
+ </div>
138
+ <div
139
+ slot="page-pagination"
140
+ class="w-full min-w-0"
141
+ data-rd-mdx-shell
142
+ >
143
+ <div class="mx-auto max-w-3xl w-full" data-rd-mdx-content>
133
144
  <PagePagination
134
145
  previousRoute={previousRoute}
135
146
  nextRoute={nextRoute}
136
147
  homePath={homePath}
137
148
  />
138
149
  </div>
139
- <aside class="hidden xl:block w-48 shrink-0" data-rd-toc-column>
140
- <TableOfContents headings={tocHeadings} />
141
- </aside>
142
150
  </div>
143
151
  <script is:inline>
144
152
  function fallbackCopy(text) {