@writedocs/generator 0.4.7 → 0.4.9

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.
@@ -0,0 +1,156 @@
1
+ ---
2
+ // Mintlify's <GitHub.Repo repo="owner/name" variant="inset|flat"> - a card
3
+ // linking to a public GitHub repository. Attached as GitHub.Repo in
4
+ // components/compound.ts. `repo` is an "owner/name" slug or a full
5
+ // github.com URL.
6
+ //
7
+ // The repository's name and link are built into the page; its description,
8
+ // star count and fork count are fetched from the public GitHub API when the
9
+ // page loads, as on Mintlify. The unauthenticated API allows 60 requests an
10
+ // hour per reader's IP, so the response is cached for the browser session.
11
+ // If the request fails, the card stays a plain link to the repository.
12
+ import AppIcon from './AppIcon.astro';
13
+
14
+ interface Props {
15
+ repo: string;
16
+ variant?: 'inset' | 'flat';
17
+ }
18
+ const { repo, variant = 'inset' } = Astro.props as Props;
19
+ const slug = String(repo ?? '')
20
+ .trim()
21
+ .replace(/^(?:https?:\/\/)?(?:www\.)?github\.com\//i, '')
22
+ .replace(/\.git$/i, '')
23
+ .split(/[/?#]/)
24
+ .slice(0, 2)
25
+ .join('/');
26
+ const valid = /^[\w.-]+\/[\w.-]+$/.test(slug);
27
+ ---
28
+ {valid && (
29
+ <a
30
+ class:list={['wd-github-repo', `wd-github-repo-${variant}`]}
31
+ href={`https://github.com/${slug}`}
32
+ target="_blank"
33
+ rel="noopener noreferrer"
34
+ data-repo={slug}
35
+ >
36
+ <div class="wd-github-repo-inner">
37
+ <div class="wd-github-repo-name">
38
+ <AppIcon icon="fa6-brands:github" class="wd-github-repo-icon" />
39
+ <span>{slug}</span>
40
+ </div>
41
+ <p class="wd-github-repo-description" hidden></p>
42
+ <div class="wd-github-repo-stats" hidden>
43
+ <span><span aria-hidden="true">&#9733;</span> <span data-stat="stars"></span> stars</span>
44
+ <span><span data-stat="forks"></span> forks</span>
45
+ </div>
46
+ </div>
47
+ </a>
48
+ )}
49
+ <script>
50
+ type RepoInfo = { description: string | null; stargazers_count: number; forks_count: number };
51
+ const compact = (n: number) =>
52
+ new Intl.NumberFormat('en', { notation: 'compact', maximumFractionDigits: 1 }).format(n);
53
+
54
+ async function loadRepo(slug: string): Promise<RepoInfo | null> {
55
+ const key = `wd-github-repo:${slug}`;
56
+ try {
57
+ const cached = sessionStorage.getItem(key);
58
+ if (cached) return JSON.parse(cached);
59
+ } catch {}
60
+ try {
61
+ const res = await fetch(`https://api.github.com/repos/${slug}`, {
62
+ headers: { Accept: 'application/vnd.github+json' },
63
+ });
64
+ if (!res.ok) return null;
65
+ const data = await res.json();
66
+ const info: RepoInfo = {
67
+ description: data.description ?? null,
68
+ stargazers_count: data.stargazers_count ?? 0,
69
+ forks_count: data.forks_count ?? 0,
70
+ };
71
+ try {
72
+ sessionStorage.setItem(key, JSON.stringify(info));
73
+ } catch {}
74
+ return info;
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ function initGitHubRepos(root: ParentNode) {
81
+ root.querySelectorAll<HTMLElement>('.wd-github-repo[data-repo]').forEach(async (card) => {
82
+ if (card.dataset.wdInit) return;
83
+ card.dataset.wdInit = 'true';
84
+ const info = await loadRepo(card.dataset.repo!);
85
+ if (!info) return;
86
+ const desc = card.querySelector<HTMLElement>('.wd-github-repo-description');
87
+ if (desc && info.description) {
88
+ desc.textContent = info.description;
89
+ desc.hidden = false;
90
+ }
91
+ const stats = card.querySelector<HTMLElement>('.wd-github-repo-stats');
92
+ if (stats) {
93
+ stats.querySelector('[data-stat="stars"]')!.textContent = compact(info.stargazers_count);
94
+ stats.querySelector('[data-stat="forks"]')!.textContent = compact(info.forks_count);
95
+ stats.hidden = false;
96
+ }
97
+ });
98
+ }
99
+ initGitHubRepos(document);
100
+ document.addEventListener('astro:page-load', () => initGitHubRepos(document));
101
+ </script>
102
+ <style>
103
+ .wd-github-repo {
104
+ display: block;
105
+ margin: 1.25rem 0;
106
+ border: 1px solid var(--wd-border);
107
+ border-radius: 0.75rem;
108
+ text-decoration: none;
109
+ color: inherit;
110
+ transition: border-color 0.15s ease;
111
+ }
112
+ .wd-github-repo:hover {
113
+ border-color: var(--wd-primary);
114
+ }
115
+ /* inset (the default): the details sit on a rounded inner surface. */
116
+ .wd-github-repo-inset {
117
+ padding: 0.4rem;
118
+ }
119
+ .wd-github-repo-inset .wd-github-repo-inner {
120
+ padding: 0.9rem 1rem;
121
+ border-radius: 0.5rem;
122
+ background: var(--wd-surface);
123
+ }
124
+ /* flat: one surface, tighter padding. */
125
+ .wd-github-repo-flat .wd-github-repo-inner {
126
+ padding: 0.75rem 0.9rem;
127
+ }
128
+ .wd-github-repo-name {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: 0.5rem;
132
+ font-weight: 600;
133
+ color: var(--wd-text);
134
+ }
135
+ :global(svg.wd-github-repo-icon) {
136
+ width: 1.1rem;
137
+ height: 1.1rem;
138
+ flex-shrink: 0;
139
+ }
140
+ .wd-github-repo-description {
141
+ margin: 0.4rem 0 0;
142
+ font-size: 0.875rem;
143
+ color: var(--wd-text-muted);
144
+ }
145
+ .wd-github-repo-stats {
146
+ display: flex;
147
+ gap: 1rem;
148
+ margin-top: 0.5rem;
149
+ font-size: 0.8rem;
150
+ color: var(--wd-text-muted);
151
+ }
152
+ .wd-github-repo-stats[hidden],
153
+ .wd-github-repo-description[hidden] {
154
+ display: none;
155
+ }
156
+ </style>
@@ -0,0 +1,11 @@
1
+ ---
2
+ // Mintlify's <Panel> - content pinned to the right-hand column on desktop,
3
+ // in place of the table of contents. It's the same docking
4
+ // RequestExample/ResponseExample already use (initExamplePanels() in
5
+ // [...slug].astro): the `wd-example-panel` class is what that script moves
6
+ // into the column at >= 1151px wide, and back into the page below that.
7
+ // A RequestExample/ResponseExample inside a Panel moves with it. On a page
8
+ // with no table-of-contents column (any mode but `default`), the Panel
9
+ // stays where it is in the page.
10
+ ---
11
+ <div class="wd-example-panel wd-panel"><slot /></div>
@@ -0,0 +1,143 @@
1
+ ---
2
+ // Mintlify's <Prompt> - a ready-made AI prompt: a card showing
3
+ // `description` (inline Markdown) and an optional icon, with actions to
4
+ // copy the prompt or open it in Cursor. The prompt itself is the slot; it's
5
+ // also viewable in a collapsed "Show prompt" section under the card.
6
+ //
7
+ // What gets copied/sent is the prompt's *source* text - `_text`, read from
8
+ // the MDX file by remarkMintlifyPromptText (lib/mdx-mintlify.js) - so its
9
+ // Markdown survives. Without it (a Prompt used outside MDX), the copy falls
10
+ // back to the rendered text.
11
+ //
12
+ // `actions` defaults to ["copy"]; add "cursor" for an "Open in Cursor"
13
+ // link (Cursor's own https://cursor.com/link/prompt?text=... deeplink,
14
+ // which also works for readers without Cursor installed). Cursor caps a
15
+ // deeplink at 10,000 URL-encoded characters, so a longer prompt gets no
16
+ // Cursor link - just the copy button.
17
+ import AppIcon from './AppIcon.astro';
18
+ import { inlineMarkdown } from '../lib/inline-markdown.js';
19
+
20
+ interface Props {
21
+ description?: string;
22
+ icon?: string;
23
+ actions?: Array<'copy' | 'cursor'>;
24
+ _text?: string;
25
+ }
26
+ const { description, icon, actions = ['copy'], _text } = Astro.props as Props;
27
+ const cursorHref = _text ? `https://cursor.com/link/prompt?text=${encodeURIComponent(_text)}` : null;
28
+ const showCursor = actions.includes('cursor') && cursorHref !== null && cursorHref.length <= 10000;
29
+ ---
30
+ <div class="wd-prompt">
31
+ <div class="wd-prompt-head">
32
+ {icon && <AppIcon icon={icon} class="wd-prompt-icon" />}
33
+ {description && <div class="wd-prompt-description" set:html={inlineMarkdown(description)} />}
34
+ <div class="wd-prompt-actions">
35
+ {actions.includes('copy') && (
36
+ <button type="button" class="wd-prompt-action" data-role="copy-prompt">Copy prompt</button>
37
+ )}
38
+ {showCursor && (
39
+ <a class="wd-prompt-action" href={cursorHref} target="_blank" rel="noopener noreferrer">Open in Cursor</a>
40
+ )}
41
+ </div>
42
+ </div>
43
+ <details class="wd-prompt-text">
44
+ <summary>Show prompt</summary>
45
+ <div class="wd-prompt-body"><slot /></div>
46
+ </details>
47
+ {_text && <template class="wd-prompt-source">{_text}</template>}
48
+ </div>
49
+ <script>
50
+ function initPrompts(root: ParentNode) {
51
+ root.querySelectorAll<HTMLButtonElement>('[data-role="copy-prompt"]').forEach((btn) => {
52
+ if (btn.dataset.wdInit) return;
53
+ btn.dataset.wdInit = 'true';
54
+ btn.addEventListener('click', async () => {
55
+ const card = btn.closest('.wd-prompt');
56
+ const source = card?.querySelector<HTMLTemplateElement>('template.wd-prompt-source');
57
+ const text = source ? source.content.textContent ?? '' : card?.querySelector('.wd-prompt-body')?.textContent?.trim() ?? '';
58
+ try {
59
+ await navigator.clipboard.writeText(text);
60
+ btn.textContent = 'Copied';
61
+ } catch {
62
+ btn.textContent = 'Copy failed';
63
+ }
64
+ setTimeout(() => (btn.textContent = 'Copy prompt'), 1500);
65
+ });
66
+ });
67
+ }
68
+ initPrompts(document);
69
+ document.addEventListener('astro:page-load', () => initPrompts(document));
70
+ </script>
71
+ <style>
72
+ .wd-prompt {
73
+ margin: 1.25rem 0;
74
+ border: 1px solid var(--wd-border);
75
+ border-radius: 0.6rem;
76
+ overflow: hidden;
77
+ }
78
+ .wd-prompt-head {
79
+ display: flex;
80
+ align-items: center;
81
+ gap: 0.75rem;
82
+ padding: 0.9rem 1.1rem;
83
+ }
84
+ :global(svg.wd-prompt-icon),
85
+ :global(span.wd-prompt-icon) {
86
+ flex-shrink: 0;
87
+ width: 1.1rem;
88
+ height: 1.1rem;
89
+ color: var(--wd-primary);
90
+ }
91
+ .wd-prompt-description {
92
+ flex: 1;
93
+ min-width: 0;
94
+ color: var(--wd-text);
95
+ }
96
+ .wd-prompt-actions {
97
+ display: flex;
98
+ flex-shrink: 0;
99
+ gap: 0.4rem;
100
+ }
101
+ .wd-prompt-action {
102
+ padding: 0.3rem 0.7rem;
103
+ border: 1px solid var(--wd-border);
104
+ border-radius: 0.4rem;
105
+ background: var(--wd-background);
106
+ color: var(--wd-text);
107
+ font-size: 0.8rem;
108
+ text-decoration: none;
109
+ cursor: pointer;
110
+ white-space: nowrap;
111
+ }
112
+ .wd-prompt-action:hover {
113
+ border-color: var(--wd-primary);
114
+ color: var(--wd-primary);
115
+ }
116
+ .wd-prompt-text {
117
+ border-top: 1px solid var(--wd-border);
118
+ background: var(--wd-surface);
119
+ }
120
+ .wd-prompt-text summary {
121
+ padding: 0.5rem 1.1rem;
122
+ font-size: 0.8rem;
123
+ color: var(--wd-text-muted);
124
+ cursor: pointer;
125
+ }
126
+ .wd-prompt-body {
127
+ padding: 0 1.1rem 0.9rem;
128
+ font-size: 0.9rem;
129
+ color: var(--wd-text-muted);
130
+ }
131
+ .wd-prompt-body :global(p:first-child) {
132
+ margin-top: 0;
133
+ }
134
+ .wd-prompt-body :global(p:last-child),
135
+ .wd-prompt-body :global(ul:last-child) {
136
+ margin-bottom: 0;
137
+ }
138
+ @media (max-width: 640px) {
139
+ .wd-prompt-head {
140
+ flex-wrap: wrap;
141
+ }
142
+ }
143
+ </style>
@@ -0,0 +1,65 @@
1
+ ---
2
+ // Mintlify's <Tile> - a visual preview (the slot, usually an image or a
3
+ // light/dark image pair) on a patterned background, with a title and
4
+ // description under it. Usually laid out in a <Columns> grid. `title`
5
+ // takes inline Markdown (`code`, **bold**, *italic*), like Mintlify's.
6
+ import { inlineMarkdown } from '../lib/inline-markdown.js';
7
+
8
+ interface Props {
9
+ href?: string;
10
+ title?: string;
11
+ description?: string;
12
+ }
13
+ const { href, title, description } = Astro.props as Props;
14
+ const Tag = href ? 'a' : 'div';
15
+ ---
16
+ <Tag class="wd-tile" href={href}>
17
+ <div class="wd-tile-preview"><slot /></div>
18
+ {title && <div class="wd-tile-title" set:html={inlineMarkdown(title)} />}
19
+ {description && <div class="wd-tile-description">{description}</div>}
20
+ </Tag>
21
+ <style>
22
+ .wd-tile {
23
+ display: block;
24
+ text-decoration: none;
25
+ color: inherit;
26
+ }
27
+ /* Dotted pattern behind the preview, drawn from the theme's own border
28
+ color so it reads in both themes. */
29
+ .wd-tile-preview {
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ height: 10rem;
34
+ overflow: hidden;
35
+ border: 1px solid var(--wd-border);
36
+ border-radius: 0.6rem;
37
+ background-color: var(--wd-surface);
38
+ background-image: radial-gradient(var(--wd-border) 1px, transparent 1px);
39
+ background-size: 14px 14px;
40
+ transition: border-color 0.15s ease;
41
+ }
42
+ a.wd-tile:hover .wd-tile-preview {
43
+ border-color: var(--wd-primary);
44
+ }
45
+ .wd-tile-preview :global(img),
46
+ .wd-tile-preview :global(svg) {
47
+ max-width: 100%;
48
+ max-height: 100%;
49
+ object-fit: contain;
50
+ margin: 0;
51
+ }
52
+ .wd-tile-preview :global(p) {
53
+ display: contents;
54
+ }
55
+ .wd-tile-title {
56
+ margin-top: 0.6rem;
57
+ font-weight: 600;
58
+ color: var(--wd-text);
59
+ }
60
+ .wd-tile-description {
61
+ margin-top: 0.15rem;
62
+ font-size: 0.875rem;
63
+ color: var(--wd-text-muted);
64
+ }
65
+ </style>
@@ -0,0 +1,213 @@
1
+ ---
2
+ // Mintlify's <Tree> (alias <FileTree>) - a file/folder tree built from
3
+ // <Tree.Folder> and <Tree.File> (TreeFolder.astro / TreeFile.astro,
4
+ // attached as properties in components/compound.ts), or from a Markdown
5
+ // list, which remarkMintlifyTreeLists (lib/mdx-mintlify.js) rewrites into
6
+ // those same elements at build time.
7
+ //
8
+ // Rendered as an ARIA tree. The script below adds Mintlify's documented
9
+ // keyboard navigation: Up/Down between visible items, Right to open a
10
+ // folder (or step into it), Left to close it (or step out to its parent),
11
+ // Home/End, Enter/Space to toggle, * to open every sibling folder, and
12
+ // type-ahead to jump to an item by its first letters.
13
+ //
14
+ // The highlight color is the `--tree-highlight` custom property, which a
15
+ // page can set on the tree itself: <Tree style={{ "--tree-highlight": "..." }}>.
16
+ interface Props {
17
+ style?: string | Record<string, string>;
18
+ class?: string;
19
+ className?: string;
20
+ }
21
+ const { style, class: className, className: mintlifyClassName } = Astro.props as Props;
22
+ ---
23
+ <ul class:list={['wd-tree', className, mintlifyClassName]} role="tree" style={style}><slot /></ul>
24
+ <script>
25
+ function initTrees(root: ParentNode) {
26
+ root.querySelectorAll<HTMLElement>('.wd-tree').forEach((tree) => {
27
+ if (tree.dataset.wdInit) return;
28
+ tree.dataset.wdInit = 'true';
29
+ const items = () => Array.from(tree.querySelectorAll<HTMLElement>('.wd-tree-item'));
30
+ const isFolder = (el: HTMLElement) => el.classList.contains('wd-tree-folder');
31
+ const isOpen = (el: HTMLElement) => el.getAttribute('aria-expanded') === 'true';
32
+ // Visible = not inside a closed folder.
33
+ const visible = () =>
34
+ items().filter((el) => {
35
+ let parent = el.parentElement?.closest<HTMLElement>('.wd-tree-folder');
36
+ while (parent && tree.contains(parent)) {
37
+ if (!isOpen(parent)) return false;
38
+ parent = parent.parentElement?.closest<HTMLElement>('.wd-tree-folder');
39
+ }
40
+ return true;
41
+ });
42
+ const setOpen = (el: HTMLElement, open: boolean) => {
43
+ if (!isFolder(el) || el.classList.contains('wd-tree-static')) return;
44
+ el.setAttribute('aria-expanded', String(open));
45
+ };
46
+ const focus = (el: HTMLElement | undefined) => {
47
+ if (!el) return;
48
+ items().forEach((i) => (i.tabIndex = -1));
49
+ el.tabIndex = 0;
50
+ el.focus();
51
+ };
52
+ const first = items()[0];
53
+ if (first) first.tabIndex = 0;
54
+
55
+ tree.addEventListener('click', (e) => {
56
+ const row = (e.target as HTMLElement).closest('.wd-tree-row');
57
+ const item = row?.parentElement as HTMLElement | null;
58
+ if (!item || !tree.contains(item)) return;
59
+ if (isFolder(item)) setOpen(item, !isOpen(item));
60
+ focus(item);
61
+ });
62
+
63
+ let typed = '';
64
+ let typedAt = 0;
65
+ tree.addEventListener('keydown', (e) => {
66
+ const current = (e.target as HTMLElement).closest<HTMLElement>('.wd-tree-item');
67
+ if (!current) return;
68
+ const list = visible();
69
+ const i = list.indexOf(current);
70
+ const parentFolder = current.parentElement?.closest<HTMLElement>('.wd-tree-folder');
71
+ switch (e.key) {
72
+ case 'ArrowDown':
73
+ focus(list[i + 1]);
74
+ break;
75
+ case 'ArrowUp':
76
+ focus(list[i - 1]);
77
+ break;
78
+ case 'ArrowRight':
79
+ if (isFolder(current) && !isOpen(current) && !current.classList.contains('wd-tree-static')) setOpen(current, true);
80
+ else if (isFolder(current) && isOpen(current)) focus(current.querySelector<HTMLElement>('.wd-tree-item') ?? undefined);
81
+ break;
82
+ case 'ArrowLeft':
83
+ if (isFolder(current) && isOpen(current) && !current.classList.contains('wd-tree-static')) setOpen(current, false);
84
+ else if (parentFolder && tree.contains(parentFolder)) focus(parentFolder);
85
+ break;
86
+ case 'Home':
87
+ focus(list[0]);
88
+ break;
89
+ case 'End':
90
+ focus(list[list.length - 1]);
91
+ break;
92
+ case 'Enter':
93
+ case ' ':
94
+ if (isFolder(current)) setOpen(current, !isOpen(current));
95
+ break;
96
+ case '*':
97
+ Array.from(current.parentElement?.children ?? [])
98
+ .filter((el): el is HTMLElement => el instanceof HTMLElement && isFolder(el))
99
+ .forEach((el) => setOpen(el, true));
100
+ break;
101
+ default:
102
+ if (e.key.length === 1 && /\S/.test(e.key) && !e.ctrlKey && !e.metaKey && !e.altKey) {
103
+ const now = Date.now();
104
+ typed = now - typedAt > 700 ? e.key.toLowerCase() : typed + e.key.toLowerCase();
105
+ typedAt = now;
106
+ const nameOf = (el: HTMLElement) =>
107
+ el.querySelector(':scope > .wd-tree-row .wd-tree-name')?.textContent?.toLowerCase() ?? '';
108
+ // A single letter looks past the current item; a longer
109
+ // prefix (typed quickly) keeps matching from it, so "pa"
110
+ // after "p" landed on page.tsx stays there.
111
+ const startAt = typed.length > 1 ? i : i + 1;
112
+ const ordered = [...list.slice(startAt), ...list.slice(0, startAt)];
113
+ const match = ordered.find((el) => nameOf(el).startsWith(typed));
114
+ if (match) focus(match);
115
+ break;
116
+ }
117
+ return;
118
+ }
119
+ e.preventDefault();
120
+ });
121
+ });
122
+ }
123
+ initTrees(document);
124
+ document.addEventListener('astro:page-load', () => initTrees(document));
125
+ </script>
126
+ <style is:global>
127
+ .wd-tree {
128
+ --wd-tree-accent: var(--tree-highlight, var(--wd-primary));
129
+ margin: 1.25rem 0;
130
+ padding: 0.6rem;
131
+ list-style: none;
132
+ border: 1px solid var(--wd-border);
133
+ border-radius: 0.6rem;
134
+ font-family: monospace;
135
+ font-size: 0.875rem;
136
+ }
137
+ .wd-tree .wd-tree-group {
138
+ margin: 0;
139
+ padding-left: 1.1rem;
140
+ list-style: none;
141
+ }
142
+ .wd-tree .wd-tree-item {
143
+ margin: 0;
144
+ padding: 0;
145
+ outline: none;
146
+ }
147
+ .wd-tree-folder[aria-expanded='false'] > .wd-tree-group {
148
+ display: none;
149
+ }
150
+ .wd-tree-row {
151
+ display: flex;
152
+ align-items: center;
153
+ gap: 0.4rem;
154
+ padding: 0.2rem 0.4rem;
155
+ border-radius: 0.35rem;
156
+ color: var(--wd-text);
157
+ cursor: default;
158
+ user-select: none;
159
+ }
160
+ .wd-tree-folder:not(.wd-tree-static) > .wd-tree-row {
161
+ cursor: pointer;
162
+ }
163
+ .wd-tree-row:hover,
164
+ .wd-tree-item:focus-visible > .wd-tree-row {
165
+ background: var(--wd-surface);
166
+ }
167
+ .wd-tree-item:focus-visible > .wd-tree-row {
168
+ box-shadow: inset 0 0 0 1px var(--wd-tree-accent);
169
+ }
170
+ .wd-tree-chevron {
171
+ width: 0.8rem;
172
+ flex-shrink: 0;
173
+ display: inline-flex;
174
+ justify-content: center;
175
+ }
176
+ .wd-tree-folder > .wd-tree-row > .wd-tree-chevron::before {
177
+ content: '';
178
+ width: 0.35rem;
179
+ height: 0.35rem;
180
+ border-right: 1.5px solid var(--wd-text-muted);
181
+ border-bottom: 1.5px solid var(--wd-text-muted);
182
+ transform: rotate(-45deg);
183
+ transition: transform 0.12s ease;
184
+ }
185
+ .wd-tree-folder[aria-expanded='true'] > .wd-tree-row > .wd-tree-chevron::before {
186
+ transform: rotate(45deg);
187
+ }
188
+ .wd-tree-static > .wd-tree-row > .wd-tree-chevron::before {
189
+ opacity: 0.35;
190
+ }
191
+ svg.wd-tree-icon {
192
+ width: 1em;
193
+ height: 1em;
194
+ flex-shrink: 0;
195
+ color: var(--wd-text-muted);
196
+ }
197
+ .wd-tree-folder[aria-expanded='true'] > .wd-tree-row > .wd-tree-icon-closed,
198
+ .wd-tree-folder[aria-expanded='false'] > .wd-tree-row > .wd-tree-icon-open {
199
+ display: none;
200
+ }
201
+ /* The highlighted item gets a tinted row; a highlighted folder also
202
+ tints the text of everything inside it, so the active path reads. */
203
+ .wd-tree-highlight > .wd-tree-row {
204
+ background: color-mix(in srgb, var(--wd-tree-accent) 14%, transparent);
205
+ color: var(--wd-tree-accent);
206
+ font-weight: 600;
207
+ }
208
+ .wd-tree-highlight > .wd-tree-row .wd-tree-icon,
209
+ .wd-tree-folder.wd-tree-highlight .wd-tree-row,
210
+ .wd-tree-folder.wd-tree-highlight .wd-tree-icon {
211
+ color: var(--wd-tree-accent);
212
+ }
213
+ </style>
@@ -0,0 +1,17 @@
1
+ ---
2
+ // Mintlify's <Tree.File name="..."> - see Tree.astro. `highlight` marks it
3
+ // as the active item.
4
+ import AppIcon from './AppIcon.astro';
5
+ interface Props {
6
+ name: string;
7
+ highlight?: boolean;
8
+ }
9
+ const { name, highlight = false } = Astro.props as Props;
10
+ ---
11
+ <li class:list={['wd-tree-item', 'wd-tree-file', { 'wd-tree-highlight': highlight }]} role="treeitem" tabindex="-1">
12
+ <span class="wd-tree-row">
13
+ <span class="wd-tree-chevron wd-tree-chevron-spacer" aria-hidden="true"></span>
14
+ <AppIcon icon="lucide:file" class="wd-tree-icon" />
15
+ <span class="wd-tree-name">{name}</span>
16
+ </span>
17
+ </li>
@@ -0,0 +1,28 @@
1
+ ---
2
+ // Mintlify's <Tree.Folder name="..."> - see Tree.astro. `defaultOpen`
3
+ // starts it expanded; `openable={false}` makes it a fixed, non-toggling
4
+ // folder (shown open or closed per `defaultOpen`); `highlight` marks it as
5
+ // the active item and tints everything inside it.
6
+ import AppIcon from './AppIcon.astro';
7
+ interface Props {
8
+ name: string;
9
+ defaultOpen?: boolean;
10
+ openable?: boolean;
11
+ highlight?: boolean;
12
+ }
13
+ const { name, defaultOpen = false, openable = true, highlight = false } = Astro.props as Props;
14
+ ---
15
+ <li
16
+ class:list={['wd-tree-item', 'wd-tree-folder', { 'wd-tree-highlight': highlight, 'wd-tree-static': !openable }]}
17
+ role="treeitem"
18
+ aria-expanded={defaultOpen ? 'true' : 'false'}
19
+ tabindex="-1"
20
+ >
21
+ <span class="wd-tree-row">
22
+ <span class="wd-tree-chevron" aria-hidden="true"></span>
23
+ <AppIcon icon="lucide:folder" class="wd-tree-icon wd-tree-icon-closed" />
24
+ <AppIcon icon="lucide:folder-open" class="wd-tree-icon wd-tree-icon-open" />
25
+ <span class="wd-tree-name">{name}</span>
26
+ </span>
27
+ <ul class="wd-tree-group" role="group"><slot /></ul>
28
+ </li>