Merge pull request #227 from cosmos/hkeep/update-deps

Update deps and minor housekeeping
This commit is contained in:
Abel Fernández
2024-06-27 15:50:42 +02:00
committed by GitHub
16 changed files with 2172 additions and 2973 deletions
+12 -2
View File
@@ -1,7 +1,7 @@
import { ChainInfo } from "@/context/ChainsContext/types";
import { useEffect, useRef, useState } from "react";
import { CommandGroup } from "../ui/command";
import ChainItem from "./ChainItem";
import { useRef } from "react";
interface ChainsGroupProps {
readonly chains: readonly ChainInfo[];
@@ -11,6 +11,16 @@ interface ChainsGroupProps {
export default function ChainsGroup({ chains, heading, emptyMsg }: ChainsGroupProps) {
const containerRef = useRef<HTMLDivElement>(null);
const [numChainsToRender, setNumChainsToRender] = useState(10);
useEffect(() => {
// Unblock the main thread
setTimeout(() => {
if (numChainsToRender < chains.length) {
setNumChainsToRender((prev) => prev + 10);
}
}, 0);
}, [chains.length, numChainsToRender]);
return (
<CommandGroup
@@ -19,7 +29,7 @@ export default function ChainsGroup({ chains, heading, emptyMsg }: ChainsGroupPr
>
{chains.length ? (
<div ref={containerRef} className="flex flex-wrap gap-2">
{chains.map((chain) => (
{chains.slice(0, numChainsToRender).map((chain) => (
<ChainItem
key={chain.registryName}
chain={chain}
+7 -4
View File
@@ -1,7 +1,7 @@
import { useChains } from "@/context/ChainsContext";
import { getRecentChainsFromStorage } from "@/context/ChainsContext/storage";
import { ChainInfo } from "@/context/ChainsContext/types";
import { useLayoutEffect, useState } from "react";
import { useEffect, useState } from "react";
import { Command, CommandEmpty, CommandInput, CommandList, CommandSeparator } from "../ui/command";
import ChainsGroup from "./ChainsGroup";
@@ -9,9 +9,12 @@ export default function ChooseChain() {
const { chains } = useChains();
const [recentChains, setRecentChains] = useState<readonly ChainInfo[]>([]);
useLayoutEffect(() => {
const newRecentChains = getRecentChainsFromStorage(chains);
setRecentChains(newRecentChains);
useEffect(() => {
// Unblock the main thread
setTimeout(() => {
const newRecentChains = getRecentChainsFromStorage(chains);
setRecentChains(newRecentChains);
}, 0);
}, [chains]);
return (
+30 -19
View File
@@ -3,6 +3,7 @@ import { setNewConnection } from "@/context/ChainsContext/helpers";
import { RegistryAsset } from "@/types/chainRegistry";
import { zodResolver } from "@hookform/resolvers/zod";
import dynamic from "next/dynamic";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { Button } from "../ui/button";
@@ -21,6 +22,14 @@ const JsonEditor = dynamic(() => import("../inputs/JsonEditor"), { ssr: false })
export default function CustomChainForm() {
const { chain, chains, newConnection, chainsDispatch } = useChains();
const [showAssetsEditor, setShowAssetsEditor] = useState(false);
useEffect(() => {
// Unblock the main thread
setTimeout(() => {
setShowAssetsEditor(true);
}, 0);
}, []);
const formSchema = z
.object({
@@ -246,25 +255,27 @@ export default function CustomChainForm() {
</FormItem>
)}
/>
<FormField
name="assets"
render={({ field }) => (
<FormItem className="mt-4">
<FormLabel>Assets</FormLabel>
<FormControl>
<div>
<JsonEditor
content={{ text: field.value }}
onChange={(newMsgContent) => {
field.onChange("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}");
}}
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{showAssetsEditor ? (
<FormField
name="assets"
render={({ field }) => (
<FormItem className="mt-4">
<FormLabel>Assets</FormLabel>
<FormControl>
<div>
<JsonEditor
content={{ text: field.value }}
onChange={(newMsgContent) => {
field.onChange("text" in newMsgContent ? newMsgContent.text ?? "{}" : "{}");
}}
/>
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
) : null}
<Button type="submit" className="mt-4">
Submit
</Button>
+3 -1
View File
@@ -1,7 +1,7 @@
import { useChains } from "@/context/ChainsContext";
import { setNewConnection } from "@/context/ChainsContext/helpers";
import { useState } from "react";
import { Dialog, DialogContent, DialogHeader } from "../ui/dialog";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
import { Tabs, TabsContent, TabsList } from "../ui/tabs";
import ChooseChain from "./ChooseChain";
import ConfirmConnection from "./ConfirmConnection";
@@ -25,9 +25,11 @@ export default function ChainConnect() {
>
<DialogButton />
<DialogContent
aria-describedby={undefined}
className={"max-h-[75%] max-w-[75%] overflow-y-auto bg-fuchsia-900"}
style={newConnection.action === "confirm" ? { width: "auto" } : {}}
>
<DialogTitle className="hidden">Connect to a new chain</DialogTitle>
{newConnection.action === "confirm" ? (
<ConfirmConnection closeDialog={() => setDialogOpen(false)} />
) : (
@@ -1,57 +0,0 @@
"use client";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import { CalendarIcon } from "@radix-ui/react-icons";
import { addDays, format } from "date-fns";
import * as React from "react";
import { DateRange } from "react-day-picker";
export function CalendarDateRangePicker({ className }: React.HTMLAttributes<HTMLDivElement>) {
const [date, setDate] = React.useState<DateRange | undefined>({
from: new Date(2023, 0, 20),
to: addDays(new Date(2023, 0, 20), 20),
});
return (
<div className={cn("grid gap-2", className)}>
<Popover>
<PopoverTrigger asChild>
<Button
id="date"
variant={"outline"}
className={cn(
"w-[260px] justify-start text-left font-normal",
!date && "text-muted-foreground",
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{date?.from ? (
date.to ? (
<>
{format(date.from, "LLL dd, y")} - {format(date.to, "LLL dd, y")}
</>
) : (
format(date.from, "LLL dd, y")
)
) : (
<span>Pick a date</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="end">
<Calendar
initialFocus
mode="range"
defaultMonth={date?.from}
selected={date}
onSelect={setDate}
numberOfMonths={2}
/>
</PopoverContent>
</Popover>
</div>
);
}
-30
View File
@@ -1,30 +0,0 @@
import { cn } from "@/lib/utils";
import Link from "next/link";
export function MainNav({ className, ...props }: React.HTMLAttributes<HTMLElement>) {
return (
<nav className={cn("flex items-center space-x-4 lg:space-x-6", className)} {...props}>
<Link href="" className="text-sm font-medium transition-colors hover:text-primary">
Overview
</Link>
<Link
href=""
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
>
Customers
</Link>
<Link
href=""
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
>
Products
</Link>
<Link
href=""
className="text-sm font-medium text-muted-foreground transition-colors hover:text-primary"
>
Settings
</Link>
</nav>
);
}
-72
View File
@@ -1,72 +0,0 @@
"use client";
import { Bar, BarChart, ResponsiveContainer, XAxis, YAxis } from "recharts";
const data = [
{
name: "Jan",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Feb",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Mar",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Apr",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "May",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Jun",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Jul",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Aug",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Sep",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Oct",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Nov",
total: Math.floor(Math.random() * 5000) + 1000,
},
{
name: "Dec",
total: Math.floor(Math.random() * 5000) + 1000,
},
];
export function Overview() {
return (
<ResponsiveContainer width="100%" height={350}>
<BarChart data={data}>
<XAxis dataKey="name" stroke="#888888" fontSize={12} tickLine={false} axisLine={false} />
<YAxis
stroke="#888888"
fontSize={12}
tickLine={false}
axisLine={false}
tickFormatter={(value) => `$${value}`}
/>
<Bar dataKey="total" fill="#adfa1d" radius={[4, 4, 0, 0]} />
</BarChart>
</ResponsiveContainer>
);
}
-63
View File
@@ -1,63 +0,0 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
export function RecentSales() {
return (
<div className="space-y-8">
<div className="flex items-center">
<Avatar className="h-9 w-9">
<AvatarImage src="/avatars/01.png" alt="Avatar" />
<AvatarFallback>OM</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">Olivia Martin</p>
<p className="text-sm text-muted-foreground">olivia.martin@email.com</p>
</div>
<div className="ml-auto font-medium">+$1,999.00</div>
</div>
<div className="flex items-center">
<Avatar className="flex h-9 w-9 items-center justify-center space-y-0 border">
<AvatarImage src="/avatars/02.png" alt="Avatar" />
<AvatarFallback>JL</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">Jackson Lee</p>
<p className="text-sm text-muted-foreground">jackson.lee@email.com</p>
</div>
<div className="ml-auto font-medium">+$39.00</div>
</div>
<div className="flex items-center">
<Avatar className="h-9 w-9">
<AvatarImage src="/avatars/03.png" alt="Avatar" />
<AvatarFallback>IN</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">Isabella Nguyen</p>
<p className="text-sm text-muted-foreground">isabella.nguyen@email.com</p>
</div>
<div className="ml-auto font-medium">+$299.00</div>
</div>
<div className="flex items-center">
<Avatar className="h-9 w-9">
<AvatarImage src="/avatars/04.png" alt="Avatar" />
<AvatarFallback>WK</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">William Kim</p>
<p className="text-sm text-muted-foreground">will@email.com</p>
</div>
<div className="ml-auto font-medium">+$99.00</div>
</div>
<div className="flex items-center">
<Avatar className="h-9 w-9">
<AvatarImage src="/avatars/05.png" alt="Avatar" />
<AvatarFallback>SD</AvatarFallback>
</Avatar>
<div className="ml-4 space-y-1">
<p className="text-sm font-medium leading-none">Sofia Davis</p>
<p className="text-sm text-muted-foreground">sofia.davis@email.com</p>
</div>
<div className="ml-auto font-medium">+$39.00</div>
</div>
</div>
);
}
-9
View File
@@ -1,9 +0,0 @@
import { Input } from "@/components/ui/input";
export function Search() {
return (
<div>
<Input type="search" placeholder="Search..." className="md:w-[100px] lg:w-[300px]" />
</div>
);
}
-190
View File
@@ -1,190 +0,0 @@
"use client";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
} from "@/components/ui/command";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { cn } from "@/lib/utils";
import { CaretSortIcon, CheckIcon, PlusCircledIcon } from "@radix-ui/react-icons";
import * as React from "react";
const groups = [
{
label: "Personal Account",
teams: [
{
label: "Alicia Koch",
value: "personal",
},
],
},
{
label: "Teams",
teams: [
{
label: "Acme Inc.",
value: "acme-inc",
},
{
label: "Monsters Inc.",
value: "monsters",
},
],
},
];
type Team = (typeof groups)[number]["teams"][number];
type PopoverTriggerProps = React.ComponentPropsWithoutRef<typeof PopoverTrigger>;
interface TeamSwitcherProps extends PopoverTriggerProps {}
export default function TeamSwitcher({ className }: TeamSwitcherProps) {
const [open, setOpen] = React.useState(false);
const [showNewTeamDialog, setShowNewTeamDialog] = React.useState(false);
const [selectedTeam, setSelectedTeam] = React.useState<Team>(groups[0].teams[0]);
return (
<Dialog open={showNewTeamDialog} onOpenChange={setShowNewTeamDialog}>
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
aria-label="Select a team"
className={cn("w-[200px] justify-between", className)}
>
<Avatar className="mr-2 h-5 w-5">
<AvatarImage
src={`https://avatar.vercel.sh/${selectedTeam.value}.png`}
alt={selectedTeam.label}
/>
<AvatarFallback>SC</AvatarFallback>
</Avatar>
{selectedTeam.label}
<CaretSortIcon className="ml-auto h-4 w-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command>
<CommandList>
<CommandInput placeholder="Search team..." />
<CommandEmpty>No team found.</CommandEmpty>
{groups.map((group) => (
<CommandGroup key={group.label} heading={group.label}>
{group.teams.map((team) => (
<CommandItem
key={team.value}
onSelect={() => {
setSelectedTeam(team);
setOpen(false);
}}
className="text-sm"
>
<Avatar className="mr-2 h-5 w-5">
<AvatarImage
src={`https://avatar.vercel.sh/${team.value}.png`}
alt={team.label}
className="grayscale"
/>
<AvatarFallback>SC</AvatarFallback>
</Avatar>
{team.label}
<CheckIcon
className={cn(
"ml-auto h-4 w-4",
selectedTeam.value === team.value ? "opacity-100" : "opacity-0",
)}
/>
</CommandItem>
))}
</CommandGroup>
))}
</CommandList>
<CommandSeparator />
<CommandList>
<CommandGroup>
<DialogTrigger asChild>
<CommandItem
onSelect={() => {
setOpen(false);
setShowNewTeamDialog(true);
}}
>
<PlusCircledIcon className="mr-2 h-5 w-5" />
Create Team
</CommandItem>
</DialogTrigger>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<DialogContent>
<DialogHeader>
<DialogTitle>Create team</DialogTitle>
<DialogDescription>Add a new team to manage products and customers.</DialogDescription>
</DialogHeader>
<div>
<div className="space-y-4 py-2 pb-4">
<div className="space-y-2">
<Label htmlFor="name">Team name</Label>
<Input id="name" placeholder="Acme Inc." />
</div>
<div className="space-y-2">
<Label htmlFor="plan">Subscription plan</Label>
<Select>
<SelectTrigger>
<SelectValue placeholder="Select a plan" />
</SelectTrigger>
<SelectContent>
<SelectItem value="free">
<span className="font-medium">Free</span> -{" "}
<span className="text-muted-foreground">Trial for two weeks</span>
</SelectItem>
<SelectItem value="pro">
<span className="font-medium">Pro</span> -{" "}
<span className="text-muted-foreground">$9/month per user</span>
</SelectItem>
</SelectContent>
</Select>
</div>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowNewTeamDialog(false)}>
Cancel
</Button>
<Button type="submit">Continue</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
}
-56
View File
@@ -1,56 +0,0 @@
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuShortcut,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
export function UserNav() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
<Avatar className="h-8 w-8">
<AvatarImage src="/avatars/01.png" alt="@shadcn" />
<AvatarFallback>SC</AvatarFallback>
</Avatar>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-56" align="end" forceMount>
<DropdownMenuLabel className="font-normal">
<div className="flex flex-col space-y-1">
<p className="text-sm font-medium leading-none">shadcn</p>
<p className="text-xs leading-none text-muted-foreground">m@example.com</p>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>
Profile
<DropdownMenuShortcut>P</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
Billing
<DropdownMenuShortcut>B</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
Settings
<DropdownMenuShortcut>S</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>New Team</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem>
Log out
<DropdownMenuShortcut>Q</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}
+1 -1
View File
@@ -100,8 +100,8 @@ const CreateTxForm = ({ router, senderAddress, accountOnChain }: CreateTxFormPro
description: "Failed to create transaction",
fullError: e instanceof Error ? e : undefined,
});
} finally {
setProcessing(false);
} finally {
toast.dismiss(loadingToastId);
}
};
+3 -3
View File
@@ -28,9 +28,9 @@ export default function JsonEditor({ label, ...editorProps }: JsonEditorProps) {
const refEditor = useRef<VanillaJsonEditor | null>(null);
useEffect(() => {
if (!refContainer.current) return;
refEditor.current = new VanillaJsonEditor({ target: refContainer.current, props: {} });
if (refContainer.current) {
refEditor.current = new VanillaJsonEditor({ target: refContainer.current, props: {} });
}
return () => {
if (refEditor.current) {
+1 -1
View File
@@ -115,7 +115,7 @@ const CommandItem = React.forwardRef<
<CommandPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled='true']:pointer-events-none data-[disabled='true']:opacity-50",
className
)}
{...props}
+2044 -2394
View File
File diff suppressed because it is too large Load Diff
+71 -71
View File
@@ -12,85 +12,85 @@
"lint:fix": "eslint --max-warnings 0 \"./**/*.{js,jsx,ts,tsx}\" --fix"
},
"dependencies": {
"@cosmjs/amino": "^0.32.2",
"@cosmjs/cosmwasm-stargate": "^0.32.2",
"@cosmjs/crypto": "^0.32.2",
"@cosmjs/encoding": "^0.32.2",
"@cosmjs/ledger-amino": "^0.32.2",
"@cosmjs/math": "^0.32.2",
"@cosmjs/proto-signing": "^0.32.2",
"@cosmjs/stargate": "^0.32.2",
"@cosmjs/tendermint-rpc": "^0.32.2",
"@cosmjs/utils": "^0.32.2",
"@hookform/resolvers": "^3.3.1",
"@keplr-wallet/cosmos": "^0.12.101",
"@keplr-wallet/types": "^0.12.76",
"@ledgerhq/hw-transport-webusb": "^6.27.19",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-alert-dialog": "^1.0.5",
"@radix-ui/react-aspect-ratio": "^1.0.3",
"@radix-ui/react-avatar": "^1.0.4",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-collapsible": "^1.0.3",
"@radix-ui/react-context-menu": "^2.1.5",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-hover-card": "^1.0.7",
"@cosmjs/amino": "^0.32.4",
"@cosmjs/cosmwasm-stargate": "^0.32.4",
"@cosmjs/crypto": "^0.32.4",
"@cosmjs/encoding": "^0.32.4",
"@cosmjs/ledger-amino": "^0.32.4",
"@cosmjs/math": "^0.32.4",
"@cosmjs/proto-signing": "^0.32.4",
"@cosmjs/stargate": "^0.32.4",
"@cosmjs/tendermint-rpc": "^0.32.4",
"@cosmjs/utils": "^0.32.4",
"@hookform/resolvers": "^3.6.0",
"@keplr-wallet/cosmos": "^0.12.107",
"@keplr-wallet/types": "^0.12.107",
"@ledgerhq/hw-transport-webusb": "^6.29.0",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-aspect-ratio": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-checkbox": "^1.1.0",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-context-menu": "^2.2.1",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-menubar": "^1.0.4",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-tabs": "^1.0.4",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.7",
"@testing-library/jest-dom": "^6.1.3",
"@testing-library/react": "^14.0.0",
"@types/node": "20.5.9",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-menubar": "^1.1.1",
"@radix-ui/react-navigation-menu": "^1.2.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.1",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
"@types/node": "20.14.9",
"@types/react": "18.3.3",
"@types/react-dom": "18.3.0",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"autoprefixer": "10.4.15",
"autoprefixer": "10.4.19",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cmdk": "^0.2.0",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"copy-to-clipboard": "^3.3.3",
"cosmjs-types": "^0.9.0",
"date-fns": "^2.30.0",
"eslint": "8.48.0",
"eslint-config-next": "13.4.19",
"eslint-config-prettier": "^9.0.0",
"date-fns": "^3.6.0",
"eslint": "^8.56.0",
"eslint-config-next": "14.2.4",
"eslint-config-prettier": "^9.1.0",
"graphql": "^16.9.0",
"graphql-request": "^7.1.0",
"jest": "^29.6.4",
"jest-environment-jsdom": "^29.6.4",
"lucide-react": "^0.274.0",
"next": "13.4.19",
"next-themes": "^0.2.1",
"postcss": "8.4.29",
"prettier": "^3.0.3",
"prettier-plugin-tailwindcss": "^0.5.4",
"react": "18.2.0",
"react-day-picker": "^8.8.2",
"react-dom": "18.2.0",
"react-hook-form": "^7.47.0",
"react-select": "^5.7.4",
"recharts": "^2.8.0",
"sonner": "^1.4.3",
"tailwind-merge": "^1.14.0",
"tailwindcss": "3.3.3",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"lucide-react": "^0.397.0",
"next": "14.2.4",
"next-themes": "^0.3.0",
"postcss": "8.4.38",
"prettier": "^3.3.2",
"prettier-plugin-tailwindcss": "^0.6.5",
"react": "18.3.1",
"react-day-picker": "^8.10.1",
"react-dom": "18.3.1",
"react-hook-form": "^7.52.0",
"react-select": "^5.8.0",
"recharts": "^2.12.7",
"sonner": "^1.5.0",
"tailwind-merge": "^2.3.0",
"tailwindcss": "3.4.4",
"tailwindcss-animate": "^1.0.7",
"typescript": "5.2.2",
"vanilla-jsoneditor": "^0.22.0",
"zod": "^3.22.2"
"typescript": "5.5.2",
"vanilla-jsoneditor": "^0.23.7",
"zod": "^3.23.8"
}
}