@assistant-ui/docs-theme 0.0.0 → 0.0.3
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/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/action-icons.d.ts +5 -0
- package/dist/action-icons.d.ts.map +1 -0
- package/dist/action-icons.js +52 -0
- package/dist/action-icons.js.map +1 -0
- package/dist/brand.d.ts +7 -0
- package/dist/brand.d.ts.map +1 -0
- package/dist/brand.js +37 -0
- package/dist/brand.js.map +1 -0
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -0
- package/dist/header.d.ts +12 -0
- package/dist/header.d.ts.map +1 -0
- package/dist/header.js +73 -0
- package/dist/header.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation.d.ts +23 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +41 -0
- package/dist/navigation.js.map +1 -0
- package/dist/next.d.ts +29 -0
- package/dist/next.d.ts.map +1 -0
- package/dist/next.js +63 -0
- package/dist/next.js.map +1 -0
- package/dist/page-content.d.ts +12 -0
- package/dist/page-content.d.ts.map +1 -0
- package/dist/page-content.js +274 -0
- package/dist/page-content.js.map +1 -0
- package/dist/provider.d.ts +2 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +1 -0
- package/dist/site/constants.d.ts +2 -0
- package/dist/site/constants.d.ts.map +1 -0
- package/dist/site/constants.js +5 -0
- package/dist/site/constants.js.map +1 -0
- package/dist/site/footer.d.ts +13 -0
- package/dist/site/footer.d.ts.map +1 -0
- package/dist/site/footer.js +35 -0
- package/dist/site/footer.js.map +1 -0
- package/dist/site/header.d.ts +13 -0
- package/dist/site/header.d.ts.map +1 -0
- package/dist/site/header.js +81 -0
- package/dist/site/header.js.map +1 -0
- package/dist/site/layout.d.ts +8 -0
- package/dist/site/layout.d.ts.map +1 -0
- package/dist/site/layout.js +21 -0
- package/dist/site/layout.js.map +1 -0
- package/dist/site/page.d.ts +9 -0
- package/dist/site/page.d.ts.map +1 -0
- package/dist/site/page.js +32 -0
- package/dist/site/page.js.map +1 -0
- package/dist/site/pager.d.ts +13 -0
- package/dist/site/pager.d.ts.map +1 -0
- package/dist/site/pager.js +36 -0
- package/dist/site/pager.js.map +1 -0
- package/dist/site/sidebar-navigation.d.ts +13 -0
- package/dist/site/sidebar-navigation.d.ts.map +1 -0
- package/dist/site/sidebar-navigation.js +185 -0
- package/dist/site/sidebar-navigation.js.map +1 -0
- package/dist/site/sidebar.d.ts +16 -0
- package/dist/site/sidebar.d.ts.map +1 -0
- package/dist/site/sidebar.js +46 -0
- package/dist/site/sidebar.js.map +1 -0
- package/dist/site/toc.d.ts +12 -0
- package/dist/site/toc.d.ts.map +1 -0
- package/dist/site/toc.js +92 -0
- package/dist/site/toc.js.map +1 -0
- package/dist/site/tree.d.ts +24 -0
- package/dist/site/tree.d.ts.map +1 -0
- package/dist/site/tree.js +14 -0
- package/dist/site/tree.js.map +1 -0
- package/dist/site/utils.d.ts +2 -0
- package/dist/site/utils.d.ts.map +1 -0
- package/dist/site/utils.js +5 -0
- package/dist/site/utils.js.map +1 -0
- package/dist/ui.d.ts +10 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +9 -0
- package/package.json +101 -1
- package/src/action-icons.tsx +48 -0
- package/src/brand.tsx +36 -0
- package/src/config.ts +23 -0
- package/src/header.test.tsx +41 -0
- package/src/header.tsx +94 -0
- package/src/index.test.ts +37 -0
- package/src/index.ts +38 -0
- package/src/layout-hosts.test.tsx +98 -0
- package/src/navigation.test.ts +123 -0
- package/src/navigation.ts +61 -0
- package/src/next.test.tsx +110 -0
- package/src/next.tsx +101 -0
- package/src/page-content.test.tsx +87 -0
- package/src/page-content.tsx +416 -0
- package/src/provider.ts +1 -0
- package/src/site/constants.ts +1 -0
- package/src/site/footer.tsx +59 -0
- package/src/site/header.test.tsx +89 -0
- package/src/site/header.tsx +117 -0
- package/src/site/layout.tsx +33 -0
- package/src/site/page.tsx +38 -0
- package/src/site/pager.tsx +54 -0
- package/src/site/sidebar-navigation.test.tsx +92 -0
- package/src/site/sidebar-navigation.tsx +267 -0
- package/src/site/sidebar.tsx +77 -0
- package/src/site/toc.test.tsx +187 -0
- package/src/site/toc.tsx +118 -0
- package/src/site/tree.ts +36 -0
- package/src/site/utils.ts +2 -0
- package/src/ui.ts +19 -0
- package/styles/site.css +223 -0
- package/styles/theme.css +858 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
|
|
3
|
+
import { act } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { expect, it, vi } from "vitest";
|
|
6
|
+
import { DocsTableOfContents } from "./toc";
|
|
7
|
+
|
|
8
|
+
it("observes the current page's headings and releases them when the page changes", async () => {
|
|
9
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
10
|
+
const viewport = {
|
|
11
|
+
matches: true,
|
|
12
|
+
addEventListener: vi.fn(),
|
|
13
|
+
removeEventListener: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
vi.stubGlobal("matchMedia", () => viewport);
|
|
16
|
+
const observers: {
|
|
17
|
+
observe: ReturnType<typeof vi.fn>;
|
|
18
|
+
disconnect: ReturnType<typeof vi.fn>;
|
|
19
|
+
}[] = [];
|
|
20
|
+
vi.stubGlobal(
|
|
21
|
+
"IntersectionObserver",
|
|
22
|
+
class {
|
|
23
|
+
observe = vi.fn();
|
|
24
|
+
disconnect = vi.fn();
|
|
25
|
+
constructor() {
|
|
26
|
+
observers.push(this);
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
);
|
|
30
|
+
const container = document.createElement("div");
|
|
31
|
+
document.body.append(container);
|
|
32
|
+
const root = createRoot(container);
|
|
33
|
+
const render = (id: string) =>
|
|
34
|
+
act(async () =>
|
|
35
|
+
root.render(
|
|
36
|
+
<>
|
|
37
|
+
<h2 id={id}>Current heading</h2>
|
|
38
|
+
<DocsTableOfContents
|
|
39
|
+
items={[{ title: "Current heading", url: `#${id}`, depth: 2 }]}
|
|
40
|
+
>
|
|
41
|
+
<button>Copy page</button>
|
|
42
|
+
</DocsTableOfContents>
|
|
43
|
+
</>,
|
|
44
|
+
),
|
|
45
|
+
);
|
|
46
|
+
try {
|
|
47
|
+
await render("install");
|
|
48
|
+
expect(container.querySelector('a[href="#install"]')?.textContent).toBe(
|
|
49
|
+
"Current heading",
|
|
50
|
+
);
|
|
51
|
+
expect(observers[0]!.observe).toHaveBeenCalledWith(
|
|
52
|
+
container.querySelector("h2"),
|
|
53
|
+
);
|
|
54
|
+
await render("usage");
|
|
55
|
+
expect(observers[0]!.disconnect).toHaveBeenCalledOnce();
|
|
56
|
+
expect(observers[1]!.observe).toHaveBeenCalledWith(
|
|
57
|
+
container.querySelector("h2"),
|
|
58
|
+
);
|
|
59
|
+
expect(container.querySelector('a[href="#install"]')).toBeNull();
|
|
60
|
+
expect(container.querySelector("button")?.textContent).toBe("Copy page");
|
|
61
|
+
await act(async () =>
|
|
62
|
+
root.render(
|
|
63
|
+
<DocsTableOfContents items={[]}>
|
|
64
|
+
<button>Copy page</button>
|
|
65
|
+
</DocsTableOfContents>,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
expect(observers[1]!.disconnect).toHaveBeenCalledOnce();
|
|
69
|
+
expect(container.querySelector("button")).toBeNull();
|
|
70
|
+
} finally {
|
|
71
|
+
await act(async () => root.unmount());
|
|
72
|
+
container.remove();
|
|
73
|
+
vi.unstubAllGlobals();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("does no heading observation while the TOC is hidden and resumes when it becomes visible", async () => {
|
|
78
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
79
|
+
let onChange = () => {};
|
|
80
|
+
const viewport = {
|
|
81
|
+
matches: false,
|
|
82
|
+
addEventListener: (_: string, listener: () => void) => {
|
|
83
|
+
onChange = listener;
|
|
84
|
+
},
|
|
85
|
+
removeEventListener: vi.fn(),
|
|
86
|
+
};
|
|
87
|
+
vi.stubGlobal("matchMedia", () => viewport);
|
|
88
|
+
const observe = vi.fn();
|
|
89
|
+
const disconnect = vi.fn();
|
|
90
|
+
const Observer = vi.fn(function () {
|
|
91
|
+
return { observe, disconnect };
|
|
92
|
+
});
|
|
93
|
+
vi.stubGlobal("IntersectionObserver", Observer);
|
|
94
|
+
const container = document.createElement("div");
|
|
95
|
+
document.body.append(container);
|
|
96
|
+
const root = createRoot(container);
|
|
97
|
+
try {
|
|
98
|
+
await act(async () =>
|
|
99
|
+
root.render(
|
|
100
|
+
<>
|
|
101
|
+
<h2 id="setup">Setup</h2>
|
|
102
|
+
<DocsTableOfContents
|
|
103
|
+
items={[{ title: "Setup", url: "#setup", depth: 2 }]}
|
|
104
|
+
/>
|
|
105
|
+
</>,
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
expect(Observer).not.toHaveBeenCalled();
|
|
109
|
+
viewport.matches = true;
|
|
110
|
+
await act(async () => onChange());
|
|
111
|
+
expect(Observer).toHaveBeenCalledOnce();
|
|
112
|
+
expect(observe).toHaveBeenCalledWith(container.querySelector("h2"));
|
|
113
|
+
viewport.matches = false;
|
|
114
|
+
await act(async () => onChange());
|
|
115
|
+
expect(disconnect).toHaveBeenCalledOnce();
|
|
116
|
+
} finally {
|
|
117
|
+
await act(async () => root.unmount());
|
|
118
|
+
expect(viewport.removeEventListener).toHaveBeenCalledWith(
|
|
119
|
+
"change",
|
|
120
|
+
onChange,
|
|
121
|
+
);
|
|
122
|
+
container.remove();
|
|
123
|
+
vi.unstubAllGlobals();
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it.each([
|
|
128
|
+
["café-配置", "#caf%C3%A9-%E9%85%8D%E7%BD%AE"],
|
|
129
|
+
['quoted"id', "#quoted%22id"],
|
|
130
|
+
["literal%id", "#literal%25id"],
|
|
131
|
+
])(
|
|
132
|
+
"tracks the rendered heading %s from an encoded fragment",
|
|
133
|
+
async (id, url) => {
|
|
134
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
135
|
+
vi.stubGlobal("matchMedia", () => ({
|
|
136
|
+
matches: true,
|
|
137
|
+
addEventListener() {},
|
|
138
|
+
removeEventListener() {},
|
|
139
|
+
}));
|
|
140
|
+
const observe = vi.fn();
|
|
141
|
+
let notify: (
|
|
142
|
+
entries: { isIntersecting: boolean; target: Element }[],
|
|
143
|
+
) => void;
|
|
144
|
+
vi.stubGlobal(
|
|
145
|
+
"IntersectionObserver",
|
|
146
|
+
class {
|
|
147
|
+
observe = observe;
|
|
148
|
+
disconnect() {}
|
|
149
|
+
constructor(callback: typeof notify) {
|
|
150
|
+
notify = callback;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
const container = document.createElement("div");
|
|
155
|
+
document.body.append(container);
|
|
156
|
+
const root = createRoot(container);
|
|
157
|
+
try {
|
|
158
|
+
await act(async () =>
|
|
159
|
+
root.render(
|
|
160
|
+
<>
|
|
161
|
+
<h2 id={id}>Current heading</h2>
|
|
162
|
+
<DocsTableOfContents
|
|
163
|
+
items={[{ title: "Current heading", url, depth: 2 }]}
|
|
164
|
+
/>
|
|
165
|
+
</>,
|
|
166
|
+
),
|
|
167
|
+
);
|
|
168
|
+
const heading = container.querySelector("h2")!;
|
|
169
|
+
expect(observe).toHaveBeenCalledWith(heading);
|
|
170
|
+
const item = container.querySelector("li")!;
|
|
171
|
+
const scrollIntoView = vi.fn();
|
|
172
|
+
item.scrollIntoView = scrollIntoView;
|
|
173
|
+
await act(async () =>
|
|
174
|
+
notify([{ isIntersecting: true, target: heading }]),
|
|
175
|
+
);
|
|
176
|
+
expect(scrollIntoView).toHaveBeenCalledWith({
|
|
177
|
+
behavior: "smooth",
|
|
178
|
+
block: "nearest",
|
|
179
|
+
});
|
|
180
|
+
expect(container.querySelector("a")?.getAttribute("href")).toBe(url);
|
|
181
|
+
} finally {
|
|
182
|
+
await act(async () => root.unmount());
|
|
183
|
+
container.remove();
|
|
184
|
+
vi.unstubAllGlobals();
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
);
|
package/src/site/toc.tsx
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState, type ReactNode } from "react";
|
|
4
|
+
import { cn } from "./utils";
|
|
5
|
+
|
|
6
|
+
type TOCItem = {
|
|
7
|
+
title: ReactNode;
|
|
8
|
+
url: string;
|
|
9
|
+
depth: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function headingId(url: string) {
|
|
13
|
+
const fragment = url.slice(1);
|
|
14
|
+
try {
|
|
15
|
+
return decodeURIComponent(fragment);
|
|
16
|
+
} catch {
|
|
17
|
+
return fragment;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function DocsTableOfContents({
|
|
22
|
+
items,
|
|
23
|
+
children,
|
|
24
|
+
}: {
|
|
25
|
+
items: TOCItem[];
|
|
26
|
+
children?: ReactNode;
|
|
27
|
+
}) {
|
|
28
|
+
const [activeId, setActiveId] = useState<string | null>(null);
|
|
29
|
+
const listRef = useRef<HTMLUListElement>(null);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (items.length === 0) return;
|
|
33
|
+
|
|
34
|
+
const headingIds = items.map((item) => headingId(item.url));
|
|
35
|
+
|
|
36
|
+
const viewport = window.matchMedia("(min-width: 1280px)");
|
|
37
|
+
let observer: IntersectionObserver | undefined;
|
|
38
|
+
const observeVisibleHeadings = () => {
|
|
39
|
+
observer?.disconnect();
|
|
40
|
+
if (!viewport.matches) return;
|
|
41
|
+
observer = new IntersectionObserver(
|
|
42
|
+
(entries) => {
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
if (entry.isIntersecting) {
|
|
45
|
+
setActiveId(entry.target.id);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{ rootMargin: "-80px 0px -70% 0px", threshold: 0 },
|
|
51
|
+
);
|
|
52
|
+
for (const id of headingIds) {
|
|
53
|
+
const element = document.getElementById(id);
|
|
54
|
+
if (element) observer.observe(element);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
observeVisibleHeadings();
|
|
58
|
+
viewport.addEventListener("change", observeVisibleHeadings);
|
|
59
|
+
return () => {
|
|
60
|
+
observer?.disconnect();
|
|
61
|
+
viewport.removeEventListener("change", observeVisibleHeadings);
|
|
62
|
+
};
|
|
63
|
+
}, [items]);
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!activeId || !listRef.current) return;
|
|
67
|
+
|
|
68
|
+
const activeElement = Array.from(listRef.current.children).find(
|
|
69
|
+
(item) => item.getAttribute("data-toc-id") === activeId,
|
|
70
|
+
);
|
|
71
|
+
if (activeElement) {
|
|
72
|
+
activeElement.scrollIntoView({
|
|
73
|
+
behavior: "smooth",
|
|
74
|
+
block: "nearest",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}, [activeId]);
|
|
78
|
+
|
|
79
|
+
if (items.length === 0) return null;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div className="docs-toc w-56 max-xl:hidden">
|
|
83
|
+
<div className="sticky top-[calc(var(--docs-header-height)_+_1rem)] flex max-h-[calc(100vh_-_var(--docs-header-height)_-_1rem)] flex-col pe-4 pt-4 pb-2">
|
|
84
|
+
<p className="text-muted-foreground mb-3 shrink-0 text-xs">
|
|
85
|
+
On this page
|
|
86
|
+
</p>
|
|
87
|
+
<ul
|
|
88
|
+
ref={listRef}
|
|
89
|
+
className="flex min-h-0 flex-1 [scrollbar-width:none] flex-col gap-1 overflow-x-hidden overflow-y-auto [&::-webkit-scrollbar]:hidden"
|
|
90
|
+
>
|
|
91
|
+
{items.map((item) => {
|
|
92
|
+
const id = headingId(item.url);
|
|
93
|
+
const isActive = activeId === id;
|
|
94
|
+
const indent = Math.max(0, item.depth - 2) * 12;
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<li key={item.url} data-toc-id={id}>
|
|
98
|
+
<a
|
|
99
|
+
href={item.url}
|
|
100
|
+
style={{ paddingLeft: indent || undefined }}
|
|
101
|
+
className={cn(
|
|
102
|
+
"block py-1 text-[13px] leading-snug wrap-break-word transition-colors",
|
|
103
|
+
isActive
|
|
104
|
+
? "text-foreground font-medium"
|
|
105
|
+
: "text-muted-foreground hover:text-foreground",
|
|
106
|
+
)}
|
|
107
|
+
>
|
|
108
|
+
{item.title}
|
|
109
|
+
</a>
|
|
110
|
+
</li>
|
|
111
|
+
);
|
|
112
|
+
})}
|
|
113
|
+
</ul>
|
|
114
|
+
<div className="mt-6 shrink-0">{children}</div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
);
|
|
118
|
+
}
|
package/src/site/tree.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
interface DocsNodeBase {
|
|
4
|
+
$id?: string;
|
|
5
|
+
name?: ReactNode;
|
|
6
|
+
icon?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export interface DocsPage extends DocsNodeBase {
|
|
9
|
+
type: "page";
|
|
10
|
+
name: ReactNode;
|
|
11
|
+
url: string;
|
|
12
|
+
}
|
|
13
|
+
export interface DocsFolder extends DocsNodeBase {
|
|
14
|
+
type: "folder";
|
|
15
|
+
name: ReactNode;
|
|
16
|
+
index?: DocsPage;
|
|
17
|
+
children: DocsNode[];
|
|
18
|
+
}
|
|
19
|
+
export interface DocsSeparator extends DocsNodeBase {
|
|
20
|
+
type: "separator";
|
|
21
|
+
}
|
|
22
|
+
export type DocsNode = DocsPage | DocsFolder | DocsSeparator;
|
|
23
|
+
|
|
24
|
+
export function findActivePath(
|
|
25
|
+
nodes: readonly DocsNode[],
|
|
26
|
+
pathname: string,
|
|
27
|
+
): DocsNode[] | null {
|
|
28
|
+
for (const node of nodes) {
|
|
29
|
+
if (node.type === "page" && node.url === pathname) return [node];
|
|
30
|
+
if (node.type !== "folder") continue;
|
|
31
|
+
if (node.index?.url === pathname) return [node, node.index];
|
|
32
|
+
const path = findActivePath(node.children, pathname);
|
|
33
|
+
if (path) return [node, ...path];
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
package/src/ui.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { DocsShell, DocsContent } from "./site/layout";
|
|
2
|
+
export { DocsPageShell, DocsBody } from "./site/page";
|
|
3
|
+
export { DocsFooter } from "./site/footer";
|
|
4
|
+
export {
|
|
5
|
+
DOCS_SIDEBAR_ID,
|
|
6
|
+
DocsSidebar,
|
|
7
|
+
DocsSidebarProvider,
|
|
8
|
+
useDocsSidebar,
|
|
9
|
+
} from "./site/sidebar";
|
|
10
|
+
export { DocsSidebarNavigation } from "./site/sidebar-navigation";
|
|
11
|
+
export { DocsTableOfContents } from "./site/toc";
|
|
12
|
+
export type {
|
|
13
|
+
DocsNode,
|
|
14
|
+
DocsPage,
|
|
15
|
+
DocsFolder,
|
|
16
|
+
DocsSeparator,
|
|
17
|
+
} from "./site/tree";
|
|
18
|
+
export { DocsSiteHeader } from "./site/header";
|
|
19
|
+
export { DocsPagerNavigation } from "./site/pager";
|
package/styles/site.css
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
@source "../dist/site";
|
|
2
|
+
|
|
3
|
+
:root {
|
|
4
|
+
--docs-header-height: 48px;
|
|
5
|
+
--docs-article-width: 56rem;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.docs-layout {
|
|
9
|
+
display: grid;
|
|
10
|
+
grid-template-columns: minmax(0, 1fr);
|
|
11
|
+
|
|
12
|
+
@media (min-width: 1280px) {
|
|
13
|
+
&:has(.docs-toc) {
|
|
14
|
+
grid-template-columns: minmax(0, 1fr) 14rem;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
html:has(.docs-layout) {
|
|
20
|
+
scroll-padding-top: calc(var(--docs-header-height) + 6rem);
|
|
21
|
+
|
|
22
|
+
@media (min-width: 768px) {
|
|
23
|
+
scroll-padding-top: calc(var(--docs-header-height) + 2.5rem);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@media (min-width: 1280px) {
|
|
27
|
+
scroll-padding-top: calc(var(--docs-header-height) + 2rem);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.docs-prose {
|
|
32
|
+
font-size: 0.875rem;
|
|
33
|
+
line-height: 1.7;
|
|
34
|
+
|
|
35
|
+
& :where(p):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
36
|
+
margin-top: 1.25rem;
|
|
37
|
+
margin-bottom: 1.25rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
& :where(h2):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
41
|
+
font-size: 1.25rem;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
letter-spacing: -0.02em;
|
|
44
|
+
margin-top: 2.5rem;
|
|
45
|
+
margin-bottom: 1rem;
|
|
46
|
+
line-height: 1.4;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
& :where(h3):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
50
|
+
font-size: 1rem;
|
|
51
|
+
font-weight: 500;
|
|
52
|
+
letter-spacing: -0.01em;
|
|
53
|
+
margin-top: 2rem;
|
|
54
|
+
margin-bottom: 0.75rem;
|
|
55
|
+
line-height: 1.5;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
& :where(h4):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
59
|
+
font-size: 0.875rem;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
margin-top: 1.5rem;
|
|
62
|
+
margin-bottom: 0.5rem;
|
|
63
|
+
line-height: 1.5;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
& :where(ul, ol):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
67
|
+
margin-top: 1rem;
|
|
68
|
+
margin-bottom: 1rem;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
& :where(li):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
72
|
+
margin-top: 0.25rem;
|
|
73
|
+
margin-bottom: 0.25rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&
|
|
77
|
+
:where(code):not(:where(pre code)):not(
|
|
78
|
+
:where([class~="not-prose"], [class~="not-prose"] *)
|
|
79
|
+
) {
|
|
80
|
+
font-size: 0.8125rem;
|
|
81
|
+
padding: 0.15rem 0.4rem;
|
|
82
|
+
border-radius: 0.5rem;
|
|
83
|
+
border: none;
|
|
84
|
+
background: var(--muted);
|
|
85
|
+
font-weight: 500;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
& [class~="not-prose"] :where(code):not(:where(pre code)) {
|
|
89
|
+
font-size: 0.75rem;
|
|
90
|
+
padding: 0.0625rem 0.3rem;
|
|
91
|
+
border-radius: 0.5rem;
|
|
92
|
+
border: none;
|
|
93
|
+
background: var(--muted);
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
& :where(pre):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
98
|
+
margin-top: 1.25rem;
|
|
99
|
+
margin-bottom: 1.25rem;
|
|
100
|
+
border-radius: 0.75rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&
|
|
104
|
+
:where(blockquote):not(
|
|
105
|
+
:where([class~="not-prose"], [class~="not-prose"] *)
|
|
106
|
+
) {
|
|
107
|
+
font-style: normal;
|
|
108
|
+
font-weight: 400;
|
|
109
|
+
color: var(--muted-foreground);
|
|
110
|
+
margin-top: 1.25rem;
|
|
111
|
+
margin-bottom: 1.25rem;
|
|
112
|
+
padding-left: 1rem;
|
|
113
|
+
border-left-width: 2px;
|
|
114
|
+
border-left-color: var(--border);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
&
|
|
118
|
+
:where(a):not(:where([class~="not-prose"], [class~="not-prose"] *)):not(
|
|
119
|
+
[data-card]
|
|
120
|
+
) {
|
|
121
|
+
text-decoration: underline;
|
|
122
|
+
text-underline-offset: 2px;
|
|
123
|
+
text-decoration-color: var(--muted-foreground);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
& :where(.prose-no-margin):has(table) {
|
|
127
|
+
margin-top: 0rem;
|
|
128
|
+
margin-bottom: 0rem;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
& :where(table):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
132
|
+
margin-top: 0rem;
|
|
133
|
+
margin-bottom: 0rem;
|
|
134
|
+
width: 100%;
|
|
135
|
+
border-collapse: separate;
|
|
136
|
+
border-spacing: 0;
|
|
137
|
+
background: var(--muted);
|
|
138
|
+
border-radius: 0.75rem;
|
|
139
|
+
overflow: hidden;
|
|
140
|
+
|
|
141
|
+
& thead {
|
|
142
|
+
background: transparent;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
& th {
|
|
146
|
+
padding: 0.5rem 0.75rem;
|
|
147
|
+
text-align: left;
|
|
148
|
+
font-weight: 500;
|
|
149
|
+
color: var(--muted-foreground);
|
|
150
|
+
border: none;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
& td {
|
|
154
|
+
padding: 0.5rem 0.75rem;
|
|
155
|
+
border: none;
|
|
156
|
+
vertical-align: top;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
& tr {
|
|
160
|
+
border: none;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
& tbody tr {
|
|
164
|
+
background: var(--background);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
& tbody tr:first-child td:first-child {
|
|
168
|
+
border-top-left-radius: 0.5rem;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
& tbody tr:first-child td:last-child {
|
|
172
|
+
border-top-right-radius: 0.5rem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
& tbody tr:last-child td:first-child {
|
|
176
|
+
border-bottom-left-radius: 0.5rem;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
& tbody tr:last-child td:last-child {
|
|
180
|
+
border-bottom-right-radius: 0.5rem;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
& code {
|
|
184
|
+
font-size: 0.75rem;
|
|
185
|
+
padding: 0.0625rem 0.25rem;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
& :where(hr):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
190
|
+
margin-top: 2rem;
|
|
191
|
+
margin-bottom: 2rem;
|
|
192
|
+
border-color: var(--border);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
&
|
|
196
|
+
:where(h2 + p, h3 + p, h4 + p):not(
|
|
197
|
+
:where([class~="not-prose"], [class~="not-prose"] *)
|
|
198
|
+
) {
|
|
199
|
+
margin-top: 0;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
&
|
|
203
|
+
:where(h2 + ul, h3 + ul, h4 + ul, h2 + ol, h3 + ol, h4 + ol):not(
|
|
204
|
+
:where([class~="not-prose"], [class~="not-prose"] *)
|
|
205
|
+
) {
|
|
206
|
+
margin-top: 0.5rem;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
& :where(img):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
210
|
+
margin-left: auto;
|
|
211
|
+
margin-right: auto;
|
|
212
|
+
border-radius: 0.75rem;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.sidebar-tree-content {
|
|
217
|
+
scrollbar-width: none;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.sidebar-tree-content::-webkit-scrollbar {
|
|
221
|
+
width: 0;
|
|
222
|
+
height: 0;
|
|
223
|
+
}
|