From 7eca41f8fb0929afbe21594f131818a6c443b281 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 6 Aug 2025 06:33:20 +0300 Subject: [PATCH] [frontend]: add header, sidebar, dashboard page --- frontend/graphql.config.ts | 16 +- frontend/package.json | 10 +- .../app/(site)/dashboard/settings/page.tsx | 19 + frontend/src/app/(site)/layout.tsx | 23 + frontend/src/app/(site)/page.tsx | 19 + frontend/src/app/page.tsx | 7 - .../src/components/layout/LayoutContainer.tsx | 31 + .../src/components/layout/header/Header.tsx | 13 + .../components/layout/header/HeaderMenu.tsx | 38 + .../src/components/layout/header/Logo.tsx | 29 + .../components/layout/header/ProfileMenu.tsx | 90 +++ .../src/components/layout/header/Search.tsx | 44 ++ .../header/notifications/Notification.tsx | 40 ++ .../notifications/NotificationsList.tsx | 73 ++ .../layout/sidebar/DashboardNav.tsx | 64 ++ .../src/components/layout/sidebar/Sidebar.tsx | 31 + .../layout/sidebar/SidebarHeader.tsx | 42 ++ .../components/layout/sidebar/SidebarItem.tsx | 53 ++ .../src/components/layout/sidebar/UserNav.tsx | 38 + .../layout/sidebar/route.interface.ts | 7 + frontend/src/components/ui/common/Alert.tsx | 2 +- frontend/src/components/ui/common/Avatar.tsx | 54 ++ frontend/src/components/ui/common/Button.tsx | 4 +- frontend/src/components/ui/common/Card.tsx | 2 +- .../src/components/ui/common/DropdownMenu.tsx | 210 ++++++ frontend/src/components/ui/common/Form.tsx | 2 +- frontend/src/components/ui/common/Input.tsx | 2 +- .../src/components/ui/common/InputOTP.tsx | 2 +- frontend/src/components/ui/common/Label.tsx | 2 +- frontend/src/components/ui/common/Popover.tsx | 37 + .../src/components/ui/common/Separator.tsx | 39 ++ frontend/src/components/ui/common/Tooltip.tsx | 36 + .../components/ui/elements/ChannelAvatar.tsx | 52 ++ frontend/src/components/ui/elements/Hint.tsx | 41 ++ frontend/src/graphql/generated/output.ts | 223 +++++- .../mutations/auth/ClearSessionCookie.graphql | 3 + .../auth/CreateUser.graphql | 0 .../auth/LoginUser.graphql | 0 .../graphql/mutations/auth/LogoutUser.graphql | 3 + .../auth/NewPassword.graphql | 0 .../auth/ResetPassword.graphql | 0 .../auth/VerifyAccount.graphql | 0 .../{ => user}/FindChannelByUsername.graphql | 0 .../user/FindNotificationsByUser.graphql | 11 + .../user/FindNotificationsUnreadCount.graphql | 3 + .../graphql/queries/user/FindProfile.graphql | 20 + frontend/src/hooks/useCurrent.ts | 37 + frontend/src/hooks/useMediaQuery.ts | 22 + frontend/src/hooks/useSidebar.ts | 22 + frontend/src/libs/apollo-client.ts | 3 +- frontend/src/libs/constants/url.constants.ts | 2 + frontend/src/store/sidebar/sidebar.store.ts | 21 + frontend/src/store/sidebar/sidebar.types.ts | 4 + frontend/src/utils/get-media-source.ts | 5 + frontend/src/utils/get-notification-icon.ts | 22 + .../src/utils/{twMerge.ts => tw-merge.ts} | 0 frontend/yarn.lock | 651 +++++++++++++++++- 57 files changed, 2194 insertions(+), 30 deletions(-) create mode 100644 frontend/src/app/(site)/dashboard/settings/page.tsx create mode 100644 frontend/src/app/(site)/layout.tsx create mode 100644 frontend/src/app/(site)/page.tsx delete mode 100644 frontend/src/app/page.tsx create mode 100644 frontend/src/components/layout/LayoutContainer.tsx create mode 100644 frontend/src/components/layout/header/Header.tsx create mode 100644 frontend/src/components/layout/header/HeaderMenu.tsx create mode 100644 frontend/src/components/layout/header/Logo.tsx create mode 100644 frontend/src/components/layout/header/ProfileMenu.tsx create mode 100644 frontend/src/components/layout/header/Search.tsx create mode 100644 frontend/src/components/layout/header/notifications/Notification.tsx create mode 100644 frontend/src/components/layout/header/notifications/NotificationsList.tsx create mode 100644 frontend/src/components/layout/sidebar/DashboardNav.tsx create mode 100644 frontend/src/components/layout/sidebar/Sidebar.tsx create mode 100644 frontend/src/components/layout/sidebar/SidebarHeader.tsx create mode 100644 frontend/src/components/layout/sidebar/SidebarItem.tsx create mode 100644 frontend/src/components/layout/sidebar/UserNav.tsx create mode 100644 frontend/src/components/layout/sidebar/route.interface.ts create mode 100644 frontend/src/components/ui/common/Avatar.tsx create mode 100644 frontend/src/components/ui/common/DropdownMenu.tsx create mode 100644 frontend/src/components/ui/common/Popover.tsx create mode 100644 frontend/src/components/ui/common/Separator.tsx create mode 100644 frontend/src/components/ui/common/Tooltip.tsx create mode 100644 frontend/src/components/ui/elements/ChannelAvatar.tsx create mode 100644 frontend/src/components/ui/elements/Hint.tsx create mode 100644 frontend/src/graphql/mutations/auth/ClearSessionCookie.graphql rename frontend/src/graphql/{metations => mutations}/auth/CreateUser.graphql (100%) rename frontend/src/graphql/{metations => mutations}/auth/LoginUser.graphql (100%) create mode 100644 frontend/src/graphql/mutations/auth/LogoutUser.graphql rename frontend/src/graphql/{metations => mutations}/auth/NewPassword.graphql (100%) rename frontend/src/graphql/{metations => mutations}/auth/ResetPassword.graphql (100%) rename frontend/src/graphql/{metations => mutations}/auth/VerifyAccount.graphql (100%) rename frontend/src/graphql/queries/{ => user}/FindChannelByUsername.graphql (100%) create mode 100644 frontend/src/graphql/queries/user/FindNotificationsByUser.graphql create mode 100644 frontend/src/graphql/queries/user/FindNotificationsUnreadCount.graphql create mode 100644 frontend/src/graphql/queries/user/FindProfile.graphql create mode 100644 frontend/src/hooks/useCurrent.ts create mode 100644 frontend/src/hooks/useMediaQuery.ts create mode 100644 frontend/src/hooks/useSidebar.ts create mode 100644 frontend/src/libs/constants/url.constants.ts create mode 100644 frontend/src/store/sidebar/sidebar.store.ts create mode 100644 frontend/src/store/sidebar/sidebar.types.ts create mode 100644 frontend/src/utils/get-media-source.ts create mode 100644 frontend/src/utils/get-notification-icon.ts rename frontend/src/utils/{twMerge.ts => tw-merge.ts} (100%) diff --git a/frontend/graphql.config.ts b/frontend/graphql.config.ts index dd581df..276d4ea 100644 --- a/frontend/graphql.config.ts +++ b/frontend/graphql.config.ts @@ -1,5 +1,5 @@ -import { CodegenConfig } from '@graphql-codegen/cli'; -import 'dotenv/config' +import type { CodegenConfig } from '@graphql-codegen/cli'; +import 'dotenv/config'; const config: CodegenConfig = { schema: process.env.NEXT_PUBLIC_SERVER_URL, @@ -9,11 +9,11 @@ const config: CodegenConfig = { plugins: [ 'typescript', 'typescript-operations', - 'typescript-react-apollo' - ] - } + 'typescript-react-apollo', + ], + }, }, - ignoreNoDocuments: true -} + ignoreNoDocuments: true, +}; -export default config +export default config; diff --git a/frontend/package.json b/frontend/package.json index 24f2f82..daf0fbf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -7,7 +7,7 @@ "build": "yarn run codegen && next build", "start": "next start", "lint": "next lint", - "codegen": "graphql-codegen --config graphql.config.ts" + "codegen": "graphql-codegen --config graphql.config.ts --watch" }, "dependencies": { "@apollo/client": "3.13.9", @@ -16,11 +16,17 @@ "@graphql-codegen/typescript-operations": "4.6.1", "@graphql-codegen/typescript-react-apollo": "4.3.3", "@hookform/resolvers": "5.2.1", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-dropdown-menu": "2.1.15", "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-popover": "^1.1.14", + "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-tooltip": "1.2.7", "class-variance-authority": "0.7.1", "clsx": "2.1.1", "graphql": "16.11.0", + "html-react-parser": "^5.2.6", "input-otp": "1.4.2", "lucide-react": "0.534.0", "next": "15.4.5", @@ -37,6 +43,7 @@ "devDependencies": { "@eslint/eslintrc": "3.3.1", "@next/eslint-plugin-next": "15.4.5", + "@parcel/watcher": "^2.5.1", "@tailwindcss/postcss": "4.1.11", "@types/node": "22.17.0", "@types/react": "19.1.9", @@ -45,6 +52,7 @@ "eslint-config-ksv741": "0.2.0", "eslint-config-next": "15.4.4", "tailwindcss": "4.1.11", + "ts-node": "10.9.2", "tw-animate-css": "1.3.6", "typescript": "5.8.3" } diff --git a/frontend/src/app/(site)/dashboard/settings/page.tsx b/frontend/src/app/(site)/dashboard/settings/page.tsx new file mode 100644 index 0000000..f9178a0 --- /dev/null +++ b/frontend/src/app/(site)/dashboard/settings/page.tsx @@ -0,0 +1,19 @@ +import { getTranslations } from 'next-intl/server'; + +import type { Metadata } from 'next'; + +export async function generateMetadata(): Promise { + const t = await getTranslations('layout.header.headerMenu.profileMenu'); + + return { + title: t('dashboard'), + }; +} + +const DashboardSettings = () => ( +
+ DashboardSettings page +
+); + +export default DashboardSettings; diff --git a/frontend/src/app/(site)/layout.tsx b/frontend/src/app/(site)/layout.tsx new file mode 100644 index 0000000..e0a7d8e --- /dev/null +++ b/frontend/src/app/(site)/layout.tsx @@ -0,0 +1,23 @@ +import { Header } from '@/components/layout/header/Header'; +import { LayoutContainer } from '@/components/layout/LayoutContainer'; +import { Sidebar } from '@/components/layout/sidebar/Sidebar'; + +import type { PropsWithChildren } from 'react'; + +const SiteLayout = ({ children }: PropsWithChildren) => ( +
+
+
+
+
+ + + + + {children} + +
+
+); + +export default SiteLayout; diff --git a/frontend/src/app/(site)/page.tsx b/frontend/src/app/(site)/page.tsx new file mode 100644 index 0000000..e7172fc --- /dev/null +++ b/frontend/src/app/(site)/page.tsx @@ -0,0 +1,19 @@ +import { getTranslations } from 'next-intl/server'; + +import type { Metadata } from 'next'; + +export async function generateMetadata(): Promise { + const t = await getTranslations('layout.header.logo'); + + return { + title: t('platform'), + }; +} + +const Home = () => ( +
+ home +
+); + +export default Home; diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx deleted file mode 100644 index e31bc52..0000000 --- a/frontend/src/app/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -'use client'; - -import { redirect } from 'next/navigation'; - -export default function Home() { - redirect('account/login'); -} diff --git a/frontend/src/components/layout/LayoutContainer.tsx b/frontend/src/components/layout/LayoutContainer.tsx new file mode 100644 index 0000000..dbdb02d --- /dev/null +++ b/frontend/src/components/layout/LayoutContainer.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { type PropsWithChildren, useEffect } from 'react'; + +import { useMediaQuery } from '@/hooks/useMediaQuery'; +import { useSidebar } from '@/hooks/useSidebar'; +import { cn } from '@/utils/tw-merge'; + +export const LayoutContainer = ({ children }: PropsWithChildren) => { + const isMobile: boolean = useMediaQuery('(max-width: 1024px)'); + + const { isCollapsed, open, close } = useSidebar(); + + useEffect(() => { + if (isMobile) { + if (!isCollapsed) close(); + } else if (isCollapsed) open(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isMobile]); + + return ( +
+ {children} +
+ ); +}; diff --git a/frontend/src/components/layout/header/Header.tsx b/frontend/src/components/layout/header/Header.tsx new file mode 100644 index 0000000..d3f876d --- /dev/null +++ b/frontend/src/components/layout/header/Header.tsx @@ -0,0 +1,13 @@ +import { HeaderMenu } from './HeaderMenu'; +import { Logo } from './Logo'; +import { Search } from './Search'; + +export const Header = () => ( +
+ + + + + +
+); diff --git a/frontend/src/components/layout/header/HeaderMenu.tsx b/frontend/src/components/layout/header/HeaderMenu.tsx new file mode 100644 index 0000000..615d55a --- /dev/null +++ b/frontend/src/components/layout/header/HeaderMenu.tsx @@ -0,0 +1,38 @@ +'use client'; + +import Link from 'next/link'; +import { useTranslations } from 'next-intl'; + +import { Button } from '@/components/ui/common/Button'; +import { useAuth } from '@/hooks/useAuth'; + +import { ProfileMenu } from './ProfileMenu'; + +export const HeaderMenu = () => { + const t = useTranslations('layout.header.headerMenu'); + const { isAuthenticated } = useAuth(); + + return ( +
+ {isAuthenticated + ? ( + + ) + : ( + <> + + + + + + + + + )} +
+ ); +}; diff --git a/frontend/src/components/layout/header/Logo.tsx b/frontend/src/components/layout/header/Logo.tsx new file mode 100644 index 0000000..5bca0dd --- /dev/null +++ b/frontend/src/components/layout/header/Logo.tsx @@ -0,0 +1,29 @@ +'use client'; + +import Link from 'next/link'; +import { useTranslations } from 'next-intl'; + +import { LogoImage } from '@/components/images/LogoImage'; + +export const Logo = () => { + const t = useTranslations('layout.header.logo'); + + return ( + + + +
+

+ TeaStream +

+ +

+ {t('platform')} +

+
+ + ); +}; diff --git a/frontend/src/components/layout/header/ProfileMenu.tsx b/frontend/src/components/layout/header/ProfileMenu.tsx new file mode 100644 index 0000000..b490f62 --- /dev/null +++ b/frontend/src/components/layout/header/ProfileMenu.tsx @@ -0,0 +1,90 @@ +'use client'; + +import { + LayoutDashboard, Loader, LogOut, User, +} from 'lucide-react'; +import Link from 'next/link'; +import { useRouter } from 'next/navigation'; +import { useTranslations } from 'next-intl'; +import { toast } from 'sonner'; + +import { Notifications } from '@/components/layout/header/notifications/Notification'; +import { + DropdownMenu, DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/common/DropdownMenu'; +import { ChannelAvatar } from '@/components/ui/elements/ChannelAvatar'; +import { useLogoutUserMutation } from '@/graphql/generated/output'; +import { useAuth } from '@/hooks/useAuth'; +import { useCurrent } from '@/hooks/useCurrent'; + +export const ProfileMenu = () => { + const t = useTranslations('layout.header.headerMenu.profileMenu'); + const router = useRouter(); + + const { exit } = useAuth(); + const { user, isLoadingProfile } = useCurrent(); + + const [logout] = useLogoutUserMutation({ + onCompleted() { + exit(); + toast.success(t('successMessage')); + router.push('/account/login'); + }, + onError() { + toast.error(t('errorMessage')); + }, + }); + + return isLoadingProfile || !user + ? ( + + ) + : ( + <> + + + + + + + + +
+ + +

+ {user.name} +

+
+ + + + + + + + {t('channel')} + + + + + + + + {t('dashboard')} + + + + logout()}> + + + {t('logout')} + +
+
+ + ); +}; diff --git a/frontend/src/components/layout/header/Search.tsx b/frontend/src/components/layout/header/Search.tsx new file mode 100644 index 0000000..d500d7e --- /dev/null +++ b/frontend/src/components/layout/header/Search.tsx @@ -0,0 +1,44 @@ +'use client'; + +import { SearchIcon } from 'lucide-react'; +import { useRouter } from 'next/navigation'; +import { useTranslations } from 'next-intl'; +import { type FormEvent, useState } from 'react'; + +import { Button } from '@/components/ui/common/Button'; +import { Input } from '@/components/ui/common/Input'; + +export const Search = () => { + const t = useTranslations('layout.header.search'); + + const [searchTerm, setSearchTerm] = useState(''); + const router = useRouter(); + + function onSubmit(event: FormEvent) { + event.preventDefault(); + + if (searchTerm.trim()) { + router.push(`/streams?searchTerm=${searchTerm}`); + } else { + router.push('/streams'); + } + } + + return ( +
+
+ { setSearchTerm(e.target.value); }} + /> + + +
+
+ ); +}; diff --git a/frontend/src/components/layout/header/notifications/Notification.tsx b/frontend/src/components/layout/header/notifications/Notification.tsx new file mode 100644 index 0000000..71a3fa9 --- /dev/null +++ b/frontend/src/components/layout/header/notifications/Notification.tsx @@ -0,0 +1,40 @@ +import { Bell } from 'lucide-react'; + +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/ui/common/Popover'; +import { useFindUnreadNotificationsCountQuery } from '@/graphql/generated/output'; + +import { NotificationsList } from './NotificationsList'; + +export const Notifications = () => { + const { data, loading: isLoadingCount } = useFindUnreadNotificationsCountQuery(); + const count = data?.findUnreadNotificationsCount ?? 0; + + const displayCount = count > 10 ? '+9' : count; + + if (isLoadingCount) return null; + + return ( + + + {count !== 0 && ( +
+ {displayCount} +
+ )} + + +
+ + + + +
+ ); +}; diff --git a/frontend/src/components/layout/header/notifications/NotificationsList.tsx b/frontend/src/components/layout/header/notifications/NotificationsList.tsx new file mode 100644 index 0000000..ce92869 --- /dev/null +++ b/frontend/src/components/layout/header/notifications/NotificationsList.tsx @@ -0,0 +1,73 @@ +import parse from 'html-react-parser'; +import { Loader2 } from 'lucide-react'; +import { useTranslations } from 'next-intl'; +import { Fragment } from 'react'; + +import { Separator } from '@/components/ui/common/Separator'; +import { + useFindNotificationByUserQuery, + useFindUnreadNotificationsCountQuery, +} from '@/graphql/generated/output'; +import { getNotificationIcon } from '@/utils/get-notification-icon'; + +export const NotificationsList = () => { + const t = useTranslations( + 'layout.header.headerMenu.profileMenu.notifications', + ); + + const { refetch } = useFindUnreadNotificationsCountQuery(); + + const { data, loading: isLoadingNotifications } = useFindNotificationByUserQuery({ + onCompleted() { + void refetch(); + }, + }); + const notifications = data?.findNotificationByUser ?? []; + + return ( + <> +

+ {t('heading')} +

+ + + + {/* eslint-disable-next-line no-nested-ternary */} + {isLoadingNotifications + ? ( +
+ + + {t('loading')} +
+ ) + : notifications.length + ? notifications.map((notification, index) => { + const Icon = getNotificationIcon(notification.type); + + return ( + +
+
+ +
+ +
+ {parse(notification.text)} +
+
+ + {index < notifications.length - 1 && ( + + )} +
+ ); + }) + : ( +
+ {t('empty')} +
+ )} + + ); +}; diff --git a/frontend/src/components/layout/sidebar/DashboardNav.tsx b/frontend/src/components/layout/sidebar/DashboardNav.tsx new file mode 100644 index 0000000..9cbee43 --- /dev/null +++ b/frontend/src/components/layout/sidebar/DashboardNav.tsx @@ -0,0 +1,64 @@ +import { + Banknote, + DollarSign, + KeyRound, + Medal, + MessageSquare, + Settings, + Users, +} from 'lucide-react'; +import { useTranslations } from 'next-intl'; + +import { SidebarItem } from './SidebarItem'; + +import type { Route } from './route.interface'; + +export const DashboardNav = () => { + const t = useTranslations('layout.sidebar.dashboardNav'); + + const routes: Route[] = [ + { + label: t('settings'), + href: '/dashboard/settings', + icon: Settings, + }, + { + label: t('keys'), + href: '/dashboard/keys', + icon: KeyRound, + }, + { + label: t('chatSettings'), + href: '/dashboard/chat', + icon: MessageSquare, + }, + { + label: t('followers'), + href: '/dashboard/followers', + icon: Users, + }, + { + label: t('sponsors'), + href: '/dashboard/sponsors', + icon: Medal, + }, + { + label: t('premium'), + href: '/dashboard/plans', + icon: DollarSign, + }, + { + label: t('transactions'), + href: '/dashboard/transactions', + icon: Banknote, + }, + ]; + + return ( +
+ {routes.map((route) => ( + + ))} +
+ ); +}; diff --git a/frontend/src/components/layout/sidebar/Sidebar.tsx b/frontend/src/components/layout/sidebar/Sidebar.tsx new file mode 100644 index 0000000..7f47204 --- /dev/null +++ b/frontend/src/components/layout/sidebar/Sidebar.tsx @@ -0,0 +1,31 @@ +'use client'; + +import { usePathname } from 'next/navigation'; + +import { UserNav } from '@/components/layout/sidebar/UserNav'; +import { useSidebar } from '@/hooks/useSidebar'; +import { cn } from '@/utils/tw-merge'; + +import { DashboardNav } from './DashboardNav'; +import { SidebarHeader } from './SidebarHeader'; + +export const Sidebar = () => { + const { isCollapsed } = useSidebar(); + + const pathname = usePathname(); + + const isDashboardPage = pathname.includes('/dashboard'); + + return ( + + ); +}; diff --git a/frontend/src/components/layout/sidebar/SidebarHeader.tsx b/frontend/src/components/layout/sidebar/SidebarHeader.tsx new file mode 100644 index 0000000..9c783b8 --- /dev/null +++ b/frontend/src/components/layout/sidebar/SidebarHeader.tsx @@ -0,0 +1,42 @@ +'use client'; + +import { ArrowLeftFromLine, ArrowRightFromLine } from 'lucide-react'; +import { usePathname } from 'next/navigation'; +import { useTranslations } from 'next-intl'; + +import { Button } from '@/components/ui/common/Button'; +import { Hint } from '@/components/ui/elements/Hint'; +import { useSidebar } from '@/hooks/useSidebar'; + +export const SidebarHeader = () => { + const t = useTranslations('layout.sidebar.header'); + const pathname = usePathname(); + + const { isCollapsed, open, close } = useSidebar(); + + const label = isCollapsed ? t('expand') : t('collapse'); + + return isCollapsed + ? ( +
+ + + +
+ ) + : ( +
+

+ {t('navigation')} +

+ + + + +
+ ); +}; diff --git a/frontend/src/components/layout/sidebar/SidebarItem.tsx b/frontend/src/components/layout/sidebar/SidebarItem.tsx new file mode 100644 index 0000000..fdaa612 --- /dev/null +++ b/frontend/src/components/layout/sidebar/SidebarItem.tsx @@ -0,0 +1,53 @@ +'use client'; + +import Link from 'next/link'; +import { usePathname } from 'next/navigation'; + +import { Button } from '@/components/ui/common/Button'; +import { Hint } from '@/components/ui/elements/Hint'; +import { useSidebar } from '@/hooks/useSidebar'; +import { cn } from '@/utils/tw-merge'; + +import type { Route } from './route.interface'; + +type SidebarItemProps = { + route: Route; +}; + +export const SidebarItem = ({ route }: SidebarItemProps) => { + const pathname = usePathname(); + const { isCollapsed } = useSidebar(); + + const isActive = pathname === route.href; + + return isCollapsed + ? ( + + + + ) + : ( + + ); +}; diff --git a/frontend/src/components/layout/sidebar/UserNav.tsx b/frontend/src/components/layout/sidebar/UserNav.tsx new file mode 100644 index 0000000..3e10e7d --- /dev/null +++ b/frontend/src/components/layout/sidebar/UserNav.tsx @@ -0,0 +1,38 @@ +import { Folder, Home, Radio } from 'lucide-react'; +import { useTranslations } from 'next-intl'; + +import { SidebarItem } from './SidebarItem'; + +import type { Route } from './route.interface'; + +export const UserNav = () => { + const t = useTranslations('layout.sidebar.userNav'); + + const routes: Route[] = [ + { + label: t('home'), + href: '/', + icon: Home, + }, + { + label: t('categories'), + href: '/categories', + icon: Folder, + }, + { + label: t('streams'), + href: '/streams', + icon: Radio, + }, + ]; + + return ( +
+ {routes.map((route) => ( + + ))} + + {/* */} +
+ ); +}; diff --git a/frontend/src/components/layout/sidebar/route.interface.ts b/frontend/src/components/layout/sidebar/route.interface.ts new file mode 100644 index 0000000..13dc215 --- /dev/null +++ b/frontend/src/components/layout/sidebar/route.interface.ts @@ -0,0 +1,7 @@ +import type { LucideIcon } from 'lucide-react'; + +export type Route = { + label: string; + href: string; + icon: LucideIcon; +}; diff --git a/frontend/src/components/ui/common/Alert.tsx b/frontend/src/components/ui/common/Alert.tsx index 3c2b880..6fc9021 100644 --- a/frontend/src/components/ui/common/Alert.tsx +++ b/frontend/src/components/ui/common/Alert.tsx @@ -1,7 +1,7 @@ import { type VariantProps, cva } from 'class-variance-authority'; import { type HTMLAttributes, forwardRef } from 'react'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; const alertVariants = cva( 'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground', diff --git a/frontend/src/components/ui/common/Avatar.tsx b/frontend/src/components/ui/common/Avatar.tsx new file mode 100644 index 0000000..6411101 --- /dev/null +++ b/frontend/src/components/ui/common/Avatar.tsx @@ -0,0 +1,54 @@ +'use client'; + +import * as AvatarPrimitive from '@radix-ui/react-avatar'; +import { + type ComponentPropsWithoutRef, + type ComponentRef, + forwardRef, +} from 'react'; + +import { cn } from '@/utils/tw-merge'; + +const Avatar = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarFallback, AvatarImage }; diff --git a/frontend/src/components/ui/common/Button.tsx b/frontend/src/components/ui/common/Button.tsx index 94e823f..e713f00 100644 --- a/frontend/src/components/ui/common/Button.tsx +++ b/frontend/src/components/ui/common/Button.tsx @@ -2,10 +2,10 @@ import { Slot } from '@radix-ui/react-slot'; import { type VariantProps, cva } from 'class-variance-authority'; import { type ButtonHTMLAttributes, forwardRef } from 'react'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; const buttonVariants = cva( - 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', + 'inline-flex items-center justify-center gap-2 cursor-pointer whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', { variants: { variant: { diff --git a/frontend/src/components/ui/common/Card.tsx b/frontend/src/components/ui/common/Card.tsx index 36160af..0d5497f 100644 --- a/frontend/src/components/ui/common/Card.tsx +++ b/frontend/src/components/ui/common/Card.tsx @@ -1,6 +1,6 @@ import { type HTMLAttributes, forwardRef } from 'react'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; const Card = forwardRef>( ({ className, ...props }, ref) => ( diff --git a/frontend/src/components/ui/common/DropdownMenu.tsx b/frontend/src/components/ui/common/DropdownMenu.tsx new file mode 100644 index 0000000..425a825 --- /dev/null +++ b/frontend/src/components/ui/common/DropdownMenu.tsx @@ -0,0 +1,210 @@ +'use client'; + +import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'; +import { Check, ChevronRight, Circle } from 'lucide-react'; +import { + type ComponentPropsWithoutRef, + type ComponentRef, + type HTMLAttributes, + forwardRef, +} from 'react'; + +import { cn } from '@/utils/tw-merge'; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = forwardRef< + ComponentRef, + ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ + className, inset, children, ...props +}, ref) => ( + + {children} + + + +)); +DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = forwardRef< + ComponentRef, + ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ + className, children, checked, ...props +}, ref) => ( + + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = forwardRef< + ComponentRef, + ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: HTMLAttributes) => ( + +); +DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'; + +export { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuPortal, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuTrigger, +}; diff --git a/frontend/src/components/ui/common/Form.tsx b/frontend/src/components/ui/common/Form.tsx index 1b52fc0..a240d9c 100644 --- a/frontend/src/components/ui/common/Form.tsx +++ b/frontend/src/components/ui/common/Form.tsx @@ -19,7 +19,7 @@ import { useFormContext, } from 'react-hook-form'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; import { Label } from './Label'; diff --git a/frontend/src/components/ui/common/Input.tsx b/frontend/src/components/ui/common/Input.tsx index 4a8e41b..3c8d072 100644 --- a/frontend/src/components/ui/common/Input.tsx +++ b/frontend/src/components/ui/common/Input.tsx @@ -1,6 +1,6 @@ import { type ComponentProps, forwardRef } from 'react'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; const Input = forwardRef>( ({ className, type, ...props }, ref) => ( diff --git a/frontend/src/components/ui/common/InputOTP.tsx b/frontend/src/components/ui/common/InputOTP.tsx index d5f092e..459e68a 100644 --- a/frontend/src/components/ui/common/InputOTP.tsx +++ b/frontend/src/components/ui/common/InputOTP.tsx @@ -9,7 +9,7 @@ import { useContext, } from 'react'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; const InputOTP = forwardRef< ComponentRef, diff --git a/frontend/src/components/ui/common/Label.tsx b/frontend/src/components/ui/common/Label.tsx index c04616e..8a8912c 100644 --- a/frontend/src/components/ui/common/Label.tsx +++ b/frontend/src/components/ui/common/Label.tsx @@ -8,7 +8,7 @@ import { forwardRef, } from 'react'; -import { cn } from '@/utils/twMerge'; +import { cn } from '@/utils/tw-merge'; const labelVariants = cva( 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70', diff --git a/frontend/src/components/ui/common/Popover.tsx b/frontend/src/components/ui/common/Popover.tsx new file mode 100644 index 0000000..b731654 --- /dev/null +++ b/frontend/src/components/ui/common/Popover.tsx @@ -0,0 +1,37 @@ +'use client'; + +import * as PopoverPrimitive from '@radix-ui/react-popover'; +import { + type ComponentPropsWithoutRef, + type ComponentRef, + forwardRef, +} from 'react'; + +import { cn } from '@/utils/tw-merge'; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverContent = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ + className, align = 'center', sideOffset = 4, ...props +}, ref) => ( + + + +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { Popover, PopoverContent, PopoverTrigger }; diff --git a/frontend/src/components/ui/common/Separator.tsx b/frontend/src/components/ui/common/Separator.tsx new file mode 100644 index 0000000..bf92d29 --- /dev/null +++ b/frontend/src/components/ui/common/Separator.tsx @@ -0,0 +1,39 @@ +'use client'; + +import * as SeparatorPrimitive from '@radix-ui/react-separator'; +import { + type ComponentPropsWithoutRef, + type ComponentRef, + forwardRef, +} from 'react'; + +import { cn } from '@/utils/tw-merge'; + +const Separator = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>( + ( + { + className, orientation = 'horizontal', decorative = true, ...props + }, + ref, + ) => ( + + ), +); +Separator.displayName = SeparatorPrimitive.Root.displayName; + +export { Separator }; diff --git a/frontend/src/components/ui/common/Tooltip.tsx b/frontend/src/components/ui/common/Tooltip.tsx new file mode 100644 index 0000000..1dcadb6 --- /dev/null +++ b/frontend/src/components/ui/common/Tooltip.tsx @@ -0,0 +1,36 @@ +'use client'; + +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; +import { + type ComponentPropsWithoutRef, + type ComponentRef, + forwardRef, +} from 'react'; + +import { cn } from '@/utils/tw-merge'; + +const TooltipProvider = TooltipPrimitive.Provider; + +const Tooltip = TooltipPrimitive.Root; + +const TooltipTrigger = TooltipPrimitive.Trigger; + +const TooltipContent = forwardRef< + ComponentRef, + ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)); +TooltipContent.displayName = TooltipPrimitive.Content.displayName; + +export { + Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, +}; diff --git a/frontend/src/components/ui/elements/ChannelAvatar.tsx b/frontend/src/components/ui/elements/ChannelAvatar.tsx new file mode 100644 index 0000000..8fb1e63 --- /dev/null +++ b/frontend/src/components/ui/elements/ChannelAvatar.tsx @@ -0,0 +1,52 @@ +import { type VariantProps, cva } from 'class-variance-authority'; + +import { getMediaSource } from '@/utils/get-media-source'; +import { cn } from '@/utils/tw-merge'; + +import { Avatar, AvatarFallback, AvatarImage } from '../common/Avatar'; + +import type { FindProfileQuery } from '@/graphql/generated/output'; + +const avatarSizes = cva('', { + variants: { + size: { + sm: 'size-7', + default: 'size-9', + lg: 'size-14', + xl: 'size-32', + }, + }, + defaultVariants: { + size: 'default', + }, +}); + +type ChannelAvatarProps = VariantProps & { + channel: Pick; + isLive?: boolean; +}; + +export const ChannelAvatar = ({ size, channel, isLive }: ChannelAvatarProps) => ( +
+ + + + + {channel.name[0]} + + +
+); diff --git a/frontend/src/components/ui/elements/Hint.tsx b/frontend/src/components/ui/elements/Hint.tsx new file mode 100644 index 0000000..639491c --- /dev/null +++ b/frontend/src/components/ui/elements/Hint.tsx @@ -0,0 +1,41 @@ +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '../common/Tooltip'; + +import type { PropsWithChildren } from 'react'; + +type HintProps = { + label: string; + asChild?: boolean; + side?: 'bottom' | 'left' | 'right' | 'top'; + aling?: 'center' | 'end' | 'start'; +}; + +export const Hint = ({ + children, + label, + asChild, + aling, + side, +}: PropsWithChildren) => ( + + + + {children} + + + +

+ {label} +

+
+
+
+); diff --git a/frontend/src/graphql/generated/output.ts b/frontend/src/graphql/generated/output.ts index 08e6a52..fa40bae 100644 --- a/frontend/src/graphql/generated/output.ts +++ b/frontend/src/graphql/generated/output.ts @@ -591,6 +591,11 @@ export type VerificationInput = { token: Scalars['String']['input']; }; +export type ClearSessionCookieMutationVariables = Exact<{ [key: string]: never; }>; + + +export type ClearSessionCookieMutation = { __typename?: 'Mutation', clearSessionCookie: boolean }; + export type CreateUserMutationVariables = Exact<{ data: CreateUserInput; }>; @@ -605,6 +610,11 @@ export type LoginUserMutationVariables = Exact<{ export type LoginUserMutation = { __typename?: 'Mutation', loginUser: { __typename?: 'AuthModel', message?: string | null, user?: { __typename?: 'UserModel', id: string, name: string, email: string } | null } }; +export type LogoutUserMutationVariables = Exact<{ [key: string]: never; }>; + + +export type LogoutUserMutation = { __typename?: 'Mutation', logoutUser: boolean }; + export type NewPasswordMutationVariables = Exact<{ data: NewPasswordInput; }>; @@ -633,7 +643,52 @@ export type FindChannelByUsernameQueryVariables = Exact<{ export type FindChannelByUsernameQuery = { __typename?: 'Query', findChannelByUsername: { __typename?: 'UserModel', name: string, avatar?: string | null, displayName: string, stream: { __typename?: 'StreamModel', title: string } } }; +export type FindNotificationByUserQueryVariables = Exact<{ [key: string]: never; }>; + +export type FindNotificationByUserQuery = { __typename?: 'Query', findNotificationByUser: Array<{ __typename?: 'NotificationModel', createdAt: any, id: string, isRead: boolean, text: string, type: NotificationType, updatedAt: any, userId: string }> }; + +export type FindUnreadNotificationsCountQueryVariables = Exact<{ [key: string]: never; }>; + + +export type FindUnreadNotificationsCountQuery = { __typename?: 'Query', findUnreadNotificationsCount: number }; + +export type FindProfileQueryVariables = Exact<{ [key: string]: never; }>; + + +export type FindProfileQuery = { __typename?: 'Query', findProfile: { __typename?: 'UserModel', avatar?: string | null, bio?: string | null, createdAt: any, email: string, id: string, name: string, updatedAt: any, isEmailVerified: boolean, isTotpEnabled: boolean, isVerified: boolean, displayName: string, socialLink: Array<{ __typename?: 'SocialLinkModel', title: string, url: string, position: number }> } }; + + +export const ClearSessionCookieDocument = gql` + mutation ClearSessionCookie { + clearSessionCookie +} + `; +export type ClearSessionCookieMutationFn = Apollo.MutationFunction; + +/** + * __useClearSessionCookieMutation__ + * + * To run a mutation, you first call `useClearSessionCookieMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useClearSessionCookieMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [clearSessionCookieMutation, { data, loading, error }] = useClearSessionCookieMutation({ + * variables: { + * }, + * }); + */ +export function useClearSessionCookieMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(ClearSessionCookieDocument, options); + } +export type ClearSessionCookieMutationHookResult = ReturnType; +export type ClearSessionCookieMutationResult = Apollo.MutationResult; +export type ClearSessionCookieMutationOptions = Apollo.BaseMutationOptions; export const CreateUserDocument = gql` mutation CreateUser($data: CreateUserInput!) { createUser(data: $data) { @@ -707,6 +762,36 @@ export function useLoginUserMutation(baseOptions?: Apollo.MutationHookOptions; export type LoginUserMutationResult = Apollo.MutationResult; export type LoginUserMutationOptions = Apollo.BaseMutationOptions; +export const LogoutUserDocument = gql` + mutation LogoutUser { + logoutUser +} + `; +export type LogoutUserMutationFn = Apollo.MutationFunction; + +/** + * __useLogoutUserMutation__ + * + * To run a mutation, you first call `useLogoutUserMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useLogoutUserMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [logoutUserMutation, { data, loading, error }] = useLogoutUserMutation({ + * variables: { + * }, + * }); + */ +export function useLogoutUserMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(LogoutUserDocument, options); + } +export type LogoutUserMutationHookResult = ReturnType; +export type LogoutUserMutationResult = Apollo.MutationResult; +export type LogoutUserMutationOptions = Apollo.BaseMutationOptions; export const NewPasswordDocument = gql` mutation NewPassword($data: NewPasswordInput!) { setNewPassword(data: $data) @@ -849,4 +934,140 @@ export function useFindChannelByUsernameSuspenseQuery(baseOptions?: Apollo.SkipT export type FindChannelByUsernameQueryHookResult = ReturnType; export type FindChannelByUsernameLazyQueryHookResult = ReturnType; export type FindChannelByUsernameSuspenseQueryHookResult = ReturnType; -export type FindChannelByUsernameQueryResult = Apollo.QueryResult; \ No newline at end of file +export type FindChannelByUsernameQueryResult = Apollo.QueryResult; +export const FindNotificationByUserDocument = gql` + query FindNotificationByUser { + findNotificationByUser { + createdAt + id + isRead + text + type + updatedAt + userId + } +} + `; + +/** + * __useFindNotificationByUserQuery__ + * + * To run a query within a React component, call `useFindNotificationByUserQuery` and pass it any options that fit your needs. + * When your component renders, `useFindNotificationByUserQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindNotificationByUserQuery({ + * variables: { + * }, + * }); + */ +export function useFindNotificationByUserQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FindNotificationByUserDocument, options); + } +export function useFindNotificationByUserLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FindNotificationByUserDocument, options); + } +export function useFindNotificationByUserSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(FindNotificationByUserDocument, options); + } +export type FindNotificationByUserQueryHookResult = ReturnType; +export type FindNotificationByUserLazyQueryHookResult = ReturnType; +export type FindNotificationByUserSuspenseQueryHookResult = ReturnType; +export type FindNotificationByUserQueryResult = Apollo.QueryResult; +export const FindUnreadNotificationsCountDocument = gql` + query FindUnreadNotificationsCount { + findUnreadNotificationsCount +} + `; + +/** + * __useFindUnreadNotificationsCountQuery__ + * + * To run a query within a React component, call `useFindUnreadNotificationsCountQuery` and pass it any options that fit your needs. + * When your component renders, `useFindUnreadNotificationsCountQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindUnreadNotificationsCountQuery({ + * variables: { + * }, + * }); + */ +export function useFindUnreadNotificationsCountQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FindUnreadNotificationsCountDocument, options); + } +export function useFindUnreadNotificationsCountLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FindUnreadNotificationsCountDocument, options); + } +export function useFindUnreadNotificationsCountSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(FindUnreadNotificationsCountDocument, options); + } +export type FindUnreadNotificationsCountQueryHookResult = ReturnType; +export type FindUnreadNotificationsCountLazyQueryHookResult = ReturnType; +export type FindUnreadNotificationsCountSuspenseQueryHookResult = ReturnType; +export type FindUnreadNotificationsCountQueryResult = Apollo.QueryResult; +export const FindProfileDocument = gql` + query FindProfile { + findProfile { + avatar + bio + createdAt + email + id + name + updatedAt + isEmailVerified + isTotpEnabled + isVerified + displayName + socialLink { + title + url + position + } + } +} + `; + +/** + * __useFindProfileQuery__ + * + * To run a query within a React component, call `useFindProfileQuery` and pass it any options that fit your needs. + * When your component renders, `useFindProfileQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindProfileQuery({ + * variables: { + * }, + * }); + */ +export function useFindProfileQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(FindProfileDocument, options); + } +export function useFindProfileLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(FindProfileDocument, options); + } +export function useFindProfileSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(FindProfileDocument, options); + } +export type FindProfileQueryHookResult = ReturnType; +export type FindProfileLazyQueryHookResult = ReturnType; +export type FindProfileSuspenseQueryHookResult = ReturnType; +export type FindProfileQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/frontend/src/graphql/mutations/auth/ClearSessionCookie.graphql b/frontend/src/graphql/mutations/auth/ClearSessionCookie.graphql new file mode 100644 index 0000000..8945904 --- /dev/null +++ b/frontend/src/graphql/mutations/auth/ClearSessionCookie.graphql @@ -0,0 +1,3 @@ +mutation ClearSessionCookie { + clearSessionCookie +} diff --git a/frontend/src/graphql/metations/auth/CreateUser.graphql b/frontend/src/graphql/mutations/auth/CreateUser.graphql similarity index 100% rename from frontend/src/graphql/metations/auth/CreateUser.graphql rename to frontend/src/graphql/mutations/auth/CreateUser.graphql diff --git a/frontend/src/graphql/metations/auth/LoginUser.graphql b/frontend/src/graphql/mutations/auth/LoginUser.graphql similarity index 100% rename from frontend/src/graphql/metations/auth/LoginUser.graphql rename to frontend/src/graphql/mutations/auth/LoginUser.graphql diff --git a/frontend/src/graphql/mutations/auth/LogoutUser.graphql b/frontend/src/graphql/mutations/auth/LogoutUser.graphql new file mode 100644 index 0000000..e26b49a --- /dev/null +++ b/frontend/src/graphql/mutations/auth/LogoutUser.graphql @@ -0,0 +1,3 @@ +mutation LogoutUser { + logoutUser +} diff --git a/frontend/src/graphql/metations/auth/NewPassword.graphql b/frontend/src/graphql/mutations/auth/NewPassword.graphql similarity index 100% rename from frontend/src/graphql/metations/auth/NewPassword.graphql rename to frontend/src/graphql/mutations/auth/NewPassword.graphql diff --git a/frontend/src/graphql/metations/auth/ResetPassword.graphql b/frontend/src/graphql/mutations/auth/ResetPassword.graphql similarity index 100% rename from frontend/src/graphql/metations/auth/ResetPassword.graphql rename to frontend/src/graphql/mutations/auth/ResetPassword.graphql diff --git a/frontend/src/graphql/metations/auth/VerifyAccount.graphql b/frontend/src/graphql/mutations/auth/VerifyAccount.graphql similarity index 100% rename from frontend/src/graphql/metations/auth/VerifyAccount.graphql rename to frontend/src/graphql/mutations/auth/VerifyAccount.graphql diff --git a/frontend/src/graphql/queries/FindChannelByUsername.graphql b/frontend/src/graphql/queries/user/FindChannelByUsername.graphql similarity index 100% rename from frontend/src/graphql/queries/FindChannelByUsername.graphql rename to frontend/src/graphql/queries/user/FindChannelByUsername.graphql diff --git a/frontend/src/graphql/queries/user/FindNotificationsByUser.graphql b/frontend/src/graphql/queries/user/FindNotificationsByUser.graphql new file mode 100644 index 0000000..8200a15 --- /dev/null +++ b/frontend/src/graphql/queries/user/FindNotificationsByUser.graphql @@ -0,0 +1,11 @@ +query FindNotificationByUser { + findNotificationByUser { + createdAt + id + isRead + text + type + updatedAt + userId + } +} diff --git a/frontend/src/graphql/queries/user/FindNotificationsUnreadCount.graphql b/frontend/src/graphql/queries/user/FindNotificationsUnreadCount.graphql new file mode 100644 index 0000000..07b1748 --- /dev/null +++ b/frontend/src/graphql/queries/user/FindNotificationsUnreadCount.graphql @@ -0,0 +1,3 @@ +query FindUnreadNotificationsCount { + findUnreadNotificationsCount +} diff --git a/frontend/src/graphql/queries/user/FindProfile.graphql b/frontend/src/graphql/queries/user/FindProfile.graphql new file mode 100644 index 0000000..95461bd --- /dev/null +++ b/frontend/src/graphql/queries/user/FindProfile.graphql @@ -0,0 +1,20 @@ +query FindProfile { + findProfile { + avatar + bio + createdAt + email + id + name + updatedAt + isEmailVerified + isTotpEnabled + isVerified + displayName + socialLink { + title + url + position + } + } +} diff --git a/frontend/src/hooks/useCurrent.ts b/frontend/src/hooks/useCurrent.ts new file mode 100644 index 0000000..becf550 --- /dev/null +++ b/frontend/src/hooks/useCurrent.ts @@ -0,0 +1,37 @@ +import { useEffect } from 'react'; + +import { + useClearSessionCookieMutation, + useFindProfileQuery, +} from '@/graphql/generated/output'; + +import { useAuth } from './useAuth'; + +export function useCurrent() { + const { isAuthenticated, exit } = useAuth(); + + const { + data, loading, refetch, error, + } = useFindProfileQuery({ + skip: !isAuthenticated, + }); + const [clear] = useClearSessionCookieMutation(); + + useEffect(() => { + if (error) { + console.log('error', error); + if (isAuthenticated) { + console.log('CLEAR'); + void clear(); + } + console.log('exit'); + exit(); + } + }, [isAuthenticated, exit, clear]); + + return { + user: data?.findProfile, + isLoadingProfile: loading, + refetch, + }; +} diff --git a/frontend/src/hooks/useMediaQuery.ts b/frontend/src/hooks/useMediaQuery.ts new file mode 100644 index 0000000..d8deca5 --- /dev/null +++ b/frontend/src/hooks/useMediaQuery.ts @@ -0,0 +1,22 @@ +import { useEffect, useState } from 'react'; + +export function useMediaQuery(query: string) { + const [value, setValue] = useState(false); + + useEffect(() => { + function onChange(event: MediaQueryListEvent) { + setValue(event.matches); + } + + const result = matchMedia(query); + result.addEventListener('change', onChange); + + setValue(result.matches); + + return () => { + result.removeEventListener('change', onChange); + }; + }, [query]); + + return value; +} diff --git a/frontend/src/hooks/useSidebar.ts b/frontend/src/hooks/useSidebar.ts new file mode 100644 index 0000000..2361b8b --- /dev/null +++ b/frontend/src/hooks/useSidebar.ts @@ -0,0 +1,22 @@ +import { useCallback } from 'react'; + +import { sidebarStore } from '@/store/sidebar/sidebar.store'; + +export function useSidebar() { + const isCollapsed = sidebarStore((state) => state.isCollapsed); + const setIsCollapsed = sidebarStore((state) => state.setIsCollapsed); + + const open = useCallback(() => { + setIsCollapsed(false); + }, []); + + const close = useCallback(() => { + setIsCollapsed(true); + }, []); + + return { + isCollapsed, + open, + close, + }; +} diff --git a/frontend/src/libs/apollo-client.ts b/frontend/src/libs/apollo-client.ts index 109098b..7c39c6f 100644 --- a/frontend/src/libs/apollo-client.ts +++ b/frontend/src/libs/apollo-client.ts @@ -1,7 +1,8 @@ import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client'; +import { SERVER_URL } from './constants/url.constants'; const httpLink = createHttpLink({ - uri: process.env.NEXT_PUBLIC_SERVER_URL, + uri: SERVER_URL, credentials: 'include', }); diff --git a/frontend/src/libs/constants/url.constants.ts b/frontend/src/libs/constants/url.constants.ts new file mode 100644 index 0000000..bc22c6d --- /dev/null +++ b/frontend/src/libs/constants/url.constants.ts @@ -0,0 +1,2 @@ +export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL as string; +export const MEDIA_URL = process.env.NEXT_PUBLIC_MEDIA_URL as string; diff --git a/frontend/src/store/sidebar/sidebar.store.ts b/frontend/src/store/sidebar/sidebar.store.ts new file mode 100644 index 0000000..82a2cf5 --- /dev/null +++ b/frontend/src/store/sidebar/sidebar.store.ts @@ -0,0 +1,21 @@ +import { create } from 'zustand'; +import { createJSONStorage, persist } from 'zustand/middleware'; + +import type { SidebarStore } from './sidebar.types'; + +const STORAGE_NAME = 'sidebar'; + +export const sidebarStore = create( + persist( + (set) => ({ + isCollapsed: false, + setIsCollapsed: (value: boolean) => { + set({ isCollapsed: value }); + }, + }), + { + name: STORAGE_NAME, + storage: createJSONStorage(() => localStorage), + }, + ), +); diff --git a/frontend/src/store/sidebar/sidebar.types.ts b/frontend/src/store/sidebar/sidebar.types.ts new file mode 100644 index 0000000..2910d0c --- /dev/null +++ b/frontend/src/store/sidebar/sidebar.types.ts @@ -0,0 +1,4 @@ +export type SidebarStore = { + isCollapsed: boolean; + setIsCollapsed: (value: boolean) => void; +}; diff --git a/frontend/src/utils/get-media-source.ts b/frontend/src/utils/get-media-source.ts new file mode 100644 index 0000000..75153ac --- /dev/null +++ b/frontend/src/utils/get-media-source.ts @@ -0,0 +1,5 @@ +import { MEDIA_URL } from '@/libs/constants/url.constants'; + +export function getMediaSource(path: string | null | undefined) { + return MEDIA_URL + path; +} diff --git a/frontend/src/utils/get-notification-icon.ts b/frontend/src/utils/get-notification-icon.ts new file mode 100644 index 0000000..8374e23 --- /dev/null +++ b/frontend/src/utils/get-notification-icon.ts @@ -0,0 +1,22 @@ +import { + Bell, Check, Fingerprint, Medal, Radio, User, +} from 'lucide-react'; + +import { NotificationType } from '@/graphql/generated/output'; + +export function getNotificationIcon(type: NotificationType) { + switch (type) { + case NotificationType.StreamStart: + return Radio; + case NotificationType.NewFollower: + return User; + case NotificationType.NewSponsorship: + return Medal; + case NotificationType.EnableTwoFactor: + return Fingerprint; + case NotificationType.VerifiedChannel: + return Check; + default: + return Bell; + } +} diff --git a/frontend/src/utils/twMerge.ts b/frontend/src/utils/tw-merge.ts similarity index 100% rename from frontend/src/utils/twMerge.ts rename to frontend/src/utils/tw-merge.ts diff --git a/frontend/yarn.lock b/frontend/yarn.lock index c397df5..d9f09f5 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -486,6 +486,13 @@ "@babel/helper-string-parser" "^7.27.1" "@babel/helper-validator-identifier" "^7.27.1" +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@emnapi/core@^1.4.3": version "1.4.5" resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.4.5.tgz#bfbb0cbbbb9f96ec4e2c4fd917b7bbe5495ceccb" @@ -605,6 +612,33 @@ resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-3.1.1.tgz#af3aea7f1e52ec916d8b5c9dcc0f09d4c060a3fc" integrity sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw== +"@floating-ui/core@^1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.3.tgz#462d722f001e23e46d86fd2bd0d21b7693ccb8b7" + integrity sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w== + dependencies: + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/dom@^1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.3.tgz#6174ac3409e6a064bbdf1f4bb07188ee9461f8cf" + integrity sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag== + dependencies: + "@floating-ui/core" "^1.7.3" + "@floating-ui/utils" "^0.2.10" + +"@floating-ui/react-dom@^2.0.0": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.5.tgz#d11e3726d2eb385d8cf3216348742907c1d49fcf" + integrity sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q== + dependencies: + "@floating-ui/dom" "^1.7.3" + +"@floating-ui/utils@^0.2.10": + version "0.2.10" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.10.tgz#a2a1e3812d14525f725d011a73eceb41fef5bc1c" + integrity sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ== + "@formatjs/ecma402-abstract@2.3.4": version "2.3.4" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz#e90c5a846ba2b33d92bc400fdd709da588280fbc" @@ -1360,16 +1394,24 @@ "@jridgewell/sourcemap-codec" "^1.5.0" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.4" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz#7358043433b2e5da569aa02cbc4c121da3af27d7" integrity sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": version "0.3.29" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz#a58d31eaadaf92c6695680b2e1d464a9b8fbf7fc" @@ -1472,11 +1514,188 @@ resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== +"@parcel/watcher-android-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" + integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== + +"@parcel/watcher-darwin-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" + integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== + +"@parcel/watcher-darwin-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" + integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== + +"@parcel/watcher-freebsd-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" + integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== + +"@parcel/watcher-linux-arm-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" + integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== + +"@parcel/watcher-linux-arm-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" + integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== + +"@parcel/watcher-linux-arm64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" + integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== + +"@parcel/watcher-linux-arm64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" + integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== + +"@parcel/watcher-linux-x64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" + integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== + +"@parcel/watcher-linux-x64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" + integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== + +"@parcel/watcher-win32-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" + integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== + +"@parcel/watcher-win32-ia32@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" + integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== + +"@parcel/watcher-win32-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947" + integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== + +"@parcel/watcher@^2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200" + integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== + dependencies: + detect-libc "^1.0.3" + is-glob "^4.0.3" + micromatch "^4.0.5" + node-addon-api "^7.0.0" + optionalDependencies: + "@parcel/watcher-android-arm64" "2.5.1" + "@parcel/watcher-darwin-arm64" "2.5.1" + "@parcel/watcher-darwin-x64" "2.5.1" + "@parcel/watcher-freebsd-x64" "2.5.1" + "@parcel/watcher-linux-arm-glibc" "2.5.1" + "@parcel/watcher-linux-arm-musl" "2.5.1" + "@parcel/watcher-linux-arm64-glibc" "2.5.1" + "@parcel/watcher-linux-arm64-musl" "2.5.1" + "@parcel/watcher-linux-x64-glibc" "2.5.1" + "@parcel/watcher-linux-x64-musl" "2.5.1" + "@parcel/watcher-win32-arm64" "2.5.1" + "@parcel/watcher-win32-ia32" "2.5.1" + "@parcel/watcher-win32-x64" "2.5.1" + +"@radix-ui/primitive@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.2.tgz#83f415c4425f21e3d27914c12b3272a32e3dae65" + integrity sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA== + +"@radix-ui/react-arrow@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz#e14a2657c81d961598c5e72b73dd6098acc04f09" + integrity sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + +"@radix-ui/react-avatar@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz#c58a8800ef3d3ee783b3168fee7c76f6534bfd93" + integrity sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog== + dependencies: + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-is-hydrated" "0.1.0" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-collection@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.7.tgz#d05c25ca9ac4695cc19ba91f42f686e3ea2d9aec" + integrity sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-compose-refs@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== +"@radix-ui/react-context@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.2.tgz#61628ef269a433382c364f6f1e3788a6dc213a36" + integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA== + +"@radix-ui/react-direction@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.1.tgz#39e5a5769e676c753204b792fbe6cf508e550a14" + integrity sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw== + +"@radix-ui/react-dismissable-layer@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz#429b9bada3672c6895a5d6a642aca6ecaf4f18c3" + integrity sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-escape-keydown" "1.1.1" + +"@radix-ui/react-dropdown-menu@2.1.15": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz#f507320de8e11bc1e671a6ec0c27a7a89e725131" + integrity sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-menu" "2.1.15" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-focus-guards@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz#4ec9a7e50925f7fb661394460045b46212a33bed" + integrity sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA== + +"@radix-ui/react-focus-scope@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz#dfe76fc103537d80bf42723a183773fd07bfb58d" + integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + +"@radix-ui/react-id@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.1.tgz#1404002e79a03fe062b7e3864aa01e24bd1471f7" + integrity sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-label@2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-2.1.7.tgz#ad959ff9c6e4968d533329eb95696e1ba8ad72ab" @@ -1484,6 +1703,83 @@ dependencies: "@radix-ui/react-primitive" "2.1.3" +"@radix-ui/react-menu@2.1.15": + version "2.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.15.tgz#a1a8f06cab3c309f9998cdbd2b3ad279e42ed483" + integrity sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-popper" "1.2.7" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-roving-focus" "1.1.10" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-popover@^1.1.14": + version "1.1.14" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.14.tgz#5496d1986f0287cdfc77e73f70a887e4cb77ad08" + integrity sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-focus-guards" "1.1.2" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-popper" "1.2.7" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-popper@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.7.tgz#531cf2eebb3d3270d58f7d8136e4517646429978" + integrity sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ== + dependencies: + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-use-rect" "1.1.1" + "@radix-ui/react-use-size" "1.1.1" + "@radix-ui/rect" "1.1.1" + +"@radix-ui/react-portal@1.1.9": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz#14c3649fe48ec474ac51ed9f2b9f5da4d91c4472" + integrity sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-presence@1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.4.tgz#253ac0ad4946c5b4a9c66878335f5cf07c967ced" + integrity sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + "@radix-ui/react-primitive@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz#db9b8bcff49e01be510ad79893fb0e4cda50f1bc" @@ -1491,6 +1787,28 @@ dependencies: "@radix-ui/react-slot" "1.2.3" +"@radix-ui/react-roving-focus@1.1.10": + version "1.1.10" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz#46030496d2a490c4979d29a7e1252465e51e4b0b" + integrity sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-collection" "1.1.7" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-direction" "1.1.1" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-controllable-state" "1.2.2" + +"@radix-ui/react-separator@^1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.7.tgz#a18bd7fd07c10fda1bba14f2a3032e7b1a2b3470" + integrity sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot@1.2.3": version "1.2.3" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz#502d6e354fc847d4169c3bc5f189de777f68cfe1" @@ -1498,6 +1816,89 @@ dependencies: "@radix-ui/react-compose-refs" "1.1.2" +"@radix-ui/react-tooltip@1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz#23612ac7a5e8e1f6829e46d0e0ad94afe3976c72" + integrity sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw== + dependencies: + "@radix-ui/primitive" "1.1.2" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.10" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-popper" "1.2.7" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.4" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + "@radix-ui/react-visually-hidden" "1.2.3" + +"@radix-ui/react-use-callback-ref@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz#62a4dba8b3255fdc5cc7787faeac1c6e4cc58d40" + integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg== + +"@radix-ui/react-use-controllable-state@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz#905793405de57d61a439f4afebbb17d0645f3190" + integrity sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg== + dependencies: + "@radix-ui/react-use-effect-event" "0.0.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-effect-event@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz#090cf30d00a4c7632a15548512e9152217593907" + integrity sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-escape-keydown@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz#b3fed9bbea366a118f40427ac40500aa1423cc29" + integrity sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g== + dependencies: + "@radix-ui/react-use-callback-ref" "1.1.1" + +"@radix-ui/react-use-is-hydrated@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz#544da73369517036c77659d7cdd019dc0f5ff9a0" + integrity sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA== + dependencies: + use-sync-external-store "^1.5.0" + +"@radix-ui/react-use-layout-effect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz#0c4230a9eed49d4589c967e2d9c0d9d60a23971e" + integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ== + +"@radix-ui/react-use-rect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz#01443ca8ed071d33023c1113e5173b5ed8769152" + integrity sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w== + dependencies: + "@radix-ui/rect" "1.1.1" + +"@radix-ui/react-use-size@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz#6de276ffbc389a537ffe4316f5b0f24129405b37" + integrity sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-visually-hidden@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz#a8c38c8607735dc9f05c32f87ab0f9c2b109efbf" + integrity sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + +"@radix-ui/rect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.1.tgz#78244efe12930c56fd255d7923865857c41ac8cb" + integrity sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw== + "@repeaterjs/repeater@^3.0.4", "@repeaterjs/repeater@^3.0.6": version "3.0.6" resolved "https://registry.yarnpkg.com/@repeaterjs/repeater/-/repeater-3.0.6.tgz#be23df0143ceec3c69f8b6c2517971a5578fdaa2" @@ -1664,6 +2065,26 @@ json5 "^2.2.3" lodash.sortby "^4.7.0" +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@tybys/wasm-util@^0.10.0": version "0.10.0" resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.0.tgz#2fd3cd754b94b378734ce17058d0507c45c88369" @@ -2090,7 +2511,14 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.15.0: +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.15.0, acorn@^8.4.1: version "8.15.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== @@ -2137,11 +2565,23 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +aria-hidden@^1.2.4: + version "1.2.6" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a" + integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA== + dependencies: + tslib "^2.0.0" + aria-query@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" @@ -2636,6 +3076,11 @@ cosmiconfig@^8.1.0, cosmiconfig@^8.1.3: parse-json "^5.2.0" path-type "^4.0.0" +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + cross-fetch@^3.1.5: version "3.2.0" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.2.0.tgz#34e9192f53bc757d6614304d9e5e6fb4edb782e3" @@ -2775,11 +3220,26 @@ detect-indent@^6.0.0: resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + detect-libc@^2.0.3, detect-libc@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -2794,6 +3254,36 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +dom-serializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53" + integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.2" + entities "^4.2.0" + +domelementtype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" + integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== + +domhandler@5.0.3, domhandler@^5.0.2, domhandler@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31" + integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w== + dependencies: + domelementtype "^2.3.0" + +domutils@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.2.2.tgz#edbfe2b668b0c1d97c24baf0f1062b132221bc78" + integrity sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw== + dependencies: + dom-serializer "^2.0.0" + domelementtype "^2.3.0" + domhandler "^5.0.3" + dot-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" @@ -2844,6 +3334,16 @@ enhanced-resolve@^5.18.1: graceful-fs "^4.2.4" tapable "^2.2.0" +entities@^4.2.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +entities@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-6.0.1.tgz#c28c34a43379ca7f61d074130b2f5f7020a30694" + integrity sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -3479,6 +3979,11 @@ get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@ hasown "^2.0.2" math-intrinsics "^1.1.0" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-proto@^1.0.0, get-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" @@ -3674,6 +4179,34 @@ hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" +html-dom-parser@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-5.1.1.tgz#9efb2cfa055f6a71de1bb2f07c5b019db5004f9e" + integrity sha512-+o4Y4Z0CLuyemeccvGN4bAO20aauB2N9tFEAep5x4OW34kV4PTarBHm6RL02afYt2BMKcr0D2Agep8S3nJPIBg== + dependencies: + domhandler "5.0.3" + htmlparser2 "10.0.0" + +html-react-parser@^5.2.6: + version "5.2.6" + resolved "https://registry.yarnpkg.com/html-react-parser/-/html-react-parser-5.2.6.tgz#547a8820be5c76bc2a10f0bb32dd9119d440438b" + integrity sha512-qcpPWLaSvqXi+TndiHbCa+z8qt0tVzjMwFGFBAa41ggC+ZA5BHaMIeMJla9g3VSp4SmiZb9qyQbmbpHYpIfPOg== + dependencies: + domhandler "5.0.3" + html-dom-parser "5.1.1" + react-property "2.0.2" + style-to-js "1.1.17" + +htmlparser2@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-10.0.0.tgz#77ad249037b66bf8cc99c6e286ef73b83aeb621d" + integrity sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g== + dependencies: + domelementtype "^2.3.0" + domhandler "^5.0.3" + domutils "^3.2.1" + entities "^6.0.0" + http-proxy-agent@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" @@ -3753,6 +4286,11 @@ inherits@2, inherits@^2.0.3, inherits@^2.0.4: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +inline-style-parser@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.2.4.tgz#f4af5fe72e612839fcd453d989a586566d695f22" + integrity sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q== + input-otp@1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/input-otp/-/input-otp-1.4.2.tgz#f4d3d587d0f641729e55029b3b8c4870847f4f07" @@ -4370,6 +4908,11 @@ magic-string@^0.30.17: dependencies: "@jridgewell/sourcemap-codec" "^1.5.0" +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + map-cache@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -4512,6 +5055,11 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -4899,6 +5447,38 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-property@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6" + integrity sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug== + +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.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz#d2101d414f6d81d7d3bf033f3c1cb4785789f753" + integrity sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA== + dependencies: + react-remove-scroll-bar "^2.3.7" + react-style-singleton "^2.2.3" + tslib "^2.1.0" + use-callback-ref "^1.3.3" + use-sidecar "^1.1.3" + +react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: + 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@19.1.1: version "19.1.1" resolved "https://registry.yarnpkg.com/react/-/react-19.1.1.tgz#06d9149ec5e083a67f9a1e39ce97b06a03b644af" @@ -5439,6 +6019,20 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +style-to-js@1.1.17: + version "1.1.17" + resolved "https://registry.yarnpkg.com/style-to-js/-/style-to-js-1.1.17.tgz#488b1558a8c1fd05352943f088cc3ce376813d83" + integrity sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA== + dependencies: + style-to-object "1.0.9" + +style-to-object@1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-1.0.9.tgz#35c65b713f4a6dba22d3d0c61435f965423653f0" + integrity sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw== + dependencies: + inline-style-parser "0.2.4" + styled-jsx@5.1.6: version "5.1.6" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499" @@ -5567,6 +6161,25 @@ ts-log@^2.2.3: resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.7.tgz#4f4512144898b77c9984e91587076fcb8518688e" integrity sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg== +ts-node@10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -5577,7 +6190,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.3, tslib@^2.8.0, tslib@^2.8.1: +tslib@2, tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.3, tslib@^2.8.0, tslib@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -5767,6 +6380,13 @@ urlpattern-polyfill@^10.0.0: resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz#1b2517e614136c73ba32948d5e7a3a063cba8e74" integrity sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw== +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-intl@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/use-intl/-/use-intl-4.3.4.tgz#42bb2141480032623ffe412799c62cbdf306ed0f" @@ -5776,11 +6396,29 @@ use-intl@^4.3.4: "@schummar/icu-type-parser" "1.21.5" intl-messageformat "^10.5.14" +use-sidecar@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" + integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + +use-sync-external-store@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz#55122e2a3edd2a6c106174c27485e0fd59bcfca0" + integrity sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A== + util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -5982,6 +6620,11 @@ yargs@^17.0.0: y18n "^5.0.5" yargs-parser "^21.1.1" +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"