boltdocs 1.4.1 → 1.6.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.
Files changed (43) hide show
  1. package/dist/{PackageManagerTabs-XW3AVXVX.mjs → PackageManagerTabs-NVT7G625.mjs} +1 -1
  2. package/dist/{SearchDialog-O3V36MXA.css → SearchDialog-3QICRMWF.css} +145 -5
  3. package/dist/{SearchDialog-FBNGKRPK.mjs → SearchDialog-J3KNRGNO.mjs} +1 -1
  4. package/dist/{chunk-S5G55FBI.mjs → chunk-7SFUJWTB.mjs} +4 -4
  5. package/dist/{chunk-D7YBQG6H.mjs → chunk-HSPDIRTW.mjs} +312 -134
  6. package/dist/client/index.css +145 -5
  7. package/dist/client/index.d.mts +22 -5
  8. package/dist/client/index.d.ts +22 -5
  9. package/dist/client/index.js +725 -459
  10. package/dist/client/index.mjs +182 -61
  11. package/dist/client/ssr.css +145 -5
  12. package/dist/client/ssr.d.mts +1 -1
  13. package/dist/client/ssr.d.ts +1 -1
  14. package/dist/client/ssr.js +544 -395
  15. package/dist/client/ssr.mjs +1 -1
  16. package/dist/{config-BD5ZHz15.d.mts → config-DkZg5aCf.d.mts} +2 -0
  17. package/dist/{config-BD5ZHz15.d.ts → config-DkZg5aCf.d.ts} +2 -0
  18. package/dist/node/index.d.mts +2 -2
  19. package/dist/node/index.d.ts +2 -2
  20. package/dist/node/index.js +5 -1
  21. package/dist/node/index.mjs +5 -1
  22. package/dist/{types-CvrzTbEX.d.mts → types-DGIo1VKD.d.mts} +2 -0
  23. package/dist/{types-CvrzTbEX.d.ts → types-DGIo1VKD.d.ts} +2 -0
  24. package/package.json +1 -1
  25. package/src/client/app/index.tsx +2 -12
  26. package/src/client/app/preload.tsx +3 -1
  27. package/src/client/index.ts +2 -0
  28. package/src/client/theme/components/CodeBlock/CodeBlock.tsx +0 -11
  29. package/src/client/theme/components/mdx/FileTree.tsx +229 -0
  30. package/src/client/theme/components/mdx/Tabs.tsx +1 -4
  31. package/src/client/theme/components/mdx/index.ts +3 -0
  32. package/src/client/theme/components/mdx/mdx-components.css +109 -0
  33. package/src/client/theme/icons/pnpm.tsx +5 -5
  34. package/src/client/theme/styles/markdown.css +1 -5
  35. package/src/client/theme/ui/Link/Link.tsx +156 -18
  36. package/src/client/theme/ui/Link/LinkPreview.tsx +64 -0
  37. package/src/client/theme/ui/Link/link-preview.css +64 -0
  38. package/src/client/types.ts +2 -0
  39. package/src/node/config.ts +2 -0
  40. package/src/node/routes/parser.ts +14 -1
  41. package/dist/CodeBlock-QYIKJMEB.mjs +0 -7
  42. package/dist/chunk-KS5B3O6W.mjs +0 -43
  43. package/src/client/theme/icons/yarn.tsx +0 -16
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AppShell
3
- } from "../chunk-D7YBQG6H.mjs";
3
+ } from "../chunk-HSPDIRTW.mjs";
4
4
  import "../chunk-FMTOYQLO.mjs";
5
5
 
6
6
  // src/client/ssr.tsx
@@ -54,6 +54,8 @@ interface BoltdocsThemeConfig {
54
54
  githubRepo?: string;
55
55
  /** Whether to show the 'Powered by LiteDocs' badge in the sidebar (default: true) */
56
56
  poweredBy?: boolean;
57
+ /** Whether to show a preview tooltip on internal links hover (default: true) */
58
+ linkPreview?: boolean;
57
59
  /** Granular layout customization props */
58
60
  layoutProps?: {
59
61
  navbar?: any;
@@ -54,6 +54,8 @@ interface BoltdocsThemeConfig {
54
54
  githubRepo?: string;
55
55
  /** Whether to show the 'Powered by LiteDocs' badge in the sidebar (default: true) */
56
56
  poweredBy?: boolean;
57
+ /** Whether to show a preview tooltip on internal links hover (default: true) */
58
+ linkPreview?: boolean;
57
59
  /** Granular layout customization props */
58
60
  layoutProps?: {
59
61
  navbar?: any;
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
- import { B as BoltdocsConfig } from '../config-BD5ZHz15.mjs';
3
- export { a as BoltdocsThemeConfig } from '../config-BD5ZHz15.mjs';
2
+ import { B as BoltdocsConfig } from '../config-DkZg5aCf.mjs';
3
+ export { a as BoltdocsThemeConfig } from '../config-DkZg5aCf.mjs';
4
4
 
5
5
  /**
6
6
  * Configuration options specifically for the Boltdocs Vite plugin.
@@ -1,6 +1,6 @@
1
1
  import { Plugin } from 'vite';
2
- import { B as BoltdocsConfig } from '../config-BD5ZHz15.js';
3
- export { a as BoltdocsThemeConfig } from '../config-BD5ZHz15.js';
2
+ import { B as BoltdocsConfig } from '../config-DkZg5aCf.js';
3
+ export { a as BoltdocsThemeConfig } from '../config-DkZg5aCf.js';
4
4
 
5
5
  /**
6
6
  * Configuration options specifically for the Boltdocs Vite plugin.
@@ -514,7 +514,11 @@ function parseDocFile(file, docsDir, basePath, config) {
514
514
  headings.push({ level, text: escapeHtml(text), id });
515
515
  }
516
516
  const sanitizedTitle = data.title ? escapeHtml(data.title) : inferredTitle;
517
- const sanitizedDescription = data.description ? escapeHtml(data.description) : "";
517
+ let sanitizedDescription = data.description ? escapeHtml(data.description) : "";
518
+ if (!sanitizedDescription && content) {
519
+ const summary = content.replace(/^#+.*$/gm, "").replace(/\[([^\]]+)\]\([^\)]+\)/g, "$1").replace(/[_*`]/g, "").replace(/\n+/g, " ").trim().slice(0, 160);
520
+ sanitizedDescription = escapeHtml(summary);
521
+ }
518
522
  const sanitizedBadge = data.badge ? escapeHtml(data.badge) : void 0;
519
523
  return {
520
524
  route: {
@@ -96,7 +96,11 @@ function parseDocFile(file, docsDir, basePath, config) {
96
96
  headings.push({ level, text: escapeHtml(text), id });
97
97
  }
98
98
  const sanitizedTitle = data.title ? escapeHtml(data.title) : inferredTitle;
99
- const sanitizedDescription = data.description ? escapeHtml(data.description) : "";
99
+ let sanitizedDescription = data.description ? escapeHtml(data.description) : "";
100
+ if (!sanitizedDescription && content) {
101
+ const summary = content.replace(/^#+.*$/gm, "").replace(/\[([^\]]+)\]\([^\)]+\)/g, "$1").replace(/[_*`]/g, "").replace(/\n+/g, " ").trim().slice(0, 160);
102
+ sanitizedDescription = escapeHtml(summary);
103
+ }
100
104
  const sanitizedBadge = data.badge ? escapeHtml(data.badge) : void 0;
101
105
  return {
102
106
  route: {
@@ -27,6 +27,8 @@ interface ComponentRoute {
27
27
  text: string;
28
28
  id: string;
29
29
  }[];
30
+ /** The page summary or description */
31
+ description?: string;
30
32
  /** The locale this route belongs to, if i18n is configured */
31
33
  locale?: string;
32
34
  /** The version this route belongs to, if versioning is configured */
@@ -27,6 +27,8 @@ interface ComponentRoute {
27
27
  text: string;
28
28
  id: string;
29
29
  }[];
30
+ /** The page summary or description */
31
+ description?: string;
30
32
  /** The locale this route belongs to, if i18n is configured */
31
33
  locale?: string;
32
34
  /** The version this route belongs to, if versioning is configured */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boltdocs",
3
- "version": "1.4.1",
3
+ "version": "1.6.0",
4
4
  "description": "A lightweight documentation generator for React projects.",
5
5
  "main": "dist/node/index.js",
6
6
  "module": "dist/node/index.mjs",
@@ -27,11 +27,7 @@ export function useConfig() {
27
27
  return useContext(ConfigContext);
28
28
  }
29
29
 
30
- const CodeBlock = lazy(() =>
31
- import("../theme/components/CodeBlock").then((m) => ({
32
- default: m.CodeBlock,
33
- })),
34
- );
30
+ import { CodeBlock } from "../theme/components/CodeBlock";
35
31
  const Video = lazy(() =>
36
32
  import("../theme/components/Video").then((m) => ({ default: m.Video })),
37
33
  );
@@ -77,13 +73,7 @@ const mdxComponents = {
77
73
  h4: (props: any) => <Heading level={4} {...props} />,
78
74
  h5: (props: any) => <Heading level={5} {...props} />,
79
75
  h6: (props: any) => <Heading level={6} {...props} />,
80
- pre: (props: any) => {
81
- return (
82
- <Suspense fallback={<div className="code-block-skeleton" />}>
83
- <CodeBlock {...props}>{props.children}</CodeBlock>
84
- </Suspense>
85
- );
86
- },
76
+ pre: (props: any) => <CodeBlock {...props}>{props.children}</CodeBlock>,
87
77
  video: (props: any) => (
88
78
  <Suspense fallback={<div className="video-skeleton" />}>
89
79
  <Video {...props} />
@@ -3,10 +3,12 @@ import { ComponentRoute } from "../types";
3
3
 
4
4
  interface PreloadContextType {
5
5
  preload: (path: string) => void;
6
+ routes: ComponentRoute[];
6
7
  }
7
8
 
8
9
  const PreloadContext = createContext<PreloadContextType>({
9
10
  preload: () => {},
11
+ routes: [],
10
12
  });
11
13
 
12
14
  export function usePreload() {
@@ -49,7 +51,7 @@ export function PreloadProvider({
49
51
  );
50
52
 
51
53
  return (
52
- <PreloadContext.Provider value={{ preload }}>
54
+ <PreloadContext.Provider value={{ preload, routes }}>
53
55
  {children}
54
56
  </PreloadContext.Provider>
55
57
  );
@@ -28,6 +28,7 @@ export {
28
28
  Danger,
29
29
  InfoBox,
30
30
  List,
31
+ FileTree,
31
32
  } from "./theme/components/mdx";
32
33
  export type {
33
34
  ButtonProps,
@@ -38,4 +39,5 @@ export type {
38
39
  TabProps,
39
40
  AdmonitionProps,
40
41
  ListProps,
42
+ FileTreeProps,
41
43
  } from "./theme/components/mdx";
@@ -16,17 +16,6 @@ export function CodeBlock({ children, ...props }: CodeBlockProps) {
16
16
  const [copied, setCopied] = useState(false);
17
17
  const preRef = useRef<HTMLPreElement>(null);
18
18
 
19
- // Extract language from the child <code> element's data-language or className
20
- let language = "";
21
- if (React.isValidElement(children)) {
22
- const childProps = children.props as any;
23
- language = childProps?.["data-language"] || "";
24
- if (!language && childProps?.className) {
25
- const match = childProps.className.match(/language-(\w+)/);
26
- if (match) language = match[1];
27
- }
28
- }
29
-
30
19
  const handleCopy = useCallback(async () => {
31
20
  const code = preRef.current?.textContent || "";
32
21
  copyToClipboard(code);
@@ -0,0 +1,229 @@
1
+ import React, { Children, isValidElement, useState } from "react";
2
+ import {
3
+ Folder,
4
+ FileText,
5
+ File,
6
+ FileCode,
7
+ FileImage,
8
+ ChevronRight,
9
+ } from "lucide-react";
10
+
11
+ export interface FileTreeProps {
12
+ children: React.ReactNode;
13
+ }
14
+
15
+ function getTextContent(node: React.ReactNode): string {
16
+ if (typeof node === "string") return node;
17
+ if (typeof node === "number") return node.toString();
18
+ if (Array.isArray(node)) return node.map(getTextContent).join("");
19
+ if (isValidElement(node)) {
20
+ return getTextContent((node.props as any).children);
21
+ }
22
+ return "";
23
+ }
24
+
25
+ function getFileIcon(filename: string) {
26
+ const name = filename.toLowerCase();
27
+
28
+ if (
29
+ name.endsWith(".ts") ||
30
+ name.endsWith(".tsx") ||
31
+ name.endsWith(".js") ||
32
+ name.endsWith(".jsx") ||
33
+ name.endsWith(".json") ||
34
+ name.endsWith(".mjs") ||
35
+ name.endsWith(".cjs") ||
36
+ name.endsWith(".astro") ||
37
+ name.endsWith(".vue") ||
38
+ name.endsWith(".svelte")
39
+ ) {
40
+ return (
41
+ <FileCode size={16} strokeWidth={2} className="ld-file-tree__icon-file" />
42
+ );
43
+ }
44
+
45
+ if (name.endsWith(".md") || name.endsWith(".mdx") || name.endsWith(".txt")) {
46
+ return (
47
+ <FileText size={16} strokeWidth={2} className="ld-file-tree__icon-file" />
48
+ );
49
+ }
50
+
51
+ if (
52
+ name.endsWith(".png") ||
53
+ name.endsWith(".jpg") ||
54
+ name.endsWith(".jpeg") ||
55
+ name.endsWith(".svg") ||
56
+ name.endsWith(".gif")
57
+ ) {
58
+ return (
59
+ <FileImage
60
+ size={16}
61
+ strokeWidth={2}
62
+ className="ld-file-tree__icon-file"
63
+ />
64
+ );
65
+ }
66
+
67
+ return <File size={16} strokeWidth={2} className="ld-file-tree__icon-file" />;
68
+ }
69
+
70
+ // Helper to reliably check for ul and li elements, including MDX wrappers
71
+ function isListElement(node: any, tag: "ul" | "li"): boolean {
72
+ if (typeof node.type === "string") {
73
+ return node.type === tag;
74
+ }
75
+ if (typeof node.type === "function") {
76
+ return node.type.name === tag || node.type.name?.toLowerCase() === tag;
77
+ }
78
+ // MDX specific wrapper detection
79
+ if (node.props && node.props.originalType === tag) {
80
+ return true;
81
+ }
82
+ if (node.props && node.props.mdxType === tag) {
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+
88
+ function FolderNode({
89
+ labelText,
90
+ nestedNodes,
91
+ depth,
92
+ }: {
93
+ labelText: string;
94
+ nestedNodes: React.ReactNode[];
95
+ depth: number;
96
+ }) {
97
+ const [isOpen, setIsOpen] = useState(true);
98
+
99
+ return (
100
+ <li className="ld-file-tree__item">
101
+ <div
102
+ className="ld-file-tree__label ld-file-tree__label--folder"
103
+ onClick={() => setIsOpen(!isOpen)}
104
+ style={{ cursor: "pointer" }}
105
+ >
106
+ <span className="ld-file-tree__icon ld-file-tree__icon--chevron">
107
+ <ChevronRight
108
+ size={14}
109
+ className={`ld-file-tree__chevron ${isOpen ? "ld-file-tree__chevron--open" : ""}`}
110
+ strokeWidth={3}
111
+ />
112
+ </span>
113
+ <span className="ld-file-tree__icon">
114
+ <Folder
115
+ size={16}
116
+ strokeWidth={2}
117
+ className="ld-file-tree__icon-folder"
118
+ fill="currentColor"
119
+ fillOpacity={0.15}
120
+ />
121
+ </span>
122
+ <span className="ld-file-tree__name">{labelText}</span>
123
+ </div>
124
+ {isOpen && nestedNodes.length > 0 && (
125
+ <div className="ld-file-tree__nested">
126
+ {nestedNodes.map((child, index) => (
127
+ <React.Fragment key={index}>
128
+ {parseNode(child, depth)}
129
+ </React.Fragment>
130
+ ))}
131
+ </div>
132
+ )}
133
+ </li>
134
+ );
135
+ }
136
+
137
+ function parseNode(node: React.ReactNode, depth: number = 0): React.ReactNode {
138
+ if (!isValidElement(node)) {
139
+ return node;
140
+ }
141
+
142
+ if (isListElement(node, "ul")) {
143
+ return (
144
+ <ul
145
+ className={`ld-file-tree__list ${depth === 0 ? "ld-file-tree__list--root" : ""}`}
146
+ >
147
+ {Children.map((node.props as any).children, (child, index) => (
148
+ <React.Fragment key={index}>
149
+ {parseNode(child, depth + 1)}
150
+ </React.Fragment>
151
+ ))}
152
+ </ul>
153
+ );
154
+ }
155
+
156
+ if (isListElement(node, "li")) {
157
+ const children = Children.toArray((node.props as any).children);
158
+
159
+ // Find nested list indicating a directory
160
+ const nestedListIndex = children.findIndex(
161
+ (child) => isValidElement(child) && isListElement(child, "ul"),
162
+ );
163
+ const hasNested = nestedListIndex !== -1;
164
+
165
+ // Separate text label from nested items
166
+ const labelNodes = hasNested
167
+ ? children.slice(0, nestedListIndex)
168
+ : children;
169
+ const nestedNodes = hasNested ? children.slice(nestedListIndex) : [];
170
+
171
+ const rawLabelContent = getTextContent(labelNodes).trim();
172
+ const isExplicitDir = rawLabelContent.endsWith("/");
173
+ const labelText = isExplicitDir
174
+ ? rawLabelContent.slice(0, -1)
175
+ : rawLabelContent;
176
+
177
+ const isFolder = hasNested || isExplicitDir;
178
+
179
+ if (isFolder) {
180
+ return (
181
+ <FolderNode
182
+ labelText={labelText}
183
+ nestedNodes={nestedNodes}
184
+ depth={depth}
185
+ />
186
+ );
187
+ }
188
+
189
+ return (
190
+ <li className="ld-file-tree__item">
191
+ <div className="ld-file-tree__label ld-file-tree__label--file">
192
+ <span className="ld-file-tree__icon ld-file-tree__icon--spacer"></span>
193
+ <span className="ld-file-tree__icon">{getFileIcon(labelText)}</span>
194
+ <span className="ld-file-tree__name">{labelText}</span>
195
+ </div>
196
+ </li>
197
+ );
198
+ }
199
+
200
+ // If node is e.g. a paragraph injected by MDX wrapping the list
201
+ if ((node.props as any).children) {
202
+ return Children.map((node.props as any).children, (child, index) => (
203
+ <React.Fragment key={index}>{parseNode(child, depth)}</React.Fragment>
204
+ ));
205
+ }
206
+
207
+ return node;
208
+ }
209
+
210
+ /**
211
+ * FileTree component displays a customized, styled tree structure for markdown lists.
212
+ *
213
+ * ```mdx
214
+ * <FileTree>
215
+ * - src/
216
+ * - index.ts
217
+ * - components/
218
+ * - Button.tsx
219
+ * - package.json
220
+ * </FileTree>
221
+ * ```
222
+ */
223
+ export function FileTree({ children }: FileTreeProps) {
224
+ return (
225
+ <div className="ld-file-tree" dir="ltr">
226
+ {Children.map(children, (child) => parseNode(child, 0))}
227
+ </div>
228
+ );
229
+ }
@@ -4,7 +4,6 @@ import { NPM } from "../../icons/npm";
4
4
  import { Pnpm } from "../../icons/pnpm";
5
5
  import { Bun } from "../../icons/bun";
6
6
  import { Deno } from "../../icons/deno";
7
- import { Yarn } from "../../icons/yarn";
8
7
 
9
8
  /* ─── Tab (individual panel) ──────────────────────────────── */
10
9
  export interface TabProps {
@@ -43,9 +42,8 @@ export interface TabsProps {
43
42
 
44
43
  const getIconForLabel = (label: string) => {
45
44
  const l = label.toLowerCase();
46
- if (l.includes("npm")) return <NPM />;
47
45
  if (l.includes("pnpm")) return <Pnpm />;
48
- if (l.includes("yarn")) return <Yarn />;
46
+ if (l.includes("npm")) return <NPM />;
49
47
  if (l.includes("bun")) return <Bun />;
50
48
  if (l.includes("deno")) return <Deno />;
51
49
  return null;
@@ -58,7 +56,6 @@ const getIconForLabel = (label: string) => {
58
56
  * <Tabs>
59
57
  * <Tab label="npm">npm install boltdocs</Tab>
60
58
  * <Tab label="pnpm">pnpm add boltdocs</Tab>
61
- * <Tab label="yarn">yarn add boltdocs</Tab>
62
59
  * </Tabs>
63
60
  * ```
64
61
  */
@@ -16,3 +16,6 @@ export type { AdmonitionProps } from "./Admonition";
16
16
 
17
17
  export { List } from "./List";
18
18
  export type { ListProps } from "./List";
19
+
20
+ export { FileTree } from "./FileTree";
21
+ export type { FileTreeProps } from "./FileTree";
@@ -430,3 +430,112 @@
430
430
  .ld-list--arrow .ld-list__icon {
431
431
  color: var(--ld-color-primary);
432
432
  }
433
+
434
+ /* ─── FileTree ────────────────────────────────────────────── */
435
+ .ld-file-tree {
436
+ margin: 1.5rem 0;
437
+ padding: 1rem;
438
+ border-radius: var(--ld-radius-lg);
439
+ border: 1px solid var(--ld-border-subtle);
440
+ background: var(--ld-bg-soft);
441
+ font-family: var(--ld-font-mono);
442
+ font-size: 0.875rem;
443
+ overflow-x: auto;
444
+ }
445
+
446
+ .ld-file-tree__list {
447
+ list-style: none !important;
448
+ margin: 0 !important;
449
+ padding: 0;
450
+ position: relative;
451
+ }
452
+
453
+ .ld-file-tree__list:not(.ld-file-tree__list--root) {
454
+ padding-left: 1.25rem;
455
+ margin-top: 0.25rem !important;
456
+ position: relative;
457
+ }
458
+
459
+ /* Vertical line for nested folders */
460
+ .ld-file-tree__list:not(.ld-file-tree__list--root)::before {
461
+ content: "";
462
+ position: absolute;
463
+ top: 0;
464
+ bottom: 0;
465
+ left: 0.45rem; /* align with folder icon */
466
+ width: 1px;
467
+ background-color: var(--ld-border-subtle);
468
+ z-index: 0;
469
+ }
470
+
471
+ .ld-file-tree__item {
472
+ position: relative;
473
+ margin: 0.2rem 0 !important;
474
+ padding: 0 !important;
475
+ display: block !important;
476
+ }
477
+
478
+ .ld-file-tree__label {
479
+ display: inline-flex;
480
+ align-items: center;
481
+ gap: 0.5rem;
482
+ color: var(--ld-text-muted);
483
+ user-select: none;
484
+ border-radius: var(--ld-radius-sm);
485
+ padding: 0.25rem 0.6rem 0.25rem 0.4rem;
486
+ transition: all 0.2s ease;
487
+ position: relative;
488
+ z-index: 1;
489
+ }
490
+
491
+ .ld-file-tree__label:hover {
492
+ background: var(--ld-bg-mute);
493
+ color: var(--ld-text-main);
494
+ }
495
+
496
+ .ld-file-tree__label--folder {
497
+ color: var(--ld-text-main);
498
+ font-weight: 500;
499
+ }
500
+
501
+ .ld-file-tree__icon {
502
+ display: inline-flex;
503
+ align-items: center;
504
+ justify-content: center;
505
+ opacity: 0.8;
506
+ flex-shrink: 0;
507
+ }
508
+
509
+ .ld-file-tree__icon-folder {
510
+ color: var(--ld-color-primary);
511
+ }
512
+
513
+ .ld-file-tree__name {
514
+ white-space: nowrap;
515
+ }
516
+
517
+ .ld-file-tree__icon--chevron {
518
+ width: 14px;
519
+ height: 14px;
520
+ opacity: 0.5;
521
+ transition: opacity 0.2s ease;
522
+ display: flex !important;
523
+ align-items: center;
524
+ justify-content: center;
525
+ }
526
+
527
+ .ld-file-tree__label:hover .ld-file-tree__icon--chevron {
528
+ opacity: 1;
529
+ }
530
+
531
+ .ld-file-tree__chevron {
532
+ transition: transform 0.2s ease;
533
+ }
534
+
535
+ .ld-file-tree__chevron--open {
536
+ transform: rotate(90deg);
537
+ }
538
+
539
+ .ld-file-tree__icon--spacer {
540
+ width: 14px;
541
+ }
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import type { SVGProps } from "react";
2
2
 
3
3
  const Pnpm = (props: SVGProps<SVGSVGElement>) => (
4
4
  <svg
@@ -54,16 +54,16 @@ const Pnpm = (props: SVGProps<SVGSVGElement>) => (
54
54
  <use xlinkHref="#pnpm_dark__dqv5133G8" fill="#f9ad00" />
55
55
  </g>
56
56
  <g>
57
- <use xlinkHref="#pnpm_dark__b1Lv79ypvm" fill="currentColor" />
57
+ <use xlinkHref="#pnpm_dark__b1Lv79ypvm" fill="#ffffff" />
58
58
  </g>
59
59
  <g>
60
- <use xlinkHref="#pnpm_dark__hy1IZWwLX" fill="currentColor" />
60
+ <use xlinkHref="#pnpm_dark__hy1IZWwLX" fill="#ffffff" />
61
61
  </g>
62
62
  <g>
63
- <use xlinkHref="#pnpm_dark__akQfjxQes" fill="currentColor" />
63
+ <use xlinkHref="#pnpm_dark__akQfjxQes" fill="#ffffff" />
64
64
  </g>
65
65
  <g>
66
- <use xlinkHref="#pnpm_dark__bdSrwE5pk" fill="currentColor" />
66
+ <use xlinkHref="#pnpm_dark__bdSrwE5pk" fill="#ffffff" />
67
67
  </g>
68
68
  </g>
69
69
  </svg>
@@ -218,7 +218,7 @@
218
218
  right: 0.75rem;
219
219
  z-index: 50;
220
220
  padding: 0.4rem;
221
- background-color: rgba(20, 20, 30, 0.8);
221
+ background-color: var(--ld-surface);
222
222
  backdrop-filter: blur(8px);
223
223
  -webkit-backdrop-filter: blur(8px);
224
224
  border: 1px solid var(--ld-border-subtle);
@@ -227,14 +227,10 @@
227
227
  cursor: pointer;
228
228
  transition: all 0.2s ease;
229
229
  opacity: 0;
230
- visibility: hidden;
231
- pointer-events: none;
232
230
  }
233
231
 
234
232
  .code-block-wrapper:hover .code-block-copy {
235
233
  opacity: 1;
236
- visibility: visible;
237
- pointer-events: auto;
238
234
  }
239
235
 
240
236
  .code-block-copy:hover {