@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,54 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Logo Component
|
|
5
|
+
*
|
|
6
|
+
* Displays the branding logo or falls back to text-based name.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useState } from "react";
|
|
10
|
+
import { useBranding } from "../../lib/branding-context";
|
|
11
|
+
|
|
12
|
+
export interface LogoProps {
|
|
13
|
+
/** Custom class name */
|
|
14
|
+
className?: string;
|
|
15
|
+
/** Logo size variant */
|
|
16
|
+
size?: "small" | "medium" | "large";
|
|
17
|
+
/** Whether to show text alongside logo */
|
|
18
|
+
showText?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function Logo({ className = "", size = "medium", showText = false }: LogoProps) {
|
|
22
|
+
const { name, logo, primaryColor } = useBranding();
|
|
23
|
+
const [imageError, setImageError] = useState(false);
|
|
24
|
+
|
|
25
|
+
const sizeClasses: Record<string, string> = {
|
|
26
|
+
small: "logo--small",
|
|
27
|
+
medium: "logo--medium",
|
|
28
|
+
large: "logo--large",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleImageError = () => {
|
|
32
|
+
setImageError(true);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// If logo URL provided and no error, show image
|
|
36
|
+
if (logo && !imageError) {
|
|
37
|
+
return (
|
|
38
|
+
<span className={`logo ${sizeClasses[size]} ${className}`}>
|
|
39
|
+
<img src={logo} alt={name} className="logo__image" onError={handleImageError} />
|
|
40
|
+
{showText && <span className="logo__text">{name}</span>}
|
|
41
|
+
</span>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Fallback to text-based logo
|
|
46
|
+
return (
|
|
47
|
+
<span className={`logo logo--text ${sizeClasses[size]} ${className}`}>
|
|
48
|
+
<span className="logo__initial" style={{ backgroundColor: primaryColor }}>
|
|
49
|
+
{name.charAt(0).toUpperCase()}
|
|
50
|
+
</span>
|
|
51
|
+
<span className="logo__text">{name}</span>
|
|
52
|
+
</span>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Feedback Widget Component (Stub)
|
|
5
|
+
*
|
|
6
|
+
* Placeholder component for collecting user feedback.
|
|
7
|
+
* Full implementation will integrate with feedback API.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { useState } from "react";
|
|
11
|
+
|
|
12
|
+
export interface FeedbackWidgetProps {
|
|
13
|
+
/** Current page URL or identifier */
|
|
14
|
+
pageId?: string;
|
|
15
|
+
/** Custom class name */
|
|
16
|
+
className?: string;
|
|
17
|
+
/** Position of the widget */
|
|
18
|
+
position?: "bottom-right" | "bottom-left";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function FeedbackWidget({
|
|
22
|
+
pageId,
|
|
23
|
+
className = "",
|
|
24
|
+
position = "bottom-right",
|
|
25
|
+
}: FeedbackWidgetProps) {
|
|
26
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
27
|
+
const [submitted, setSubmitted] = useState(false);
|
|
28
|
+
|
|
29
|
+
const handleSubmit = (helpful: boolean) => {
|
|
30
|
+
// Stub: In production, this would send feedback to an API
|
|
31
|
+
console.info(`Feedback submitted for ${pageId}: ${helpful ? "helpful" : "not helpful"}`);
|
|
32
|
+
setSubmitted(true);
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
setIsOpen(false);
|
|
35
|
+
setSubmitted(false);
|
|
36
|
+
}, 2000);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const positionClass =
|
|
40
|
+
position === "bottom-left" ? "feedback-widget--left" : "feedback-widget--right";
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className={`feedback-widget ${positionClass} ${className}`}>
|
|
44
|
+
{!isOpen ? (
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
className="feedback-widget__trigger"
|
|
48
|
+
onClick={() => setIsOpen(true)}
|
|
49
|
+
aria-label="Give feedback"
|
|
50
|
+
>
|
|
51
|
+
<svg
|
|
52
|
+
width="20"
|
|
53
|
+
height="20"
|
|
54
|
+
viewBox="0 0 20 20"
|
|
55
|
+
fill="none"
|
|
56
|
+
stroke="currentColor"
|
|
57
|
+
strokeWidth="2"
|
|
58
|
+
aria-hidden="true"
|
|
59
|
+
>
|
|
60
|
+
<path d="M18 10c0 4.4-3.6 8-8 8a8 8 0 0 1-3.5-.8L2 18l.8-4.5A8 8 0 1 1 18 10Z" />
|
|
61
|
+
</svg>
|
|
62
|
+
<span>Feedback</span>
|
|
63
|
+
</button>
|
|
64
|
+
) : (
|
|
65
|
+
<div className="feedback-widget__panel" aria-label="Feedback form">
|
|
66
|
+
{submitted ? (
|
|
67
|
+
<div className="feedback-widget__thanks">
|
|
68
|
+
<svg
|
|
69
|
+
width="24"
|
|
70
|
+
height="24"
|
|
71
|
+
viewBox="0 0 24 24"
|
|
72
|
+
fill="none"
|
|
73
|
+
stroke="currentColor"
|
|
74
|
+
strokeWidth="2"
|
|
75
|
+
aria-hidden="true"
|
|
76
|
+
>
|
|
77
|
+
<circle cx="12" cy="12" r="10" />
|
|
78
|
+
<path d="m9 12 2 2 4-4" />
|
|
79
|
+
</svg>
|
|
80
|
+
<span>Thank you for your feedback!</span>
|
|
81
|
+
</div>
|
|
82
|
+
) : (
|
|
83
|
+
<>
|
|
84
|
+
<div className="feedback-widget__header">
|
|
85
|
+
<span>Was this page helpful?</span>
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
className="feedback-widget__close"
|
|
89
|
+
onClick={() => setIsOpen(false)}
|
|
90
|
+
aria-label="Close feedback"
|
|
91
|
+
>
|
|
92
|
+
<svg
|
|
93
|
+
width="16"
|
|
94
|
+
height="16"
|
|
95
|
+
viewBox="0 0 16 16"
|
|
96
|
+
fill="none"
|
|
97
|
+
stroke="currentColor"
|
|
98
|
+
strokeWidth="2"
|
|
99
|
+
aria-hidden="true"
|
|
100
|
+
>
|
|
101
|
+
<path d="M4 4l8 8M12 4l-8 8" />
|
|
102
|
+
</svg>
|
|
103
|
+
</button>
|
|
104
|
+
</div>
|
|
105
|
+
<div className="feedback-widget__buttons">
|
|
106
|
+
<button
|
|
107
|
+
type="button"
|
|
108
|
+
className="feedback-widget__btn feedback-widget__btn--yes"
|
|
109
|
+
onClick={() => handleSubmit(true)}
|
|
110
|
+
>
|
|
111
|
+
<svg
|
|
112
|
+
width="20"
|
|
113
|
+
height="20"
|
|
114
|
+
viewBox="0 0 20 20"
|
|
115
|
+
fill="none"
|
|
116
|
+
stroke="currentColor"
|
|
117
|
+
strokeWidth="2"
|
|
118
|
+
aria-hidden="true"
|
|
119
|
+
>
|
|
120
|
+
<path d="M6 10h.01M10 10h.01M14 10h.01M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" />
|
|
121
|
+
<path d="M7 13s1.5 2 3 2 3-2 3-2" />
|
|
122
|
+
</svg>
|
|
123
|
+
Yes
|
|
124
|
+
</button>
|
|
125
|
+
<button
|
|
126
|
+
type="button"
|
|
127
|
+
className="feedback-widget__btn feedback-widget__btn--no"
|
|
128
|
+
onClick={() => handleSubmit(false)}
|
|
129
|
+
>
|
|
130
|
+
<svg
|
|
131
|
+
width="20"
|
|
132
|
+
height="20"
|
|
133
|
+
viewBox="0 0 20 20"
|
|
134
|
+
fill="none"
|
|
135
|
+
stroke="currentColor"
|
|
136
|
+
strokeWidth="2"
|
|
137
|
+
aria-hidden="true"
|
|
138
|
+
>
|
|
139
|
+
<path d="M6 10h.01M10 10h.01M14 10h.01M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" />
|
|
140
|
+
<path d="M7 14s1.5-2 3-2 3 2 3 2" />
|
|
141
|
+
</svg>
|
|
142
|
+
No
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
</>
|
|
146
|
+
)}
|
|
147
|
+
</div>
|
|
148
|
+
)}
|
|
149
|
+
|
|
150
|
+
<style jsx>{`
|
|
151
|
+
.feedback-widget {
|
|
152
|
+
position: fixed;
|
|
153
|
+
bottom: 1.5rem;
|
|
154
|
+
z-index: 1000;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.feedback-widget--right {
|
|
158
|
+
right: 1.5rem;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.feedback-widget--left {
|
|
162
|
+
left: 1.5rem;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.feedback-widget__trigger {
|
|
166
|
+
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
gap: 0.5rem;
|
|
169
|
+
padding: 0.75rem 1rem;
|
|
170
|
+
background: var(--ds-brand-primary, #0066cc);
|
|
171
|
+
color: white;
|
|
172
|
+
border: none;
|
|
173
|
+
border-radius: 9999px;
|
|
174
|
+
font-size: 0.875rem;
|
|
175
|
+
font-weight: 500;
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
178
|
+
transition: transform 0.15s, box-shadow 0.15s;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.feedback-widget__trigger:hover {
|
|
182
|
+
transform: translateY(-2px);
|
|
183
|
+
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.feedback-widget__panel {
|
|
187
|
+
background: var(--ds-color-background-surface, #fff);
|
|
188
|
+
border: 1px solid var(--ds-color-border-default, #e5e5e5);
|
|
189
|
+
border-radius: 12px;
|
|
190
|
+
padding: 1rem;
|
|
191
|
+
min-width: 240px;
|
|
192
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.feedback-widget__header {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
justify-content: space-between;
|
|
199
|
+
margin-bottom: 0.75rem;
|
|
200
|
+
font-weight: 500;
|
|
201
|
+
color: var(--ds-color-foreground-default, #1a1a1a);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.feedback-widget__close {
|
|
205
|
+
padding: 0.25rem;
|
|
206
|
+
background: transparent;
|
|
207
|
+
border: none;
|
|
208
|
+
color: var(--ds-color-foreground-muted, #666);
|
|
209
|
+
cursor: pointer;
|
|
210
|
+
border-radius: 4px;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
.feedback-widget__close:hover {
|
|
214
|
+
background: var(--ds-color-background-subtle, #f5f5f5);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.feedback-widget__buttons {
|
|
218
|
+
display: flex;
|
|
219
|
+
gap: 0.75rem;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.feedback-widget__btn {
|
|
223
|
+
flex: 1;
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
gap: 0.5rem;
|
|
228
|
+
padding: 0.75rem;
|
|
229
|
+
background: var(--ds-color-background-subtle, #f5f5f5);
|
|
230
|
+
border: 1px solid var(--ds-color-border-default, #e5e5e5);
|
|
231
|
+
border-radius: 8px;
|
|
232
|
+
font-size: 0.875rem;
|
|
233
|
+
font-weight: 500;
|
|
234
|
+
cursor: pointer;
|
|
235
|
+
transition: background 0.15s, border-color 0.15s;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.feedback-widget__btn:hover {
|
|
239
|
+
background: var(--ds-color-background-surface, #fff);
|
|
240
|
+
border-color: var(--ds-brand-primary, #0066cc);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.feedback-widget__btn--yes:hover {
|
|
244
|
+
color: #16a34a;
|
|
245
|
+
border-color: #16a34a;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.feedback-widget__btn--no:hover {
|
|
249
|
+
color: #dc2626;
|
|
250
|
+
border-color: #dc2626;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.feedback-widget__thanks {
|
|
254
|
+
display: flex;
|
|
255
|
+
align-items: center;
|
|
256
|
+
gap: 0.75rem;
|
|
257
|
+
padding: 0.5rem;
|
|
258
|
+
color: #16a34a;
|
|
259
|
+
}
|
|
260
|
+
`}</style>
|
|
261
|
+
</div>
|
|
262
|
+
);
|
|
263
|
+
}
|