@gunjo/ui 0.0.1-alpha.1 → 0.0.1-alpha.2
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.ja.md +90 -0
- package/README.md +52 -91
- package/package.json +47 -6
- package/src/components/display/Accordion.tsx +185 -0
- package/src/components/display/AccordionGroup.tsx +155 -0
- package/src/components/display/ActionDataTable.tsx +413 -0
- package/src/components/display/ActivityTimelineCard.tsx +483 -0
- package/src/components/display/AnalyticsCard.tsx +167 -0
- package/src/components/display/AssetCard.tsx +242 -0
- package/src/components/display/AssetGrid.tsx +164 -0
- package/src/components/display/Avatar.tsx +127 -0
- package/src/components/display/AvatarGroup.tsx +131 -0
- package/src/components/{atoms → display}/Badge.tsx +3 -3
- package/src/components/display/BarChart.tsx +247 -0
- package/src/components/{molecules → display}/Card.tsx +1 -1
- package/src/components/display/Carousel.tsx +593 -0
- package/src/components/display/ChartLegend.tsx +124 -0
- package/src/components/display/ChatMessage.tsx +382 -0
- package/src/components/display/ChoroplethMap.tsx +613 -0
- package/src/components/display/Code.tsx +42 -0
- package/src/components/display/CodeBlock.tsx +338 -0
- package/src/components/display/ColorSwatch.tsx +71 -0
- package/src/components/display/ConcentricProgressCard.tsx +545 -0
- package/src/components/display/DataTable.tsx +522 -0
- package/src/components/display/DistributionBar.tsx +102 -0
- package/src/components/display/DocNote.tsx +36 -0
- package/src/components/display/DonutChart.tsx +257 -0
- package/src/components/display/EmptyState.tsx +44 -0
- package/src/components/display/FileTree.tsx +180 -0
- package/src/components/display/GaugeChart.tsx +219 -0
- package/src/components/display/HeatmapChart.tsx +266 -0
- package/src/components/display/Icon.tsx +66 -0
- package/src/components/display/ImagePreview.tsx +140 -0
- package/src/components/{atoms → display}/Img.tsx +46 -12
- package/src/components/display/LabeledDonutCard.tsx +475 -0
- package/src/components/display/LineChart.tsx +464 -0
- package/src/components/{molecules → display}/List.tsx +20 -13
- package/src/components/display/MarkdownRenderer.tsx +157 -0
- package/src/components/display/MetadataList.tsx +81 -0
- package/src/components/display/MiniDistributionBarCard.tsx +314 -0
- package/src/components/display/PieChart.tsx +234 -0
- package/src/components/display/QuadrantMatrix.tsx +330 -0
- package/src/components/display/RadarChart.tsx +335 -0
- package/src/components/display/RadialBarChart.tsx +264 -0
- package/src/components/display/RetentionCohortCard.tsx +350 -0
- package/src/components/display/RibbonChart.tsx +618 -0
- package/src/components/display/SearchableAccordion.tsx +270 -0
- package/src/components/display/SegmentTimelineCard.tsx +452 -0
- package/src/components/display/SegmentedGaugeCard.tsx +607 -0
- package/src/components/display/Spacer.tsx +51 -0
- package/src/components/display/SparklineChart.tsx +394 -0
- package/src/components/display/StackedBarChart.tsx +393 -0
- package/src/components/display/Statistic.tsx +70 -0
- package/src/components/{molecules → display}/Table.tsx +22 -7
- package/src/components/display/Tag.tsx +80 -0
- package/src/components/display/TagEditor.tsx +141 -0
- package/src/components/display/Timeline.tsx +121 -0
- package/src/components/{atoms → display}/ToolPill.tsx +42 -18
- package/src/components/display/TreeView.tsx +226 -0
- package/src/components/display/chart-tooltip.tsx +423 -0
- package/src/components/display/chart-utils.ts +71 -0
- package/src/components/display/circular-chart-utils.ts +147 -0
- package/src/components/display/generated/default-variant-keys.ts +90 -0
- package/src/components/display/generated/variant-keys.ts +169 -0
- package/src/components/{atoms → feedback}/Alert.tsx +12 -5
- package/src/components/feedback/Banner.tsx +90 -0
- package/src/components/{molecules → feedback}/NotificationCenter.tsx +64 -31
- package/src/components/feedback/ProgressWidget.tsx +44 -0
- package/src/components/{atoms → feedback}/Spinner.tsx +2 -2
- package/src/components/{molecules → feedback}/StatusBar.tsx +4 -4
- package/src/components/feedback/StatusScreen.tsx +148 -0
- package/src/components/{molecules → feedback}/Stepper.tsx +10 -5
- package/src/components/feedback/Toast.tsx +108 -0
- package/src/components/feedback/ToastProvider.tsx +78 -0
- package/src/components/feedback/generated/default-variant-keys.ts +16 -0
- package/src/components/feedback/generated/variant-keys.ts +21 -0
- package/src/components/generated/component-manifest.ts +1568 -454
- package/src/components/generated/component-style-hints.ts +1958 -718
- package/src/components/{atoms → inputs}/ButtonVariants.ts +13 -3
- package/src/components/inputs/Calendar.tsx +212 -0
- package/src/components/inputs/ChatComposer.tsx +75 -0
- package/src/components/inputs/ChatInput.tsx +528 -0
- package/src/components/{atoms → inputs}/Checkbox.tsx +2 -2
- package/src/components/inputs/Combobox.tsx +175 -0
- package/src/components/inputs/CopyButton.tsx +187 -0
- package/src/components/inputs/DatePicker.tsx +519 -0
- package/src/components/inputs/DateRangePicker.tsx +878 -0
- package/src/components/inputs/EditableField.tsx +182 -0
- package/src/components/{organisms → inputs}/FileUploader.tsx +24 -9
- package/src/components/inputs/FilterButton.tsx +163 -0
- package/src/components/{molecules → inputs}/Form.tsx +20 -3
- package/src/components/{atoms → inputs}/Input.tsx +2 -0
- package/src/components/inputs/InputOTP.tsx +75 -0
- package/src/components/inputs/Mention.tsx +279 -0
- package/src/components/inputs/NumberInput.tsx +109 -0
- package/src/components/inputs/PasswordGroup.tsx +138 -0
- package/src/components/inputs/PasswordInput.tsx +74 -0
- package/src/components/inputs/PasswordRequirementList.tsx +96 -0
- package/src/components/inputs/PasswordStrengthMeter.tsx +93 -0
- package/src/components/inputs/PhoneInput.tsx +99 -0
- package/src/components/inputs/PostalCodeInput.tsx +98 -0
- package/src/components/inputs/RangeSlider.tsx +129 -0
- package/src/components/inputs/SearchInput.tsx +76 -0
- package/src/components/inputs/Select.tsx +39 -0
- package/src/components/{atoms → inputs}/Slider.tsx +18 -5
- package/src/components/{molecules → inputs}/SortButton.tsx +5 -2
- package/src/components/{atoms → inputs}/Switch.tsx +15 -4
- package/src/components/inputs/TagInput.tsx +114 -0
- package/src/components/{atoms → inputs}/Textarea.tsx +1 -0
- package/src/components/inputs/TimePicker.tsx +150 -0
- package/src/components/inputs/Toggle.tsx +48 -0
- package/src/components/{atoms → inputs}/ToggleGroup.tsx +2 -2
- package/src/components/inputs/TooltipButton.tsx +148 -0
- package/src/components/inputs/VoiceInputButton.tsx +317 -0
- package/src/components/inputs/calendar-holidays.ts +56 -0
- package/src/components/inputs/generated/default-variant-keys.ts +32 -0
- package/src/components/{atoms → inputs}/generated/variant-keys.ts +19 -27
- package/src/components/layout/AspectRatio.tsx +12 -0
- package/src/components/layout/AssetInspectorPanel.tsx +416 -0
- package/src/components/layout/Cluster.tsx +56 -0
- package/src/components/layout/CollapsiblePanelToggle.tsx +94 -0
- package/src/components/layout/Container.tsx +43 -0
- package/src/components/layout/DeviceFrame.tsx +227 -0
- package/src/components/layout/Grid.tsx +65 -0
- package/src/components/layout/HStack.tsx +73 -0
- package/src/components/{organisms → layout}/InspectorPanel.tsx +6 -5
- package/src/components/layout/MarqueeFrame.tsx +158 -0
- package/src/components/layout/Resizable.tsx +94 -0
- package/src/components/layout/ScrollArea.tsx +71 -0
- package/src/components/{organisms → layout}/SpatialCanvas.tsx +12 -7
- package/src/components/layout/VStack.tsx +69 -0
- package/src/components/layout/generated/default-variant-keys.ts +16 -0
- package/src/components/layout/generated/variant-keys.ts +21 -0
- package/src/components/{molecules → navigation}/Breadcrumb.tsx +5 -4
- package/src/components/navigation/Command.tsx +266 -0
- package/src/components/navigation/CommandPalette.tsx +83 -0
- package/src/components/navigation/DocumentPager.tsx +171 -0
- package/src/components/navigation/Footer.tsx +88 -0
- package/src/components/navigation/Header.tsx +80 -0
- package/src/components/{molecules → navigation}/Menubar.tsx +45 -12
- package/src/components/navigation/NavigationMenu.tsx +128 -0
- package/src/components/navigation/PageAside.tsx +84 -0
- package/src/components/{molecules → navigation}/Pagination.tsx +60 -7
- package/src/components/{organisms → navigation}/RightRail.tsx +1 -1
- package/src/components/navigation/Sidebar.tsx +223 -0
- package/src/components/navigation/SidebarItem.tsx +160 -0
- package/src/components/{molecules → navigation}/Tabs.tsx +2 -2
- package/src/components/navigation/TextLink.tsx +71 -0
- package/src/components/navigation/generated/default-variant-keys.ts +12 -0
- package/src/components/navigation/generated/variant-keys.ts +13 -0
- package/src/components/overlay/AIChatInput.tsx +5 -0
- package/src/components/overlay/AIChatMessage.tsx +6 -0
- package/src/components/overlay/AlertDialog.tsx +145 -0
- package/src/components/overlay/ChatPanel.tsx +180 -0
- package/src/components/{molecules → overlay}/ContextMenu.tsx +65 -29
- package/src/components/{molecules → overlay}/Dialog.tsx +21 -13
- package/src/components/overlay/Drawer.tsx +131 -0
- package/src/components/{molecules → overlay}/DropdownMenu.tsx +52 -17
- package/src/components/overlay/FloatingPanel.tsx +90 -0
- package/src/components/overlay/HoverCard.tsx +36 -0
- package/src/components/overlay/MediaLightbox.tsx +403 -0
- package/src/components/overlay/MediaPickerDialog.tsx +198 -0
- package/src/components/overlay/Modal.tsx +103 -0
- package/src/components/overlay/OnboardingFlow.tsx +172 -0
- package/src/components/overlay/Popover.tsx +36 -0
- package/src/components/overlay/ShareModal.tsx +324 -0
- package/src/components/{molecules → overlay}/Sheet.tsx +76 -19
- package/src/components/overlay/Tooltip.tsx +130 -0
- package/src/components/overlay/generated/default-variant-keys.ts +14 -0
- package/src/components/overlay/generated/variant-keys.ts +17 -0
- package/src/components/patterns/BlogTemplate.tsx +46 -0
- package/src/components/{templates → patterns}/DashboardTemplate.tsx +2 -2
- package/src/components/patterns/DocsTemplate.tsx +41 -0
- package/src/components/{templates → patterns}/MediaLibraryTemplate.tsx +1 -1
- package/src/components/patterns/OnboardingTemplate.tsx +32 -0
- package/src/components/patterns/PricingTemplate.tsx +106 -0
- package/src/globals.css +173 -22
- package/src/index.ts +177 -76
- package/tailwind-theme-extend.cjs +48 -3
- package/design/atoms-metadata.json +0 -82
- package/design/molecules-metadata.json +0 -130
- package/design/organisms-metadata.json +0 -38
- package/design/templates-metadata.json +0 -38
- package/src/components/atoms/Avatar.tsx +0 -57
- package/src/components/atoms/Select.tsx +0 -28
- package/src/components/atoms/generated/default-variant-keys.ts +0 -36
- package/src/components/molecules/AIChatInput.tsx +0 -140
- package/src/components/molecules/AIChatMessage.tsx +0 -109
- package/src/components/molecules/Accordion.tsx +0 -99
- package/src/components/molecules/Calendar.tsx +0 -60
- package/src/components/molecules/Carousel.tsx +0 -261
- package/src/components/molecules/Command.tsx +0 -152
- package/src/components/molecules/FilterButton.tsx +0 -133
- package/src/components/molecules/HoverCard.tsx +0 -29
- package/src/components/molecules/Modal.tsx +0 -66
- package/src/components/molecules/Popover.tsx +0 -31
- package/src/components/molecules/ProgressWidget.tsx +0 -40
- package/src/components/molecules/Resizable.tsx +0 -47
- package/src/components/molecules/ScrollArea.tsx +0 -48
- package/src/components/molecules/SidebarItem.tsx +0 -134
- package/src/components/molecules/Toast.tsx +0 -57
- package/src/components/molecules/Tooltip.tsx +0 -30
- package/src/components/molecules/generated/default-variant-keys.ts +0 -22
- package/src/components/molecules/generated/variant-keys.ts +0 -33
- package/src/components/organisms/CommandPalette.tsx +0 -58
- package/src/components/organisms/FloatingPanel.tsx +0 -46
- package/src/components/organisms/ShareModal.tsx +0 -182
- package/src/components/organisms/ToastProvider.tsx +0 -49
- /package/src/components/{atoms → display}/Kbd.tsx +0 -0
- /package/src/components/{atoms → display}/Separator.tsx +0 -0
- /package/src/components/{atoms → display}/Skeleton.tsx +0 -0
- /package/src/components/{atoms → feedback}/Progress.tsx +0 -0
- /package/src/components/{atoms → inputs}/Button.tsx +0 -0
- /package/src/components/{atoms → inputs}/Label.tsx +0 -0
- /package/src/components/{atoms → inputs}/RadioGroup.tsx +0 -0
- /package/src/components/{organisms → navigation}/AppRail.tsx +0 -0
- /package/src/components/{templates → patterns}/AuthTemplate.tsx +0 -0
- /package/src/components/{templates → patterns}/BannalyzeTemplate.tsx +0 -0
- /package/src/components/{templates → patterns}/ChatTemplate.tsx +0 -0
- /package/src/components/{templates → patterns}/EditorTemplate.tsx +0 -0
- /package/src/components/{templates → patterns}/KanbanTemplate.tsx +0 -0
- /package/src/components/{templates → patterns}/LandingTemplate.tsx +0 -0
- /package/src/components/{templates → patterns}/SettingsTemplate.tsx +0 -0
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { IconChevronLeft as ChevronLeft, IconChevronRight as ChevronRight } from "@tabler/icons-react";
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
export interface DocumentPagerItem {
|
|
8
|
+
href: string
|
|
9
|
+
directionLabel: React.ReactNode
|
|
10
|
+
title: React.ReactNode
|
|
11
|
+
subtitle?: React.ReactNode
|
|
12
|
+
description?: React.ReactNode
|
|
13
|
+
categoryLabel?: React.ReactNode
|
|
14
|
+
thumbnailSrc?: string
|
|
15
|
+
thumbnailAlt?: string
|
|
16
|
+
thumbnailFallback?: React.ReactNode
|
|
17
|
+
ariaLabel?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface DocumentPagerLinkProps {
|
|
21
|
+
href: string
|
|
22
|
+
className?: string
|
|
23
|
+
"aria-label"?: string
|
|
24
|
+
children: React.ReactNode
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface DocumentPagerProps extends React.HTMLAttributes<HTMLElement> {
|
|
28
|
+
previous?: DocumentPagerItem | null
|
|
29
|
+
next?: DocumentPagerItem | null
|
|
30
|
+
linkComponent?: React.ElementType<DocumentPagerLinkProps>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function DocumentPagerThumb({
|
|
34
|
+
src,
|
|
35
|
+
alt,
|
|
36
|
+
fallback,
|
|
37
|
+
}: {
|
|
38
|
+
src?: string
|
|
39
|
+
alt?: string
|
|
40
|
+
fallback?: React.ReactNode
|
|
41
|
+
}) {
|
|
42
|
+
const [errored, setErrored] = React.useState(false)
|
|
43
|
+
|
|
44
|
+
if (!src && !errored) return null
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div className="relative h-20 w-24 shrink-0 overflow-hidden rounded-md border border-border/70 bg-muted/40 p-1.5 sm:w-28">
|
|
48
|
+
{src && !errored ? (
|
|
49
|
+
/* eslint-disable-next-line @next/next/no-img-element */
|
|
50
|
+
<img
|
|
51
|
+
src={src}
|
|
52
|
+
alt={alt ?? ""}
|
|
53
|
+
onError={() => setErrored(true)}
|
|
54
|
+
loading="lazy"
|
|
55
|
+
decoding="async"
|
|
56
|
+
className="h-full w-full rounded-[4px] object-cover object-top shadow-sm"
|
|
57
|
+
/>
|
|
58
|
+
) : (
|
|
59
|
+
<div className="grid h-full w-full place-items-center rounded-[4px] bg-muted text-center text-[10px] leading-tight text-muted-foreground">
|
|
60
|
+
{fallback ?? "Preview"}
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function DocumentPagerCard({
|
|
68
|
+
item,
|
|
69
|
+
direction,
|
|
70
|
+
LinkComponent,
|
|
71
|
+
}: {
|
|
72
|
+
item: DocumentPagerItem
|
|
73
|
+
direction: "previous" | "next"
|
|
74
|
+
LinkComponent: React.ElementType<DocumentPagerLinkProps>
|
|
75
|
+
}) {
|
|
76
|
+
const ariaLabel =
|
|
77
|
+
item.ariaLabel ??
|
|
78
|
+
`${typeof item.directionLabel === "string" ? item.directionLabel : direction}: ${
|
|
79
|
+
typeof item.title === "string" ? item.title : ""
|
|
80
|
+
}`
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<LinkComponent
|
|
84
|
+
href={item.href}
|
|
85
|
+
className="group block h-full rounded-md border border-border/70 bg-background p-3 transition-colors hover:border-primary-border hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
|
86
|
+
aria-label={ariaLabel}
|
|
87
|
+
>
|
|
88
|
+
<div
|
|
89
|
+
className={cn(
|
|
90
|
+
"mb-2.5 flex items-center",
|
|
91
|
+
direction === "next" ? "justify-end" : "justify-start"
|
|
92
|
+
)}
|
|
93
|
+
>
|
|
94
|
+
<span className="inline-flex items-center gap-1.5 text-sm font-semibold text-muted-foreground transition-colors group-hover:text-primary">
|
|
95
|
+
{direction === "previous" ? <ChevronLeft className="h-4 w-4" /> : null}
|
|
96
|
+
{item.directionLabel}
|
|
97
|
+
{direction === "next" ? <ChevronRight className="h-4 w-4" /> : null}
|
|
98
|
+
</span>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div className="flex min-w-0 gap-3">
|
|
102
|
+
<DocumentPagerThumb
|
|
103
|
+
src={item.thumbnailSrc}
|
|
104
|
+
alt={item.thumbnailAlt}
|
|
105
|
+
fallback={item.thumbnailFallback}
|
|
106
|
+
/>
|
|
107
|
+
<div className="min-w-0 flex-1 space-y-2">
|
|
108
|
+
<div className="flex min-w-0 flex-col items-start gap-1.5">
|
|
109
|
+
<span className="min-w-0 max-w-full space-y-0.5 text-sm font-semibold tracking-tight transition-colors group-hover:text-primary">
|
|
110
|
+
<span className="block break-words leading-snug">{item.title}</span>
|
|
111
|
+
{item.subtitle ? (
|
|
112
|
+
<span className="block break-words text-[10px] font-normal leading-snug text-muted-foreground">
|
|
113
|
+
{item.subtitle}
|
|
114
|
+
</span>
|
|
115
|
+
) : null}
|
|
116
|
+
</span>
|
|
117
|
+
{item.categoryLabel ? (
|
|
118
|
+
<span className="inline-flex min-h-5 max-w-full shrink-0 items-center rounded-full border border-border/60 px-2.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground">
|
|
119
|
+
{item.categoryLabel}
|
|
120
|
+
</span>
|
|
121
|
+
) : null}
|
|
122
|
+
</div>
|
|
123
|
+
{item.description ? (
|
|
124
|
+
<p className="line-clamp-3 text-xs leading-relaxed text-muted-foreground">
|
|
125
|
+
{item.description}
|
|
126
|
+
</p>
|
|
127
|
+
) : null}
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</LinkComponent>
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const DocumentPager = React.forwardRef<HTMLElement, DocumentPagerProps>(
|
|
135
|
+
({ previous, next, linkComponent, className, ...props }, ref) => {
|
|
136
|
+
const LinkComponent = linkComponent ?? "a"
|
|
137
|
+
|
|
138
|
+
if (!previous && !next) return null
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<nav
|
|
142
|
+
ref={ref}
|
|
143
|
+
className={cn(
|
|
144
|
+
"grid w-full gap-3 border-t border-border/60 px-0 pb-0 pt-5 xl:grid-cols-2",
|
|
145
|
+
className
|
|
146
|
+
)}
|
|
147
|
+
{...props}
|
|
148
|
+
>
|
|
149
|
+
{previous ? (
|
|
150
|
+
<DocumentPagerCard
|
|
151
|
+
item={previous}
|
|
152
|
+
direction="previous"
|
|
153
|
+
LinkComponent={LinkComponent}
|
|
154
|
+
/>
|
|
155
|
+
) : (
|
|
156
|
+
<div className="hidden md:block" aria-hidden="true" />
|
|
157
|
+
)}
|
|
158
|
+
{next ? (
|
|
159
|
+
<DocumentPagerCard
|
|
160
|
+
item={next}
|
|
161
|
+
direction="next"
|
|
162
|
+
LinkComponent={LinkComponent}
|
|
163
|
+
/>
|
|
164
|
+
) : null}
|
|
165
|
+
</nav>
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
DocumentPager.displayName = "DocumentPager"
|
|
170
|
+
|
|
171
|
+
export { DocumentPager }
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
const Footer = React.forwardRef<
|
|
6
|
+
HTMLElement,
|
|
7
|
+
React.HTMLAttributes<HTMLElement>
|
|
8
|
+
>(({ className, ...props }, ref) => (
|
|
9
|
+
<footer
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn(
|
|
12
|
+
"flex w-full flex-col gap-6 border-t border-border bg-background px-6 py-8",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
))
|
|
18
|
+
Footer.displayName = "Footer"
|
|
19
|
+
|
|
20
|
+
const FooterColumns = React.forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<div
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
))
|
|
30
|
+
FooterColumns.displayName = "FooterColumns"
|
|
31
|
+
|
|
32
|
+
interface FooterSectionProps
|
|
33
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
34
|
+
title?: React.ReactNode
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const FooterSection = React.forwardRef<HTMLDivElement, FooterSectionProps>(
|
|
38
|
+
({ className, title, children, ...props }, ref) => (
|
|
39
|
+
<div ref={ref} className={cn("flex flex-col gap-2", className)} {...props}>
|
|
40
|
+
{title ? (
|
|
41
|
+
<p className="text-sm font-semibold text-foreground">{title}</p>
|
|
42
|
+
) : null}
|
|
43
|
+
{children}
|
|
44
|
+
</div>
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
FooterSection.displayName = "FooterSection"
|
|
48
|
+
|
|
49
|
+
const FooterLink = React.forwardRef<
|
|
50
|
+
HTMLAnchorElement,
|
|
51
|
+
React.AnchorHTMLAttributes<HTMLAnchorElement>
|
|
52
|
+
>(({ className, ...props }, ref) => (
|
|
53
|
+
<a
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn(
|
|
56
|
+
"text-sm text-muted-foreground transition-colors hover:text-foreground",
|
|
57
|
+
className
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
))
|
|
62
|
+
FooterLink.displayName = "FooterLink"
|
|
63
|
+
|
|
64
|
+
const FooterBrand = React.forwardRef<
|
|
65
|
+
HTMLDivElement,
|
|
66
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
67
|
+
>(({ className, ...props }, ref) => (
|
|
68
|
+
<div
|
|
69
|
+
ref={ref}
|
|
70
|
+
className={cn("flex flex-col gap-2", className)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
))
|
|
74
|
+
FooterBrand.displayName = "FooterBrand"
|
|
75
|
+
|
|
76
|
+
const FooterCopyright = React.forwardRef<
|
|
77
|
+
HTMLParagraphElement,
|
|
78
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
79
|
+
>(({ className, ...props }, ref) => (
|
|
80
|
+
<p
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn("border-t border-border pt-4 text-xs text-muted-foreground", className)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
))
|
|
86
|
+
FooterCopyright.displayName = "FooterCopyright"
|
|
87
|
+
|
|
88
|
+
export { Footer, FooterColumns, FooterSection, FooterLink, FooterBrand, FooterCopyright }
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
const Header = React.forwardRef<
|
|
8
|
+
HTMLElement,
|
|
9
|
+
React.HTMLAttributes<HTMLElement>
|
|
10
|
+
>(({ className, ...props }, ref) => (
|
|
11
|
+
<header
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn(
|
|
14
|
+
"flex w-full flex-wrap items-center justify-between gap-x-4 gap-y-3 border-b border-border bg-background px-4 py-3 sm:px-6",
|
|
15
|
+
className
|
|
16
|
+
)}
|
|
17
|
+
{...props}
|
|
18
|
+
/>
|
|
19
|
+
))
|
|
20
|
+
Header.displayName = "Header"
|
|
21
|
+
|
|
22
|
+
const HeaderBrand = React.forwardRef<
|
|
23
|
+
HTMLDivElement,
|
|
24
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
25
|
+
>(({ className, ...props }, ref) => (
|
|
26
|
+
<div
|
|
27
|
+
ref={ref}
|
|
28
|
+
className={cn("flex min-w-0 shrink-0 items-center gap-2", className)}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
))
|
|
32
|
+
HeaderBrand.displayName = "HeaderBrand"
|
|
33
|
+
|
|
34
|
+
const HeaderNav = React.forwardRef<
|
|
35
|
+
HTMLElement,
|
|
36
|
+
React.HTMLAttributes<HTMLElement>
|
|
37
|
+
>(({ className, ...props }, ref) => (
|
|
38
|
+
<nav
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={cn(
|
|
41
|
+
"order-last flex w-full min-w-0 items-center gap-4 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden sm:order-none sm:w-auto",
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
))
|
|
47
|
+
HeaderNav.displayName = "HeaderNav"
|
|
48
|
+
|
|
49
|
+
interface HeaderNavLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
50
|
+
active?: boolean
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const HeaderNavLink = React.forwardRef<HTMLAnchorElement, HeaderNavLinkProps>(
|
|
54
|
+
({ className, active, ...props }, ref) => (
|
|
55
|
+
<a
|
|
56
|
+
ref={ref}
|
|
57
|
+
className={cn(
|
|
58
|
+
"whitespace-nowrap text-sm transition-colors hover:text-foreground",
|
|
59
|
+
active ? "font-medium text-foreground" : "text-muted-foreground",
|
|
60
|
+
className
|
|
61
|
+
)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
HeaderNavLink.displayName = "HeaderNavLink"
|
|
67
|
+
|
|
68
|
+
const HeaderActions = React.forwardRef<
|
|
69
|
+
HTMLDivElement,
|
|
70
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
71
|
+
>(({ className, ...props }, ref) => (
|
|
72
|
+
<div
|
|
73
|
+
ref={ref}
|
|
74
|
+
className={cn("ml-auto flex shrink-0 items-center gap-2", className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
))
|
|
78
|
+
HeaderActions.displayName = "HeaderActions"
|
|
79
|
+
|
|
80
|
+
export { Header, HeaderBrand, HeaderNav, HeaderNavLink, HeaderActions }
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react"
|
|
4
4
|
import * as MenubarPrimitive from "@radix-ui/react-menubar"
|
|
5
|
-
import { Check, ChevronRight, Circle } from "
|
|
5
|
+
import { IconCheck as Check, IconChevronRight as ChevronRight, IconCircle as Circle } from "@tabler/icons-react";
|
|
6
6
|
|
|
7
7
|
import { cn } from "../../lib/utils"
|
|
8
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "../overlay/Tooltip"
|
|
8
9
|
|
|
9
10
|
const Menubar = React.forwardRef<
|
|
10
11
|
React.ElementRef<typeof MenubarPrimitive.Root>,
|
|
@@ -98,18 +99,50 @@ const MenubarItem = React.forwardRef<
|
|
|
98
99
|
React.ElementRef<typeof MenubarPrimitive.Item>,
|
|
99
100
|
React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Item> & {
|
|
100
101
|
inset?: boolean
|
|
102
|
+
disabledReason?: React.ReactNode
|
|
103
|
+
disabledReasonLabel?: string
|
|
104
|
+
disabledReasonPortalContainer?: HTMLElement | null
|
|
101
105
|
}
|
|
102
|
-
>(({ className, inset, ...props }, ref) =>
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
)
|
|
106
|
+
>(({ className, inset, disabledReason, disabledReasonLabel, disabledReasonPortalContainer, disabled, onSelect, ...props }, ref) => {
|
|
107
|
+
const item = (
|
|
108
|
+
<MenubarPrimitive.Item
|
|
109
|
+
ref={ref}
|
|
110
|
+
disabled={disabled}
|
|
111
|
+
onSelect={(event) => {
|
|
112
|
+
if (disabled) {
|
|
113
|
+
event.preventDefault()
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
onSelect?.(event)
|
|
117
|
+
}}
|
|
118
|
+
className={cn(
|
|
119
|
+
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50",
|
|
120
|
+
inset && "pl-8",
|
|
121
|
+
className
|
|
122
|
+
)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if (!disabled || !disabledReason) return item
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<Tooltip>
|
|
131
|
+
<TooltipTrigger asChild>
|
|
132
|
+
<span
|
|
133
|
+
className="block w-full"
|
|
134
|
+
tabIndex={0}
|
|
135
|
+
aria-label={disabledReasonLabel ?? (typeof disabledReason === "string" ? disabledReason : undefined)}
|
|
136
|
+
>
|
|
137
|
+
{item}
|
|
138
|
+
</span>
|
|
139
|
+
</TooltipTrigger>
|
|
140
|
+
<TooltipContent portalContainer={disabledReasonPortalContainer} className="max-w-64 text-left">
|
|
141
|
+
{disabledReason}
|
|
142
|
+
</TooltipContent>
|
|
143
|
+
</Tooltip>
|
|
144
|
+
)
|
|
145
|
+
})
|
|
113
146
|
MenubarItem.displayName = MenubarPrimitive.Item.displayName
|
|
114
147
|
|
|
115
148
|
const MenubarCheckboxItem = React.forwardRef<
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as NavigationMenuPrimitive from "@radix-ui/react-navigation-menu"
|
|
5
|
+
import { IconChevronDown as ChevronDown } from "@tabler/icons-react";
|
|
6
|
+
import { cva } from "class-variance-authority"
|
|
7
|
+
|
|
8
|
+
import { cn } from "../../lib/utils"
|
|
9
|
+
|
|
10
|
+
const NavigationMenu = React.forwardRef<
|
|
11
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Root>,
|
|
12
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Root>
|
|
13
|
+
>(({ className, children, ...props }, ref) => (
|
|
14
|
+
<NavigationMenuPrimitive.Root
|
|
15
|
+
ref={ref}
|
|
16
|
+
className={cn(
|
|
17
|
+
"relative z-10 flex max-w-max flex-1 items-center justify-center",
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
>
|
|
22
|
+
{children}
|
|
23
|
+
<NavigationMenuViewport />
|
|
24
|
+
</NavigationMenuPrimitive.Root>
|
|
25
|
+
))
|
|
26
|
+
NavigationMenu.displayName = NavigationMenuPrimitive.Root.displayName
|
|
27
|
+
|
|
28
|
+
const NavigationMenuList = React.forwardRef<
|
|
29
|
+
React.ElementRef<typeof NavigationMenuPrimitive.List>,
|
|
30
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.List>
|
|
31
|
+
>(({ className, ...props }, ref) => (
|
|
32
|
+
<NavigationMenuPrimitive.List
|
|
33
|
+
ref={ref}
|
|
34
|
+
className={cn(
|
|
35
|
+
"group flex flex-1 list-none items-center justify-center space-x-1",
|
|
36
|
+
className
|
|
37
|
+
)}
|
|
38
|
+
{...props}
|
|
39
|
+
/>
|
|
40
|
+
))
|
|
41
|
+
NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
|
|
42
|
+
|
|
43
|
+
const NavigationMenuItem = NavigationMenuPrimitive.Item
|
|
44
|
+
|
|
45
|
+
export const navigationMenuTriggerStyle = cva(
|
|
46
|
+
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-muted hover:text-foreground focus:bg-muted focus:text-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-muted/50 data-[state=open]:bg-muted/50"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const NavigationMenuTrigger = React.forwardRef<
|
|
50
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Trigger>,
|
|
51
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Trigger>
|
|
52
|
+
>(({ className, children, ...props }, ref) => (
|
|
53
|
+
<NavigationMenuPrimitive.Trigger
|
|
54
|
+
ref={ref}
|
|
55
|
+
className={cn(navigationMenuTriggerStyle(), "group", className)}
|
|
56
|
+
{...props}
|
|
57
|
+
>
|
|
58
|
+
{children}{" "}
|
|
59
|
+
<ChevronDown
|
|
60
|
+
className="relative top-[1px] ml-1 h-3 w-3 transition duration-200 group-data-[state=open]:rotate-180"
|
|
61
|
+
aria-hidden
|
|
62
|
+
/>
|
|
63
|
+
</NavigationMenuPrimitive.Trigger>
|
|
64
|
+
))
|
|
65
|
+
NavigationMenuTrigger.displayName = NavigationMenuPrimitive.Trigger.displayName
|
|
66
|
+
|
|
67
|
+
const NavigationMenuContent = React.forwardRef<
|
|
68
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Content>,
|
|
69
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Content>
|
|
70
|
+
>(({ className, ...props }, ref) => (
|
|
71
|
+
<NavigationMenuPrimitive.Content
|
|
72
|
+
ref={ref}
|
|
73
|
+
className={cn(
|
|
74
|
+
"left-0 top-0 w-full data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 md:absolute md:w-auto",
|
|
75
|
+
className
|
|
76
|
+
)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
))
|
|
80
|
+
NavigationMenuContent.displayName = NavigationMenuPrimitive.Content.displayName
|
|
81
|
+
|
|
82
|
+
const NavigationMenuLink = NavigationMenuPrimitive.Link
|
|
83
|
+
|
|
84
|
+
const NavigationMenuViewport = React.forwardRef<
|
|
85
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
|
|
86
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
|
|
87
|
+
>(({ className, ...props }, ref) => (
|
|
88
|
+
<div className={cn("absolute left-1/2 top-full flex -translate-x-1/2 justify-center")}>
|
|
89
|
+
<NavigationMenuPrimitive.Viewport
|
|
90
|
+
className={cn(
|
|
91
|
+
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-[min(var(--radix-navigation-menu-viewport-width),calc(100vw-2rem))] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90",
|
|
92
|
+
className
|
|
93
|
+
)}
|
|
94
|
+
ref={ref}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
</div>
|
|
98
|
+
))
|
|
99
|
+
NavigationMenuViewport.displayName = NavigationMenuPrimitive.Viewport.displayName
|
|
100
|
+
|
|
101
|
+
const NavigationMenuIndicator = React.forwardRef<
|
|
102
|
+
React.ElementRef<typeof NavigationMenuPrimitive.Indicator>,
|
|
103
|
+
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Indicator>
|
|
104
|
+
>(({ className, ...props }, ref) => (
|
|
105
|
+
<NavigationMenuPrimitive.Indicator
|
|
106
|
+
ref={ref}
|
|
107
|
+
className={cn(
|
|
108
|
+
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden data-[state=visible]:animate-in data-[state=hidden]:animate-out data-[state=hidden]:fade-out data-[state=visible]:fade-in",
|
|
109
|
+
className
|
|
110
|
+
)}
|
|
111
|
+
{...props}
|
|
112
|
+
>
|
|
113
|
+
<div className="relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md" />
|
|
114
|
+
</NavigationMenuPrimitive.Indicator>
|
|
115
|
+
))
|
|
116
|
+
NavigationMenuIndicator.displayName =
|
|
117
|
+
NavigationMenuPrimitive.Indicator.displayName
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
NavigationMenu,
|
|
121
|
+
NavigationMenuList,
|
|
122
|
+
NavigationMenuItem,
|
|
123
|
+
NavigationMenuContent,
|
|
124
|
+
NavigationMenuTrigger,
|
|
125
|
+
NavigationMenuLink,
|
|
126
|
+
NavigationMenuIndicator,
|
|
127
|
+
NavigationMenuViewport,
|
|
128
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "../../lib/utils"
|
|
5
|
+
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "../display/Accordion"
|
|
6
|
+
import { RightRail } from "./RightRail"
|
|
7
|
+
|
|
8
|
+
export interface PageAsideProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
9
|
+
title: React.ReactNode
|
|
10
|
+
renderAside: () => React.ReactNode
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
asideLabel?: string
|
|
13
|
+
contentLabel?: string
|
|
14
|
+
mobileDescription?: React.ReactNode
|
|
15
|
+
defaultOpen?: boolean
|
|
16
|
+
width?: string
|
|
17
|
+
contentClassName?: string
|
|
18
|
+
mobileClassName?: string
|
|
19
|
+
railClassName?: string
|
|
20
|
+
railContentClassName?: string
|
|
21
|
+
openLabel?: string
|
|
22
|
+
closeLabel?: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const PageAside = React.forwardRef<HTMLDivElement, PageAsideProps>(
|
|
26
|
+
(
|
|
27
|
+
{
|
|
28
|
+
className,
|
|
29
|
+
title,
|
|
30
|
+
renderAside,
|
|
31
|
+
children,
|
|
32
|
+
asideLabel,
|
|
33
|
+
contentLabel,
|
|
34
|
+
mobileDescription,
|
|
35
|
+
defaultOpen = true,
|
|
36
|
+
width = "w-72",
|
|
37
|
+
contentClassName,
|
|
38
|
+
mobileClassName,
|
|
39
|
+
railClassName,
|
|
40
|
+
railContentClassName,
|
|
41
|
+
openLabel = "Open",
|
|
42
|
+
closeLabel = "Close",
|
|
43
|
+
...props
|
|
44
|
+
},
|
|
45
|
+
ref
|
|
46
|
+
) => {
|
|
47
|
+
const label = asideLabel ?? (typeof title === "string" ? title : undefined)
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<div ref={ref} className={cn("flex min-h-0 w-full flex-col lg:flex-row", className)} {...props}>
|
|
51
|
+
<div className={cn("min-w-0 flex-1", contentClassName)} aria-label={contentLabel}>
|
|
52
|
+
<aside className={cn("mb-4 rounded-md border bg-background p-3 lg:hidden", mobileClassName)} aria-label={label}>
|
|
53
|
+
<Accordion type="single" collapsible defaultValue={defaultOpen ? "page-aside" : undefined} className="w-full border-0">
|
|
54
|
+
<AccordionItem value="page-aside" className="border-0">
|
|
55
|
+
<AccordionTrigger className="px-0 py-0 text-left hover:no-underline" openLabel={openLabel} closeLabel={closeLabel}>
|
|
56
|
+
<span className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
57
|
+
{title}
|
|
58
|
+
</span>
|
|
59
|
+
</AccordionTrigger>
|
|
60
|
+
<AccordionContent className="px-0 pb-0 pt-3">
|
|
61
|
+
<div className="space-y-3">
|
|
62
|
+
{mobileDescription ? (
|
|
63
|
+
<p className="text-xs text-muted-foreground">{mobileDescription}</p>
|
|
64
|
+
) : null}
|
|
65
|
+
{renderAside()}
|
|
66
|
+
</div>
|
|
67
|
+
</AccordionContent>
|
|
68
|
+
</AccordionItem>
|
|
69
|
+
</Accordion>
|
|
70
|
+
</aside>
|
|
71
|
+
{children}
|
|
72
|
+
</div>
|
|
73
|
+
<RightRail width={width} className={cn("hidden bg-background lg:flex", railClassName)} aria-label={label}>
|
|
74
|
+
<div className={cn("space-y-5 p-4", railContentClassName)}>
|
|
75
|
+
{renderAside()}
|
|
76
|
+
</div>
|
|
77
|
+
</RightRail>
|
|
78
|
+
</div>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
PageAside.displayName = "PageAside"
|
|
83
|
+
|
|
84
|
+
export { PageAside }
|