diff --git a/packages/frontend/app/components/ApiCredentialsForm.tsx b/packages/frontend/app/components/ApiCredentialsForm.tsx index 9f42409025..b6183430bc 100644 --- a/packages/frontend/app/components/ApiCredentialsForm.tsx +++ b/packages/frontend/app/components/ApiCredentialsForm.tsx @@ -1,6 +1,6 @@ import { Form, useActionData, useNavigation } from '@remix-run/react' import { useRef, useState, useEffect } from 'react' -import { Input, Button } from '~/components/ui' +import { Button, Text, TextField } from '@radix-ui/themes' import { validate as validateUUID } from 'uuid' interface ApiCredentialsFormProps { @@ -52,11 +52,11 @@ export const ApiCredentialsForm = ({
{showClearCredentials ? (
-

✓ API credentials configured

+

✓ API credentials configured

-
-
-
-
-
- - {title} - -
-

- {message - ? message - : `Please note that this action is not reversible.`} -

-

- To confirm, type " - {keyword} - " below: -

- - setConfirmationPrompt(e.currentTarget.value) - } - /> -
-
- -
-
-
- - - - - - - + + {message + ? message + : 'Please note that this action is not reversible.'} + + + + + To confirm, type " + + {keyword} + + " below: + + setConfirmationPrompt(e.currentTarget.value)} + size='3' + placeholder={keyword} + /> + + + + + + + + + + ) } ) diff --git a/packages/frontend/app/components/DangerZone.tsx b/packages/frontend/app/components/DangerZone.tsx index 31d301528a..bfb5433daf 100644 --- a/packages/frontend/app/components/DangerZone.tsx +++ b/packages/frontend/app/components/DangerZone.tsx @@ -7,14 +7,13 @@ type DangerZoneProps = { export const DangerZone = ({ title, children }: DangerZoneProps) => { return ( -
-
-

{title}

+
+ {children} +

Please note that this action is not reversible. Continue with caution.

- {children}
) } diff --git a/packages/frontend/app/components/Filters.tsx b/packages/frontend/app/components/Filters.tsx index be48fcc9ed..47ad7fc729 100644 --- a/packages/frontend/app/components/Filters.tsx +++ b/packages/frontend/app/components/Filters.tsx @@ -19,9 +19,23 @@ export const PopoverFilter = ({ values }: PopoverFilterProps) => { return ( - - - {label} + + + {label} + { return ( - -
-
-
- -
- -
-
- - {title} - -
-

- Are you sure you want to {type.toLowerCase()} {displayAmount}? -

- - {/* no input needed - form submit is confirmation */} -
- - -
- -
-
-
-
-
-
+ Cancel + + + + + + + ) } diff --git a/packages/frontend/app/components/LiquidityDialog.tsx b/packages/frontend/app/components/LiquidityDialog.tsx index 917370ab1c..2e0f5193db 100644 --- a/packages/frontend/app/components/LiquidityDialog.tsx +++ b/packages/frontend/app/components/LiquidityDialog.tsx @@ -1,9 +1,8 @@ -import { Dialog } from '@headlessui/react' import { Form } from '@remix-run/react' import type { ChangeEvent } from 'react' -import { useEffect, useRef, useState } from 'react' -import { XIcon } from '~/components/icons' -import { Button, Input } from '~/components/ui' +import { useEffect, useId, useRef, useState } from 'react' +import { Button, Dialog, Flex, Text, TextField } from '@radix-ui/themes' +import { renderFieldError } from '~/lib/form-errors' type BasicAsset = { code: string @@ -25,6 +24,7 @@ export const LiquidityDialog = ({ }: LiquidityDialogProps) => { const [actualAmount, setActualAmount] = useState(0) const [errorMessage, setErrorMessage] = useState('') + const amountId = useId() const handleChange = (e: ChangeEvent) => { const userInput = e.target.value @@ -50,59 +50,63 @@ export const LiquidityDialog = ({ }, []) return ( - -
-
-
- -
- -
-
- !open && onClose()}> + + + + {title} + + + + + + + + Amount + + + {asset.code} + + + + {renderFieldError(errorMessage)} + + +
+ + + + + + -
- -
-
- -
-
- + {type} liquidity + + + + + + ) } diff --git a/packages/frontend/app/components/RedirectDialog.tsx b/packages/frontend/app/components/RedirectDialog.tsx index 06df44f42c..c37be6c40b 100644 --- a/packages/frontend/app/components/RedirectDialog.tsx +++ b/packages/frontend/app/components/RedirectDialog.tsx @@ -1,6 +1,6 @@ import { Dialog, Transition } from '@headlessui/react' import { useNavigate } from '@remix-run/react' -import { Button } from './ui' +import { Button } from '@radix-ui/themes' import { Fragment } from 'react/jsx-runtime' import { forwardRef, useImperativeHandle, useState } from 'react' diff --git a/packages/frontend/app/components/Sidebar.tsx b/packages/frontend/app/components/Sidebar.tsx index 5e37ef29d5..e0b71ee373 100644 --- a/packages/frontend/app/components/Sidebar.tsx +++ b/packages/frontend/app/components/Sidebar.tsx @@ -3,8 +3,8 @@ import { NavLink } from '@remix-run/react' import { cx } from 'class-variance-authority' import type { FC } from 'react' import { Fragment, useState } from 'react' +import { Box, Button, Flex, Heading, IconButton } from '@radix-ui/themes' import { Bars, XIcon } from './icons' -import { Button } from '~/components/ui' interface SidebarProps { logoutUrl: string @@ -84,16 +84,19 @@ export const Sidebar: FC = ({ leaveTo='-translate-x-full' >
- -
+ + Logo - -
-
- -
+
- ) diff --git a/packages/frontend/app/components/Snackbar.tsx b/packages/frontend/app/components/Snackbar.tsx index 1f34235d2b..784037e4fa 100644 --- a/packages/frontend/app/components/Snackbar.tsx +++ b/packages/frontend/app/components/Snackbar.tsx @@ -60,18 +60,29 @@ export const Snackbar: FC = ({ leaveFrom='opacity-100 scale-100' leaveTo='opacity-0 scale-95' > -
+
{message.type === 'success' && ( - + )} {message.type === 'error' && ( )} -

{message.content}

+

{message.content}

-
- {description ? ( -
{description}
- ) : null} - -
- ) - } -) - -PasswordInput.displayName = 'PasswordInput' diff --git a/packages/frontend/app/components/ui/Select.tsx b/packages/frontend/app/components/ui/Select.tsx deleted file mode 100644 index 2d604ae374..0000000000 --- a/packages/frontend/app/components/ui/Select.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import type { ReactNode } from 'react' -import { Fragment, useId, useState } from 'react' -import { Combobox, Transition } from '@headlessui/react' -import { Input } from './Input' -import { Check, Chevron } from '../icons' -import { Label } from './Label' -import { FieldError } from './FieldError' - -export type SelectOption = { - label: string - value: string -} - -type SelectProps = { - options: SelectOption[] - placeholder: string - name?: string - label?: string - disabled?: boolean - required?: boolean - error?: string | string[] - defaultValue?: SelectOption - description?: ReactNode - onChange?: (value: React.SetStateAction) => void - bringForward?: boolean -} - -export const Select = ({ - options, - name, - placeholder, - label, - error, - disabled = false, - required = false, - defaultValue = { - label: '', - value: '' - }, - description, - onChange, - bringForward -}: SelectProps) => { - const id = useId() - const [internalValue, setInternalValue] = useState(defaultValue) - const [searchTerm, setSearchTerm] = useState('') - - const filteredOptions = - searchTerm === '' - ? options - : options.filter((option) => - option.label - .toLowerCase() - .replace(/\s+/g, '') - .includes(searchTerm.toLowerCase().replace(/\s+/g, '')) - ) - - return ( - { - setInternalValue(value) - if (onChange) { - onChange(value) - } - }} - disabled={disabled} - > - {name ? ( - - ) : null} -
- {label ? ( - - {label} - - ) : null} -
- option.label} - onChange={(event) => setSearchTerm(event.target.value)} - placeholder={placeholder} - /> - - {({ open }) => ( - - )} - -
- {description ? ( -
{description}
- ) : null} - {error ? : null} - setSearchTerm('')} - > - - {filteredOptions.length === 0 && searchTerm !== '' ? ( -
- Nothing found. -
- ) : ( - filteredOptions.map((option) => ( - - `relative select-none py-2 px-4 ${active && 'bg-pearl'}` - } - value={option} - > - {({ selected }) => ( - <> - - {option.label} - - {selected ? ( - - - - ) : null} - - )} - - )) - )} -
-
-
-
- ) -} diff --git a/packages/frontend/app/components/ui/Table.tsx b/packages/frontend/app/components/ui/Table.tsx deleted file mode 100644 index 3fd784279e..0000000000 --- a/packages/frontend/app/components/ui/Table.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { cx } from 'class-variance-authority' -import { type ComponentProps, type ReactNode } from 'react' - -type TableProps = ComponentProps<'table'> & { - children: ReactNode -} - -type THeadProps = ComponentProps<'thead'> & { - columns: string[] - thProps?: ComponentProps<'th'> - trProps?: ComponentProps<'tr'> -} - -type TBodyProps = ComponentProps<'tbody'> & { - children: ReactNode -} - -type TRowProps = ComponentProps<'tr'> & { - children: ReactNode -} - -type TCellProps = ComponentProps<'td'> & { - children: ReactNode -} - -const THead = ({ - columns, - thProps, - trProps, - className, - ...props -}: THeadProps) => { - return ( - - - {columns.map((col) => ( - - {col} - - ))} - - - ) -} - -const TBody = ({ children, ...props }: TBodyProps) => { - return {children} -} - -const TRow = ({ children, className, ...props }: TRowProps) => { - return ( - - {children} - - ) -} - -const TCell = ({ children, className, ...props }: TCellProps) => { - return ( - - {children} - - ) -} - -export const Table = ({ children, className, ...props }: TableProps) => { - return ( -
- - {children} -
-
- ) -} - -Table.Head = THead -Table.Body = TBody -Table.Row = TRow -Table.Cell = TCell diff --git a/packages/frontend/app/components/ui/index.tsx b/packages/frontend/app/components/ui/index.tsx deleted file mode 100644 index 29b1dd318b..0000000000 --- a/packages/frontend/app/components/ui/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -export * from './Button' -export * from './ErrorPanel' -export * from './FieldError' -export * from './Input' -export * from './Label' -export * from './PasswordInput' -export * from './Select' -export * from './Table' -export * from './Dropdown' diff --git a/packages/frontend/app/lib/form-errors.tsx b/packages/frontend/app/lib/form-errors.tsx new file mode 100644 index 0000000000..c1d0f88421 --- /dev/null +++ b/packages/frontend/app/lib/form-errors.tsx @@ -0,0 +1,41 @@ +import { Box, Flex, Text } from '@radix-ui/themes' +import { XCircle } from '~/components/icons' + +export const renderFieldError = (error?: string | string[]) => { + if (!error) return null + + const message = Array.isArray(error) ? error.join('; ') : error + + return ( + + {message} + + ) +} + +export const renderErrorPanel = (errors?: string[]) => { + if (!errors?.length) return null + + const errorMessage = + errors.length > 1 + ? `There were ${errors.length} errors with your submission` + : 'There was an error with your submission!' + + return ( + + + +
+ + {errorMessage} + +
    + {errors.map((error) => ( +
  • {error}
  • + ))} +
+
+
+
+ ) +} diff --git a/packages/frontend/app/root.tsx b/packages/frontend/app/root.tsx index 229e4c5f0a..3b57d71cdf 100644 --- a/packages/frontend/app/root.tsx +++ b/packages/frontend/app/root.tsx @@ -2,24 +2,27 @@ import type { MetaFunction } from '@remix-run/node' import { json, type LoaderFunctionArgs } from '@remix-run/node' import { Links, + Link, LiveReload, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData, + useLocation, useRouteError, isRouteErrorResponse } from '@remix-run/react' import type { ReactNode } from 'react' import { useEffect, useState } from 'react' +import { Button, Theme } from '@radix-ui/themes' import logo from '../public/logo.svg' import { XCircle } from './components/icons' import { Sidebar } from './components/Sidebar' import { Snackbar } from './components/Snackbar' -import { Button } from './components/ui/Button' import { messageStorage, type Message } from './lib/message.server' import tailwind from './styles/tailwind.css' +import radixStyles from '@radix-ui/themes/styles.css' import { getOpenPaymentsUrl } from './shared/utils' import { PublicEnv, type PublicEnvironment } from './PublicEnv' import { isLoggedIn, checkAuthAndRedirect } from './lib/kratos_checks.server' @@ -108,6 +111,8 @@ export default function App() { authEnabled, hasApiCredentials } = useLoaderData() + const location = useLocation() + const isIndex = location.pathname === '/' const [snackbarOpen, setSnackbarOpen] = useState(false) useEffect(() => { @@ -120,36 +125,42 @@ export default function App() { return ( -
- {displaySidebar && ( - - )} -
-
+ +
+ {displaySidebar && ( + + )} +
+
+
-
- setSnackbarOpen(false)} - show={snackbarOpen} - message={message} - dismissAfter={2000} - /> + setSnackbarOpen(false)} + show={snackbarOpen} + message={message} + dismissAfter={2000} + /> + @@ -166,7 +177,7 @@ export function ErrorBoundary() { return ( @@ -196,8 +207,10 @@ export function ErrorBoundary() { {error.status}

{error.statusText}

-
@@ -223,8 +236,10 @@ export function ErrorBoundary() {
Cause: {errorMessage}
-
@@ -233,6 +248,7 @@ export function ErrorBoundary() { export function links() { return [ + { rel: 'stylesheet', href: radixStyles }, { rel: 'stylesheet', href: tailwind }, { rel: 'icon', href: logo } ] diff --git a/packages/frontend/app/routes/_index.tsx b/packages/frontend/app/routes/_index.tsx index 921478d1ed..407149c3e1 100644 --- a/packages/frontend/app/routes/_index.tsx +++ b/packages/frontend/app/routes/_index.tsx @@ -2,6 +2,7 @@ import { checkAuthAndRedirect } from '../lib/kratos_checks.server' import type { TypedResponse } from '@remix-run/node' import { json, type LoaderFunctionArgs } from '@remix-run/node' import { useLoaderData } from '@remix-run/react' +import { Card, Heading, Text } from '@radix-ui/themes' import { ApiCredentialsForm } from '~/components/ApiCredentialsForm' import { getSession } from '~/lib/session.server' @@ -40,26 +41,27 @@ export default function Index() { useLoaderData() return ( -
-
-
-

- Welcome! -

-
-

Rafiki Admin

-

This is Rafiki's administrative user interface.

-
-

- In this web application, you'll be able to manage peering - relationships, assets, and wallet addresses, among other settings. -

- -
-

- To get started, please configure your API credentials -

-
+
+
+
+
+ +
+ + Welcome + + + Rafiki Admin + + + Configure your API credentials to start managing tenants, assets, + and wallet addresses. + +
-

- - https://rafiki.dev - -

-
+
) diff --git a/packages/frontend/app/routes/assets.$assetId.tsx b/packages/frontend/app/routes/assets.$assetId.tsx index c72c686961..b42539e6d1 100644 --- a/packages/frontend/app/routes/assets.$assetId.tsx +++ b/packages/frontend/app/routes/assets.$assetId.tsx @@ -10,12 +10,13 @@ import { useFormAction, useLoaderData, useNavigation, - useSubmit + useSubmit, + Link } from '@remix-run/react' -import { type FormEvent, useState, useRef } from 'react' +import { type ChangeEventHandler, type FormEvent, useRef, useState } from 'react' import { z } from 'zod' -import { DangerZone, PageHeader } from '~/components' -import { Button, ErrorPanel, Input } from '~/components/ui' +import { Box, Button, Card, Flex, Heading, Text, TextField } from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { ConfirmationDialog, type ConfirmationDialogRef @@ -37,6 +38,58 @@ import type { ZodFieldErrors } from '~/shared/types' import { formatAmount } from '~/shared/utils' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean + defaultValue?: string | number + value?: string | number + disabled?: boolean + readOnly?: boolean + onChange?: ChangeEventHandler +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required, + defaultValue, + value, + disabled, + readOnly, + onChange +}: FormFieldProps) => ( + + + + + + {renderFieldError(error)} + +) + export async function loader({ request, params }: LoaderFunctionArgs) { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -86,138 +139,155 @@ export default function ViewAssetPage() { } return ( -
-
- - - -
-
-

General Information

-

- Created at {new Date(asset.createdAt).toLocaleString()} -

- -
-
-
-
-
- - - - - -
-
- + +
+
+ +
+ + + Liquidity Information + + + + Amount + + {formatAmount(asset.liquidity ?? '0', asset.scale)} {asset.code} + + + + -
- - -
-
- {/* Asset Liquidity Info */} -
-
-

Liquidity Information

-
-
-
-
-

Amount

-

- {formatAmount(asset.liquidity ?? '0', asset.scale)}{' '} - {asset.code} -

-
-
- - + + + +
+ + + + Sending Fee + + {asset.sendingFee ? ( + + Created at {new Date(asset.sendingFee.createdAt).toLocaleString()} + + ) : null} + + {renderErrorPanel(response?.errors.sendingFee.message)} + + -
-
-
-
- {/* Asset Liquidity Info - END */} - {/* Asset Fee Info */} -
-
-

Sending Fee

- {asset.sendingFee ? ( -

- Created at{' '} - {new Date(asset.sendingFee.createdAt).toLocaleString()} -

- ) : null} - -
-
-
- -
-
-
-
- - - - setBasisPointsInput(parseFloat(e?.target?.value)) - } - /> -

- A single basis point is a fee equal to 0.01% of the total - amount. A fee of {basisPointsInput || 1} basis point on $100 - is ${((basisPointsInput || 1) * 0.01).toFixed(4)}. -

-
+ + +
+ + + + + + + + + setBasisPointsInput(parseFloat(e?.target?.value)) + } + /> + + + + A single basis point is a fee equal to 0.01% of the total amount. + A fee of {basisPointsInput || 1} basis point on $100 is $ + {((basisPointsInput || 1) * 0.01).toFixed(4)}. + + + -
-
-
-
-
-
- {/* Asset Fee Info - END */} + + + + + + - {/* DELETE ASSET - Danger zone */} - +
- - -
-
-
- + + + + -
+ ) } diff --git a/packages/frontend/app/routes/assets.$assetId_.fee-history.tsx b/packages/frontend/app/routes/assets.$assetId_.fee-history.tsx index 16bfeca15b..032e43e89f 100644 --- a/packages/frontend/app/routes/assets.$assetId_.fee-history.tsx +++ b/packages/frontend/app/routes/assets.$assetId_.fee-history.tsx @@ -2,8 +2,7 @@ import { json, type LoaderFunctionArgs } from '@remix-run/node' import { paginationSchema } from '~/lib/validate.server' import { getAssetWithFees } from '~/lib/api/asset.server' import { useLoaderData, useNavigate } from '@remix-run/react' -import { PageHeader } from '~/components' -import { Button, Table } from '~/components/ui' +import { Box, Button, Flex, Heading, Table, Text } from '@radix-ui/themes' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' export const loader = async ({ request, params }: LoaderFunctionArgs) => { @@ -52,70 +51,88 @@ export default function AssetFeesPage() { const navigate = useNavigate() return ( -
-
- -
-

Asset Fees

-
-
- -
-
- - - - {fees?.edges.length ? ( - fees.edges.map((fee) => ( - - {fee.node.id} - {fee.node.type} - {fee.node.fixed} - {fee.node.basisPoints} - - {new Date(fee.node.createdAt).toLocaleString()} - - - )) - ) : ( - - - No fees found. - - - )} - -
-
+ + + + Asset Fees - -
-
-
+ + + + + + + + ID + Type + Fixed + Basis points + Creation date + + + + {fees?.edges.length ? ( + fees.edges.map((fee) => ( + + + {fee.node.id} + + + {fee.node.type} + + + {fee.node.fixed} + + + {fee.node.basisPoints} + + + {new Date(fee.node.createdAt).toLocaleString()} + + + )) + ) : ( + + + No fees found. + + + )} + + + + + + + + + + + ) } diff --git a/packages/frontend/app/routes/assets._index.tsx b/packages/frontend/app/routes/assets._index.tsx index 758f40d613..b49235b119 100644 --- a/packages/frontend/app/routes/assets._index.tsx +++ b/packages/frontend/app/routes/assets._index.tsx @@ -1,7 +1,6 @@ import { json, type LoaderFunctionArgs } from '@remix-run/node' import { useLoaderData, useNavigate } from '@remix-run/react' -import { PageHeader } from '~/components' -import { Button, Table } from '~/components/ui' +import { Box, Button, Flex, Heading, Table, Text } from '@radix-ui/themes' import { listAssets } from '~/lib/api/asset.server' import { paginationSchema } from '~/lib/validate.server' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' @@ -43,74 +42,81 @@ export default function AssetsPage() { const navigate = useNavigate() return ( -
-
- -
-

Assets

-
-
- -
-
- - - - {assets.edges.length ? ( - assets.edges.map((asset) => ( - navigate(`/assets/${asset.node.id}`)} - > - {asset.node.id} - {asset.node.code} - {asset.node.scale} - - {asset.node.withdrawalThreshold ? ( - asset.node.withdrawalThreshold - ) : ( - - No withdrawal threshold - - )} + + + + Assets + + + + + + + + + ID + Code + Scale + Withdrawal threshold + + + + {assets.edges.length ? ( + assets.edges.map((asset) => ( + navigate(`/assets/${asset.node.id}`)} + > + + {asset.node.id} + + + {asset.node.code} + + + {asset.node.scale} + + + {asset.node.withdrawalThreshold ? ( + {asset.node.withdrawalThreshold} + ) : ( + No withdrawal threshold + )} + + + )) + ) : ( + + + No assets found. - )) - ) : ( - - - No assets found. - - - )} - -
-
- - -
-
-
+ )} + + + + + + + + + + + ) } diff --git a/packages/frontend/app/routes/assets.create.tsx b/packages/frontend/app/routes/assets.create.tsx index d68b8932fc..14327b08e0 100644 --- a/packages/frontend/app/routes/assets.create.tsx +++ b/packages/frontend/app/routes/assets.create.tsx @@ -1,12 +1,13 @@ import { json, type ActionFunctionArgs } from '@remix-run/node' +import { useState } from 'react' import { Form, useActionData, useLoaderData, useNavigation } from '@remix-run/react' -import { PageHeader } from '~/components' -import { Button, Select, ErrorPanel, Input } from '~/components/ui' +import { Box, Button, Card, Flex, Heading, Select, Text, TextField } from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { createAsset } from '~/lib/api/asset.server' import { messageStorage, setMessageAndRedirect } from '~/lib/message.server' import { createAssetSchema } from '~/lib/validate.server' @@ -16,6 +17,104 @@ import { type LoaderFunctionArgs } from '@remix-run/node' import { whoAmI, loadTenants } from '~/lib/api/tenant.server' import { getSession } from '~/lib/session.server' +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean +} + +type SelectOption = { + label: string + value: string +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required +}: FormFieldProps) => ( + + + + + + {renderFieldError(error)} + +) + +type SelectFieldProps = { + label: string + name: string + options: SelectOption[] + placeholder: string + required?: boolean + error?: string | string[] + defaultValue?: SelectOption +} + +const SelectField = ({ + label, + name, + options, + placeholder, + required, + error, + defaultValue +}: SelectFieldProps) => { + const [selectedValue, setSelectedValue] = useState( + defaultValue?.value ?? '' + ) + + return ( + + + + + +
+ setSelectedValue(value)} + > + + + {options.map((option) => ( + + {option.label} + + ))} + + +
+ {renderFieldError(error)} +
+ ) +} + export const loader = async ({ request }: LoaderFunctionArgs) => { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -38,77 +137,81 @@ export default function CreateAssetPage() { const isSubmitting = state === 'submitting' return ( -
-
- -

Create Asset

- -
- {/* Create Asset form */} -
-
- -
- -
- {/* Asset General Info */} -
-
-

General Information

-
-
-
- - - - {tenants && ( - message.text) - .join('; ')} - /> + attributes.type === 'hidden' ? ( + + ) : ( +
+ + {label} + {attributes.required ? ( + * + ) : null} + + + {renderFieldError( + field.messages + .map((message) => message.text) + .join('; ') + )} +
+ ) ) } return null diff --git a/packages/frontend/app/routes/auth.manual-logout.tsx b/packages/frontend/app/routes/auth.manual-logout.tsx index e2cf27706b..e3d50b6efa 100644 --- a/packages/frontend/app/routes/auth.manual-logout.tsx +++ b/packages/frontend/app/routes/auth.manual-logout.tsx @@ -1,6 +1,6 @@ import { redirect, type LoaderFunctionArgs } from '@remix-run/node' import { Form } from '@remix-run/react' -import { Button } from '../components/ui' +import { Button } from '@radix-ui/themes' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' export const loader = async ({ request }: LoaderFunctionArgs) => { diff --git a/packages/frontend/app/routes/auth.recovery.tsx b/packages/frontend/app/routes/auth.recovery.tsx index 869b439912..8368b97ae2 100644 --- a/packages/frontend/app/routes/auth.recovery.tsx +++ b/packages/frontend/app/routes/auth.recovery.tsx @@ -7,7 +7,8 @@ import { uuidSchema } from '~/lib/validate.server' import { isUiNodeInputAttributes } from '@ory/integrations/ui' import type { UiContainer } from '@ory/client' import { useLoaderData } from '@remix-run/react' -import { Button, Input } from '../components/ui' +import { Button, Text, TextField } from '@radix-ui/themes' +import { renderFieldError } from '../lib/form-errors' import variables from '../lib/envConfig.server' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' @@ -50,6 +51,40 @@ export default function Recovery() { const uiContainer: UiContainer = responseData.ui const uiNodes = uiContainer.nodes const actionUrl = uiContainer.action + type TextFieldType = + | 'text' + | 'email' + | 'password' + | 'number' + | 'tel' + | 'url' + | 'search' + | 'date' + | 'datetime-local' + | 'time' + | 'week' + | 'month' + | 'hidden' + const normalizeType = (type: string): TextFieldType => { + const allowed: TextFieldType[] = [ + 'text', + 'email', + 'password', + 'number', + 'tel', + 'url', + 'search', + 'date', + 'datetime-local', + 'time', + 'week', + 'month', + 'hidden' + ] + return allowed.includes(type as TextFieldType) + ? (type as TextFieldType) + : 'text' + } return (
@@ -75,20 +110,44 @@ export default function Recovery() { attributes.type !== 'submit' ) { return ( - message.text) - .join('; ')} - /> + attributes.type === 'hidden' ? ( + + ) : ( +
+ + {label} + {attributes.required ? ( + * + ) : null} + + + {renderFieldError( + field.messages + .map((message) => message.text) + .join('; ') + )} +
+ ) ) } return null diff --git a/packages/frontend/app/routes/payments._index.tsx b/packages/frontend/app/routes/payments._index.tsx index 9c57ca2512..617808e0ef 100644 --- a/packages/frontend/app/routes/payments._index.tsx +++ b/packages/frontend/app/routes/payments._index.tsx @@ -12,9 +12,18 @@ import { Form, useActionData } from '@remix-run/react' -import { Badge, PageHeader } from '~/components' -import { PopoverFilter } from '~/components/Filters' -import { Button, Table, ErrorPanel, FieldError } from '~/components/ui' +import { + Box, + Button, + DropdownMenu, + Flex, + Heading, + Table, + Text, + TextField +} from '@radix-ui/themes' +import { Badge } from '~/components' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { listPayments } from '~/lib/api/payments.server' import { paymentsSearchParams } from '~/lib/validate.server' import { PaymentType } from '~/generated/graphql' @@ -119,44 +128,68 @@ export default function PaymentsPage() { } return ( -
-
- -
-

Payments

-
-
-
-

Filters

-
- -
-
- 0 ? type : ['all']} - options={[ - { - name: 'All', - value: 'all', - action: () => + + + + Payments + + + + + + {type.length + ? `Payments: ${type.map((value) => capitalize(value)).join(', ')}` + : 'All Payments'} + + + + + + updateParams({ type: null, before: null, after: null, walletAddressId }) - }, - ...Object.values(PaymentType).map((value) => ({ - name: capitalize(value), - value: value, - action: () => setTypeFilterParams(value) - })) - ]} - /> + } + > + All + + + {Object.values(PaymentType).map((value) => ( + setTypeFilterParams(value)} + > + {capitalize(value)} + + ))} + + + { if (!walletId) { e.preventDefault() @@ -169,11 +202,11 @@ export default function PaymentsPage() { } }} > -
- + setWalletId(e.target.value)} /> @@ -182,10 +215,11 @@ export default function PaymentsPage() { type='hidden' value={searchParams.get('type') ?? ''} /> - -
- +
+ {renderFieldError(response?.errors?.fieldErrors.walletAddressId)} -
-
+ + + + {renderErrorPanel(response?.errors.message)} + + + + + + + ID + Type + State + Date + + + + {payments.edges.length ? ( + payments.edges.map((payment) => ( + { + const subpath = paymentSubpathByType[payment.node.type] + return navigate(`/payments/${subpath}/${payment.node.id}`) + }} + > + + {payment.node.id} + + + {capitalize(payment.node.type)} + + + + {payment.node.state} + + + + {new Date(payment.node.createdAt).toLocaleString()} + + + )) + ) : ( + + + No payments found. + + + )} + + + + + -
-
- - - - {payments.edges.length ? ( - payments.edges.map((payment) => ( - { - const subpath = paymentSubpathByType[payment.node.type] - return navigate(`/payments/${subpath}/${payment.node.id}`) - }} - > - {payment.node.id} - {capitalize(payment.node.type)} - - - {payment.node.state} - - - - {new Date(payment.node.createdAt).toLocaleString()} - - - )) - ) : ( - - - No payments found. - - - )} - -
-
- - -
-
-
+ + + + + ) } diff --git a/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.tsx b/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.tsx index b56a30bbeb..27fa9bd463 100644 --- a/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.tsx +++ b/packages/frontend/app/routes/payments.incoming.$incomingPaymentId.tsx @@ -2,8 +2,8 @@ import type { LoaderFunctionArgs } from '@remix-run/node' import { json } from '@remix-run/node' import { Link, Outlet, useLoaderData } from '@remix-run/react' import { z } from 'zod' -import { Badge, PageHeader } from '~/components' -import { Button } from '~/components/ui' +import { Badge } from '~/components' +import { Box, Button, Card, Flex, Heading, Text } from '@radix-ui/themes' import { IncomingPaymentState } from '~/generated/graphql' import { getIncomingPayment } from '~/lib/api/payments.server' import { @@ -48,82 +48,108 @@ export default function ViewIncomingPaymentPage() { const displayLiquidityAmount = `${formatAmount( incomingPayment.liquidity ?? '0', incomingPayment.receivedAmount.assetScale - )} - ${incomingPayment.receivedAmount.assetCode}` + )} ${incomingPayment.receivedAmount.assetCode}` const expiresAtLocale = new Date(incomingPayment.expiresAt).toLocaleString() return ( -
-
- {/* Incoming Payment General Info */} - - - -
- {/* Incoming Payment General Info*/} -
-

General Information

-

- Created at {new Date(incomingPayment.createdAt).toLocaleString()}{' '} -

- {new Date(expiresAtLocale) > new Date() && ( -

Expires at {expiresAtLocale}

- )} -
-
-
-
-

Incoming Payment ID

-

{incomingPayment.id}

-
-
-

Wallet Address ID

- - {incomingPayment.walletAddressId} - -
-
-

State

- - {incomingPayment.state} - -
-
-

Incoming Amount

-

+ + + Incoming Payment Details + + + + + + General Information + + + + Created at {new Date(incomingPayment.createdAt).toLocaleString()} + + {new Date(expiresAtLocale) > new Date() && ( + + Expires at {expiresAtLocale} + + )} + + + + + + + + Incoming Payment ID + + + {incomingPayment.id} + + + + + + Wallet Address ID + + + {incomingPayment.walletAddressId} + + + + + + State + + + + {incomingPayment.state} + + + + + + + + + Incoming Amount + {incomingPayment.incomingAmount ? ( - formatAmount( - incomingPayment.incomingAmount.value, - incomingPayment.incomingAmount.assetScale - ) + - ' ' + - incomingPayment.incomingAmount.assetCode + + {formatAmount( + incomingPayment.incomingAmount.value, + incomingPayment.incomingAmount.assetScale + )}{' '} + {incomingPayment.incomingAmount.assetCode} + ) : ( - None + + None + )} -

-
-
-

Received Amount

-

- {formatAmount( - incomingPayment.receivedAmount.value, - incomingPayment.receivedAmount.assetScale - ) + - ' ' + - incomingPayment.receivedAmount.assetCode} -

-
-
+ + + + + Received Amount + + + {formatAmount( + incomingPayment.receivedAmount.value, + incomingPayment.receivedAmount.assetScale + )}{' '} + {incomingPayment.receivedAmount.assetCode} + + + + + {incomingPayment.metadata ? (
- Metadata + + Metadata +
                   
) : ( -
-

Metadata

-

- None -

-
+ <> + + Metadata + + + None + + )} -
-
-
-
- {/* Incoming Payment General Info - END */} - {/* Incoming Payment Liquidity */} -
-
-

Liquidity Information

-
-
-
-
-

Amount

-

{displayLiquidityAmount}

-
-
+ + + + + + + + + Liquidity Information + + + + Amount + + {displayLiquidityAmount} + + + {canWithdrawLiquidity ? ( - ) : ( )} -
-
-
-
- {/* Incoming Payment Liquidity - END */} -
+ + + + + -
+ ) } diff --git a/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.tsx b/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.tsx index 47db7960b2..5c7b87e8c1 100644 --- a/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.tsx +++ b/packages/frontend/app/routes/payments.outgoing.$outgoingPaymentId.tsx @@ -2,8 +2,8 @@ import type { LoaderFunctionArgs } from '@remix-run/node' import { json } from '@remix-run/node' import { Link, Outlet, useLoaderData } from '@remix-run/react' import { z } from 'zod' -import { Badge, PageHeader } from '~/components' -import { Button } from '~/components/ui' +import { Badge } from '~/components' +import { Box, Button, Card, Flex, Heading, Text } from '@radix-ui/themes' import { OutgoingPaymentState } from '~/generated/graphql' import { getOutgoingPayment } from '~/lib/api/payments.server' import { @@ -60,167 +60,204 @@ export default function ViewOutgoingPaymentPage() { ] return ( -
-
- {/* Outgoing Payment General Info */} - - - -
- {/* Outgoing Payment General Info*/} -
-

General Information

-

- Created at {new Date(outgoingPayment.createdAt).toLocaleString()}{' '} -

-
-
-
-
-

Outgoing Payment ID

-

{outgoingPayment.id}

-
-
-

Wallet Address ID

- - {outgoingPayment.walletAddressId} - -
-
-

State

- - {outgoingPayment.state} - -
-
-

Receiver

- + + + Outgoing Payment Details + + + + + + General Information + + + Created at {new Date(outgoingPayment.createdAt).toLocaleString()} + + + + + + + + Outgoing Payment ID + + + {outgoingPayment.id} + + + + + + Wallet Address ID + + + {outgoingPayment.walletAddressId} + + + + + + State + + + + {outgoingPayment.state} + + + + + + + + Receiver + + {outgoingPayment.receiver} -
-
-

Receive Amount

-

- {formatAmount( - outgoingPayment.receiveAmount.value, - outgoingPayment.receiveAmount.assetScale - ) + - ' ' + - outgoingPayment.receiveAmount.assetCode} -

-
-
-

Debit Amount

-

- {formatAmount( - outgoingPayment.debitAmount.value, - outgoingPayment.debitAmount.assetScale - ) + - ' ' + - outgoingPayment.debitAmount.assetCode} -

-
-
-

Sent Amount

-

- {formatAmount( - outgoingPayment.sentAmount.value, - outgoingPayment.sentAmount.assetScale - ) + - ' ' + - outgoingPayment.sentAmount.assetCode} -

-
-
-

Error

- {outgoingPayment.error ? ( -

{outgoingPayment.error}

- ) : ( - None - )} -
-
- {outgoingPayment.metadata ? ( -
- Metadata -
-                  
- ) : ( -
-

Metadata

-

- None -

-
- )} -
-
-
-
- {/* Outgoing Payment General Info - END */} - - {/* Outgoing Payment Liquidity */} -
-
-

Liquidity Information

-
-
-
-
-

Amount

-

{withdrawLiquidityDisplayAmount}

-
-
+ + + + + + Receive Amount + + + {formatAmount( + outgoingPayment.receiveAmount.value, + outgoingPayment.receiveAmount.assetScale + )}{' '} + {outgoingPayment.receiveAmount.assetCode} + + + + + + Debit Amount + + + {formatAmount( + outgoingPayment.debitAmount.value, + outgoingPayment.debitAmount.assetScale + )}{' '} + {outgoingPayment.debitAmount.assetCode} + + + + + + Sent Amount + + + {formatAmount( + outgoingPayment.sentAmount.value, + outgoingPayment.sentAmount.assetScale + )}{' '} + {outgoingPayment.sentAmount.assetCode} + + + + + + Error + + {outgoingPayment.error ? ( + + {outgoingPayment.error} + + ) : ( + + None + + )} + + + + {outgoingPayment.metadata ? ( +
+ + Metadata + +
+                    
+ ) : ( + <> + + Metadata + + + None + + + )} +
+
+ + + + + + + + Liquidity Information + + + + Amount + + {withdrawLiquidityDisplayAmount} + + + {BigInt(outgoingPayment.liquidity ?? '0') ? ( - ) : ( )} {outgoingPayment.state === OutgoingPaymentState.Funding ? ( - ) : ( )} -
-
-
-
- {/* Outgoing Payment Liquidity - END */} -
- {/* */} + + + + + -
+ ) } diff --git a/packages/frontend/app/routes/peers.$peerId.tsx b/packages/frontend/app/routes/peers.$peerId.tsx index 8cadf5e4c7..659c0cf63a 100644 --- a/packages/frontend/app/routes/peers.$peerId.tsx +++ b/packages/frontend/app/routes/peers.$peerId.tsx @@ -10,16 +10,25 @@ import { useFormAction, useLoaderData, useNavigation, - useSubmit + useSubmit, + Link } from '@remix-run/react' -import { type FormEvent, useRef, useState } from 'react' +import { type FormEvent, type ReactNode, useRef, useState } from 'react' import { z } from 'zod' -import { DangerZone, PageHeader } from '~/components' import { ConfirmationDialog, type ConfirmationDialogRef } from '~/components/ConfirmationDialog' -import { Button, ErrorPanel, Input, PasswordInput } from '~/components/ui' +import { + Box, + Button, + Card, + Flex, + Heading, + Text, + TextField +} from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { deletePeer, getPeer, updatePeer } from '~/lib/api/peer.server' import { messageStorage, setMessageAndRedirect } from '~/lib/message.server' import { @@ -31,6 +40,67 @@ import type { ZodFieldErrors } from '~/shared/types' import { formatAmount } from '~/shared/utils' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean + defaultValue?: string | number + value?: string | number + disabled?: boolean + readOnly?: boolean + description?: ReactNode +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required, + defaultValue, + value, + disabled, + readOnly, + description +}: FormFieldProps) => ( + + + + + {description ? ( + + {description} + + ) : null} + + {renderFieldError(error)} + +) + export async function loader({ request, params }: LoaderFunctionArgs) { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -75,292 +145,299 @@ export default function ViewPeerPage() { } return ( -
-
- {/* Peer General Info */} - -
- {peer.name ? ( -

- Name:{' '} - - {peer.name} - -

- ) : null} -
- -
-
- {/* Peer General Info*/} -
-

General Information

-

- Created at {new Date(peer.createdAt).toLocaleString()} -

- -
-
-
-
-
- - - - The name of the{' '} - - peer - - . - - } - /> - - {"The peer's "} - - address on the Interledger network. - - - } - /> - - The maximum amount of value that can be sent in a single{' '} - - Interledger STREAM Packet - - . - - } - /> -
-
- + +
+
+ +
+ + + HTTP Information + + {renderErrorPanel(response?.errors.http.message)} +
+
+ + + + List of valid tokens to accept when receiving incoming{' '} + + ILP packets + {' '} + from the peer. + + } + /> + + Valid auth token to present when sending outgoing{' '} + + ILP packets + {' '} + to the peer. + + } + /> + + Endpoint on the peer to which outgoing ILP packets + will be sent. + + } + /> + + + + +
+
+
+
+ + + Asset Information + + + + + Code + + + {peer.asset.code} + + + + + Scale + + + {peer.asset.scale} + + + + + Withdrawal threshold + + + {peer.asset.withdrawalThreshold ?? + 'No withdrawal threshold'} + + + + + + + +
+ + + Liquidity Information + + + + Amount + + {formatAmount(peer.liquidity ?? '0', peer.asset.scale)}{' '} + {peer.asset.code} + + + + -
-
- -
-
- {/* Peer General Info - END */} - {/* Peer HTTP Info */} -
-
-

HTTP Information

- -
-
-
-
-
- - - List of valid tokens to accept when receiving incoming{' '} - - ILP packets - {' '} - from the peer. - - } - /> - - Valid auth token to present when sending outgoing{' '} - - ILP packets - {' '} - to the peer. - - } - /> - - Endpoint on the peer to which outgoing ILP packets will - be sent. - - } - /> -
-
- -
-
-
-
-
- {/* Peer HTTP Info - END */} - {/* Peer Asset Info */} -
-
-

Asset Information

-
-
-
-
-

Code

-

{peer.asset.code}

-
-
-

Scale

-

{peer.asset.scale}

-
-
-

Withdrawal threshold

-

- {peer.asset.withdrawalThreshold ?? 'No withdrawal threshhold'} -

-
-
-
- -
-
-
- {/* Peer Asset Info - END */} - {/* Peer Liquidity Info */} -
-
-

Liquidity Information

-
-
-
-
-

Amount

-

- {formatAmount(peer.liquidity ?? '0', peer.asset.scale)}{' '} - {peer.asset.code} -

-
-
- - -
-
-
-
- {/* Peer Liquidity Info - END */} - {/* DELETE PEER - Danger zone */} - + + + + + + +
- - -
-
-
- + + + + -
+ ) } diff --git a/packages/frontend/app/routes/peers._index.tsx b/packages/frontend/app/routes/peers._index.tsx index a8d201f4f6..100b32b1fe 100644 --- a/packages/frontend/app/routes/peers._index.tsx +++ b/packages/frontend/app/routes/peers._index.tsx @@ -1,7 +1,6 @@ import { json, type LoaderFunctionArgs } from '@remix-run/node' import { useLoaderData, useNavigate } from '@remix-run/react' -import { PageHeader } from '~/components' -import { Button, Table } from '~/components/ui' +import { Box, Button, Flex, Heading, Table, Text } from '@radix-ui/themes' import { listPeers } from '~/lib/api/peer.server' import { paginationSchema } from '~/lib/validate.server' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' @@ -38,87 +37,90 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { } export default function PeersPage() { - const { peers, previousPageUrl, nextPageUrl } = useLoaderData() + const { peers, previousPageUrl, nextPageUrl} = useLoaderData() const navigate = useNavigate() return ( -
- {/* Peers Table */} -
- -
-

Peers

-
-
- -
-
- - - - {peers.edges.length ? ( - peers.edges.map((peer) => ( - navigate(`/peers/${peer.node.id}`)} - > - -
- {peer.node.name ? ( - {peer.node.name} - ) : ( - No peer name - )} -
- (ID: {peer.node.id}) -
-
-
- {peer.node.staticIlpAddress} - - {peer.node.asset.code} (Scale: {peer.node.asset.scale}) - - {peer.node.http.outgoing.endpoint} -
- )) - ) : ( + + + + Peers + + + + + + + - - No peers found. - + Name + ILP Address + Asset + Outgoing HTTP Endpoint - )} -
-
- {/* Pagination */} -
- - -
- {/* Pagination - END */} -
- {/* Peers Table - END*/} -
+ + + {peers.edges.length ? ( + peers.edges.map((peer) => ( + navigate(`/peers/${peer.node.id}`)} + > + + + + {peer.node.name || 'No peer name'} + + + (ID: {peer.node.id}) + + + + + {peer.node.staticIlpAddress} + + + + {peer.node.asset.code} (Scale: {peer.node.asset.scale}) + + + + {peer.node.http.outgoing.endpoint} + + + )) + ) : ( + + + No peers found. + + + )} + + + + + + + + + + + ) } diff --git a/packages/frontend/app/routes/peers.create.tsx b/packages/frontend/app/routes/peers.create.tsx index eaa520e2d4..b1b0ff0a3e 100644 --- a/packages/frontend/app/routes/peers.create.tsx +++ b/packages/frontend/app/routes/peers.create.tsx @@ -9,9 +9,8 @@ import { useLoaderData, useNavigation } from '@remix-run/react' -import { PageHeader } from '~/components/PageHeader' -import type { SelectOption } from '~/components/ui' -import { Button, ErrorPanel, Input, Select } from '~/components/ui' +import { Box, Button, Card, Flex, Heading, Select, Text, TextField } from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { loadAssets } from '~/lib/api/asset.server' import { createPeer } from '~/lib/api/peer.server' import { messageStorage, setMessageAndRedirect } from '~/lib/message.server' @@ -20,9 +19,129 @@ import type { ZodFieldErrors } from '~/shared/types' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' import type { RedirectDialogRef } from '~/components/RedirectDialog' import { RedirectDialog } from '~/components/RedirectDialog' +import type { ReactNode } from 'react' import { useEffect, useRef, useState } from 'react' import { loadTenants, whoAmI } from '~/lib/api/tenant.server' +type SelectOption = { + label: string + value: string +} + +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean + description?: ReactNode +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required, + description +}: FormFieldProps) => ( + + + + + {description ? ( + + {description} + + ) : null} + + {renderFieldError(error)} + +) + +type SelectFieldProps = { + label: string + name: string + options: SelectOption[] + placeholder: string + required?: boolean + error?: string | string[] + description?: ReactNode + defaultValue?: SelectOption + onChange?: (value?: SelectOption) => void + bringForward?: boolean +} + +const SelectField = ({ + label, + name, + options, + placeholder, + required, + error, + description, + defaultValue, + onChange, + bringForward +}: SelectFieldProps) => { + const [selectedValue, setSelectedValue] = useState( + defaultValue?.value ?? '' + ) + + return ( + + + + + {description ? ( + + {description} + + ) : null} + +
+ { + setSelectedValue(value) + onChange?.(options.find((option) => option.value === value)) + }} + > + + + {options.map((option) => ( + + {option.label} + + ))} + + +
+ {renderFieldError(error)} +
+ ) +} + export async function loader({ request }: LoaderFunctionArgs) { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -71,240 +190,231 @@ export default function CreatePeerPage() { redirectButtonText={'Create Asset'} > -
-
- -

Create Peer

- -
- {/* Create Peer form */} -
-
- -
+ + + Create Peer -
- {/* Peer General Info */} -
-
-

General Information

-
-
-
- - The name of the{' '} - - peer - {' '} - to be added. - - } - /> - - {"The peer's "} - - address on the Interledger network. - - - } - /> - - The maximum amount of value that can be sent in a - single{' '} - - Interledger STREAM Packet - - . - - } - /> -
-
-
- {/* Peer General Info - END */} - {/* Peer HTTP Info */} -
-
-

HTTP Information

-
-
-
- - List of valid tokens to accept when receiving incoming{' '} - - ILP packets - {' '} - from the peer. - - } - /> - - Valid auth token to present when sending outgoing{' '} - - ILP packets - {' '} - to the peer. - - } - /> - - Endpoint on the peer to which outgoing ILP packets - will be sent. - - } - /> -
-
-
- {/* Peer HTTP Info - END */} - {/* Peer Asset */} -
-
-

Asset Information

-
-
-
- {tenants ? ( - ({ - value: asset.node.id, - label: `${asset.node.code} (Scale: ${asset.node.scale})` - }))} - error={response?.errors.fieldErrors.asset} - name='asset' - placeholder='Select asset...' - label='Asset' - description={ - <> - The type of{' '} - - asset - {' '} - that is sent to & received from the peer. - - } - required - /> - )} - {tenants && tenantId && ( - message.text) - .join('; ')} - /> + {attributes.type === 'hidden' ? ( + + ) : ( +
+ + {label} + {attributes.required ? ( + * + ) : null} + + + {renderFieldError( + field.messages + .map((message) => message.text) + .join('; ') + )} +
+ )}
) } @@ -159,19 +218,43 @@ export default function Settings() { ) { return (
- message.text) - .join('; ')} - /> + {attributes.type === 'hidden' ? ( + + ) : ( +
+ + {label} + {attributes.required ? ( + * + ) : null} + + + {renderFieldError( + field.messages + .map((message) => message.text) + .join('; ') + )} +
+ )}
) } diff --git a/packages/frontend/app/routes/tenants.$tenantId.tsx b/packages/frontend/app/routes/tenants.$tenantId.tsx index 846de98532..74d8e78f92 100644 --- a/packages/frontend/app/routes/tenants.$tenantId.tsx +++ b/packages/frontend/app/routes/tenants.$tenantId.tsx @@ -11,11 +11,11 @@ import { useNavigation, useSubmit } from '@remix-run/react' -import { type FormEvent, useState, useRef } from 'react' +import { type FormEvent, useRef, useState } from 'react' import type { ZodSchema } from 'zod' import { z } from 'zod' -import { DangerZone, PageHeader } from '~/components' -import { Button, ErrorPanel, Input, PasswordInput } from '~/components/ui' +import { Box, Button, Card, Flex, Heading, Text, TextField } from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { ConfirmationDialog, type ConfirmationDialogRef @@ -33,6 +33,55 @@ import { checkAuthAndRedirect } from '../lib/kratos_checks.server' import { getTenantInfo } from '~/lib/api/tenant.server' import type { UpdateTenantInput } from '~/generated/graphql' +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean + defaultValue?: string + value?: string + disabled?: boolean + readOnly?: boolean +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required, + defaultValue, + value, + disabled, + readOnly +}: FormFieldProps) => ( + + + + + + {renderFieldError(error)} + +) + export async function loader({ request, params }: LoaderFunctionArgs) { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -74,164 +123,165 @@ export default function ViewTenantPage() { } return ( -
-
- - - -
-
-

General Information

-

- {`Created at ${new Date(tenant.createdAt).toLocaleString()}`} - {tenantDeleted && tenant.deletedAt && ( - <> -
- {`Deleted at ${new Date(tenant.deletedAt).toLocaleString()}`} - - )} -

-
-
- -
-
- - - - -
-
- {!tenantDeleted && ( - - )} -
-
- -
-
- {/* Identity Provider Information */} -
-
-

- Identity Provider Information -

- -
-
-
-
-
- - - -
-
- {!tenantDeleted && ( - - )} -
-
-
-
-
- {/* Identity Provider Information - END */} - {/* Sensitive Info */} - {me.isOperator && ( -
-
-

Sensitive Information

- -
-
+ + + Tenant Details + + + + + + + General Information + + + {`Created at ${new Date(tenant.createdAt).toLocaleString()}`} + {tenantDeleted && tenant.deletedAt + ? ` · Deleted at ${new Date(tenant.deletedAt).toLocaleString()}` + : ''} + + + {renderErrorPanel(response?.errors?.general.message)}
-
- - + + -
-
- {!tenantDeleted && !me.isOperator && ( + + + + + + + + + + + {!tenantDeleted && ( )} -
+
-
-
- )} - {/* Sensitive - END */} - {/* DELETE TENANT - Danger zone */} + + + + + Identity Provider Information + + {renderErrorPanel(response?.errors?.idp.message)} +
+
+ + + + + + + {!tenantDeleted && ( + + )} + +
+
+
+ + {me.isOperator && ( + + + Sensitive Information + + {renderErrorPanel(response?.errors?.sensitive.message)} +
+
+ + + + + + {!tenantDeleted && !me.isOperator && ( + + )} + +
+
+
+ )} + + + {!tenantDeleted && me.isOperator && me.id !== tenant.id && ( - +
- - -
-
+ )} + -
+ -
+ ) } diff --git a/packages/frontend/app/routes/tenants._index.tsx b/packages/frontend/app/routes/tenants._index.tsx index ef1fdc848d..6d99e3de86 100644 --- a/packages/frontend/app/routes/tenants._index.tsx +++ b/packages/frontend/app/routes/tenants._index.tsx @@ -1,7 +1,6 @@ import { json, type LoaderFunctionArgs } from '@remix-run/node' import { useLoaderData, useNavigate } from '@remix-run/react' -import { Badge, BadgeColor, PageHeader } from '~/components' -import { Button, Table } from '~/components/ui' +import { Box, Button, Flex, Heading, Table, Badge, Text } from '@radix-ui/themes' import { getTenantInfo, listTenants, whoAmI } from '~/lib/api/tenant.server' import { paginationSchema } from '~/lib/validate.server' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' @@ -59,99 +58,96 @@ export default function TenantsPage() { const navigate = useNavigate() return ( -
-
- -
-

Tenants

-
-
- {me.isOperator && ( - - )} -
-
- - - - {tenantEdges.length ? ( - tenantEdges.map((tenant) => ( - navigate(`/tenants/${tenant.node.id}`)} - > - -
-
- - {tenant.node.publicName ? ( - - {tenant.node.publicName} - - ) : ( - - No public name - + + + + + Tenants + + Manage your tenants and their access. + + + {me.isOperator && ( + + )} + + + + + + + Public name + Email + Status + + + + {tenantEdges.length ? ( + tenantEdges.map((tenant) => ( + navigate(`/tenants/${tenant.node.id}`)} + > + + + + + {tenant.node.publicName || 'No public name'} + + {me.isOperator && me.id == tenant.node.id && ( + Operator )} - - {me.isOperator && me.id == tenant.node.id && ( - Operator - )} -
-
- (ID: {tenant.node.id}) -
-
-
- - {tenant.node.email ? ( - {tenant.node.email} - ) : ( - No email - )} - - - {tenant.node.deletedAt ? ( - Inactive - ) : ( - Active - )} + + + (ID: {tenant.node.id}) + + + + + + {tenant.node.email || 'No email'} + + + + {tenant.node.deletedAt ? ( + Inactive + ) : ( + Active + )} + +
+ )) + ) : ( + + + No tenants found. - )) - ) : ( - - - No tenants found. - - - )} -
-
-
+ )} + + + + + -
-
-
+ + + ) } diff --git a/packages/frontend/app/routes/tenants.create.tsx b/packages/frontend/app/routes/tenants.create.tsx index 9785e1c3b8..d0cc254f35 100644 --- a/packages/frontend/app/routes/tenants.create.tsx +++ b/packages/frontend/app/routes/tenants.create.tsx @@ -1,13 +1,7 @@ -import { useState } from 'react' import { json, type ActionFunctionArgs, redirect } from '@remix-run/node' -import { - Form, - useActionData, - useLoaderData, - useNavigation -} from '@remix-run/react' -import { PageHeader } from '~/components' -import { Button, ErrorPanel, Input, PasswordInput } from '~/components/ui' +import { Form, useActionData, useLoaderData, useNavigation } from '@remix-run/react' +import { Box, Button, Card, Flex, Heading, Text, TextField } from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { createTenant, whoAmI } from '~/lib/api/tenant.server' import { messageStorage, setMessageAndRedirect } from '~/lib/message.server' import { createTenantSchema } from '~/lib/validate.server' @@ -16,6 +10,43 @@ import { checkAuthAndRedirect } from '../lib/kratos_checks.server' import { type LoaderFunctionArgs } from '@remix-run/node' import { TenantSettingKey } from '~/generated/graphql' +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required +}: FormFieldProps) => ( + + + + + + {renderFieldError(error)} + +) + export const loader = async ({ request }: LoaderFunctionArgs) => { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -30,65 +61,43 @@ export default function CreateTenantPage() { const { me } = useLoaderData() if (!me || !me.isOperator) throw redirect('tenants') - const [exchangeRatesUrl, setExchangeRatesUrl] = useState() - const [webhookUrl, setWebhookUrl] = useState() - const [webhookTimeout, setWebhookTimeout] = useState() - const [webhookMaxRetry, setWebhookMaxRetry] = useState() - const [walletAddressUrl, setWalletAddressUrl] = useState() - const [ilpAddress, setIlpAddress] = useState() - const tenantSettings: { name: string - value: - | ReturnType>[0] - | ReturnType>[0] - setValue: - | ReturnType>[1] - | ReturnType>[1] placeholder: string label: string + type?: 'text' | 'email' | 'password' | 'number' }[] = [ { name: 'exchangeRatesUrl', placeholder: 'Exhange Rates Url', - label: 'Exchange Rates Url', - value: exchangeRatesUrl, - setValue: setExchangeRatesUrl + label: 'Exchange Rates Url' }, { name: 'webhookUrl', placeholder: 'Webhook Url', - label: 'Webhook Url', - value: webhookUrl, - setValue: setWebhookUrl + label: 'Webhook Url' }, { name: 'webhookTimeout', placeholder: 'Webhook Timeout', label: 'Webhook Timeout', - value: webhookTimeout, - setValue: setWebhookTimeout + type: 'number' }, { name: 'webhookMaxRetry', placeholder: 'Webhook Max Retry', label: 'Webhook Max Retry', - value: webhookMaxRetry, - setValue: setWebhookMaxRetry + type: 'number' }, { name: 'walletAddressUrl', placeholder: 'Wallet Address Url', - label: 'Wallet Address Url', - value: walletAddressUrl, - setValue: setWalletAddressUrl + label: 'Wallet Address Url' }, { name: 'ilpAddress', placeholder: 'ILP Address', - label: 'ILP Address', - value: ilpAddress, - setValue: setIlpAddress + label: 'ILP Address' } ] @@ -113,125 +122,134 @@ export default function CreateTenantPage() { } return ( -
-
- -

Create Tenant

- -
- {/* Create Tenant form */} -
-
- -
+ + + + Create Tenant + + + {renderErrorPanel(response?.errors.message)} + + + +
+ + + + + + General Information + +
+ + +
+
+ + + + Sensitive Information + + + -
- {/* Tenant General Info */} -
-
-

General Information

-
-
-
- - -
-
-
- {/* Tenant General Info - END */} - {/* Tenant Sensitive Info */} -
-
-

Sensitive Information

-
-
-
- -
-
-
- {/* Tenant Sensitive Info - END */} - {/* Tenant Identity Provider */} -
-
-

- Identity Provider Information -

-
-
-
- - -
-
-
- {/* Tenant Identity Provider - End */} - {/* Tenant Settings */} -
-
-

Tenant Settings

-
-
-
- {tenantSettings.map((setting) => ( -
- + + Identity Provider Information + + -

- {getTenantSettingError(setting.name)} -

-
- ))} -
- -
-
- {/* Tenant Settings - END */} -
- -
-
- - {/* Create Tenant form - END */} -
-
+ + + + + + Tenant Settings + + + +
+ + +
+ + + {renderErrorPanel(tenantSettingErrors)} +
+ + + + + + + +
+ + +
+
) } diff --git a/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx b/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx index 88b4950ee4..e07c99ff18 100644 --- a/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx +++ b/packages/frontend/app/routes/wallet-addresses.$walletAddressId.tsx @@ -8,11 +8,21 @@ import { Outlet, useActionData, useLoaderData, - useNavigation + useNavigation, + Link } from '@remix-run/react' import { z } from 'zod' -import { PageHeader } from '~/components' -import { Button, ErrorPanel, Input, Dropdown } from '~/components/ui' +import { + Box, + Button, + Card, + Flex, + Heading, + Text, + TextField, + Select +} from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { getWalletAddress, updateWalletAddress @@ -20,9 +30,63 @@ import { import { messageStorage, setMessageAndRedirect } from '~/lib/message.server' import { updateWalletAddressSchema } from '~/lib/validate.server' import type { ZodFieldErrors } from '~/shared/types' -import { capitalize, formatAmount } from '~/shared/utils' +import { formatAmount } from '~/shared/utils' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean + defaultValue?: string + value?: string + disabled?: boolean + readOnly?: boolean +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required, + defaultValue, + value, + disabled, + readOnly +}: FormFieldProps) => ( + + + + + + {renderFieldError(error)} + +) + export async function loader({ request, params }: LoaderFunctionArgs) { const cookies = request.headers.get('cookie') await checkAuthAndRedirect(request.url, cookies) @@ -55,161 +119,190 @@ export default function ViewWalletAddressPage() { )} ${walletAddress.asset.code}` return ( -
-
- - - -
-
-

General Information

-

- Created at {new Date(walletAddress.createdAt).toLocaleString()} -

- -
-
-
-
-
- - - - - -
-
- -
-
-
-
-
-
-
-

Asset Information

-
-
-
-
-

Code

-

{walletAddress.asset.code}

-
-
-

Scale

-

{walletAddress.asset.scale}

-
-
-

Withdrawal threshold

-

- {walletAddress.asset.withdrawalThreshold ?? - 'No withdrawal threshold'} -

-
-
-
- -
-
-
-
-
-

Liquidity Information

-
-
-
-
-

Amount

-

{displayLiquidityAmount}

-
-
- {BigInt(walletAddress.liquidity ?? '0') ? ( - + + + + +
+ + + Asset Information + + + + + Code + + + {walletAddress.asset.code} + + + + + Scale + + + {walletAddress.asset.scale} + + + + + Withdrawal threshold + + + {walletAddress.asset.withdrawalThreshold ?? + 'No withdrawal threshold'} + + + + + - ) : ( - + + +
+ + + Liquidity Information + + + + Amount + + {displayLiquidityAmount} + + + + {BigInt(walletAddress.liquidity ?? '0') ? ( + + ) : ( + + )} + + + +
+ + + Payments + + + View the payments involving this wallet address on the payments + page. + + + - )} -
-
-
-
-
-
-

Payments

-

- View the payments involving this wallet address on the payments - page -

-
-
-
- -
-
-
-
+ Go to payments page + + + + + + + -
+ ) } diff --git a/packages/frontend/app/routes/wallet-addresses._index.tsx b/packages/frontend/app/routes/wallet-addresses._index.tsx index 0ff8612a98..454d5a0d4d 100644 --- a/packages/frontend/app/routes/wallet-addresses._index.tsx +++ b/packages/frontend/app/routes/wallet-addresses._index.tsx @@ -1,10 +1,8 @@ import { json, type LoaderFunctionArgs } from '@remix-run/node' import { useLoaderData, useNavigate } from '@remix-run/react' -import { Badge, PageHeader } from '~/components' -import { Button, Table } from '~/components/ui' +import { Box, Button, Flex, Heading, Table, Badge, Text } from '@radix-ui/themes' import { listWalletAddresses } from '~/lib/api/wallet-address.server' import { paginationSchema } from '~/lib/validate.server' -import { badgeColorByWalletAddressStatus } from '~/shared/utils' import { checkAuthAndRedirect } from '../lib/kratos_checks.server' export const loader = async ({ request }: LoaderFunctionArgs) => { @@ -38,88 +36,88 @@ export const loader = async ({ request }: LoaderFunctionArgs) => { return json({ walletAddresses, previousPageUrl, nextPageUrl }) } +const statusColorMap: Record = { + ACTIVE: 'green', + INACTIVE: 'red' +} + export default function WalletAddressesPage() { const { walletAddresses, previousPageUrl, nextPageUrl } = useLoaderData() const navigate = useNavigate() return ( -
-
- -
-

Wallet Addresses

-
-
+ + + + Wallet Addresses + + + + + + + + + Wallet address + Public name + Status + + + + {walletAddresses.edges.length ? ( + walletAddresses.edges.map((wa) => ( + navigate(`/wallet-addresses/${wa.node.id}`)} + > + + {wa.node.address} + + + + {wa.node.publicName || 'No public name'} + + + + + {wa.node.status} + + + + )) + ) : ( + + + No wallet addresses found. + + + )} + + + + + -
-
- - - - {walletAddresses.edges.length ? ( - walletAddresses.edges.map((wa) => ( - navigate(`/wallet-addresses/${wa.node.id}`)} - > - {wa.node.address} - -
- {wa.node.publicName ? ( - - {wa.node.publicName} - - ) : ( - No public name - )} -
-
- - - {wa.node.status} - - -
- )) - ) : ( - - - No wallet addresses found. - - - )} -
-
-
- - -
-
-
+ + + + + ) } diff --git a/packages/frontend/app/routes/wallet-addresses.create.tsx b/packages/frontend/app/routes/wallet-addresses.create.tsx index 10753d723c..d840eed484 100644 --- a/packages/frontend/app/routes/wallet-addresses.create.tsx +++ b/packages/frontend/app/routes/wallet-addresses.create.tsx @@ -1,4 +1,5 @@ -import React, { useState } from 'react' +import type { ReactNode } from 'react' +import { useState } from 'react' import { json, type ActionFunctionArgs } from '@remix-run/node' import { Form, @@ -6,9 +7,8 @@ import { useLoaderData, useNavigation } from '@remix-run/react' -import { PageHeader } from '~/components' -import type { SelectOption } from '~/components/ui' -import { Button, ErrorPanel, Input, Select } from '~/components/ui' +import { Box, Button, Card, Flex, Heading, Select, Text, TextField } from '@radix-ui/themes' +import { renderErrorPanel, renderFieldError } from '~/lib/form-errors' import { loadAssets } from '~/lib/api/asset.server' import { createWalletAddress } from '~/lib/api/wallet-address.server' import { messageStorage, setMessageAndRedirect } from '~/lib/message.server' @@ -25,6 +25,175 @@ import { whoAmI, loadTenants, getTenantInfo } from '~/lib/api/tenant.server' const WALLET_ADDRESS_URL_KEY = 'WALLET_ADDRESS_URL' +type SelectOption = { + label: string + value: string +} + +type FormFieldProps = { + name: string + label: string + placeholder?: string + type?: 'text' | 'email' | 'password' | 'number' + error?: string | string[] + required?: boolean + description?: ReactNode +} + +const FormField = ({ + name, + label, + placeholder, + type = 'text', + error, + required, + description +}: FormFieldProps) => ( + + + + + {description ? ( + + {description} + + ) : null} + + {renderFieldError(error)} + +) + +const PlainInputField = ({ + name, + label, + placeholder, + error, + required, + description, + addOn +}: FormFieldProps & { addOn?: ReactNode }) => ( + + + + + {description ? ( + + {description} + + ) : null} +
+ {addOn ? ( + + {addOn} + + ) : null} + +
+ {renderFieldError(error)} +
+) + +type SelectFieldProps = { + label: string + name: string + options: SelectOption[] + placeholder: string + required?: boolean + error?: string | string[] + description?: ReactNode + defaultValue?: SelectOption + onChange?: (value?: SelectOption) => void + bringForward?: boolean +} + +const SelectField = ({ + label, + name, + options, + placeholder, + required, + error, + description, + defaultValue, + onChange, + bringForward +}: SelectFieldProps) => { + const [selectedValue, setSelectedValue] = useState( + defaultValue?.value ?? '' + ) + + return ( + + + + + {description ? ( + + {description} + + ) : null} + +
+ { + setSelectedValue(value) + onChange?.(options.find((option) => option.value === value)) + }} + > + + + {options.map((option) => ( + + {option.label} + + ))} + + +
+ {renderFieldError(error)} +
+ ) +} + const findWASetting = ( tenantSettings: Awaited>['settings'] ) => { @@ -85,95 +254,98 @@ export default function CreateWalletAddressPage() { : tenantWAPrefix return ( -
-
- -

Create Wallet Address

- -
-
-
- -
-
-
-
-

General Information

-
-
-
- - - - {tenants ? ( - ({ - value: asset.node.id, - label: `${asset.node.code} (Scale: ${asset.node.scale})` - }))} - error={response?.errors.fieldErrors.asset} - name='asset' - placeholder='Select asset...' - label='Asset' - required - /> - )} - {tenants && tenantId && ( - + + + {tenants ? ( + ({ + value: tenant.node.id, + label: `${tenant.node.id} ${ + tenant.node.publicName + ? `(${tenant.node.publicName})` + : '' + }` + }))} + name='tenantId' + placeholder='Select tenant...' + label='Tenant' + required + onChange={(value) => setTenantId(value)} + bringForward + error={response?.errors?.fieldErrors.tenantId} + /> + ) : ( + ({ + value: asset.node.id, + label: `${asset.node.code} (Scale: ${asset.node.scale})` + }))} + error={response?.errors.fieldErrors.asset} + name='asset' + placeholder='Select asset...' + label='Asset' + required + /> + )} + {tenants && tenantId && ( + + )} + + + + + + + + +
+
+ + + ) } diff --git a/packages/frontend/app/routes/webhook-events.data.tsx b/packages/frontend/app/routes/webhook-events.data.tsx index f51a6d0b28..2402341f00 100644 --- a/packages/frontend/app/routes/webhook-events.data.tsx +++ b/packages/frontend/app/routes/webhook-events.data.tsx @@ -63,8 +63,8 @@ export default function WebhookEventData() {
-
-
+                  
-      
-
- -
-

Webhook Events

-
-
-
-

Filters

-
+ + + + Webhook Events + + value.charAt(0).toUpperCase() + + value.slice(1).replace(/[_.]/g, ' ') + ) + .join(', ')}` + : 'All Events' + } values={type.length > 0 ? type : ['all']} options={[ { @@ -116,68 +119,88 @@ export default function WebhookEventsPage() { })) ]} /> -
-
- - - - {webhooks.edges.length ? ( - webhooks.edges.map((webhook) => ( - - {webhook.node.id} - {webhook.node.type} - - {new Date(webhook.node.createdAt).toLocaleString()} - - - - - - )) - ) : ( + + + + + + + - - No webhook events found. - + ID + Type + Date + Data - )} - -
-
- - -
-
-
+ + + {webhooks.edges.length ? ( + webhooks.edges.map((webhook) => ( + + + {webhook.node.id} + + + {webhook.node.type} + + + {new Date(webhook.node.createdAt).toLocaleString()} + + + + + + )) + ) : ( + + + No webhook events found. + + + )} + + + + + + + + + + + ) diff --git a/packages/frontend/app/styles/tailwind.css b/packages/frontend/app/styles/tailwind.css index ba6adb470b..dd0450fcb7 100644 --- a/packages/frontend/app/styles/tailwind.css +++ b/packages/frontend/app/styles/tailwind.css @@ -10,3 +10,62 @@ a.default-link { div.forward { z-index: 1; } + +/* Diagonal Flow Background */ +.bg-diagonal { + background: #fffdf9; + position: relative; +} + +.bg-diagonal::before { + content: ''; + position: fixed; + inset: 0; + background: linear-gradient( + 120deg, + #fff6f1 0%, + #ffe7d2 26%, + #f3e7ff 52%, + #e8f2ff 76%, + #fff1e3 100% + ); + opacity: 0.25; + z-index: 0; + pointer-events: none; +} + +/* Allow the body background to show through the Radix Theme wrapper. */ +.radix-themes { + background-color: transparent; +} + +/* Ensure Radix card surfaces stay white over the page background. */ +.rt-Card { + background-color: #fff; + padding: 24px; +} + +/* Remove the inner gap between Radix text field borders and fill. */ +.rt-TextFieldRoot { + background-clip: padding-box; + border-radius: var(--text-field-border-radius); + overflow: hidden; +} + +.rt-TextFieldInput { + border-radius: inherit; + padding-left: 0; + padding-right: 6px; + font-size: 14px; +} + +.rt-TextFieldInput::placeholder { + color: #6b7280; + opacity: 0.8; + font-size: 14px; +} + +/* Ensure Radix Select dropdown content has white background. */ +.rt-SelectContent { + background-color: #fff !important; +} diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 253f807ceb..aeb3cb6bfa 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -17,6 +17,7 @@ "@headlessui/react": "^1.7.19", "@ory/client": "^1.9.0", "@ory/integrations": "^1.3.1", + "@radix-ui/themes": "^3.2.1", "@remix-run/node": "^2.16.4", "@remix-run/react": "^2.16.4", "@remix-run/serve": "^2.16.4", diff --git a/packages/frontend/public/bg.svg b/packages/frontend/public/bg.svg deleted file mode 100644 index d340683d24..0000000000 --- a/packages/frontend/public/bg.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/packages/frontend/public/bg.webp b/packages/frontend/public/bg.webp index dcd5cfa2f2..ce29eda341 100644 Binary files a/packages/frontend/public/bg.webp and b/packages/frontend/public/bg.webp differ diff --git a/packages/frontend/remix.env.d.ts b/packages/frontend/remix.env.d.ts index dcf8c45e1d..4213fe7ed9 100644 --- a/packages/frontend/remix.env.d.ts +++ b/packages/frontend/remix.env.d.ts @@ -1,2 +1,7 @@ /// /// + +declare module '*.webp' { + const src: string + export default src +} diff --git a/packages/frontend/tailwind.config.js b/packages/frontend/tailwind.config.js index bac9de89d6..8420254913 100644 --- a/packages/frontend/tailwind.config.js +++ b/packages/frontend/tailwind.config.js @@ -3,9 +3,6 @@ module.exports = { content: ['./app/**/*.{js,ts,jsx,tsx}'], theme: { extend: { - backgroundImage: { - polkadot: 'url("public/bg.webp")' - }, colors: { pearl: '#eee6e2', offwhite: '#fbf7f4', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee8f9930bf..7198c8666d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -240,7 +240,7 @@ importers: version: link:../token-introspection ts-node-dev: specifier: ^2.0.0 - version: 2.0.0(@swc/core@1.15.3)(@types/node@24.10.1)(typescript@5.9.3) + version: 2.0.0(@swc/core@1.15.3)(@types/node@20.14.15)(typescript@5.9.3) uuid: specifier: ^9.0.1 version: 9.0.1 @@ -253,7 +253,7 @@ importers: version: 8.4.1 '@graphql-codegen/cli': specifier: 5.0.4 - version: 5.0.4(@babel/core@7.28.5)(@types/node@24.10.1)(graphql@16.11.0) + version: 5.0.4(@babel/core@7.28.5)(@types/node@20.14.15)(graphql@16.11.0) '@graphql-codegen/introspection': specifier: 4.0.3 version: 4.0.3(graphql@16.11.0) @@ -292,7 +292,7 @@ importers: version: 14.0.0-beta.19 node-mocks-http: specifier: ^1.16.2 - version: 1.16.2(@types/node@24.10.1) + version: 1.16.2(@types/node@20.14.15) openapi-types: specifier: ^12.1.3 version: 12.1.3 @@ -473,7 +473,7 @@ importers: devDependencies: '@graphql-codegen/cli': specifier: 5.0.4 - version: 5.0.4(@babel/core@7.28.5)(@types/node@24.10.1)(graphql@16.11.0) + version: 5.0.4(@babel/core@7.28.5)(@types/node@20.14.15)(graphql@16.11.0) '@graphql-codegen/introspection': specifier: 4.0.3 version: 4.0.3(graphql@16.11.0) @@ -530,7 +530,7 @@ importers: version: 14.0.0-beta.19 node-mocks-http: specifier: ^1.16.2 - version: 1.16.2(@types/node@24.10.1) + version: 1.16.2(@types/node@20.14.15) openapi-types: specifier: ^12.1.3 version: 12.1.3 @@ -548,7 +548,7 @@ importers: version: 0.2.3 ts-node-dev: specifier: ^2.0.0 - version: 2.0.0(@swc/core@1.15.3)(@types/node@24.10.1)(typescript@5.9.3) + version: 2.0.0(@swc/core@1.15.3)(@types/node@20.14.15)(typescript@5.9.3) packages/card-service: dependencies: @@ -676,6 +676,9 @@ importers: '@ory/integrations': specifier: ^1.3.1 version: 1.3.1(@ory/client@1.9.0)(next@15.5.6) + '@radix-ui/themes': + specifier: ^3.2.1 + version: 3.2.1(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) '@remix-run/node': specifier: ^2.16.4 version: 2.16.4(typescript@5.9.3) @@ -842,14 +845,14 @@ importers: version: 8.19.0 ts-node-dev: specifier: ^2.0.0 - version: 2.0.0(@swc/core@1.15.3)(@types/node@24.10.1)(typescript@5.9.3) + version: 2.0.0(@swc/core@1.15.3)(@types/node@20.14.15)(typescript@5.9.3) uuid: specifier: ^9.0.1 version: 9.0.1 devDependencies: '@graphql-codegen/cli': specifier: 5.0.4 - version: 5.0.4(@babel/core@7.28.5)(@types/node@24.10.1)(graphql@16.11.0) + version: 5.0.4(@babel/core@7.28.5)(@types/node@20.14.15)(graphql@16.11.0) '@graphql-codegen/introspection': specifier: 4.0.3 version: 4.0.3(graphql@16.11.0) @@ -894,7 +897,7 @@ importers: version: 14.0.0-beta.19 node-mocks-http: specifier: ^1.16.2 - version: 1.16.2(@types/node@24.10.1) + version: 1.16.2(@types/node@20.14.15) testcontainers: specifier: ^10.16.0 version: 10.16.0 @@ -4783,6 +4786,34 @@ packages: engines: {node: '>=14'} dev: true + /@floating-ui/core@1.7.3: + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + dependencies: + '@floating-ui/utils': 0.2.10 + dev: false + + /@floating-ui/dom@1.7.4: + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + dev: false + + /@floating-ui/react-dom@2.1.6(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.7.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@floating-ui/utils@0.2.10: + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + dev: false + /@graphql-codegen/add@5.0.3(graphql@16.11.0): resolution: {integrity: sha512-SxXPmramkth8XtBlAHu4H4jYcYXM/o3p01+psU+0NADQowA8jtYkK6MW5rV6T+CxkEaNZItfSmZRPgIuypcqnA==} peerDependencies: @@ -4793,7 +4824,7 @@ packages: tslib: 2.6.2 dev: true - /@graphql-codegen/cli@5.0.4(@babel/core@7.28.5)(@types/node@24.10.1)(graphql@16.11.0): + /@graphql-codegen/cli@5.0.4(@babel/core@7.28.5)(@types/node@20.14.15)(graphql@16.11.0): resolution: {integrity: sha512-vPO1mCtrttFVy8mPR+jMAvsYTv8E/7payIPaneeGE15mQjyvQXXsHoAg06Qpf6tykOdCwKVLWre0Mf6g0KBwUg==} engines: {node: '>=16'} hasBin: true @@ -4813,12 +4844,12 @@ packages: '@graphql-tools/apollo-engine-loader': 8.0.0(graphql@16.11.0) '@graphql-tools/code-file-loader': 8.0.1(@babel/core@7.28.5)(graphql@16.11.0) '@graphql-tools/git-loader': 8.0.1(@babel/core@7.28.5)(graphql@16.11.0) - '@graphql-tools/github-loader': 8.0.0(@babel/core@7.28.5)(@types/node@24.10.1)(graphql@16.11.0) + '@graphql-tools/github-loader': 8.0.0(@babel/core@7.28.5)(@types/node@20.14.15)(graphql@16.11.0) '@graphql-tools/graphql-file-loader': 8.0.12(graphql@16.11.0) '@graphql-tools/json-file-loader': 8.0.11(graphql@16.11.0) '@graphql-tools/load': 8.0.12(graphql@16.11.0) - '@graphql-tools/prisma-loader': 8.0.1(@types/node@24.10.1)(graphql@16.11.0) - '@graphql-tools/url-loader': 8.0.24(@types/node@24.10.1)(graphql@16.11.0) + '@graphql-tools/prisma-loader': 8.0.1(@types/node@20.14.15)(graphql@16.11.0) + '@graphql-tools/url-loader': 8.0.24(@types/node@20.14.15)(graphql@16.11.0) '@graphql-tools/utils': 10.7.2(graphql@16.11.0) '@whatwg-node/fetch': 0.10.3 chalk: 4.1.2 @@ -4826,7 +4857,7 @@ packages: debounce: 1.2.1 detect-indent: 6.1.0 graphql: 16.11.0 - graphql-config: 5.1.3(@types/node@24.10.1)(graphql@16.11.0) + graphql-config: 5.1.3(@types/node@20.14.15)(graphql@16.11.0) inquirer: 8.2.4 is-glob: 4.0.3 jiti: 1.21.6 @@ -5210,7 +5241,7 @@ packages: - utf-8-validate dev: true - /@graphql-tools/executor-http@1.2.5(@types/node@24.10.1)(graphql@16.11.0): + /@graphql-tools/executor-http@1.2.5(@types/node@20.14.15)(graphql@16.11.0): resolution: {integrity: sha512-pG5YXsF2EhKS4JMhwFwI+0S5RGhPuJ3j3Dg1vWItzeBFiTzr2+VO8yyyahHIncLx7OzSYP/6pBDFp76FC55e+g==} engines: {node: '>=18.0.0'} peerDependencies: @@ -5224,7 +5255,7 @@ packages: '@whatwg-node/fetch': 0.10.3 extract-files: 11.0.0 graphql: 16.11.0 - meros: 1.2.1(@types/node@24.10.1) + meros: 1.2.1(@types/node@20.14.15) tslib: 2.8.1 value-or-promise: 1.0.12 transitivePeerDependencies: @@ -5281,14 +5312,14 @@ packages: - supports-color dev: true - /@graphql-tools/github-loader@8.0.0(@babel/core@7.28.5)(@types/node@24.10.1)(graphql@16.11.0): + /@graphql-tools/github-loader@8.0.0(@babel/core@7.28.5)(@types/node@20.14.15)(graphql@16.11.0): resolution: {integrity: sha512-VuroArWKcG4yaOWzV0r19ElVIV6iH6UKDQn1MXemND0xu5TzrFme0kf3U9o0YwNo0kUYEk9CyFM0BYg4he17FA==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: '@ardatan/sync-fetch': 0.0.1 - '@graphql-tools/executor-http': 1.2.5(@types/node@24.10.1)(graphql@16.11.0) + '@graphql-tools/executor-http': 1.2.5(@types/node@20.14.15)(graphql@16.11.0) '@graphql-tools/graphql-tag-pluck': 8.0.1(@babel/core@7.28.5)(graphql@16.11.0) '@graphql-tools/utils': 10.7.2(graphql@16.11.0) '@whatwg-node/fetch': 0.9.8 @@ -5441,13 +5472,13 @@ packages: tslib: 2.8.1 dev: true - /@graphql-tools/prisma-loader@8.0.1(@types/node@24.10.1)(graphql@16.11.0): + /@graphql-tools/prisma-loader@8.0.1(@types/node@20.14.15)(graphql@16.11.0): resolution: {integrity: sha512-bl6e5sAYe35Z6fEbgKXNrqRhXlCJYeWKBkarohgYA338/SD9eEhXtg3Cedj7fut3WyRLoQFpHzfiwxKs7XrgXg==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: - '@graphql-tools/url-loader': 8.0.24(@types/node@24.10.1)(graphql@16.11.0) + '@graphql-tools/url-loader': 8.0.24(@types/node@20.14.15)(graphql@16.11.0) '@graphql-tools/utils': 10.7.2(graphql@16.11.0) '@types/js-yaml': 4.0.9 '@types/json-stable-stringify': 1.0.34 @@ -5537,14 +5568,14 @@ packages: value-or-promise: 1.0.12 dev: false - /@graphql-tools/url-loader@8.0.24(@types/node@24.10.1)(graphql@16.11.0): + /@graphql-tools/url-loader@8.0.24(@types/node@20.14.15)(graphql@16.11.0): resolution: {integrity: sha512-f+Yt6sswiEPrcWsInMbmf+3HNENV2IZK1z3IiGMHuyqb+QsMbJLxzDPHnxMtF2QGJOiRjBQy2sF2en7DPG+jSw==} engines: {node: '>=16.0.0'} peerDependencies: graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 dependencies: '@graphql-tools/executor-graphql-ws': 1.3.7(graphql@16.11.0) - '@graphql-tools/executor-http': 1.2.5(@types/node@24.10.1)(graphql@16.11.0) + '@graphql-tools/executor-http': 1.2.5(@types/node@20.14.15)(graphql@16.11.0) '@graphql-tools/executor-legacy-ws': 1.1.10(graphql@16.11.0) '@graphql-tools/utils': 10.7.2(graphql@16.11.0) '@graphql-tools/wrap': 10.0.28(graphql@16.11.0) @@ -7428,39 +7459,1386 @@ packages: resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} dev: false - /@protobufjs/codegen@2.0.4: - resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + /@protobufjs/codegen@2.0.4: + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + dev: false + + /@protobufjs/eventemitter@1.1.0: + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + dev: false + + /@protobufjs/fetch@1.1.0: + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + dev: false + + /@protobufjs/float@1.0.2: + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + dev: false + + /@protobufjs/inquire@1.1.0: + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + dev: false + + /@protobufjs/path@1.1.2: + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + dev: false + + /@protobufjs/pool@1.1.0: + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + dev: false + + /@protobufjs/utf8@1.1.0: + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + dev: false + + /@radix-ui/colors@3.0.0: + resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} + dev: false + + /@radix-ui/number@1.1.1: + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + dev: false + + /@radix-ui/primitive@1.1.3: + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + dev: false + + /@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-accordion@1.2.12(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-arrow@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-avatar@1.1.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-checkbox@1.3.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-collection@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-compose-refs@1.1.2(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-context-menu@2.2.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-context@1.1.2(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-dialog@1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.7.2(@types/react@18.2.73)(react@18.2.0) + dev: false + + /@radix-ui/react-direction@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-focus-guards@1.1.3(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-form@0.1.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-label': 2.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-hover-card@1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-id@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-label@2.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-menu@2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.7.2(@types/react@18.2.73)(react@18.2.0) + dev: false + + /@radix-ui/react-menubar@1.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-popover@1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.7.2(@types/react@18.2.73)(react@18.2.0) + dev: false + + /@radix-ui/react-popper@1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/rect': 1.1.1 + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-portal@1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-presence@1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-primitive@2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-progress@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-radio-group@1.3.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-scroll-area@1.2.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-select@2.2.6(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + aria-hidden: 1.2.6 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.7.2(@types/react@18.2.73)(react@18.2.0) + dev: false + + /@radix-ui/react-separator@1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-slider@1.3.6(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-slot@1.2.3(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-switch@1.2.6(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-tabs@1.1.13(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-toast@1.2.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-toggle-group@1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-toggle@1.1.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-toolbar@1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-effect-event@0.0.2(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-is-hydrated@0.1.0(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + use-sync-external-store: 1.6.0(react@18.2.0) dev: false - /@protobufjs/eventemitter@1.1.0: - resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + /@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 dev: false - /@protobufjs/fetch@1.1.0: - resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + /@radix-ui/react-use-previous@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true dependencies: - '@protobufjs/aspromise': 1.1.2 - '@protobufjs/inquire': 1.1.0 + '@types/react': 18.2.73 + react: 18.2.0 dev: false - /@protobufjs/float@1.0.2: - resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + /@radix-ui/react-use-rect@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/rect': 1.1.1 + '@types/react': 18.2.73 + react: 18.2.0 dev: false - /@protobufjs/inquire@1.1.0: - resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + /@radix-ui/react-use-size@1.1.1(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@types/react': 18.2.73 + react: 18.2.0 dev: false - /@protobufjs/path@1.1.2: - resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + /@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false - /@protobufjs/pool@1.1.0: - resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + /@radix-ui/rect@1.1.1: + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} dev: false - /@protobufjs/utf8@1.1.0: - resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + /@radix-ui/themes@3.2.1(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: 16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: 16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/colors': 3.0.0 + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + classnames: 2.5.1 + radix-ui: 1.4.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll-bar: 2.3.8(@types/react@18.2.73)(react@18.2.0) dev: false /@remix-run/dev@2.16.4(@remix-run/react@2.16.4)(@remix-run/serve@2.16.4)(@types/node@18.11.9)(typescript@5.4.3)(yaml@2.7.0): @@ -9091,11 +10469,6 @@ packages: dependencies: undici-types: 5.26.5 - /@types/node@24.10.1: - resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} - dependencies: - undici-types: 7.16.0 - /@types/node@8.10.66: resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} dev: false @@ -9135,7 +10508,6 @@ packages: resolution: {integrity: sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==} dependencies: '@types/react': 18.2.73 - dev: true /@types/react@18.2.73: resolution: {integrity: sha512-XcGdod0Jjv84HOC7N5ziY3x+qL0AfmubvKOZ9hJjJ2yd5EE+KYjWhdOjt387e9HPheHkdggF9atTifMRtyAaRA==} @@ -10181,6 +11553,13 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + /aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + dependencies: + tslib: 2.8.1 + dev: false + /aria-query@5.3.2: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} @@ -11329,6 +12708,10 @@ packages: clsx: 2.1.1 dev: false + /classnames@2.5.1: + resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + dev: false + /clean-css@5.3.3: resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} engines: {node: '>= 10.0'} @@ -12491,6 +13874,10 @@ packages: engines: {node: '>=8'} dev: true + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + /deterministic-object-hash@2.0.2: resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} engines: {node: '>=18'} @@ -14342,6 +15729,11 @@ packages: hasown: 2.0.2 math-intrinsics: 1.0.0 + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -14590,7 +15982,7 @@ packages: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} dev: true - /graphql-config@5.1.3(@types/node@24.10.1)(graphql@16.11.0): + /graphql-config@5.1.3(@types/node@20.14.15)(graphql@16.11.0): resolution: {integrity: sha512-RBhejsPjrNSuwtckRlilWzLVt2j8itl74W9Gke1KejDTz7oaA5kVd6wRn9zK9TS5mcmIYGxf7zN7a1ORMdxp1Q==} engines: {node: '>= 16.0.0'} peerDependencies: @@ -14604,7 +15996,7 @@ packages: '@graphql-tools/json-file-loader': 8.0.11(graphql@16.11.0) '@graphql-tools/load': 8.0.12(graphql@16.11.0) '@graphql-tools/merge': 9.0.17(graphql@16.11.0) - '@graphql-tools/url-loader': 8.0.24(@types/node@24.10.1)(graphql@16.11.0) + '@graphql-tools/url-loader': 8.0.24(@types/node@20.14.15)(graphql@16.11.0) '@graphql-tools/utils': 10.7.2(graphql@16.11.0) cosmiconfig: 8.1.3 graphql: 16.11.0 @@ -17877,7 +19269,7 @@ packages: - supports-color dev: false - /meros@1.2.1(@types/node@24.10.1): + /meros@1.2.1(@types/node@20.14.15): resolution: {integrity: sha512-R2f/jxYqCAGI19KhAvaxSOxALBMkaXWH2a7rOyqQw+ZmizX5bKkEYWLzdhC+U82ZVVPVp6MCXe3EkVligh+12g==} engines: {node: '>=13'} peerDependencies: @@ -17886,7 +19278,7 @@ packages: '@types/node': optional: true dependencies: - '@types/node': 24.10.1 + '@types/node': 20.14.15 dev: true /methods@1.1.2: @@ -18830,6 +20222,7 @@ packages: /next@15.5.6(@babel/core@7.26.0)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-zTxsnI3LQo3c9HSdSf91O1jMNsEzIXDShXd4wVdg9y5shwLqBXi4ZtUUJyB86KGVSJLZx0PFONvO54aheGX8QQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -18986,31 +20379,6 @@ packages: type-is: 1.6.18 dev: true - /node-mocks-http@1.16.2(@types/node@24.10.1): - resolution: {integrity: sha512-2Sh6YItRp1oqewZNlck3LaFp5vbyW2u51HX2p1VLxQ9U/bG90XV8JY9O7Nk+HDd6OOn/oV3nA5Tx5k4Rki0qlg==} - engines: {node: '>=14'} - peerDependencies: - '@types/express': ^4.17.21 || ^5.0.0 - '@types/node': '*' - peerDependenciesMeta: - '@types/express': - optional: true - '@types/node': - optional: true - dependencies: - '@types/node': 24.10.1 - accepts: 1.3.8 - content-disposition: 0.5.4 - depd: 1.1.2 - fresh: 0.5.2 - merge-descriptors: 1.0.3 - methods: 1.1.2 - mime: 1.6.0 - parseurl: 1.3.3 - range-parser: 1.2.1 - type-is: 1.6.18 - dev: true - /node-releases@2.0.18: resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} @@ -20454,6 +21822,80 @@ packages: engines: {node: '>=10'} dev: false + /radix-ui@1.4.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-accordion': 1.2.12(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-avatar': 1.1.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-form': 0.1.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-label': 2.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-menubar': 1.1.16(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-progress': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-select': 2.2.6(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-separator': 1.1.7(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slider': 1.3.6(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-switch': 1.2.6(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-tabs': 1.1.13(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toast': 1.2.15(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle': 1.1.10(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.2.73)(react@18.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.2.22)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.73 + '@types/react-dom': 18.2.22 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} dev: false @@ -20510,6 +21952,41 @@ packages: engines: {node: '>=0.10.0'} dev: true + /react-remove-scroll-bar@2.3.8(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + react-style-singleton: 2.2.3(@types/react@18.2.73)(react@18.2.0) + tslib: 2.8.1 + dev: false + + /react-remove-scroll@2.7.2(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@18.2.73)(react@18.2.0) + react-style-singleton: 2.2.3(@types/react@18.2.73)(react@18.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@18.2.73)(react@18.2.0) + use-sidecar: 1.1.3(@types/react@18.2.73)(react@18.2.0) + dev: false + /react-router-dom@6.30.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-x30B78HV5tFk8ex0ITwzC9TTZMua4jGyA9IUlH1JLQYQTFyxr/ZxwOJq7evg1JX1qGVUcvhsmQSKdPncQrjTgA==} engines: {node: '>=14.0.0'} @@ -20531,6 +22008,22 @@ packages: '@remix-run/router': 1.23.0 react: 18.2.0 + /react-style-singleton@2.2.3(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + get-nonce: 1.0.1 + react: 18.2.0 + tslib: 2.8.1 + dev: false + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -22932,34 +24425,6 @@ packages: - '@swc/core' - '@swc/wasm' - '@types/node' - dev: true - - /ts-node-dev@2.0.0(@swc/core@1.15.3)(@types/node@24.10.1)(typescript@5.9.3): - resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==} - engines: {node: '>=0.8.0'} - hasBin: true - peerDependencies: - node-notifier: '*' - typescript: '*' - peerDependenciesMeta: - node-notifier: - optional: true - dependencies: - chokidar: 3.6.0 - dynamic-dedupe: 0.3.0 - minimist: 1.2.8 - mkdirp: 1.0.4 - resolve: 1.22.8 - rimraf: 2.7.1 - source-map-support: 0.5.21 - tree-kill: 1.2.2 - ts-node: 10.9.2(@swc/core@1.15.3)(@types/node@24.10.1)(typescript@5.9.3) - tsconfig: 7.0.0 - typescript: 5.9.3 - transitivePeerDependencies: - - '@swc/core' - - '@swc/wasm' - - '@types/node' /ts-node@10.9.2(@swc/core@1.15.3)(@types/node@20.14.15)(typescript@5.9.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} @@ -22991,38 +24456,6 @@ packages: typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - dev: true - - /ts-node@10.9.2(@swc/core@1.15.3)(@types/node@24.10.1)(typescript@5.9.3): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@swc/core': 1.15.3 - '@tsconfig/node10': 1.0.11 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 24.10.1 - acorn: 8.14.0 - acorn-walk: 8.3.2 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 /tsconfck@3.1.6(typescript@5.9.3): resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} @@ -23325,9 +24758,6 @@ packages: /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - /undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - /undici@5.28.5: resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} engines: {node: '>=14.0'} @@ -23683,6 +25113,45 @@ packages: resolution: {integrity: sha512-WHN8KDQblxd32odxeIgo83rdVDE2bvdkb86it7bMhYZwWKJz0+O0RK/eZiHYnM+zgt/U7hAHOlCQGfjjvSkw2g==} dev: true + /use-callback-ref@1.3.3(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + react: 18.2.0 + tslib: 2.8.1 + dev: false + + /use-sidecar@1.1.3(@types/react@18.2.73)(react@18.2.0): + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.73 + detect-node-es: 1.1.0 + react: 18.2.0 + tslib: 2.8.1 + dev: false + + /use-sync-external-store@1.6.0(react@18.2.0): + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + react: 18.2.0 + dev: false + /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}