From e1f5ff1533e441f63ada2a775f62249d73c19391 Mon Sep 17 00:00:00 2001 From: Peter Zimon Date: Mon, 20 Jan 2025 13:56:21 +0100 Subject: [PATCH] Shade updates (#22025) ref https://linear.app/ghost/issue/DES-1022/overview-tab-for-post-analytics - A static version of a React-only Post analytics page needed to be worked out to learn how Charts, Tabs, Sidebars etc. work in Shade. This also is a basis for learning more about React patterns. --- .../src/assets/icons/dotdotdot.svg | 10 +- apps/posts/src/App.tsx | 8 +- apps/posts/src/components/Header.tsx | 50 ++ apps/posts/src/components/layout/Header.tsx | 26 - .../overview/ClickPerformance.tsx | 22 - .../post-analytics/overview/Conversions.tsx | 22 - .../post-analytics/overview/Feedback.tsx | 22 - .../overview/NewsletterPerformance.tsx | 22 - apps/posts/src/pages/PostAnalytics.tsx | 47 -- .../views/post-analytics/PostAnalytics.tsx | 29 + .../post-analytics/components/Newsletter.tsx | 104 +++ .../post-analytics/components}/Overview.tsx | 6 +- .../post-analytics/components/StatsTabs.tsx | 57 ++ .../components/newsletter/ClickedList.tsx | 0 .../components/newsletter/FeedbackList.tsx | 0 .../components/newsletter/LinkList.tsx | 0 .../components/newsletter/OpenedList.tsx | 68 ++ .../components/newsletter/SentList.tsx | 89 ++ .../components/overview/ClickPerformance.tsx | 65 ++ .../components/overview/Conversions.tsx | 72 ++ .../components/overview/Feedback.tsx | 107 +++ .../components/overview/Metric.tsx | 31 + .../overview/NewsletterPerformance.tsx | 72 ++ apps/shade/package.json | 14 +- apps/shade/src/assets/icons/dotdotdot.svg | 10 +- apps/shade/src/components/layout/page.tsx | 2 +- apps/shade/src/components/ui/avatar.tsx | 48 ++ apps/shade/src/components/ui/badge.tsx | 38 + apps/shade/src/components/ui/card.tsx | 18 +- apps/shade/src/components/ui/chart.tsx | 363 +++++++++ .../shade/src/components/ui/dropdown-menu.tsx | 2 +- apps/shade/src/components/ui/input.tsx | 22 + apps/shade/src/components/ui/separator.tsx | 29 + apps/shade/src/components/ui/sheet.tsx | 140 ++++ apps/shade/src/components/ui/sidebar.tsx | 765 ++++++++++++++++++ apps/shade/src/components/ui/skeleton.tsx | 15 + apps/shade/src/components/ui/table.tsx | 120 +++ apps/shade/src/components/ui/tabs.tsx | 22 +- apps/shade/src/components/ui/tooltip.tsx | 30 + apps/shade/src/hooks/use-mobile.tsx | 19 + apps/shade/src/index.ts | 24 +- apps/shade/styles.css | 66 +- apps/shade/tailwind.config.cjs | 56 +- ghost/admin/public/assets/icons/dotdotdot.svg | 10 +- yarn.lock | 307 ++++++- 45 files changed, 2804 insertions(+), 245 deletions(-) create mode 100644 apps/posts/src/components/Header.tsx delete mode 100644 apps/posts/src/components/layout/Header.tsx delete mode 100644 apps/posts/src/components/post-analytics/overview/ClickPerformance.tsx delete mode 100644 apps/posts/src/components/post-analytics/overview/Conversions.tsx delete mode 100644 apps/posts/src/components/post-analytics/overview/Feedback.tsx delete mode 100644 apps/posts/src/components/post-analytics/overview/NewsletterPerformance.tsx delete mode 100644 apps/posts/src/pages/PostAnalytics.tsx create mode 100644 apps/posts/src/views/post-analytics/PostAnalytics.tsx create mode 100644 apps/posts/src/views/post-analytics/components/Newsletter.tsx rename apps/posts/src/{components/post-analytics => views/post-analytics/components}/Overview.tsx (76%) create mode 100644 apps/posts/src/views/post-analytics/components/StatsTabs.tsx create mode 100644 apps/posts/src/views/post-analytics/components/newsletter/ClickedList.tsx create mode 100644 apps/posts/src/views/post-analytics/components/newsletter/FeedbackList.tsx create mode 100644 apps/posts/src/views/post-analytics/components/newsletter/LinkList.tsx create mode 100644 apps/posts/src/views/post-analytics/components/newsletter/OpenedList.tsx create mode 100644 apps/posts/src/views/post-analytics/components/newsletter/SentList.tsx create mode 100644 apps/posts/src/views/post-analytics/components/overview/ClickPerformance.tsx create mode 100644 apps/posts/src/views/post-analytics/components/overview/Conversions.tsx create mode 100644 apps/posts/src/views/post-analytics/components/overview/Feedback.tsx create mode 100644 apps/posts/src/views/post-analytics/components/overview/Metric.tsx create mode 100644 apps/posts/src/views/post-analytics/components/overview/NewsletterPerformance.tsx create mode 100644 apps/shade/src/components/ui/avatar.tsx create mode 100644 apps/shade/src/components/ui/badge.tsx create mode 100644 apps/shade/src/components/ui/chart.tsx create mode 100644 apps/shade/src/components/ui/input.tsx create mode 100644 apps/shade/src/components/ui/separator.tsx create mode 100644 apps/shade/src/components/ui/sheet.tsx create mode 100644 apps/shade/src/components/ui/sidebar.tsx create mode 100644 apps/shade/src/components/ui/skeleton.tsx create mode 100644 apps/shade/src/components/ui/table.tsx create mode 100644 apps/shade/src/components/ui/tooltip.tsx create mode 100644 apps/shade/src/hooks/use-mobile.tsx diff --git a/apps/admin-x-design-system/src/assets/icons/dotdotdot.svg b/apps/admin-x-design-system/src/assets/icons/dotdotdot.svg index 5a6a5fbe2a..743cb1af5e 100644 --- a/apps/admin-x-design-system/src/assets/icons/dotdotdot.svg +++ b/apps/admin-x-design-system/src/assets/icons/dotdotdot.svg @@ -1,10 +1,10 @@ - - - - \ No newline at end of file + + + + diff --git a/apps/posts/src/App.tsx b/apps/posts/src/App.tsx index c5010a29ad..886b30abfc 100644 --- a/apps/posts/src/App.tsx +++ b/apps/posts/src/App.tsx @@ -1,7 +1,7 @@ -import PostAnalytics from './pages/PostAnalytics'; +import PostAnalytics from './views/post-analytics/PostAnalytics'; import {FrameworkProvider, TopLevelFrameworkProps} from '@tryghost/admin-x-framework'; import {RoutingProvider} from '@tryghost/admin-x-framework/routing'; -import {ShadeApp, ShadeAppProps} from '@tryghost/shade'; +import {ShadeApp, ShadeAppProps, SidebarProvider} from '@tryghost/shade'; interface AppProps { framework: TopLevelFrameworkProps; @@ -13,7 +13,9 @@ const App: React.FC = ({framework, designSystem}) => { - + + + diff --git a/apps/posts/src/components/Header.tsx b/apps/posts/src/components/Header.tsx new file mode 100644 index 0000000000..b81486d0dd --- /dev/null +++ b/apps/posts/src/components/Header.tsx @@ -0,0 +1,50 @@ +import {Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, H1, LucideIcon} from '@tryghost/shade'; + +interface headerProps {}; + +const Header: React.FC = () => { + return ( +
+
+ + + + + Posts + + + + + + Analytics + + + + +
+ + + + + + + + Edit post + ⇧⌘E + + + View in browser + ⇧⌘O + + + Delete + + +
+
+

The Evolution of Basketball: From Pastime to Professional and One of the Most Popular Sports

+
+ ); +}; + +export default Header; diff --git a/apps/posts/src/components/layout/Header.tsx b/apps/posts/src/components/layout/Header.tsx deleted file mode 100644 index 5fd1ba2126..0000000000 --- a/apps/posts/src/components/layout/Header.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import {Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, H1} from '@tryghost/shade'; - -const Header = () => { - return ( -
- - - - - Posts - - - - - - Analytics - - - - -

The Evolution of Basketball: From Pastime to Professional and One of the Most Popular Sports

-
- ); -}; - -export default Header; diff --git a/apps/posts/src/components/post-analytics/overview/ClickPerformance.tsx b/apps/posts/src/components/post-analytics/overview/ClickPerformance.tsx deleted file mode 100644 index 50189e293a..0000000000 --- a/apps/posts/src/components/post-analytics/overview/ClickPerformance.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@tryghost/shade'; - -interface ClickPerformanceProps extends React.ComponentProps {}; - -const ClickPerformance: React.FC = (props) => { - return ( - - - Click performance - - Links in this newsletter - - - - Card contents - - - ); -}; - -export default ClickPerformance; diff --git a/apps/posts/src/components/post-analytics/overview/Conversions.tsx b/apps/posts/src/components/post-analytics/overview/Conversions.tsx deleted file mode 100644 index ec3f2ff00b..0000000000 --- a/apps/posts/src/components/post-analytics/overview/Conversions.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@tryghost/shade'; - -interface ConversionsProps extends React.ComponentProps {}; - -const Conversions: React.FC = (props) => { - return ( - - - Conversions - - 3 members signed up on this post - - - - Card contents - - - ); -}; - -export default Conversions; diff --git a/apps/posts/src/components/post-analytics/overview/Feedback.tsx b/apps/posts/src/components/post-analytics/overview/Feedback.tsx deleted file mode 100644 index 0e0b7d48e8..0000000000 --- a/apps/posts/src/components/post-analytics/overview/Feedback.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@tryghost/shade'; - -interface FeedbackProps extends React.ComponentProps {}; - -const Feedback: React.FC = (props) => { - return ( - - - Feedback - - 188 reactions - - - - Card contents - - - ); -}; - -export default Feedback; diff --git a/apps/posts/src/components/post-analytics/overview/NewsletterPerformance.tsx b/apps/posts/src/components/post-analytics/overview/NewsletterPerformance.tsx deleted file mode 100644 index 9f4397cf8b..0000000000 --- a/apps/posts/src/components/post-analytics/overview/NewsletterPerformance.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from 'react'; -import {Card, CardContent, CardDescription, CardHeader, CardTitle} from '@tryghost/shade'; - -interface NewsletterPerformanceProps extends React.ComponentProps {}; - -const NewsletterPerformance: React.FC = (props) => { - return ( - - - Newsletter performance - - Sent 19 Sept 2024 - - - - Card contents - - - ); -}; - -export default NewsletterPerformance; diff --git a/apps/posts/src/pages/PostAnalytics.tsx b/apps/posts/src/pages/PostAnalytics.tsx deleted file mode 100644 index 34a0d75610..0000000000 --- a/apps/posts/src/pages/PostAnalytics.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import Header from '../components/layout/Header'; -import Overview from '../components/post-analytics/Overview'; -import {Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, Icon, Page, Tabs, TabsContent, TabsList, TabsTrigger} from '@tryghost/shade'; - -const PostAnalytics = () => { - return ( - -
- -
- - Overview - Newsletter - -
- - - - - - - - Edit post - ⇧⌘E - - - View in browser - ⇧⌘O - - - Delete - - -
-
- - - - - Newsletter details - -
- - ); -}; - -export default PostAnalytics; diff --git a/apps/posts/src/views/post-analytics/PostAnalytics.tsx b/apps/posts/src/views/post-analytics/PostAnalytics.tsx new file mode 100644 index 0000000000..90cb9a8c64 --- /dev/null +++ b/apps/posts/src/views/post-analytics/PostAnalytics.tsx @@ -0,0 +1,29 @@ +import Header from '../../components/Header'; +import Newsletter from './components/Newsletter'; +import Overview from './components/Overview'; +import {LucideIcon, Page, Tabs, TabsContent, TabsList, TabsTrigger} from '@tryghost/shade'; + +interface postAnalyticsProps {}; + +const PostAnalytics: React.FC = () => { + return ( + +
+ + + Overview + Newsletter + Web + + + + + + + + + + ); +}; + +export default PostAnalytics; diff --git a/apps/posts/src/views/post-analytics/components/Newsletter.tsx b/apps/posts/src/views/post-analytics/components/Newsletter.tsx new file mode 100644 index 0000000000..8982064470 --- /dev/null +++ b/apps/posts/src/views/post-analytics/components/Newsletter.tsx @@ -0,0 +1,104 @@ +import OpenedList from './newsletter/OpenedList'; +import React from 'react'; +import SentList from './newsletter/SentList'; +import {Badge} from '@tryghost/shade'; +import {StatsTabItem, StatsTabTitle, StatsTabValue, StatsTabs, StatsTabsGroup} from './StatsTabs'; + +interface newsletterProps {}; + +const Newsletter: React.FC = () => { + const tabs = [ + [ + { + key: 'sent', + title: 'Sent', + value: '1,697', + badge: '', + content: + }, + { + key: 'opened', + title: 'Opened', + value: '560', + badge: '75%', + content: + }, + { + key: 'clicked', + title: 'Clicked', + value: '21', + badge: '18%', + content: + } + ], + [ + { + key: 'unsubscribed', + title: 'Unsubscribed', + value: '21', + badge: '', + content: + }, + { + key: 'feedback', + title: 'Feedback', + value: '5', + badge: '', + content: + }, + { + key: 'spam', + title: 'Marked as spam', + value: '17', + badge: '', + content: + }, + { + key: 'bounced', + title: 'Bounced', + value: '81', + badge: '', + content: + } + ] + ]; + + const [currentTab, setCurrentTab] = React.useState(tabs[0][0].key); + + const Content: React.FC = () => { + return tabs.map((tabGroup) => { + const selectedTab = tabGroup.find(tab => tab.key === currentTab); + return selectedTab?.content; + }); + }; + + return ( +
+
+ +
+
+ + {tabs.map(group => ( + + {group.map(item => ( + { + setCurrentTab(item.key); + }}> + + {item.title} + {item.badge && {item.badge}} + + {item.value} + + ))} + + ) + )} + +
+
+ ); +}; + +export default Newsletter; diff --git a/apps/posts/src/components/post-analytics/Overview.tsx b/apps/posts/src/views/post-analytics/components/Overview.tsx similarity index 76% rename from apps/posts/src/components/post-analytics/Overview.tsx rename to apps/posts/src/views/post-analytics/components/Overview.tsx index 73f086c174..c1392fc7f9 100644 --- a/apps/posts/src/components/post-analytics/Overview.tsx +++ b/apps/posts/src/views/post-analytics/components/Overview.tsx @@ -3,9 +3,11 @@ import Conversions from './overview/Conversions'; import Feedback from './overview/Feedback'; import NewsletterPerformance from './overview/NewsletterPerformance'; -const Overview = () => { +interface overviewProps {}; + +const Overview: React.FC = () => { return ( -
+
diff --git a/apps/posts/src/views/post-analytics/components/StatsTabs.tsx b/apps/posts/src/views/post-analytics/components/StatsTabs.tsx new file mode 100644 index 0000000000..3a79d034bc --- /dev/null +++ b/apps/posts/src/views/post-analytics/components/StatsTabs.tsx @@ -0,0 +1,57 @@ +import * as React from 'react'; +import {Button, ButtonProps} from '@tryghost/shade'; +import {cn} from '@tryghost/shade'; + +interface statsTabsProps + extends React.HTMLAttributes {} + +const StatsTabs: React.FC = ({className, ...props}) => { + return
; +}; + +interface statsTabsGroupProps + extends React.HTMLAttributes {}; + +const StatsTabsGroup: React.FC = ({className, ...props}) => { + return
; +}; + +interface subNavItemProps extends ButtonProps { + isActive?: boolean; +} + +const StatsTabItem: React.FC = ({isActive, ...props}) => { + const subNavItemClasses = cn( + 'flex flex-col items-start h-auto py-3 gap-0 border border-border group/item', + isActive ? 'bg-muted/70' : 'border-gray-200 hover:bg-muted/50' + ); + return ( + + + + ); +}; + +export default ClickPerformance; diff --git a/apps/posts/src/views/post-analytics/components/overview/Conversions.tsx b/apps/posts/src/views/post-analytics/components/overview/Conversions.tsx new file mode 100644 index 0000000000..4d6cd21b1b --- /dev/null +++ b/apps/posts/src/views/post-analytics/components/overview/Conversions.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import {Avatar, AvatarFallback, AvatarImage, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@tryghost/shade'; + +interface ConversionsProps extends React.ComponentProps {}; + +const Conversions: React.FC = (props) => { + const mockData = [ + { + name: 'Gustavo Kenter', + tier: 'Gold', + avatarImage: 'https://i.pravatar.cc/150?img=1', + avatarFallback: 'GK', + receiveDate: 'A month ago' + }, + { + name: 'Kadin Botosh', + tier: 'Free', + avatarImage: '', + avatarFallback: 'KB', + receiveDate: 'A month ago' + }, + { + name: 'Skylar Lipshutz', + tier: 'Free', + avatarImage: 'https://i.pravatar.cc/150?img=2', + avatarFallback: 'SL', + receiveDate: 'A month ago' + } + ]; + + return ( + + + Conversions + + 3 members signed up on this post + + + + + + + Member + Tier + + + + {mockData.map(member => ( + + +
+ + + {member.avatarFallback} + + {member.name} +
+
+ {member.tier} +
+ ))} +
+
+
+ + + +
+ ); +}; + +export default Conversions; diff --git a/apps/posts/src/views/post-analytics/components/overview/Feedback.tsx b/apps/posts/src/views/post-analytics/components/overview/Feedback.tsx new file mode 100644 index 0000000000..b6c6bd1f96 --- /dev/null +++ b/apps/posts/src/views/post-analytics/components/overview/Feedback.tsx @@ -0,0 +1,107 @@ +import * as React from 'react'; +import {Card, CardContent, CardDescription, CardHeader, CardTitle, ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, Recharts, Separator} from '@tryghost/shade'; +import {Metric, MetricLabel, MetricValue} from './Metric'; + +interface FeedbackProps extends React.ComponentProps {}; + +const Feedback: React.FC = (props) => { + const chartData = React.useMemo(() => { + return [ + {browser: 'chrome', visitors: 98, fill: 'var(--color-chrome)'}, + {browser: 'safari', visitors: 17, fill: 'var(--color-safari)'} + ]; + }, []); + + const chartConfig = { + visitors: { + label: 'Reactions' + }, + chrome: { + label: 'More like this', + color: 'hsl(var(--chart-1))' + }, + safari: { + label: 'Less like this', + color: 'hsl(var(--chart-5))' + } + } satisfies ChartConfig; + + const totalVisitors = React.useMemo(() => { + return chartData.reduce((acc, curr) => acc + curr.visitors, 0); + }, [chartData]); + + return ( + + + Feedback + + 188 reactions + + + + +
+ + More like this + 98 + + + + Less like this + 17 + +
+ + + } + cursor={false} + /> + + { + if (viewBox && 'cx' in viewBox && 'cy' in viewBox) { + return ( + + + {totalVisitors.toLocaleString()} + + + Reactions + + + ); + } + }} + /> + + + +
+
+ ); +}; + +export default Feedback; diff --git a/apps/posts/src/views/post-analytics/components/overview/Metric.tsx b/apps/posts/src/views/post-analytics/components/overview/Metric.tsx new file mode 100644 index 0000000000..5ce2f87463 --- /dev/null +++ b/apps/posts/src/views/post-analytics/components/overview/Metric.tsx @@ -0,0 +1,31 @@ +import * as React from 'react'; +import {cn} from '@tryghost/shade'; + +export interface metricDivProps + extends React.HTMLAttributes {} + +const Metric = ({className, ...props}: metricDivProps) => { + return ( +
+ ); +}; + +const MetricLabel = ({className, ...props}: metricDivProps) => { + return ( +
+ ); +}; + +const MetricValue = ({className, ...props}: metricDivProps) => { + return ( +
+ ); +}; + +const MetricPercentage = ({className, ...props}: metricDivProps) => { + return ( +
+ ); +}; + +export {Metric, MetricLabel, MetricValue, MetricPercentage}; diff --git a/apps/posts/src/views/post-analytics/components/overview/NewsletterPerformance.tsx b/apps/posts/src/views/post-analytics/components/overview/NewsletterPerformance.tsx new file mode 100644 index 0000000000..db7a7f94cb --- /dev/null +++ b/apps/posts/src/views/post-analytics/components/overview/NewsletterPerformance.tsx @@ -0,0 +1,72 @@ +import * as React from 'react'; +import {Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartTooltip, ChartTooltipContent, Recharts, Separator} from '@tryghost/shade'; +import {Metric, MetricLabel, MetricPercentage, MetricValue} from './Metric'; + +interface NewsletterPerformanceProps extends React.ComponentProps {}; + +const NewsletterPerformance: React.FC = (props) => { + const chartData = [ + {metric: 'Sent', current: 1697, avg: 1524}, + {metric: 'Opened', current: 1184, avg: 867}, + {metric: 'Clicked', current: 750, avg: 478} + ]; + + const chartConfig = { + current: { + label: 'This post', + color: 'hsl(var(--chart-1))' + }, + avg: { + label: 'Your average post', + color: 'hsl(var(--chart-5))' + } + } satisfies ChartConfig; + + return ( + + + Newsletter performance + + Sent 19 Sept 2024 + + + + +
+ + Sent + 1,697 + + + + Opened + 1,184 69% + + + + Clicked + 750 44% + +
+ + + + + } /> + } /> + + + + +
+
+ ); +}; + +export default NewsletterPerformance; diff --git a/apps/shade/package.json b/apps/shade/package.json index 084b146a2b..f140fc9e9f 100644 --- a/apps/shade/package.json +++ b/apps/shade/package.json @@ -67,28 +67,30 @@ "@ebay/nice-modal-react": "1.2.13", "@radix-ui/react-avatar": "1.1.0", "@radix-ui/react-checkbox": "1.1.1", + "@radix-ui/react-dialog": "^1.1.4", "@radix-ui/react-dropdown-menu": "2.1.3", "@radix-ui/react-form": "0.0.3", "@radix-ui/react-popover": "1.1.1", "@radix-ui/react-radio-group": "1.2.0", - "@radix-ui/react-separator": "1.1.0", - "@radix-ui/react-slot": "1.1.1", + "@radix-ui/react-separator": "^1.1.1", + "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-switch": "1.1.0", "@radix-ui/react-tabs": "1.1.2", - "@radix-ui/react-tooltip": "1.1.2", + "@radix-ui/react-tooltip": "^1.1.6", "@sentry/react": "7.119.2", "@tailwindcss/forms": "0.5.9", "@tailwindcss/line-clamp": "0.4.4", "@uiw/react-codemirror": "4.23.7", "autoprefixer": "10.4.19", - "class-variance-authority": "0.7.1", + "class-variance-authority": "^0.7.1", "clsx": "2.1.1", - "lucide-react": "0.468.0", + "lucide-react": "^0.471.1", "postcss": "8.4.39", "postcss-import": "16.1.0", "react-colorful": "5.6.1", "react-hot-toast": "2.5.1", "react-select": "5.8.2", + "recharts": "^2.15.0", "tailwind-merge": "2.6.0", "tailwindcss": "3.4.14", "tailwindcss-animate": "1.0.7" @@ -97,4 +99,4 @@ "react": "^18.2.0", "react-dom": "^18.2.0" } -} \ No newline at end of file +} diff --git a/apps/shade/src/assets/icons/dotdotdot.svg b/apps/shade/src/assets/icons/dotdotdot.svg index 5a6a5fbe2a..743cb1af5e 100644 --- a/apps/shade/src/assets/icons/dotdotdot.svg +++ b/apps/shade/src/assets/icons/dotdotdot.svg @@ -1,10 +1,10 @@ - - - - \ No newline at end of file + + + + diff --git a/apps/shade/src/components/layout/page.tsx b/apps/shade/src/components/layout/page.tsx index c11775bed3..50db1085e0 100644 --- a/apps/shade/src/components/layout/page.tsx +++ b/apps/shade/src/components/layout/page.tsx @@ -9,7 +9,7 @@ const Page = React.forwardRef( return (
); diff --git a/apps/shade/src/components/ui/avatar.tsx b/apps/shade/src/components/ui/avatar.tsx new file mode 100644 index 0000000000..18bd105b11 --- /dev/null +++ b/apps/shade/src/components/ui/avatar.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import * as AvatarPrimitive from '@radix-ui/react-avatar'; + +import {cn} from '@/lib/utils'; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({className, ...props}, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export {Avatar, AvatarImage, AvatarFallback}; diff --git a/apps/shade/src/components/ui/badge.tsx b/apps/shade/src/components/ui/badge.tsx new file mode 100644 index 0000000000..7d860f70c1 --- /dev/null +++ b/apps/shade/src/components/ui/badge.tsx @@ -0,0 +1,38 @@ +import * as React from 'react'; +import {cva, type VariantProps} from 'class-variance-authority'; + +import {cn} from '@/lib/utils'; + +const badgeVariants = cva( + 'inline-flex items-center rounded-sm border px-1.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', + { + variants: { + variant: { + default: + 'border-transparent bg-primary text-primary-foreground', + secondary: + 'border-transparent bg-secondary text-secondary-foreground/70', + destructive: + 'border-transparent bg-destructive/20 text-destructive', + success: + 'border-transparent bg-green/20 text-green', + outline: 'text-foreground' + } + }, + defaultVariants: { + variant: 'default' + } + } +); + +export interface BadgeProps +extends React.HTMLAttributes, + VariantProps {} + +function Badge({className, variant, ...props}: BadgeProps) { + return ( +
+ ); +} + +export {Badge, badgeVariants}; diff --git a/apps/shade/src/components/ui/card.tsx b/apps/shade/src/components/ui/card.tsx index 88ffb88313..9f252bb982 100644 --- a/apps/shade/src/components/ui/card.tsx +++ b/apps/shade/src/components/ui/card.tsx @@ -9,7 +9,7 @@ const Card = React.forwardRef<
(({className, ...props}, ref) => (
)); @@ -35,7 +35,7 @@ const CardTitle = React.forwardRef< >(({className, ...props}, ref) => (
)); @@ -65,11 +65,13 @@ const CardFooter = React.forwardRef< HTMLDivElement, React.HTMLAttributes >(({className, ...props}, ref) => ( -
+
+
+
)); CardFooter.displayName = 'CardFooter'; diff --git a/apps/shade/src/components/ui/chart.tsx b/apps/shade/src/components/ui/chart.tsx new file mode 100644 index 0000000000..1b3ffc3370 --- /dev/null +++ b/apps/shade/src/components/ui/chart.tsx @@ -0,0 +1,363 @@ +import * as React from 'react'; +import * as RechartsPrimitive from 'recharts'; + +import {cn} from '@/lib/utils'; + +// Format: { THEME_NAME: CSS_SELECTOR } +const THEMES = {light: '', dark: '.dark'} as const; + +export type ChartConfig = { +[k in string]: { + label?: React.ReactNode + icon?: React.ComponentType +} & ( + | { color?: string; theme?: never } + | { color?: never; theme: Record } +) +} + +type ChartContextProps = { +config: ChartConfig +} + +const ChartContext = React.createContext(null); + +function useChart() { + const context = React.useContext(ChartContext); + + if (!context) { + throw new Error('useChart must be used within a '); + } + + return context; +} + +const ChartContainer = React.forwardRef< +HTMLDivElement, +React.ComponentProps<'div'> & { + config: ChartConfig + children: React.ComponentProps< + typeof RechartsPrimitive.ResponsiveContainer + >['children'] +} +>(({id, className, children, config, ...props}, ref) => { + const uniqueId = React.useId(); + const chartId = `chart-${id || uniqueId.replace(/:/g, '')}`; + + return ( + +
+ + + {children} + +
+
+ ); +}); +ChartContainer.displayName = 'Chart'; + +const ChartStyle = ({id, config}: { id: string; config: ChartConfig }) => { + const colorConfig = Object.entries(config).filter( + ([, themeConfig]) => themeConfig.theme || themeConfig.color + ); + + if (!colorConfig.length) { + return null; + } + + return ( + - - - - \ No newline at end of file + + + + diff --git a/yarn.lock b/yarn.lock index 4622e76993..882f25dc33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4351,6 +4351,26 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a" integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q== +"@radix-ui/react-dialog@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.4.tgz#d68e977acfcc0d044b9dab47b6dd2c179d2b3191" + integrity sha512-Ur7EV1IwQGCyaAuyDRiOLA5JIUZxELJljF+MbM/2NC0BYwfuRrbpS30BiQBJrVruscgUkieKkqXYDOoByaxIoA== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.3" + "@radix-ui/react-focus-guards" "1.1.1" + "@radix-ui/react-focus-scope" "1.1.1" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-portal" "1.1.3" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.1" + "@radix-ui/react-slot" "1.1.1" + "@radix-ui/react-use-controllable-state" "1.1.0" + aria-hidden "^1.1.1" + react-remove-scroll "^2.6.1" + "@radix-ui/react-direction@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b" @@ -4397,6 +4417,17 @@ "@radix-ui/react-use-callback-ref" "1.1.0" "@radix-ui/react-use-escape-keydown" "1.1.0" +"@radix-ui/react-dismissable-layer@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.3.tgz#4ee0f0f82d53bf5bd9db21665799bb0d1bad5ed8" + integrity sha512-onrWn/72lQoEucDmJnr8uczSNTujT0vJnA/X5+3AkChVPowr8n1yvIKIabhWyMQeMvvmdpsvcyDqx3X1LEXCPg== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-primitive" "2.0.1" + "@radix-ui/react-use-callback-ref" "1.1.0" + "@radix-ui/react-use-escape-keydown" "1.1.0" + "@radix-ui/react-dropdown-menu@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.3.tgz#02665f99bfdcefc33a8a15dc130e9b98ebdf7671" @@ -4752,6 +4783,13 @@ dependencies: "@radix-ui/react-primitive" "2.0.0" +"@radix-ui/react-separator@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.1.tgz#dd60621553c858238d876be9b0702287424866d2" + integrity sha512-RRiNRSrD8iUiXriq/Y5n4/3iE8HzqgLHsusUSg5jVpU2+3tqcUFPJXHDymwEypunc2sWxDUS3UC+rkZRlHedsw== + dependencies: + "@radix-ui/react-primitive" "2.0.1" + "@radix-ui/react-slot@1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" @@ -4767,7 +4805,7 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.0" -"@radix-ui/react-slot@1.1.1": +"@radix-ui/react-slot@1.1.1", "@radix-ui/react-slot@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.1.tgz#ab9a0ffae4027db7dc2af503c223c978706affc3" integrity sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g== @@ -4871,6 +4909,24 @@ "@radix-ui/react-use-controllable-state" "1.1.0" "@radix-ui/react-visually-hidden" "1.1.0" +"@radix-ui/react-tooltip@^1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.1.6.tgz#eab98e9a5c876ef0abfae3cfeee229870528ed06" + integrity sha512-TLB5D8QLExS1uDn7+wH/bjEmRurNMTzNrtq7IjaS4kjion9NtzsTGkvR5+i7yc9q01Pi2KMM2cN3f8UG4IvvXA== + dependencies: + "@radix-ui/primitive" "1.1.1" + "@radix-ui/react-compose-refs" "1.1.1" + "@radix-ui/react-context" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.3" + "@radix-ui/react-id" "1.1.0" + "@radix-ui/react-popper" "1.2.1" + "@radix-ui/react-portal" "1.1.3" + "@radix-ui/react-presence" "1.1.2" + "@radix-ui/react-primitive" "2.0.1" + "@radix-ui/react-slot" "1.1.1" + "@radix-ui/react-use-controllable-state" "1.1.0" + "@radix-ui/react-visually-hidden" "1.1.1" + "@radix-ui/react-use-callback-ref@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" @@ -4982,6 +5038,13 @@ dependencies: "@radix-ui/react-primitive" "2.0.0" +"@radix-ui/react-visually-hidden@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.1.tgz#f7b48c1af50dfdc366e92726aee6d591996c5752" + integrity sha512-vVfA2IZ9q/J+gEamvj761Oq1FpWgCDaNOOIfbPVp2MVPLEomUr5+Vf7kJGwQ24YxZSlQVar7Bes8kyTo5Dshpg== + dependencies: + "@radix-ui/react-primitive" "2.0.1" + "@radix-ui/rect@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f" @@ -8240,6 +8303,57 @@ dependencies: "@types/node" "*" +"@types/d3-array@^3.0.3": + version "3.2.1" + resolved "https://registry.yarnpkg.com/@types/d3-array/-/d3-array-3.2.1.tgz#1f6658e3d2006c4fceac53fde464166859f8b8c5" + integrity sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg== + +"@types/d3-color@*": + version "3.1.3" + resolved "https://registry.yarnpkg.com/@types/d3-color/-/d3-color-3.1.3.tgz#368c961a18de721da8200e80bf3943fb53136af2" + integrity sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A== + +"@types/d3-ease@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-ease/-/d3-ease-3.0.2.tgz#e28db1bfbfa617076f7770dd1d9a48eaa3b6c51b" + integrity sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA== + +"@types/d3-interpolate@^3.0.1": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz#412b90e84870285f2ff8a846c6eb60344f12a41c" + integrity sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA== + dependencies: + "@types/d3-color" "*" + +"@types/d3-path@*": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/d3-path/-/d3-path-3.1.0.tgz#2b907adce762a78e98828f0b438eaca339ae410a" + integrity sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ== + +"@types/d3-scale@^4.0.2": + version "4.0.8" + resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-4.0.8.tgz#d409b5f9dcf63074464bf8ddfb8ee5a1f95945bb" + integrity sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ== + dependencies: + "@types/d3-time" "*" + +"@types/d3-shape@^3.1.0": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/d3-shape/-/d3-shape-3.1.7.tgz#2b7b423dc2dfe69c8c93596e673e37443348c555" + integrity sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg== + dependencies: + "@types/d3-path" "*" + +"@types/d3-time@*", "@types/d3-time@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/d3-time/-/d3-time-3.0.4.tgz#8472feecd639691450dd8000eb33edd444e1323f" + integrity sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g== + +"@types/d3-timer@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/d3-timer/-/d3-timer-3.0.2.tgz#70bbda77dc23aa727413e22e214afa3f0e852f70" + integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw== + "@types/detect-port@^1.3.0": version "1.3.2" resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.2.tgz#8c06a975e472803b931ee73740aeebd0a2eb27ae" @@ -12795,7 +12909,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -class-variance-authority@0.7.1: +class-variance-authority@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz#4008a798a0e4553a781a57ac5177c9fb5d043787" integrity sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg== @@ -12986,7 +13100,7 @@ clone@~0.1.9: resolved "https://registry.yarnpkg.com/clone/-/clone-0.1.19.tgz#613fb68639b26a494ac53253e15b1a6bd88ada85" integrity sha512-IO78I0y6JcSpEPHzK4obKdsL7E7oLdRVDVOLwr2Hkbjsb+Eoz0dxW6tef0WizoKu0gLC4oZSZuEF4U2K6w1WQw== -clsx@2.1.1, clsx@^2.1.1: +clsx@2.1.1, clsx@^2.0.0, clsx@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== @@ -14057,6 +14171,77 @@ cyclist@^1.0.1: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" integrity sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A== +"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6: + version "3.2.4" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.4.tgz#15fec33b237f97ac5d7c986dc77da273a8ed0bb5" + integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg== + dependencies: + internmap "1 - 2" + +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + +d3-ease@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-format@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + +"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +d3-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.1.0.tgz#22df939032fb5a71ae8b1800d61ddb7851c42526" + integrity sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ== + +d3-scale@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + +d3-shape@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.2.0.tgz#a1a839cbd9ba45f28674c69d7f855bcf91dfc6a5" + integrity sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA== + dependencies: + d3-path "^3.1.0" + +"d3-time-format@2 - 4": + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + +"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.1.0.tgz#9310db56e992e3c0175e1ef385e545e48a9bb5c7" + integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q== + dependencies: + d3-array "2 - 3" + +d3-timer@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + dag-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" @@ -14187,6 +14372,11 @@ decamelize@^5.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-5.0.1.tgz#db11a92e58c741ef339fb0a2868d8a06a9a7b1e9" integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== +decimal.js-light@^2.4.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/decimal.js-light/-/decimal.js-light-2.5.1.tgz#134fd32508f19e208f4fb2f8dac0d2626a867934" + integrity sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg== + decimal.js@^10.2.1, decimal.js@^10.4.3: version "10.4.3" resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" @@ -17185,7 +17375,7 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -eventemitter3@^4.0.0: +eventemitter3@^4.0.0, eventemitter3@^4.0.1: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -17621,6 +17811,11 @@ fast-deep-equal@^3, fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-equals@^5.0.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-5.2.2.tgz#885d7bfb079fac0ce0e8450374bce29e9b742484" + integrity sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw== + fast-fifo@^1.1.0, fast-fifo@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" @@ -19978,6 +20173,11 @@ internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + interpret@^2.0.0, interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" @@ -22791,10 +22991,10 @@ ltgt@^2.1.2: resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== -lucide-react@0.468.0: - version "0.468.0" - resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.468.0.tgz#830c1bfd905575ddd23b832baa420c87db166910" - integrity sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA== +lucide-react@^0.471.1: + version "0.471.1" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.471.1.tgz#16f29cd65c7c847eceab0bbf8592443104423249" + integrity sha512-syOxwPhf62gg2YOsz72HRn+CIpeudFy67AeKnSR8Hn/fIIF4ubhNbRF+pQ2CaJrl+X9Os4PL87z2DXQi3DVeDA== luxon@3.5.0, luxon@^3.5.0: version "3.5.0" @@ -27310,6 +27510,11 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== +react-is@^18.3.1: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -27323,6 +27528,14 @@ react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4, react-remove-scr react-style-singleton "^2.2.1" tslib "^2.0.0" +react-remove-scroll-bar@^2.3.7: + version "2.3.8" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223" + integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q== + dependencies: + react-style-singleton "^2.2.2" + tslib "^2.0.0" + react-remove-scroll@2.5.5: version "2.5.5" resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" @@ -27356,6 +27569,17 @@ react-remove-scroll@2.6.0: use-callback-ref "^1.3.0" use-sidecar "^1.1.2" +react-remove-scroll@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.2.tgz#2518d2c5112e71ea8928f1082a58459b5c7a2a97" + integrity sha512-KmONPx5fnlXYJQqC62Q+lwIeAk64ws/cUw6omIumRzMRPqgnYqhSSti99nbj0Ry13bv7dF+BKn7NB+OqkdZGTw== + dependencies: + react-remove-scroll-bar "^2.3.7" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.3" + use-sidecar "^1.1.2" + react-select@5.8.2: version "5.8.2" resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.8.2.tgz#0d7ccb1895d61aafcd090fbf65aa9e506225a854" @@ -27371,6 +27595,15 @@ react-select@5.8.2: react-transition-group "^4.3.0" use-isomorphic-layout-effect "^1.1.2" +react-smooth@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-4.0.4.tgz#a5875f8bb61963ca61b819cedc569dc2453894b4" + integrity sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q== + dependencies: + fast-equals "^5.0.1" + prop-types "^15.8.1" + react-transition-group "^4.4.5" + react-string-replace@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/react-string-replace/-/react-string-replace-1.1.1.tgz#8413a598c60e397fe77df3464f2889f00ba25989" @@ -27385,7 +27618,15 @@ react-style-singleton@^2.2.1: invariant "^2.2.4" tslib "^2.0.0" -react-transition-group@^4.3.0: +react-style-singleton@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388" + integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ== + dependencies: + get-nonce "^1.0.0" + tslib "^2.0.0" + +react-transition-group@^4.3.0, react-transition-group@^4.4.5: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g== @@ -27548,6 +27789,27 @@ recast@^0.23.1, recast@^0.23.3: source-map "~0.6.1" tslib "^2.0.1" +recharts-scale@^0.4.4: + version "0.4.5" + resolved "https://registry.yarnpkg.com/recharts-scale/-/recharts-scale-0.4.5.tgz#0969271f14e732e642fcc5bd4ab270d6e87dd1d9" + integrity sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w== + dependencies: + decimal.js-light "^2.4.1" + +recharts@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/recharts/-/recharts-2.15.0.tgz#0b77bff57a43885df9769ae649a14cb1a7fe19aa" + integrity sha512-cIvMxDfpAmqAmVgc4yb7pgm/O1tmmkl/CjrvXuW+62/+7jj/iF9Ykm+hb/UJt42TREHMyd3gb+pkgoa2MxgDIw== + dependencies: + clsx "^2.0.0" + eventemitter3 "^4.0.1" + lodash "^4.17.21" + react-is "^18.3.1" + react-smooth "^4.0.0" + recharts-scale "^0.4.4" + tiny-invariant "^1.3.1" + victory-vendor "^36.6.8" + rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -31331,6 +31593,13 @@ use-callback-ref@^1.3.0: dependencies: tslib "^2.0.0" +use-callback-ref@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" + integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== + dependencies: + tslib "^2.0.0" + use-debounce@10.0.4: version "10.0.4" resolved "https://registry.yarnpkg.com/use-debounce/-/use-debounce-10.0.4.tgz#2135be498ad855416c4495cfd8e0e130bd33bb24" @@ -31557,6 +31826,26 @@ vfile@^4.0.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" +victory-vendor@^36.6.8: + version "36.9.2" + resolved "https://registry.yarnpkg.com/victory-vendor/-/victory-vendor-36.9.2.tgz#668b02a448fa4ea0f788dbf4228b7e64669ff801" + integrity sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ== + dependencies: + "@types/d3-array" "^3.0.3" + "@types/d3-ease" "^3.0.0" + "@types/d3-interpolate" "^3.0.1" + "@types/d3-scale" "^4.0.2" + "@types/d3-shape" "^3.1.0" + "@types/d3-time" "^3.0.0" + "@types/d3-timer" "^3.0.0" + d3-array "^3.1.6" + d3-ease "^3.0.1" + d3-interpolate "^3.0.1" + d3-scale "^4.0.2" + d3-shape "^3.1.0" + d3-time "^3.0.0" + d3-timer "^3.0.1" + video-extensions@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/video-extensions/-/video-extensions-1.2.0.tgz#62f449f403b853f02da40964cbf34143f7d96731"