@hypoth-ui/docs-renderer-next 0.1.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.
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/app/accessibility/CategoryFilter.tsx +123 -0
- package/app/accessibility/ConformanceTable.tsx +109 -0
- package/app/accessibility/StatusBadge.tsx +47 -0
- package/app/accessibility/[component]/page.tsx +166 -0
- package/app/accessibility/page.tsx +207 -0
- package/app/api/search/route.ts +241 -0
- package/app/components/[id]/page.tsx +316 -0
- package/app/edition-upgrade/page.tsx +76 -0
- package/app/guides/[id]/page.tsx +67 -0
- package/app/layout.tsx +93 -0
- package/app/page.tsx +29 -0
- package/components/branding/header.tsx +82 -0
- package/components/branding/logo.tsx +54 -0
- package/components/feedback/feedback-widget.tsx +263 -0
- package/components/live-example.tsx +477 -0
- package/components/mdx/edition.tsx +149 -0
- package/components/mdx-renderer.tsx +90 -0
- package/components/nav-sidebar.tsx +269 -0
- package/components/search/search-input.tsx +508 -0
- package/components/theme-init-script.tsx +35 -0
- package/components/theme-switcher.tsx +166 -0
- package/components/tokens-used.tsx +135 -0
- package/components/upgrade/upgrade-prompt.tsx +141 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +751 -0
- package/package.json +66 -0
- package/styles/globals.css +613 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { Edition, NavItem } from "@hypoth-ui/docs-core";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { usePathname } from "next/navigation";
|
|
6
|
+
|
|
7
|
+
interface NavSidebarProps {
|
|
8
|
+
/** Custom navigation items (optional, uses defaults if not provided) */
|
|
9
|
+
navigation?: {
|
|
10
|
+
components: NavItem[];
|
|
11
|
+
guides: NavItem[];
|
|
12
|
+
};
|
|
13
|
+
/** Current edition for filtering */
|
|
14
|
+
edition?: Edition;
|
|
15
|
+
/** Edition map for checking component availability */
|
|
16
|
+
editionMap?: {
|
|
17
|
+
components: Record<string, { editions: Edition[]; status: string; name: string }>;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Default navigation structure
|
|
22
|
+
const defaultNavigation = {
|
|
23
|
+
guides: [
|
|
24
|
+
{
|
|
25
|
+
id: "introduction",
|
|
26
|
+
label: "Introduction",
|
|
27
|
+
href: "",
|
|
28
|
+
type: "category" as const,
|
|
29
|
+
order: 0,
|
|
30
|
+
children: [
|
|
31
|
+
{
|
|
32
|
+
id: "getting-started",
|
|
33
|
+
label: "Getting Started",
|
|
34
|
+
href: "/guides/getting-started",
|
|
35
|
+
type: "guide" as const,
|
|
36
|
+
order: 1,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "customization",
|
|
42
|
+
label: "Customization",
|
|
43
|
+
href: "",
|
|
44
|
+
type: "category" as const,
|
|
45
|
+
order: 1,
|
|
46
|
+
children: [
|
|
47
|
+
{
|
|
48
|
+
id: "theming",
|
|
49
|
+
label: "Theming",
|
|
50
|
+
href: "/guides/theming",
|
|
51
|
+
type: "guide" as const,
|
|
52
|
+
order: 1,
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
components: [
|
|
58
|
+
{
|
|
59
|
+
id: "actions",
|
|
60
|
+
label: "Actions",
|
|
61
|
+
href: "",
|
|
62
|
+
type: "category" as const,
|
|
63
|
+
order: 0,
|
|
64
|
+
children: [
|
|
65
|
+
{
|
|
66
|
+
id: "button",
|
|
67
|
+
label: "Button",
|
|
68
|
+
href: "/components/button",
|
|
69
|
+
type: "component" as const,
|
|
70
|
+
order: 0,
|
|
71
|
+
status: "stable" as const,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "forms",
|
|
77
|
+
label: "Forms",
|
|
78
|
+
href: "",
|
|
79
|
+
type: "category" as const,
|
|
80
|
+
order: 1,
|
|
81
|
+
children: [
|
|
82
|
+
{
|
|
83
|
+
id: "input",
|
|
84
|
+
label: "Input",
|
|
85
|
+
href: "/components/input",
|
|
86
|
+
type: "component" as const,
|
|
87
|
+
order: 0,
|
|
88
|
+
status: "stable" as const,
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Edition hierarchy for checking availability
|
|
97
|
+
*/
|
|
98
|
+
const EDITION_INCLUDES: Record<Edition, Edition[]> = {
|
|
99
|
+
core: [],
|
|
100
|
+
pro: ["core"],
|
|
101
|
+
enterprise: ["core", "pro"],
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if a component is available for the current edition
|
|
106
|
+
*/
|
|
107
|
+
function isComponentAvailable(
|
|
108
|
+
componentId: string,
|
|
109
|
+
edition: Edition,
|
|
110
|
+
editionMap?: NavSidebarProps["editionMap"]
|
|
111
|
+
): boolean {
|
|
112
|
+
if (!editionMap) return true; // No filtering if no edition map
|
|
113
|
+
|
|
114
|
+
const component = editionMap.components[componentId];
|
|
115
|
+
if (!component) return true; // Unknown components are shown
|
|
116
|
+
|
|
117
|
+
// Check if any of the component's editions are available
|
|
118
|
+
const includedEditions = [edition, ...EDITION_INCLUDES[edition]];
|
|
119
|
+
return component.editions.some((e) => includedEditions.includes(e));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface NavLinkProps {
|
|
123
|
+
item: NavItem;
|
|
124
|
+
disabled?: boolean;
|
|
125
|
+
requiredEdition?: Edition;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function NavLink({ item, disabled, requiredEdition }: NavLinkProps) {
|
|
129
|
+
const pathname = usePathname();
|
|
130
|
+
const isActive = pathname === item.href;
|
|
131
|
+
|
|
132
|
+
if (disabled) {
|
|
133
|
+
return (
|
|
134
|
+
<span className="nav-link nav-link--disabled" title={`Requires ${requiredEdition} edition`}>
|
|
135
|
+
<span className="nav-link-label">{item.label}</span>
|
|
136
|
+
<span className="nav-link-lock">🔒</span>
|
|
137
|
+
</span>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<Link
|
|
143
|
+
href={item.href}
|
|
144
|
+
className={`nav-link ${isActive ? "nav-link--active" : ""}`}
|
|
145
|
+
aria-current={isActive ? "page" : undefined}
|
|
146
|
+
>
|
|
147
|
+
<span className="nav-link-label">{item.label}</span>
|
|
148
|
+
{item.status && (
|
|
149
|
+
<span className={`nav-link-status nav-link-status--${item.status}`}>{item.status}</span>
|
|
150
|
+
)}
|
|
151
|
+
</Link>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
interface NavCategoryProps {
|
|
156
|
+
item: NavItem;
|
|
157
|
+
edition?: Edition;
|
|
158
|
+
editionMap?: NavSidebarProps["editionMap"];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function NavCategory({ item, edition, editionMap }: NavCategoryProps) {
|
|
162
|
+
// Filter children by edition
|
|
163
|
+
const visibleChildren = item.children?.filter((child) => {
|
|
164
|
+
if (child.type !== "component") return true;
|
|
165
|
+
if (!edition || !editionMap) return true;
|
|
166
|
+
return isComponentAvailable(child.id, edition, editionMap);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Get disabled children (for showing with lock icon)
|
|
170
|
+
const disabledChildren = item.children?.filter((child) => {
|
|
171
|
+
if (child.type !== "component") return false;
|
|
172
|
+
if (!edition || !editionMap) return false;
|
|
173
|
+
return !isComponentAvailable(child.id, edition, editionMap);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
// Don't render empty categories
|
|
177
|
+
if (!visibleChildren?.length && !disabledChildren?.length) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<div className="nav-category">
|
|
183
|
+
<h3 className="nav-category-title">{item.label}</h3>
|
|
184
|
+
<ul className="nav-category-list">
|
|
185
|
+
{visibleChildren?.map((child) => (
|
|
186
|
+
<li key={child.id}>
|
|
187
|
+
<NavLink item={child} />
|
|
188
|
+
</li>
|
|
189
|
+
))}
|
|
190
|
+
{disabledChildren?.map((child) => {
|
|
191
|
+
const component = editionMap?.components[child.id];
|
|
192
|
+
const requiredEdition = component?.editions[0] as Edition | undefined;
|
|
193
|
+
return (
|
|
194
|
+
<li key={child.id}>
|
|
195
|
+
<NavLink item={child} disabled requiredEdition={requiredEdition} />
|
|
196
|
+
</li>
|
|
197
|
+
);
|
|
198
|
+
})}
|
|
199
|
+
</ul>
|
|
200
|
+
</div>
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function NavSidebar({
|
|
205
|
+
navigation = defaultNavigation,
|
|
206
|
+
edition,
|
|
207
|
+
editionMap,
|
|
208
|
+
}: NavSidebarProps) {
|
|
209
|
+
return (
|
|
210
|
+
<nav className="nav-sidebar" aria-label="Documentation navigation">
|
|
211
|
+
<div className="nav-sidebar-header">
|
|
212
|
+
<Link href="/" className="nav-sidebar-logo">
|
|
213
|
+
Design System
|
|
214
|
+
</Link>
|
|
215
|
+
{edition && (
|
|
216
|
+
<span className={`nav-sidebar-edition nav-sidebar-edition--${edition}`}>{edition}</span>
|
|
217
|
+
)}
|
|
218
|
+
</div>
|
|
219
|
+
|
|
220
|
+
<div className="nav-sidebar-content">
|
|
221
|
+
<section className="nav-section">
|
|
222
|
+
<h2 className="nav-section-title">Guides</h2>
|
|
223
|
+
{navigation.guides.map((item) => (
|
|
224
|
+
<NavCategory key={item.id} item={item} edition={edition} editionMap={editionMap} />
|
|
225
|
+
))}
|
|
226
|
+
</section>
|
|
227
|
+
|
|
228
|
+
<section className="nav-section">
|
|
229
|
+
<h2 className="nav-section-title">Components</h2>
|
|
230
|
+
{navigation.components.map((item) => (
|
|
231
|
+
<NavCategory key={item.id} item={item} edition={edition} editionMap={editionMap} />
|
|
232
|
+
))}
|
|
233
|
+
</section>
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
<style jsx>{`
|
|
237
|
+
.nav-link--disabled {
|
|
238
|
+
opacity: 0.5;
|
|
239
|
+
cursor: not-allowed;
|
|
240
|
+
display: flex;
|
|
241
|
+
justify-content: space-between;
|
|
242
|
+
align-items: center;
|
|
243
|
+
}
|
|
244
|
+
.nav-link-lock {
|
|
245
|
+
font-size: 0.75rem;
|
|
246
|
+
}
|
|
247
|
+
.nav-sidebar-edition {
|
|
248
|
+
font-size: 0.75rem;
|
|
249
|
+
padding: 0.125rem 0.5rem;
|
|
250
|
+
border-radius: 9999px;
|
|
251
|
+
text-transform: capitalize;
|
|
252
|
+
font-weight: 600;
|
|
253
|
+
}
|
|
254
|
+
.nav-sidebar-edition--core {
|
|
255
|
+
background-color: #e0f2fe;
|
|
256
|
+
color: #0369a1;
|
|
257
|
+
}
|
|
258
|
+
.nav-sidebar-edition--pro {
|
|
259
|
+
background-color: #f0fdf4;
|
|
260
|
+
color: #15803d;
|
|
261
|
+
}
|
|
262
|
+
.nav-sidebar-edition--enterprise {
|
|
263
|
+
background-color: #faf5ff;
|
|
264
|
+
color: #7e22ce;
|
|
265
|
+
}
|
|
266
|
+
`}</style>
|
|
267
|
+
</nav>
|
|
268
|
+
);
|
|
269
|
+
}
|