@curvenote/theme-ui 1.0.1 → 2.0.1
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/dist/components/layout/app-layout.d.ts +1 -1
- package/dist/components/layout/app-layout.d.ts.map +1 -1
- package/dist/components/layout/app-layout.js +6 -5
- package/dist/components/layout/app-sidebar.d.ts.map +1 -1
- package/dist/components/layout/app-sidebar.js +10 -6
- package/dist/components/layout/article-layout.d.ts +1 -1
- package/dist/components/layout/article-layout.d.ts.map +1 -1
- package/dist/components/layout/article-layout.js +6 -7
- package/dist/components/layout/header.js +1 -1
- package/dist/components/layout/index.d.ts +1 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/components/layout/index.js +1 -0
- package/dist/components/layout/loading-bar.d.ts +8 -1
- package/dist/components/layout/loading-bar.d.ts.map +1 -1
- package/dist/components/layout/loading-bar.js +12 -4
- package/dist/components/layout/site-header.d.ts +6 -1
- package/dist/components/layout/site-header.d.ts.map +1 -1
- package/dist/components/layout/site-header.js +7 -4
- package/dist/components/layout/types.d.ts +6 -0
- package/dist/components/layout/types.d.ts.map +1 -1
- package/dist/components/providers/analytics-boundary.d.ts +18 -0
- package/dist/components/providers/analytics-boundary.d.ts.map +1 -0
- package/dist/components/providers/analytics-boundary.js +53 -0
- package/dist/components/providers/analytics-dev-log.d.ts +11 -0
- package/dist/components/providers/analytics-dev-log.d.ts.map +1 -0
- package/dist/components/providers/analytics-dev-log.js +46 -0
- package/dist/components/providers/analytics-dev-tray.d.ts +2 -0
- package/dist/components/providers/analytics-dev-tray.d.ts.map +1 -0
- package/dist/components/providers/analytics-dev-tray.js +56 -0
- package/dist/components/providers/article-versions-provider.d.ts +19 -0
- package/dist/components/providers/article-versions-provider.d.ts.map +1 -0
- package/dist/components/providers/article-versions-provider.js +13 -0
- package/dist/components/providers/curvenote-providers.d.ts +12 -13
- package/dist/components/providers/curvenote-providers.d.ts.map +1 -1
- package/dist/components/providers/curvenote-providers.js +20 -27
- package/dist/components/providers/design.d.ts +3 -33
- package/dist/components/providers/design.d.ts.map +1 -1
- package/dist/components/providers/design.js +64 -21
- package/dist/components/providers/index.d.ts +4 -2
- package/dist/components/providers/index.d.ts.map +1 -1
- package/dist/components/providers/index.js +3 -1
- package/dist/components/providers/lightbox-provider.d.ts +8 -0
- package/dist/components/providers/lightbox-provider.d.ts.map +1 -1
- package/dist/components/providers/lightbox-provider.js +28 -5
- package/dist/components/providers/overlay-depth.d.ts +16 -0
- package/dist/components/providers/overlay-depth.d.ts.map +1 -0
- package/dist/components/providers/overlay-depth.js +16 -0
- package/dist/components/providers/ping-boundary.d.ts +3 -1
- package/dist/components/providers/ping-boundary.d.ts.map +1 -1
- package/dist/components/providers/ping-boundary.js +7 -4
- package/dist/components/providers/platform-providers.d.ts +0 -7
- package/dist/components/providers/platform-providers.d.ts.map +1 -1
- package/dist/components/providers/platform-providers.js +0 -14
- package/dist/components/ui/abbreviations.d.ts +3 -1
- package/dist/components/ui/abbreviations.d.ts.map +1 -1
- package/dist/components/ui/abbreviations.js +13 -6
- package/dist/components/ui/accessibility-skip-to.d.ts +13 -3
- package/dist/components/ui/accessibility-skip-to.d.ts.map +1 -1
- package/dist/components/ui/accessibility-skip-to.js +4 -1
- package/dist/components/ui/arrow.d.ts +6 -0
- package/dist/components/ui/arrow.d.ts.map +1 -0
- package/dist/components/ui/arrow.js +15 -0
- package/dist/components/ui/article-actions-downloads.d.ts.map +1 -1
- package/dist/components/ui/article-actions-downloads.js +74 -7
- package/dist/components/ui/article-actions-dropdown.d.ts +2 -1
- package/dist/components/ui/article-actions-dropdown.d.ts.map +1 -1
- package/dist/components/ui/article-actions-dropdown.js +102 -21
- package/dist/components/ui/article-actions-share.d.ts +18 -0
- package/dist/components/ui/article-actions-share.d.ts.map +1 -1
- package/dist/components/ui/article-actions-share.js +38 -2
- package/dist/components/ui/article-actions.d.ts.map +1 -1
- package/dist/components/ui/article-actions.js +16 -3
- package/dist/components/ui/article-bar.d.ts +3 -1
- package/dist/components/ui/article-bar.d.ts.map +1 -1
- package/dist/components/ui/article-bar.js +19 -5
- package/dist/components/ui/article-card.js +1 -1
- package/dist/components/ui/author-popover.d.ts +2 -1
- package/dist/components/ui/author-popover.d.ts.map +1 -1
- package/dist/components/ui/author-popover.js +42 -7
- package/dist/components/ui/backmatter.d.ts.map +1 -1
- package/dist/components/ui/backmatter.js +23 -5
- package/dist/components/ui/banner.d.ts.map +1 -1
- package/dist/components/ui/banner.js +1 -1
- package/dist/components/ui/bibliography.d.ts +2 -2
- package/dist/components/ui/bibliography.d.ts.map +1 -1
- package/dist/components/ui/bibliography.js +10 -9
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/button.js +2 -0
- package/dist/components/ui/calendar.d.ts +10 -0
- package/dist/components/ui/calendar.d.ts.map +1 -0
- package/dist/components/ui/calendar.js +85 -0
- package/dist/components/ui/citation.d.ts +2 -2
- package/dist/components/ui/citation.d.ts.map +1 -1
- package/dist/components/ui/citation.js +45 -15
- package/dist/components/ui/collapsible-backmatter-section.d.ts +28 -0
- package/dist/components/ui/collapsible-backmatter-section.d.ts.map +1 -0
- package/dist/components/ui/collapsible-backmatter-section.js +52 -0
- package/dist/components/ui/cookie-banner.d.ts +1 -1
- package/dist/components/ui/cookie-banner.d.ts.map +1 -1
- package/dist/components/ui/cookie-banner.js +9 -2
- package/dist/components/ui/document-outline.d.ts.map +1 -1
- package/dist/components/ui/document-outline.js +38 -20
- package/dist/components/ui/footer-links.d.ts.map +1 -1
- package/dist/components/ui/footer-links.js +4 -0
- package/dist/components/ui/frontmatter-badges.d.ts +15 -5
- package/dist/components/ui/frontmatter-badges.d.ts.map +1 -1
- package/dist/components/ui/frontmatter-badges.js +41 -15
- package/dist/components/ui/frontmatter.js +1 -1
- package/dist/components/ui/hash-link.d.ts +56 -0
- package/dist/components/ui/hash-link.d.ts.map +1 -0
- package/dist/components/ui/hash-link.js +83 -0
- package/dist/components/ui/image.d.ts +5 -2
- package/dist/components/ui/image.d.ts.map +1 -1
- package/dist/components/ui/image.js +10 -8
- package/dist/components/ui/index.d.ts +10 -2
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +9 -2
- package/dist/components/ui/keywords.d.ts +4 -0
- package/dist/components/ui/keywords.d.ts.map +1 -0
- package/dist/components/ui/keywords.js +18 -0
- package/dist/components/ui/label.d.ts +4 -0
- package/dist/components/ui/label.d.ts.map +1 -0
- package/dist/components/ui/label.js +6 -0
- package/dist/components/ui/license-description.d.ts.map +1 -1
- package/dist/components/ui/license-description.js +8 -5
- package/dist/components/ui/license-frontmatter.d.ts.map +1 -1
- package/dist/components/ui/license-frontmatter.js +14 -3
- package/dist/components/ui/lightbox-container.d.ts.map +1 -1
- package/dist/components/ui/lightbox-container.js +2 -2
- package/dist/components/ui/lightbox.d.ts +3 -1
- package/dist/components/ui/lightbox.d.ts.map +1 -1
- package/dist/components/ui/lightbox.js +155 -25
- package/dist/components/ui/link-card.d.ts +2 -1
- package/dist/components/ui/link-card.d.ts.map +1 -1
- package/dist/components/ui/link-card.js +2 -2
- package/dist/components/ui/pagination.d.ts +15 -0
- package/dist/components/ui/pagination.d.ts.map +1 -0
- package/dist/components/ui/pagination.js +31 -0
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/search.d.ts +2 -1
- package/dist/components/ui/search.d.ts.map +1 -1
- package/dist/components/ui/search.js +24 -8
- package/dist/components/ui/select.d.ts +16 -0
- package/dist/components/ui/select.d.ts.map +1 -0
- package/dist/components/ui/select.js +38 -0
- package/dist/components/ui/separator.js +1 -1
- package/dist/components/ui/sidebar.d.ts +2 -12
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/sidebar.js +2 -34
- package/dist/components/ui/tooltip.d.ts +4 -2
- package/dist/components/ui/tooltip.d.ts.map +1 -1
- package/dist/components/ui/tooltip.js +5 -4
- package/dist/components/ui/types.d.ts +9 -8
- package/dist/components/ui/types.d.ts.map +1 -1
- package/dist/components/ui/types.js +1 -0
- package/dist/lib/dedupeAbbreviations.d.ts +10 -0
- package/dist/lib/dedupeAbbreviations.d.ts.map +1 -0
- package/dist/lib/dedupeAbbreviations.js +36 -0
- package/dist/lib/knownParts.d.ts +18 -0
- package/dist/lib/knownParts.d.ts.map +1 -1
- package/dist/lib/knownParts.js +38 -1
- package/package.json +12 -9
- package/dist/components/providers/types.d.ts +0 -30
- package/dist/components/providers/types.d.ts.map +0 -1
- package/dist/components/providers/types.js +0 -1
|
@@ -4,20 +4,149 @@ import { Dialog, DialogContent, DialogTitle, DialogDescription } from '@radix-ui
|
|
|
4
4
|
import { X, ChevronLeft, ChevronRight, ZoomIn, ZoomOut, RotateCcw } from 'lucide-react';
|
|
5
5
|
import { cn } from '../../lib/utils';
|
|
6
6
|
import { Button } from './button';
|
|
7
|
+
import { useAnalytics } from '../providers/analytics-boundary';
|
|
7
8
|
import { MyST } from 'myst-to-react';
|
|
8
9
|
import { Picture } from './image';
|
|
9
|
-
|
|
10
|
+
function getLightboxImageProperties(image) {
|
|
11
|
+
const isVideo = image.src.endsWith('.mp4') || image.urlSource?.endsWith('.mp4');
|
|
12
|
+
return {
|
|
13
|
+
imageUrl: image.src,
|
|
14
|
+
imageAlt: image.alt,
|
|
15
|
+
hasCaption: Boolean(image.caption),
|
|
16
|
+
mediaType: isVideo ? 'video' : 'image',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export function Lightbox({ isOpen, onClose, image, onNavigate, hasNext = false, hasPrev = false, showNavigation = true, showZoom = true, className, minZoom = 0.5, maxZoom = 7, currentIndex, imageCount, }) {
|
|
20
|
+
const capture = useAnalytics();
|
|
10
21
|
const [zoomLevel, setZoomLevel] = React.useState(1);
|
|
22
|
+
const zoomLevelRef = React.useRef(zoomLevel);
|
|
23
|
+
zoomLevelRef.current = zoomLevel;
|
|
11
24
|
const [isDragging, setIsDragging] = React.useState(false);
|
|
12
25
|
const [dragOffset, setDragOffset] = React.useState({ x: 0, y: 0 });
|
|
13
26
|
const [imageLoaded, setImageLoaded] = React.useState(false);
|
|
14
27
|
const imageRef = React.useRef(null);
|
|
15
28
|
const containerRef = React.useRef(null);
|
|
29
|
+
const captionExpandedRef = React.useRef(false);
|
|
30
|
+
const mediaLoadedRef = React.useRef(null);
|
|
31
|
+
/** At most one zoom-related analytics event per image; intent is session signal, not per gesture. */
|
|
32
|
+
const zoomAnalyticsSentForImageRef = React.useRef(false);
|
|
33
|
+
/** At most one pan-related analytics event per image; intent is session signal, not per gesture. */
|
|
34
|
+
const panAnalyticsSentForImageRef = React.useRef(false);
|
|
35
|
+
const lightboxContext = React.useMemo(() => ({
|
|
36
|
+
currentIndex,
|
|
37
|
+
imageCount,
|
|
38
|
+
...getLightboxImageProperties(image),
|
|
39
|
+
/** Full-screen lightbox is one layer above the opener's depth. */
|
|
40
|
+
overlayDepth: (image.openingOverlayDepth ?? 0) + 1,
|
|
41
|
+
}), [currentIndex, image, imageCount]);
|
|
42
|
+
const captureClose = React.useCallback((closeMethod) => {
|
|
43
|
+
capture('content_lightbox_closed', {
|
|
44
|
+
surface: 'content',
|
|
45
|
+
closeMethod,
|
|
46
|
+
...lightboxContext,
|
|
47
|
+
});
|
|
48
|
+
}, [capture, lightboxContext]);
|
|
49
|
+
const handleClose = React.useCallback((closeMethod) => {
|
|
50
|
+
captureClose(closeMethod);
|
|
51
|
+
onClose();
|
|
52
|
+
}, [captureClose, onClose]);
|
|
53
|
+
const handleNavigate = React.useCallback((direction, navigationMethod) => {
|
|
54
|
+
capture('content_lightbox_navigated', {
|
|
55
|
+
surface: 'content',
|
|
56
|
+
direction,
|
|
57
|
+
navigationMethod,
|
|
58
|
+
...lightboxContext,
|
|
59
|
+
});
|
|
60
|
+
onNavigate?.(direction);
|
|
61
|
+
}, [capture, lightboxContext, onNavigate]);
|
|
62
|
+
const captureZoom = React.useCallback((zoomMethod, nextZoom) => {
|
|
63
|
+
capture('content_lightbox_zoom_changed', {
|
|
64
|
+
surface: 'content',
|
|
65
|
+
zoomMethod,
|
|
66
|
+
zoomLevel: nextZoom,
|
|
67
|
+
...lightboxContext,
|
|
68
|
+
});
|
|
69
|
+
}, [capture, lightboxContext]);
|
|
70
|
+
const captureZoomReset = React.useCallback((zoomMethod) => {
|
|
71
|
+
capture('content_lightbox_zoom_reset', {
|
|
72
|
+
surface: 'content',
|
|
73
|
+
zoomMethod,
|
|
74
|
+
...lightboxContext,
|
|
75
|
+
});
|
|
76
|
+
}, [capture, lightboxContext]);
|
|
77
|
+
const capturePan = React.useCallback((panMethod, offset) => {
|
|
78
|
+
capture('content_lightbox_pan_changed', {
|
|
79
|
+
surface: 'content',
|
|
80
|
+
panMethod,
|
|
81
|
+
panOffsetX: offset.x,
|
|
82
|
+
panOffsetY: offset.y,
|
|
83
|
+
zoomLevel: zoomLevelRef.current,
|
|
84
|
+
...lightboxContext,
|
|
85
|
+
});
|
|
86
|
+
}, [capture, lightboxContext]);
|
|
87
|
+
const emitZoomAnalyticsOncePerImage = React.useCallback((emit) => {
|
|
88
|
+
if (zoomAnalyticsSentForImageRef.current)
|
|
89
|
+
return;
|
|
90
|
+
zoomAnalyticsSentForImageRef.current = true;
|
|
91
|
+
emit();
|
|
92
|
+
}, []);
|
|
93
|
+
const emitPanAnalyticsOncePerImage = React.useCallback((emit) => {
|
|
94
|
+
if (panAnalyticsSentForImageRef.current)
|
|
95
|
+
return;
|
|
96
|
+
panAnalyticsSentForImageRef.current = true;
|
|
97
|
+
emit();
|
|
98
|
+
}, []);
|
|
99
|
+
const updateZoom = React.useCallback((zoomMethod, updater) => {
|
|
100
|
+
const prev = zoomLevelRef.current;
|
|
101
|
+
const next = updater(prev);
|
|
102
|
+
zoomLevelRef.current = next;
|
|
103
|
+
const isReset = zoomMethod === 'keyboard_reset' || zoomMethod === 'reset_button';
|
|
104
|
+
if (isReset) {
|
|
105
|
+
if (prev !== 1 || next !== 1) {
|
|
106
|
+
emitZoomAnalyticsOncePerImage(() => captureZoomReset(zoomMethod));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (next !== prev) {
|
|
110
|
+
emitZoomAnalyticsOncePerImage(() => captureZoom(zoomMethod, next));
|
|
111
|
+
}
|
|
112
|
+
setZoomLevel(next);
|
|
113
|
+
}, [captureZoom, captureZoomReset, emitZoomAnalyticsOncePerImage]);
|
|
114
|
+
const handleCaptionExpand = React.useCallback(() => {
|
|
115
|
+
if (captionExpandedRef.current)
|
|
116
|
+
return;
|
|
117
|
+
captionExpandedRef.current = true;
|
|
118
|
+
capture('content_lightbox_caption_expanded', {
|
|
119
|
+
surface: 'content',
|
|
120
|
+
...lightboxContext,
|
|
121
|
+
});
|
|
122
|
+
}, [capture, lightboxContext]);
|
|
123
|
+
const handleMediaLoaded = React.useCallback(() => {
|
|
124
|
+
if (mediaLoadedRef.current === image.src)
|
|
125
|
+
return;
|
|
126
|
+
mediaLoadedRef.current = image.src;
|
|
127
|
+
setImageLoaded(true);
|
|
128
|
+
capture('content_lightbox_media_loaded', {
|
|
129
|
+
surface: 'content',
|
|
130
|
+
...lightboxContext,
|
|
131
|
+
});
|
|
132
|
+
}, [capture, image.src, lightboxContext]);
|
|
133
|
+
// New lightbox open: allow one zoom/pan sample again (same image may be revisited after close).
|
|
134
|
+
React.useEffect(() => {
|
|
135
|
+
if (isOpen) {
|
|
136
|
+
zoomAnalyticsSentForImageRef.current = false;
|
|
137
|
+
panAnalyticsSentForImageRef.current = false;
|
|
138
|
+
}
|
|
139
|
+
}, [isOpen]);
|
|
16
140
|
// Reset zoom and position when image changes
|
|
17
141
|
React.useEffect(() => {
|
|
142
|
+
zoomLevelRef.current = 1;
|
|
143
|
+
zoomAnalyticsSentForImageRef.current = false;
|
|
144
|
+
panAnalyticsSentForImageRef.current = false;
|
|
18
145
|
setZoomLevel(1);
|
|
19
146
|
setDragOffset({ x: 0, y: 0 });
|
|
20
147
|
setImageLoaded(false);
|
|
148
|
+
captionExpandedRef.current = false;
|
|
149
|
+
mediaLoadedRef.current = null;
|
|
21
150
|
}, [image.src]);
|
|
22
151
|
// Handle wheel events with passive listener handling
|
|
23
152
|
React.useEffect(() => {
|
|
@@ -26,64 +155,61 @@ export function Lightbox({ isOpen, onClose, image, onNavigate, hasNext = false,
|
|
|
26
155
|
const handleWheelEvent = (e) => {
|
|
27
156
|
e.preventDefault();
|
|
28
157
|
e.stopPropagation();
|
|
29
|
-
// Immediate zoom without timeout
|
|
30
158
|
const delta = e.deltaY > 0 ? 0.98 : 1.02;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
159
|
+
const prev = zoomLevelRef.current;
|
|
160
|
+
const newZoom = Math.max(minZoom, Math.min(prev * delta, maxZoom));
|
|
161
|
+
zoomLevelRef.current = newZoom;
|
|
162
|
+
if (newZoom !== prev) {
|
|
163
|
+
emitZoomAnalyticsOncePerImage(() => captureZoom('wheel', newZoom));
|
|
164
|
+
}
|
|
165
|
+
setZoomLevel(newZoom);
|
|
35
166
|
};
|
|
36
|
-
// Add wheel event listener with passive: false
|
|
37
167
|
document.addEventListener('wheel', handleWheelEvent, { passive: false });
|
|
38
168
|
return () => {
|
|
39
169
|
document.removeEventListener('wheel', handleWheelEvent);
|
|
40
170
|
};
|
|
41
|
-
}, [isOpen, showZoom]);
|
|
171
|
+
}, [captureZoom, emitZoomAnalyticsOncePerImage, isOpen, maxZoom, minZoom, showZoom]);
|
|
42
172
|
// Handle keyboard navigation
|
|
43
173
|
React.useEffect(() => {
|
|
44
174
|
const handleKeyDown = (e) => {
|
|
45
175
|
if (!isOpen)
|
|
46
176
|
return;
|
|
47
177
|
switch (e.key) {
|
|
48
|
-
case 'Escape':
|
|
49
|
-
onClose();
|
|
50
|
-
break;
|
|
51
178
|
case 'ArrowLeft':
|
|
52
179
|
if (hasPrev && onNavigate) {
|
|
53
|
-
|
|
180
|
+
handleNavigate('prev', 'keyboard');
|
|
54
181
|
}
|
|
55
182
|
break;
|
|
56
183
|
case 'ArrowRight':
|
|
57
184
|
if (hasNext && onNavigate) {
|
|
58
|
-
|
|
185
|
+
handleNavigate('next', 'keyboard');
|
|
59
186
|
}
|
|
60
187
|
break;
|
|
61
188
|
case 'PageUp':
|
|
62
189
|
case 'PageDown':
|
|
63
190
|
case 'ArrowUp':
|
|
64
191
|
case 'ArrowDown':
|
|
65
|
-
// Stops scrolling the page
|
|
66
192
|
e.preventDefault();
|
|
67
193
|
break;
|
|
68
194
|
case '=':
|
|
69
195
|
case '+':
|
|
70
196
|
e.preventDefault();
|
|
71
|
-
|
|
197
|
+
updateZoom('keyboard_zoom_in', (prev) => Math.min(prev * 1.2, maxZoom));
|
|
72
198
|
break;
|
|
73
199
|
case '-':
|
|
74
200
|
e.preventDefault();
|
|
75
|
-
|
|
201
|
+
updateZoom('keyboard_zoom_out', (prev) => Math.max(prev / 1.2, minZoom));
|
|
76
202
|
break;
|
|
77
203
|
case '0':
|
|
78
204
|
e.preventDefault();
|
|
79
|
-
setZoomLevel(1);
|
|
80
205
|
setDragOffset({ x: 0, y: 0 });
|
|
206
|
+
updateZoom('keyboard_reset', () => 1);
|
|
81
207
|
break;
|
|
82
208
|
}
|
|
83
209
|
};
|
|
84
210
|
document.addEventListener('keydown', handleKeyDown);
|
|
85
211
|
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
86
|
-
}, [isOpen, hasPrev, hasNext, onNavigate,
|
|
212
|
+
}, [handleNavigate, isOpen, hasPrev, hasNext, maxZoom, minZoom, onNavigate, updateZoom]);
|
|
87
213
|
// Handle mouse drag for panning
|
|
88
214
|
const [dragStart, setDragStart] = React.useState({ x: 0, y: 0 });
|
|
89
215
|
const handleMouseDown = (e) => {
|
|
@@ -98,21 +224,25 @@ export function Lightbox({ isOpen, onClose, image, onNavigate, hasNext = false,
|
|
|
98
224
|
// if (!isDragging || zoomLevel <= 1) return;
|
|
99
225
|
if (!isDragging)
|
|
100
226
|
return;
|
|
101
|
-
|
|
227
|
+
const offset = {
|
|
102
228
|
x: e.clientX - dragStart.x,
|
|
103
229
|
y: e.clientY - dragStart.y,
|
|
104
|
-
}
|
|
230
|
+
};
|
|
231
|
+
setDragOffset(offset);
|
|
232
|
+
emitPanAnalyticsOncePerImage(() => capturePan('drag', offset));
|
|
105
233
|
};
|
|
106
234
|
const handleMouseUp = () => {
|
|
107
235
|
setIsDragging(false);
|
|
108
236
|
};
|
|
109
237
|
const resetZoom = () => {
|
|
110
|
-
setZoomLevel(1);
|
|
111
238
|
setDragOffset({ x: 0, y: 0 });
|
|
239
|
+
updateZoom('reset_button', () => 1);
|
|
112
240
|
};
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
241
|
+
const isVideo = getLightboxImageProperties(image).mediaType === 'video';
|
|
242
|
+
return (_jsx(Dialog, { open: isOpen, onOpenChange: (open) => {
|
|
243
|
+
if (!open)
|
|
244
|
+
onClose();
|
|
245
|
+
}, children: _jsxs(DialogContent, { className: cn('flex fixed inset-0 z-50 justify-center items-center p-4 bg-black/90', className), onPointerDownOutside: () => handleClose('backdrop'), onEscapeKeyDown: () => handleClose('escape'), onTouchStart: (e) => e.preventDefault(), onTouchMove: (e) => e.preventDefault(), children: [_jsx(DialogTitle, { className: "sr-only", children: image.alt || 'Image viewer' }), _jsx(DialogDescription, { className: "sr-only", children: image.alt ? `Viewing ${image.alt}` : 'Image viewer with zoom and navigation controls' }), _jsx(Button, { variant: "ghost", size: "icon", className: "absolute top-4 right-4 z-10 text-white cursor-pointer hover:bg-white/10 hover:text-white", onClick: () => handleClose('close_button'), children: _jsx(X, { className: "w-6 h-6" }) }), showNavigation && (hasPrev || hasNext) && (_jsxs(_Fragment, { children: [hasPrev && (_jsx(Button, { variant: "ghost", size: "icon", className: "absolute left-4 top-1/2 z-10 text-white -translate-y-1/2 cursor-pointer hover:bg-white/10 hover:text-white", onClick: () => handleNavigate('prev', 'button'), children: _jsx(ChevronLeft, { className: "w-8 h-8" }) })), hasNext && (_jsx(Button, { variant: "ghost", size: "icon", className: "absolute right-4 top-1/2 z-10 text-white -translate-y-1/2 cursor-pointer hover:bg-white/10 hover:text-white", onClick: () => handleNavigate('next', 'button'), children: _jsx(ChevronRight, { className: "w-8 h-8" }) }))] })), showZoom && !isVideo && (_jsxs("div", { className: "flex absolute top-4 left-4 z-10 gap-2", children: [_jsx(Button, { variant: "ghost", size: "icon", className: "text-white cursor-pointer hover:bg-white/10 hover:text-white", onClick: () => updateZoom('zoom_in_button', (prev) => Math.min(prev * 1.2, maxZoom)), children: _jsx(ZoomIn, { className: "w-5 h-5" }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "text-white cursor-pointer hover:bg-white/10 hover:text-white", onClick: () => updateZoom('zoom_out_button', (prev) => Math.max(prev / 1.2, minZoom)), children: _jsx(ZoomOut, { className: "w-5 h-5" }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "text-white cursor-pointer hover:bg-white/10 hover:text-white", onClick: resetZoom, children: _jsx(RotateCcw, { className: "w-5 h-5" }) })] })), _jsxs("div", { ref: containerRef, className: "flex overflow-hidden relative justify-center items-center w-full h-full max-h-screen", onMouseDown: !isVideo ? handleMouseDown : undefined, onMouseMove: !isVideo ? handleMouseMove : undefined, onMouseUp: !isVideo ? handleMouseUp : undefined, onMouseLeave: !isVideo ? handleMouseUp : undefined, onTouchStart: (e) => e.preventDefault(), onTouchMove: (e) => e.preventDefault(), children: [_jsx(Picture, { ref: imageRef, src: image.src, srcOptimized: image.srcOptimized, urlSource: image.urlSource, alt: image.alt, className: cn('object-contain max-w-full max-h-full select-none', {
|
|
116
246
|
'cursor-grab active:cursor-grabbing': !isVideo,
|
|
117
247
|
'opacity-0': !imageLoaded,
|
|
118
248
|
'opacity-100': imageLoaded,
|
|
@@ -125,5 +255,5 @@ export function Lightbox({ isOpen, onClose, image, onNavigate, hasNext = false,
|
|
|
125
255
|
: {
|
|
126
256
|
maxHeight: 'calc(100vh - 8rem)', // Account for padding and controls
|
|
127
257
|
maxWidth: 'calc(100vw - 2rem)', // Account for padding
|
|
128
|
-
}, onLoad:
|
|
258
|
+
}, onLoad: handleMediaLoaded, onLoadedData: handleMediaLoaded }), !imageLoaded && (_jsx("div", { className: "flex absolute inset-0 justify-center items-center", children: _jsx("div", { className: "w-8 h-8 rounded-full border-2 animate-spin border-white/20 border-t-white" }) }))] }), image.caption && (_jsx("div", { className: "absolute right-4 bottom-4 left-4 z-10", children: _jsx("div", { className: "px-4 py-2 mx-auto max-w-6xl text-sm text-white rounded-lg backdrop-blur-sm group bg-black/80 prose prose-invert", onMouseEnter: handleCaptionExpand, children: _jsx("div", { className: "overflow-hidden transition-all duration-750 max-h-[3rem] group-hover:max-h-[50rem]", children: typeof image.caption === 'string' ? image.caption : _jsx(MyST, { ast: image.caption }) }) }) })), showZoom && !isVideo && zoomLevel !== 1 && (_jsxs("div", { className: "absolute right-4 bottom-4 z-10 px-3 py-1 text-sm text-white rounded-sm backdrop-blur-sm bg-black/50", children: [Math.round(zoomLevel * 100), "%"] }))] }) }));
|
|
129
259
|
}
|
|
@@ -3,13 +3,14 @@ declare const linkCardVariants: (props?: ({
|
|
|
3
3
|
variant?: "default" | null | undefined;
|
|
4
4
|
size?: "default" | "lg" | null | undefined;
|
|
5
5
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
6
|
-
export declare function LinkCard({ url, title, internal, loading, description, thumbnail, variant, size, }: {
|
|
6
|
+
export declare function LinkCard({ url, title, internal, loading, description, thumbnail, variant, size, onLinkClick, }: {
|
|
7
7
|
url: string;
|
|
8
8
|
internal?: boolean;
|
|
9
9
|
loading?: boolean;
|
|
10
10
|
title: React.ReactNode;
|
|
11
11
|
description?: React.ReactNode;
|
|
12
12
|
thumbnail?: string | null;
|
|
13
|
+
onLinkClick?: () => void;
|
|
13
14
|
} & VariantProps<typeof linkCardVariants>): import("react/jsx-runtime").JSX.Element;
|
|
14
15
|
export {};
|
|
15
16
|
//# sourceMappingURL=link-card.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"link-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/link-card.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,QAAA,MAAM,gBAAgB;;;8EAcpB,CAAC;AAEH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,KAAK,EACL,QAAgB,EAChB,OAAe,EACf,WAAW,EACX,SAAS,EACT,OAAO,EACP,IAAI,
|
|
1
|
+
{"version":3,"file":"link-card.d.ts","sourceRoot":"","sources":["../../../src/components/ui/link-card.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAElE,QAAA,MAAM,gBAAgB;;;8EAcpB,CAAC;AAEH,wBAAgB,QAAQ,CAAC,EACvB,GAAG,EACH,KAAK,EACL,QAAgB,EAChB,OAAe,EACf,WAAW,EACX,SAAS,EACT,OAAO,EACP,IAAI,EACJ,WAAW,GACZ,EAAE;IACD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;CAC1B,GAAG,YAAY,CAAC,OAAO,gBAAgB,CAAC,2CAsDxC"}
|
|
@@ -18,11 +18,11 @@ const linkCardVariants = cva('overflow-hidden rounded hover-card-content', {
|
|
|
18
18
|
size: 'default',
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
|
-
export function LinkCard({ url, title, internal = false, loading = false, description, thumbnail, variant, size, }) {
|
|
21
|
+
export function LinkCard({ url, title, internal = false, loading = false, description, thumbnail, variant, size, onLinkClick, }) {
|
|
22
22
|
const Link = useLinkProvider();
|
|
23
23
|
const baseurl = useBaseurl();
|
|
24
24
|
const to = internal ? withBaseurl(url, baseurl) : url;
|
|
25
25
|
return (_jsxs("div", { className: cn(linkCardVariants({ variant, size }), {
|
|
26
26
|
'animate-pulse': loading,
|
|
27
|
-
}), children: [_jsxs("div", { className: "group", children: [!loading && thumbnail && (_jsx(Link, { to: to, prefetch: internal ? 'intent' : 'none', target: internal ? '_self' : '_blank', className: "block overflow-hidden h-[150px] border-b border-gray-200", children: _jsx("img", { src: thumbnail, className: "w-full h-[150px] object-cover object-center object-middle m-0 border-b border-gray-200 transition-transform duration-500 ease-in-out group-hover:scale-125" }) })), loading && (_jsx("div", { className: "animate-pulse bg-slate-100 dark:bg-slate-800 w-full h-[150px]" })), internal && (_jsx(Link, { to: to, className: "block px-3 mt-3 text-sm font-bold text-black hover:underline", prefetch: "intent", children: title })), !internal && (_jsxs("a", { href: to, className: "block px-3 py-2 text-sm font-bold text-black bg-gray-100 border-b border-gray-200 hover:underline", target: "_blank", rel: "noreferrer", children: [_jsx(ExternalLinkIcon, { width: "1rem", height: "1rem", className: "float-right" }), title] }))] }), !loading && description && _jsx("div", { className: "p-3 max-w-none text-sm prose", children: description })] }));
|
|
27
|
+
}), children: [_jsxs("div", { className: "group", children: [!loading && thumbnail && (_jsx(Link, { to: to, prefetch: internal ? 'intent' : 'none', target: internal ? '_self' : '_blank', className: "block overflow-hidden h-[150px] border-b border-gray-200", onClick: () => onLinkClick?.(), children: _jsx("img", { src: thumbnail, className: "w-full h-[150px] object-cover object-center object-middle m-0 border-b border-gray-200 transition-transform duration-500 ease-in-out group-hover:scale-125" }) })), loading && (_jsx("div", { className: "animate-pulse bg-slate-100 dark:bg-slate-800 w-full h-[150px]" })), internal && (_jsx(Link, { to: to, className: "block px-3 mt-3 text-sm font-bold text-black hover:underline", prefetch: "intent", onClick: () => onLinkClick?.(), children: title })), !internal && (_jsxs("a", { href: to, className: "block px-3 py-2 text-sm font-bold text-black bg-gray-100 border-b border-gray-200 hover:underline", target: "_blank", rel: "noreferrer", onClick: () => onLinkClick?.(), children: [_jsx(ExternalLinkIcon, { width: "1rem", height: "1rem", className: "float-right" }), title] }))] }), !loading && description && _jsx("div", { className: "p-3 max-w-none text-sm prose", children: description })] }));
|
|
28
28
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
declare function Pagination({ className, ...props }: React.ComponentProps<'nav'>): import("react/jsx-runtime").JSX.Element;
|
|
3
|
+
declare function PaginationContent({ className, ...props }: React.ComponentProps<'ul'>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function PaginationItem({ className, ...props }: React.ComponentProps<'li'>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
type PaginationLinkProps = {
|
|
6
|
+
isActive?: boolean;
|
|
7
|
+
asChild?: boolean;
|
|
8
|
+
size?: 'default' | 'icon';
|
|
9
|
+
} & React.ComponentProps<'a'>;
|
|
10
|
+
declare function PaginationLink({ className, isActive, size, asChild, ...props }: PaginationLinkProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
declare function PaginationPrevious({ className, ...props }: React.ComponentProps<typeof PaginationLink>): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function PaginationNext({ className, ...props }: React.ComponentProps<typeof PaginationLink>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare function PaginationEllipsis({ className, ...props }: React.ComponentProps<'span'>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis, };
|
|
15
|
+
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../../src/components/ui/pagination.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,2CAUvE;AAED,iBAAS,iBAAiB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,2CAQ7E;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,2CAE1E;AAED,KAAK,mBAAmB,GAAG;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CAC3B,GAAG,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;AAE9B,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,QAAQ,EACR,IAAgB,EAChB,OAAe,EACf,GAAG,KAAK,EACT,EAAE,mBAAmB,2CAoBrB;AAED,iBAAS,kBAAkB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,2CAY/F;AAED,iBAAS,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,2CAY3F;AAED,iBAAS,kBAAkB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,2CAYhF;AAED,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,kBAAkB,GACnB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
4
|
+
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
const paginationLinkBase = 'inline-flex items-center justify-center gap-0.5 whitespace-nowrap rounded-md text-xs font-medium tabular-nums transition-colors focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-3.5 [&_svg]:shrink-0';
|
|
7
|
+
function Pagination({ className, ...props }) {
|
|
8
|
+
return (_jsx("nav", { role: "navigation", "aria-label": "pagination", "data-slot": "pagination", className: cn('flex justify-center mx-auto w-full', className), ...props }));
|
|
9
|
+
}
|
|
10
|
+
function PaginationContent({ className, ...props }) {
|
|
11
|
+
return (_jsx("ul", { "data-slot": "pagination-content", className: cn('flex flex-row items-center gap-1', className), ...props }));
|
|
12
|
+
}
|
|
13
|
+
function PaginationItem({ className, ...props }) {
|
|
14
|
+
return _jsx("li", { "data-slot": "pagination-item", className: cn('', className), ...props });
|
|
15
|
+
}
|
|
16
|
+
function PaginationLink({ className, isActive, size = 'default', asChild = false, ...props }) {
|
|
17
|
+
const Comp = asChild ? Slot : 'a';
|
|
18
|
+
return (_jsx(Comp, { "aria-current": isActive ? 'page' : undefined, "data-slot": "pagination-link", "data-active": isActive, className: cn(paginationLinkBase, size === 'icon' && 'size-8 shrink-0', size === 'default' && 'h-8 min-w-8 px-2', isActive
|
|
19
|
+
? 'border border-input bg-background text-foreground'
|
|
20
|
+
: 'border border-transparent text-foreground hover:bg-accent hover:text-accent-foreground', className), ...props }));
|
|
21
|
+
}
|
|
22
|
+
function PaginationPrevious({ className, ...props }) {
|
|
23
|
+
return (_jsxs(PaginationLink, { "aria-label": "Go to previous page", size: "default", className: cn('pl-2', className), ...props, children: [_jsx(ChevronLeft, {}), _jsx("span", { children: "Prev" })] }));
|
|
24
|
+
}
|
|
25
|
+
function PaginationNext({ className, ...props }) {
|
|
26
|
+
return (_jsxs(PaginationLink, { "aria-label": "Go to next page", size: "default", className: cn('pr-2', className), ...props, children: [_jsx("span", { children: "Next" }), _jsx(ChevronRight, {})] }));
|
|
27
|
+
}
|
|
28
|
+
function PaginationEllipsis({ className, ...props }) {
|
|
29
|
+
return (_jsxs("span", { "aria-hidden": true, "data-slot": "pagination-ellipsis", className: cn('flex justify-center items-center size-8', className), ...props, children: [_jsx(MoreHorizontal, { className: "size-3.5" }), _jsx("span", { className: "sr-only", children: "More pages" })] }));
|
|
30
|
+
}
|
|
31
|
+
export { Pagination, PaginationContent, PaginationLink, PaginationItem, PaginationPrevious, PaginationNext, PaginationEllipsis, };
|
|
@@ -9,7 +9,7 @@ function PopoverTrigger({ ...props }) {
|
|
|
9
9
|
return _jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
10
10
|
}
|
|
11
11
|
function PopoverContent({ className, align = 'center', sideOffset = 4, ...props }) {
|
|
12
|
-
return (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { "data-slot": "popover-content", align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-
|
|
12
|
+
return (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { "data-slot": "popover-content", align: align, sideOffset: sideOffset, className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-sm border p-4 shadow-md outline-hidden', className), ...props }) }));
|
|
13
13
|
}
|
|
14
14
|
function PopoverAnchor({ ...props }) {
|
|
15
15
|
return _jsx(PopoverPrimitive.Anchor, { "data-slot": "popover-anchor", ...props });
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Component that implements a basic search interface
|
|
3
3
|
*/
|
|
4
|
-
export declare function SearchDialog({ debounceTime, charLimit, children, }: {
|
|
4
|
+
export declare function SearchDialog({ debounceTime, charLimit, children, onOpenChange, }: {
|
|
5
5
|
debounceTime?: number;
|
|
6
6
|
charLimit?: number;
|
|
7
7
|
children: React.ReactNode;
|
|
8
|
+
onOpenChange?: (open: boolean) => void;
|
|
8
9
|
}): import("react/jsx-runtime").JSX.Element;
|
|
9
10
|
//# sourceMappingURL=search.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/components/ui/search.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/components/ui/search.tsx"],"names":[],"mappings":"AA8eA;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAC3B,YAAkB,EAClB,SAAc,EACd,QAAQ,EACR,YAAY,GACb,EAAE;IACD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC,2CA0FA"}
|
|
@@ -6,6 +6,7 @@ import { SPACE_OR_PUNCTUATION, rankResults } from '@myst-theme/search';
|
|
|
6
6
|
import { useSearchFactory, useLinkProvider, withBaseurl, useBaseurl, useNavigateProvider, } from '@myst-theme/providers';
|
|
7
7
|
import useSWR from 'swr';
|
|
8
8
|
import { Search as SearchIcon } from 'lucide-react';
|
|
9
|
+
import { useAnalytics } from '../providers';
|
|
9
10
|
/**
|
|
10
11
|
* Loading bar component that shows at the top of the dialog
|
|
11
12
|
*/
|
|
@@ -199,20 +200,28 @@ function useSearch(shouldLoad = true) {
|
|
|
199
200
|
function SearchForm({ debounceTime, searchResults, setSearchResults, searchInputID, searchListID, searchLabelID, selectedIndex, setSelectedIndex, closeSearch, loading, shouldLoad, }) {
|
|
200
201
|
const [query, setQuery] = useState('');
|
|
201
202
|
const { search: doSearch, enabled } = useSearch(shouldLoad);
|
|
203
|
+
const capture = useAnalytics();
|
|
202
204
|
// Debounce user input
|
|
203
205
|
useEffect(() => {
|
|
204
206
|
const timeoutId = setTimeout(() => {
|
|
205
207
|
if (query != undefined && !!doSearch) {
|
|
206
208
|
doSearch(query).then((rawResults) => {
|
|
207
|
-
|
|
209
|
+
const ranked = rawResults &&
|
|
208
210
|
rankResults(rawResults)
|
|
209
211
|
// Filter duplicates by URL
|
|
210
|
-
.filter((result, index, array) => result.url !== array[index - 1]?.url)
|
|
212
|
+
.filter((result, index, array) => result.url !== array[index - 1]?.url);
|
|
213
|
+
setSearchResults(ranked);
|
|
214
|
+
if (query.length > 0) {
|
|
215
|
+
capture('search_performed', {
|
|
216
|
+
queryLength: query.length,
|
|
217
|
+
resultCount: ranked?.length ?? 0,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
211
220
|
});
|
|
212
221
|
}
|
|
213
222
|
}, debounceTime);
|
|
214
223
|
return () => clearTimeout(timeoutId);
|
|
215
|
-
}, [doSearch, query, debounceTime]);
|
|
224
|
+
}, [doSearch, query, debounceTime, capture]);
|
|
216
225
|
// Handle user input
|
|
217
226
|
const handleSearchChange = useCallback((event) => {
|
|
218
227
|
setQuery(event.target.value);
|
|
@@ -234,6 +243,11 @@ function SearchForm({ debounceTime, searchResults, setSearchResults, searchInput
|
|
|
234
243
|
event.preventDefault();
|
|
235
244
|
const url = searchResults[selectedIndex]?.url;
|
|
236
245
|
if (url) {
|
|
246
|
+
capture('search_result_selected', {
|
|
247
|
+
queryLength: query.length,
|
|
248
|
+
selectedIndex,
|
|
249
|
+
resultUrl: url,
|
|
250
|
+
});
|
|
237
251
|
navigate(withBaseurl(url, baseurl));
|
|
238
252
|
closeSearch?.();
|
|
239
253
|
}
|
|
@@ -252,16 +266,20 @@ function SearchForm({ debounceTime, searchResults, setSearchResults, searchInput
|
|
|
252
266
|
const onSubmit = useCallback((event) => {
|
|
253
267
|
event.preventDefault();
|
|
254
268
|
}, []);
|
|
255
|
-
return (_jsxs(_Fragment, { children: [_jsx("form", { onSubmit: onSubmit, children: _jsxs("div", { className: "flex relative w-full h-10 flow-row", children: [_jsx("label", { id: searchListID, htmlFor: searchInputID, children: _jsx(SearchIcon, { className: "absolute text-gray-400 inset-y-0 start-0 h-10 w-10 p-2.5 aspect-square flex items-center pointer-events-none" }) }), _jsx("input", { autoComplete: "off", spellCheck: "false", disabled: !enabled, autoCapitalize: "false", className: cn('block
|
|
269
|
+
return (_jsxs(_Fragment, { children: [_jsx("form", { onSubmit: onSubmit, children: _jsxs("div", { className: "flex relative w-full h-10 flow-row", children: [_jsx("label", { id: searchListID, htmlFor: searchInputID, children: _jsx(SearchIcon, { className: "absolute text-gray-400 inset-y-0 start-0 h-10 w-10 p-2.5 aspect-square flex items-center pointer-events-none" }) }), _jsx("input", { autoComplete: "off", spellCheck: "false", disabled: !enabled, autoCapitalize: "false", className: cn('block grow p-2 placeholder-gray-400 ps-10', 'border border-gray-300 dark:border-gray-600', 'bg-gray-50 rounded-sm dark:bg-gray-700', 'focus:ring-blue-500 dark:focus:ring-blue-500', 'focus:border-blue-500 dark:focus:border-blue-500', 'dark:placeholder-gray-400', { 'border-red-500': !enabled && !loading }), id: searchInputID, "aria-labelledby": searchLabelID, "aria-controls": searchListID, placeholder: "Search", type: "search", required: true, onChange: handleSearchChange, onKeyDown: handleSearchKeyPress })] }) }), !enabled && !loading && (_jsx("div", { className: "mx-2 mt-4 text-sm text-gray-500", children: "Search is not enabled for this site." }))] }));
|
|
256
270
|
}
|
|
257
271
|
/**
|
|
258
272
|
* Component that implements a basic search interface
|
|
259
273
|
*/
|
|
260
|
-
export function SearchDialog({ debounceTime = 500, charLimit = 64, children, }) {
|
|
274
|
+
export function SearchDialog({ debounceTime = 500, charLimit = 64, children, onOpenChange, }) {
|
|
261
275
|
const [open, setOpen] = useState(false);
|
|
262
276
|
const [searchResults, setSearchResults] = useState();
|
|
263
277
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
264
278
|
const { loading } = useSearch(open);
|
|
279
|
+
const handleOpenChange = useCallback((next) => {
|
|
280
|
+
setOpen(next);
|
|
281
|
+
onOpenChange?.(next);
|
|
282
|
+
}, [onOpenChange]);
|
|
265
283
|
// Clear search state on close
|
|
266
284
|
useEffect(() => {
|
|
267
285
|
if (!open) {
|
|
@@ -278,13 +296,11 @@ export function SearchDialog({ debounceTime = 500, charLimit = 64, children, })
|
|
|
278
296
|
}, []);
|
|
279
297
|
// Mount the document event handlers
|
|
280
298
|
useEffect(() => {
|
|
281
|
-
// attach the event listener
|
|
282
299
|
document.addEventListener('keydown', handleDocumentKeyPress);
|
|
283
|
-
// remove the event listener
|
|
284
300
|
return () => {
|
|
285
301
|
document.removeEventListener('keydown', handleDocumentKeyPress);
|
|
286
302
|
};
|
|
287
303
|
}, [handleDocumentKeyPress]);
|
|
288
304
|
const triggerClose = useCallback(() => setOpen(false), [setOpen]);
|
|
289
|
-
return (_jsxs(Dialog.Dialog, { open: open, onOpenChange:
|
|
305
|
+
return (_jsxs(Dialog.Dialog, { open: open, onOpenChange: handleOpenChange, children: [_jsx(Dialog.DialogTrigger, { asChild: true, children: _jsx("div", { className: "cursor-pointer", children: children }) }), _jsxs(Dialog.DialogPortal, { children: [_jsx(Dialog.DialogOverlay, {}), _jsx(Dialog.DialogContent, { className: "fixed top-4 sm:top-[10vh] left-1/2 -translate-x-1/2 w-[90vw] max-w-screen-sm max-h-[calc(100vh-2rem)] sm:max-h-[70vh] overflow-hidden translate-y-0 p-0", showCloseButton: false, children: _jsxs("div", { className: "flex overflow-hidden relative flex-col gap-0 p-4", children: [_jsx(Dialog.DialogTitle, { className: "sr-only", children: "Search Website" }), _jsx(Dialog.DialogDescription, { className: "sr-only", children: "Search articles and their contents using fuzzy-search and prefix-matching" }), _jsx("div", { className: "shrink-0", children: _jsx(SearchForm, { searchListID: "search-list", searchLabelID: "search-label", searchInputID: "search-input", debounceTime: debounceTime, searchResults: searchResults, setSearchResults: setSearchResults, selectedIndex: selectedIndex, setSelectedIndex: setSelectedIndex, closeSearch: triggerClose, loading: loading, shouldLoad: open }) }), searchResults && (_jsx("div", { className: "overflow-hidden flex-1", children: _jsx(SearchResults, { searchListID: "search-list", searchLabelID: "search-label", className: "overflow-y-auto h-full", searchResults: searchResults, selectedIndex: selectedIndex, onHoverSelect: setSelectedIndex, closeSearch: triggerClose, charLimit: charLimit }) }))] }) })] })] }));
|
|
290
306
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
3
|
+
declare function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
declare function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
declare function SelectTrigger({ className, size, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
7
|
+
size?: 'sm' | 'default';
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
declare function SelectContent({ className, children, position, ...props }: React.ComponentProps<typeof SelectPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
declare function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
declare function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
declare function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
declare function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
declare function SelectScrollDownButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
|
|
16
|
+
//# sourceMappingURL=select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../../src/components/ui/select.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,eAAe,MAAM,wBAAwB,CAAC;AAK1D,iBAAS,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,2CAE9E;AAED,iBAAS,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAEpF;AAED,iBAAS,WAAW,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAEpF;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,IAAgB,EAChB,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,GAAG;IACxD,IAAI,CAAC,EAAE,IAAI,GAAG,SAAS,CAAC;CACzB,2CAiBA;AAED,iBAAS,aAAa,CAAC,EACrB,SAAS,EACT,QAAQ,EACR,QAAmB,EACnB,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,OAAO,CAAC,2CA4BtD;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,KAAK,CAAC,2CAQ/F;AAED,iBAAS,UAAU,CAAC,EAClB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,IAAI,CAAC,2CAkBnD;AAED,iBAAS,eAAe,CAAC,EACvB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,SAAS,CAAC,2CAQxD;AAED,iBAAS,oBAAoB,CAAC,EAC5B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,cAAc,CAAC,2CAU7D;AAED,iBAAS,sBAAsB,CAAC,EAC9B,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,eAAe,CAAC,gBAAgB,CAAC,2CAU/D;AAED,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,sBAAsB,EACtB,oBAAoB,EACpB,eAAe,EACf,aAAa,EACb,WAAW,GACZ,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
4
|
+
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react';
|
|
5
|
+
import { cn } from '../../lib/utils';
|
|
6
|
+
function Select({ ...props }) {
|
|
7
|
+
return _jsx(SelectPrimitive.Root, { "data-slot": "select", ...props });
|
|
8
|
+
}
|
|
9
|
+
function SelectGroup({ ...props }) {
|
|
10
|
+
return _jsx(SelectPrimitive.Group, { "data-slot": "select-group", ...props });
|
|
11
|
+
}
|
|
12
|
+
function SelectValue({ ...props }) {
|
|
13
|
+
return _jsx(SelectPrimitive.Value, { "data-slot": "select-value", ...props });
|
|
14
|
+
}
|
|
15
|
+
function SelectTrigger({ className, size = 'default', children, ...props }) {
|
|
16
|
+
return (_jsxs(SelectPrimitive.Trigger, { "data-slot": "select-trigger", "data-size": size, className: cn("border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-stone-950 dark:hover:bg-stone-900 flex w-fit items-center justify-between gap-2 rounded-md border bg-white px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className), ...props, children: [children, _jsx(SelectPrimitive.Icon, { asChild: true, children: _jsx(ChevronDownIcon, { className: "opacity-50 size-4" }) })] }));
|
|
17
|
+
}
|
|
18
|
+
function SelectContent({ className, children, position = 'popper', ...props }) {
|
|
19
|
+
return (_jsx(SelectPrimitive.Portal, { children: _jsxs(SelectPrimitive.Content, { "data-slot": "select-content", className: cn('bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md', position === 'popper' &&
|
|
20
|
+
'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1', className), position: position, ...props, children: [_jsx(SelectScrollUpButton, {}), _jsx(SelectPrimitive.Viewport, { className: cn('p-1', position === 'popper' &&
|
|
21
|
+
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1'), children: children }), _jsx(SelectScrollDownButton, {})] }) }));
|
|
22
|
+
}
|
|
23
|
+
function SelectLabel({ className, ...props }) {
|
|
24
|
+
return (_jsx(SelectPrimitive.Label, { "data-slot": "select-label", className: cn('text-muted-foreground px-2 py-1.5 text-xs', className), ...props }));
|
|
25
|
+
}
|
|
26
|
+
function SelectItem({ className, children, ...props }) {
|
|
27
|
+
return (_jsxs(SelectPrimitive.Item, { "data-slot": "select-item", className: cn("focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className), ...props, children: [_jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(CheckIcon, { className: "size-4" }) }) }), _jsx(SelectPrimitive.ItemText, { children: children })] }));
|
|
28
|
+
}
|
|
29
|
+
function SelectSeparator({ className, ...props }) {
|
|
30
|
+
return (_jsx(SelectPrimitive.Separator, { "data-slot": "select-separator", className: cn('bg-border pointer-events-none -mx-1 my-1 h-px', className), ...props }));
|
|
31
|
+
}
|
|
32
|
+
function SelectScrollUpButton({ className, ...props }) {
|
|
33
|
+
return (_jsx(SelectPrimitive.ScrollUpButton, { "data-slot": "select-scroll-up-button", className: cn('flex cursor-default items-center justify-center py-1', className), ...props, children: _jsx(ChevronUpIcon, { className: "size-4" }) }));
|
|
34
|
+
}
|
|
35
|
+
function SelectScrollDownButton({ className, ...props }) {
|
|
36
|
+
return (_jsx(SelectPrimitive.ScrollDownButton, { "data-slot": "select-scroll-down-button", className: cn('flex cursor-default items-center justify-center py-1', className), ...props, children: _jsx(ChevronDownIcon, { className: "size-4" }) }));
|
|
37
|
+
}
|
|
38
|
+
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
|
|
@@ -3,6 +3,6 @@ import * as React from 'react';
|
|
|
3
3
|
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
4
4
|
import { cn } from '../../lib/utils';
|
|
5
5
|
function Separator({ className, orientation = 'horizontal', decorative = true, ...props }) {
|
|
6
|
-
return (_jsx(SeparatorPrimitive.Root, { "data-slot": "separator", decorative: decorative, orientation: orientation, className: cn('bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px', className), ...props }));
|
|
6
|
+
return (_jsx(SeparatorPrimitive.Root, { "data-slot": "separator", decorative: decorative, orientation: orientation, className: cn('bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px dark:bg-white/60', className), ...props }));
|
|
7
7
|
}
|
|
8
8
|
export { Separator };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import { Button, Input, Separator, TooltipContent } from '.';
|
|
2
|
+
import { Button, Input, Separator } from '.';
|
|
4
3
|
type SidebarContextProps = {
|
|
5
4
|
state: 'expanded' | 'collapsed';
|
|
6
5
|
open: boolean;
|
|
@@ -39,15 +38,6 @@ declare function SidebarGroupAction({ className, asChild, ...props }: React.Comp
|
|
|
39
38
|
declare function SidebarGroupContent({ className, ...props }: React.ComponentProps<'div'>): import("react/jsx-runtime").JSX.Element;
|
|
40
39
|
declare function SidebarMenu({ className, ...props }: React.ComponentProps<'ul'>): import("react/jsx-runtime").JSX.Element;
|
|
41
40
|
declare function SidebarMenuItem({ className, ...props }: React.ComponentProps<'li'>): import("react/jsx-runtime").JSX.Element;
|
|
42
|
-
declare const sidebarMenuButtonVariants: (props?: ({
|
|
43
|
-
variant?: "default" | "outline" | null | undefined;
|
|
44
|
-
size?: "default" | "sm" | "lg" | null | undefined;
|
|
45
|
-
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
46
|
-
declare function SidebarMenuButton({ asChild, isActive, variant, size, tooltip, className, ...props }: React.ComponentProps<'button'> & {
|
|
47
|
-
asChild?: boolean;
|
|
48
|
-
isActive?: boolean;
|
|
49
|
-
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
|
|
50
|
-
} & VariantProps<typeof sidebarMenuButtonVariants>): import("react/jsx-runtime").JSX.Element;
|
|
51
41
|
declare function SidebarMenuAction({ className, asChild, showOnHover, ...props }: React.ComponentProps<'button'> & {
|
|
52
42
|
asChild?: boolean;
|
|
53
43
|
showOnHover?: boolean;
|
|
@@ -63,5 +53,5 @@ declare function SidebarMenuSubButton({ asChild, size, isActive, className, ...p
|
|
|
63
53
|
size?: 'sm' | 'md';
|
|
64
54
|
isActive?: boolean;
|
|
65
55
|
}): import("react/jsx-runtime").JSX.Element;
|
|
66
|
-
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge,
|
|
56
|
+
export { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, useSidebar, };
|
|
67
57
|
//# sourceMappingURL=sidebar.d.ts.map
|