@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.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/dist/action-icons.d.ts +5 -0
  4. package/dist/action-icons.d.ts.map +1 -0
  5. package/dist/action-icons.js +52 -0
  6. package/dist/action-icons.js.map +1 -0
  7. package/dist/brand.d.ts +7 -0
  8. package/dist/brand.d.ts.map +1 -0
  9. package/dist/brand.js +37 -0
  10. package/dist/brand.js.map +1 -0
  11. package/dist/config.d.ts +3 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +22 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/header.d.ts +12 -0
  16. package/dist/header.d.ts.map +1 -0
  17. package/dist/header.js +73 -0
  18. package/dist/header.js.map +1 -0
  19. package/dist/index.d.ts +8 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +48 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/navigation.d.ts +23 -0
  24. package/dist/navigation.d.ts.map +1 -0
  25. package/dist/navigation.js +41 -0
  26. package/dist/navigation.js.map +1 -0
  27. package/dist/next.d.ts +29 -0
  28. package/dist/next.d.ts.map +1 -0
  29. package/dist/next.js +63 -0
  30. package/dist/next.js.map +1 -0
  31. package/dist/page-content.d.ts +12 -0
  32. package/dist/page-content.d.ts.map +1 -0
  33. package/dist/page-content.js +274 -0
  34. package/dist/page-content.js.map +1 -0
  35. package/dist/provider.d.ts +2 -0
  36. package/dist/provider.d.ts.map +1 -0
  37. package/dist/provider.js +1 -0
  38. package/dist/site/constants.d.ts +2 -0
  39. package/dist/site/constants.d.ts.map +1 -0
  40. package/dist/site/constants.js +5 -0
  41. package/dist/site/constants.js.map +1 -0
  42. package/dist/site/footer.d.ts +13 -0
  43. package/dist/site/footer.d.ts.map +1 -0
  44. package/dist/site/footer.js +35 -0
  45. package/dist/site/footer.js.map +1 -0
  46. package/dist/site/header.d.ts +13 -0
  47. package/dist/site/header.d.ts.map +1 -0
  48. package/dist/site/header.js +81 -0
  49. package/dist/site/header.js.map +1 -0
  50. package/dist/site/layout.d.ts +8 -0
  51. package/dist/site/layout.d.ts.map +1 -0
  52. package/dist/site/layout.js +21 -0
  53. package/dist/site/layout.js.map +1 -0
  54. package/dist/site/page.d.ts +9 -0
  55. package/dist/site/page.d.ts.map +1 -0
  56. package/dist/site/page.js +32 -0
  57. package/dist/site/page.js.map +1 -0
  58. package/dist/site/pager.d.ts +13 -0
  59. package/dist/site/pager.d.ts.map +1 -0
  60. package/dist/site/pager.js +36 -0
  61. package/dist/site/pager.js.map +1 -0
  62. package/dist/site/sidebar-navigation.d.ts +13 -0
  63. package/dist/site/sidebar-navigation.d.ts.map +1 -0
  64. package/dist/site/sidebar-navigation.js +185 -0
  65. package/dist/site/sidebar-navigation.js.map +1 -0
  66. package/dist/site/sidebar.d.ts +16 -0
  67. package/dist/site/sidebar.d.ts.map +1 -0
  68. package/dist/site/sidebar.js +46 -0
  69. package/dist/site/sidebar.js.map +1 -0
  70. package/dist/site/toc.d.ts +12 -0
  71. package/dist/site/toc.d.ts.map +1 -0
  72. package/dist/site/toc.js +92 -0
  73. package/dist/site/toc.js.map +1 -0
  74. package/dist/site/tree.d.ts +24 -0
  75. package/dist/site/tree.d.ts.map +1 -0
  76. package/dist/site/tree.js +14 -0
  77. package/dist/site/tree.js.map +1 -0
  78. package/dist/site/utils.d.ts +2 -0
  79. package/dist/site/utils.d.ts.map +1 -0
  80. package/dist/site/utils.js +5 -0
  81. package/dist/site/utils.js.map +1 -0
  82. package/dist/ui.d.ts +10 -0
  83. package/dist/ui.d.ts.map +1 -0
  84. package/dist/ui.js +9 -0
  85. package/package.json +101 -1
  86. package/src/action-icons.tsx +48 -0
  87. package/src/brand.tsx +36 -0
  88. package/src/config.ts +23 -0
  89. package/src/header.test.tsx +41 -0
  90. package/src/header.tsx +94 -0
  91. package/src/index.test.ts +37 -0
  92. package/src/index.ts +38 -0
  93. package/src/layout-hosts.test.tsx +98 -0
  94. package/src/navigation.test.ts +123 -0
  95. package/src/navigation.ts +61 -0
  96. package/src/next.test.tsx +110 -0
  97. package/src/next.tsx +101 -0
  98. package/src/page-content.test.tsx +87 -0
  99. package/src/page-content.tsx +416 -0
  100. package/src/provider.ts +1 -0
  101. package/src/site/constants.ts +1 -0
  102. package/src/site/footer.tsx +59 -0
  103. package/src/site/header.test.tsx +89 -0
  104. package/src/site/header.tsx +117 -0
  105. package/src/site/layout.tsx +33 -0
  106. package/src/site/page.tsx +38 -0
  107. package/src/site/pager.tsx +54 -0
  108. package/src/site/sidebar-navigation.test.tsx +92 -0
  109. package/src/site/sidebar-navigation.tsx +267 -0
  110. package/src/site/sidebar.tsx +77 -0
  111. package/src/site/toc.test.tsx +187 -0
  112. package/src/site/toc.tsx +118 -0
  113. package/src/site/tree.ts +36 -0
  114. package/src/site/utils.ts +2 -0
  115. package/src/ui.ts +19 -0
  116. package/styles/site.css +223 -0
  117. 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
+ );
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,2 @@
1
+ export const cn = (...values: (string | false | undefined)[]) =>
2
+ values.filter(Boolean).join(" ");
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";
@@ -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
+ }