From fb4a6548d2af0973dc04c4ddf57b2745b79334b6 Mon Sep 17 00:00:00 2001 From: Hayden Bleasel Date: Wed, 28 Aug 2024 21:54:16 -0400 Subject: [PATCH] Redesign (#60) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes - Redesigned linked pages - Fixed client/server component usage - Added metadata to pages **Home** ![CleanShot 2024-08-28 at 13 24 23@2x](https://github.com/user-attachments/assets/6b1df778-4d31-48a9-833a-47e4710c0e06) **/versions/range** ![CleanShot 2024-08-28 at 13 24 56@2x](https://github.com/user-attachments/assets/f4fe42f2-96c3-4aa4-809f-5df42484bd4a) **/versions/range/16** ![CleanShot 2024-08-28 at 13 24 36@2x](https://github.com/user-attachments/assets/225c9f82-8429-41ea-8c12-e32785d56d02) --------- Co-authored-by: 강동윤 (Donny) --- apps/swc-plugins/app/(home)/page.tsx | 106 +++------- apps/swc-plugins/app/layout.tsx | 51 ++--- apps/swc-plugins/app/versions/layout.tsx | 28 +++ .../components/compat-range-header.tsx | 47 +++++ .../components/compat-range-tables.tsx | 81 ++++++++ .../versions/range/[compatRangeId]/page.tsx | 116 +++-------- .../versions/range/components/range-table.tsx | 51 +++++ apps/swc-plugins/app/versions/range/page.tsx | 33 ++-- apps/swc-plugins/components/logo/index.tsx | 15 ++ apps/swc-plugins/components/logo/swc.svg | 12 ++ .../components/runtime-version-selector.tsx | 52 +++++ apps/swc-plugins/components/select.tsx | 186 ++++++++++++++++++ .../components/table-container.tsx | 29 +++ apps/swc-plugins/lib/fonts.ts | 13 ++ apps/swc-plugins/package.json | 3 + pnpm-lock.yaml | 53 +++++ 16 files changed, 654 insertions(+), 222 deletions(-) create mode 100644 apps/swc-plugins/app/versions/layout.tsx create mode 100644 apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx create mode 100644 apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx create mode 100644 apps/swc-plugins/app/versions/range/components/range-table.tsx create mode 100644 apps/swc-plugins/components/logo/index.tsx create mode 100644 apps/swc-plugins/components/logo/swc.svg create mode 100644 apps/swc-plugins/components/runtime-version-selector.tsx create mode 100644 apps/swc-plugins/components/select.tsx create mode 100644 apps/swc-plugins/components/table-container.tsx create mode 100644 apps/swc-plugins/lib/fonts.ts diff --git a/apps/swc-plugins/app/(home)/page.tsx b/apps/swc-plugins/app/(home)/page.tsx index c8c992d..7deb1d1 100644 --- a/apps/swc-plugins/app/(home)/page.tsx +++ b/apps/swc-plugins/app/(home)/page.tsx @@ -1,83 +1,33 @@ -"use client"; - -import { useState } from "react"; - +import { Logo } from "@/components/logo"; +import { RuntimeVersionSelector } from "@/components/runtime-version-selector"; import { Button } from "@/components/ui/button"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; -import { apiClient } from "@/lib/trpc/web-client"; +import { Metadata } from "next"; import Link from "next/link"; -import { useRouter } from "next/navigation"; - -export default function Home() { - const [runtimes] = apiClient.runtime.list.useSuspenseQuery(); - - const [selectedRuntime, setSelectedRuntime] = useState(); - - return ( -
-
- - - {selectedRuntime && } -
-
- - - +import { FC } from "react"; + +export const metadata: Metadata = { + title: "SWC Plugins", + description: "A collection of SWC plugins, ready to use in your project.", +}; + +const Home: FC = () => ( +
+
+ +
+

+ SWC Plugins +

+

+ A collection of SWC plugins, ready to use in your project. +

+ +
- ); -} - -function VersionSelector({ runtimeId }: { runtimeId: bigint }) { - const router = useRouter(); - const versions = apiClient.runtime.listVersions.useQuery({ - runtimeId, - }); +
+); - return ( - - ); -} +export default Home; diff --git a/apps/swc-plugins/app/layout.tsx b/apps/swc-plugins/app/layout.tsx index 17b0df6..fddd209 100644 --- a/apps/swc-plugins/app/layout.tsx +++ b/apps/swc-plugins/app/layout.tsx @@ -1,42 +1,27 @@ import { Dynamic } from "@/components/dynamic"; import { Toaster } from "@/components/ui/toaster"; +import { fontBody, fontHeading } from "@/lib/fonts"; import { cn } from "@/lib/utils"; import { SessionProvider } from "next-auth/react"; -import { Manrope } from "next/font/google"; import NextTopLoader from "nextjs-toploader"; -import { PropsWithChildren } from "react"; +import { FC, PropsWithChildren } from "react"; import { ClientProviders } from "./client-providers"; import "./globals.css"; -const fontHeading = Manrope({ - subsets: ["latin"], - display: "swap", - variable: "--font-heading", -}); +const RootLayout: FC = ({ children }) => ( + + + + + + {children} + + + + + +); -const fontBody = Manrope({ - subsets: ["latin"], - display: "swap", - variable: "--font-body", -}); - -export default function RootLayout({ children }: PropsWithChildren) { - return ( - - - - - - -
- {children} -
-
-
- - - - ); -} +export default RootLayout; diff --git a/apps/swc-plugins/app/versions/layout.tsx b/apps/swc-plugins/app/versions/layout.tsx new file mode 100644 index 0000000..66a7fb4 --- /dev/null +++ b/apps/swc-plugins/app/versions/layout.tsx @@ -0,0 +1,28 @@ +import Link from "next/link"; +import { FC, ReactNode } from "react"; +import { Logo } from "../../components/logo"; +import { RuntimeVersionSelector } from "../../components/runtime-version-selector"; + +type ResultsLayoutProps = { + children: ReactNode; +}; + +const ResultsLayout: FC = ({ children }) => { + return ( + <> + +
{children}
+ + ); +}; + +export default ResultsLayout; diff --git a/apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx b/apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx new file mode 100644 index 0000000..572d8dc --- /dev/null +++ b/apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { Checkbox } from "@/components/ui/checkbox"; +import { apiClient } from "@/lib/trpc/web-client"; +import { parseAsBoolean, useQueryState } from "next-usequerystate"; +import { FC } from "react"; + +type CompatRangeHeaderProps = { + compatRangeId: string; +}; + +export const CompatRangeHeader: FC = ({ + compatRangeId, +}) => { + const [includePrerelease, setIncludePrerelease] = useQueryState( + "includePrerelease", + parseAsBoolean.withDefault(false) + ); + const [compatRange] = apiClient.compatRange.get.useSuspenseQuery({ + id: BigInt(compatRangeId), + includePrerelease, + }); + + const handleCheckedChange = (checked: boolean) => { + setIncludePrerelease(checked); + }; + + return ( +
+

+

swc_core

+ + @{compatRange.from} -{" "} + {compatRange.to} + +

+ +
+ + +
+
+ ); +}; diff --git a/apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx b/apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx new file mode 100644 index 0000000..b6eb50a --- /dev/null +++ b/apps/swc-plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx @@ -0,0 +1,81 @@ +"use client"; + +import { TableContainer } from "@/components/table-container"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { apiClient } from "@/lib/trpc/web-client"; +import { parseAsBoolean, useQueryState } from "next-usequerystate"; +import { FC } from "react"; + +type CompatRangeTablesProps = { + compatRangeId: string; +}; + +export const CompatRangeTables: FC = ({ + compatRangeId, +}) => { + const [includePrerelease] = useQueryState( + "includePrerelease", + parseAsBoolean.withDefault(false) + ); + const [compatRange] = apiClient.compatRange.get.useSuspenseQuery({ + id: BigInt(compatRangeId), + includePrerelease, + }); + + return ( + <> + + + + + Runtime + Minimum Version + Maximum Version + + + + {compatRange.runtimes.map((runtime) => ( + + {runtime.name} + + {runtime.minVersion} + + + {runtime.maxVersion} + + + ))} + +
+
+ + + + + + Plugin + Minimum Version + Maximum Version + + + + {compatRange.plugins.map((plugin) => ( + + {plugin.name} + {plugin.minVersion} + {plugin.maxVersion} + + ))} + +
+
+ + ); +}; diff --git a/apps/swc-plugins/app/versions/range/[compatRangeId]/page.tsx b/apps/swc-plugins/app/versions/range/[compatRangeId]/page.tsx index 60fab93..9e3c8af 100644 --- a/apps/swc-plugins/app/versions/range/[compatRangeId]/page.tsx +++ b/apps/swc-plugins/app/versions/range/[compatRangeId]/page.tsx @@ -1,93 +1,27 @@ -"use client"; - -import { Checkbox } from "@/components/ui/checkbox"; -import { - Table, - TableBody, - TableCaption, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { apiClient } from "@/lib/trpc/web-client"; -import { useState } from "react"; - -export default function Page({ - params: { compatRangeId }, -}: { - params: { compatRangeId: string }; -}) { - const [includePrerelease, setIncludePrerelease] = useState(false); - const [compatRange] = apiClient.compatRange.get.useSuspenseQuery({ - id: BigInt(compatRangeId), - includePrerelease, - }); - - return ( -
-
-

- swc_core - - @{compatRange.from} - {compatRange.to} - -

- -
- { - setIncludePrerelease(!!v); - }} - /> - -
-
- - - Runtime Version Ranges - - - Runtime - Minimum Version - Maximum Version - - - - {compatRange.runtimes.map((runtime) => ( - - {runtime.name} - {runtime.minVersion} - {runtime.maxVersion} - - ))} - -
- -

Plugins

- - - Compatible Plugins - - - Plugin - Minimum Version - Maximum Version - - - - {compatRange.plugins.map((plugin) => ( - - {plugin.name} - {plugin.minVersion} - {plugin.maxVersion} - - ))} - -
-
- ); -} +import { Metadata } from "next"; +import { FC } from "react"; +import { CompatRangeHeader } from "./components/compat-range-header"; +import { CompatRangeTables } from "./components/compat-range-tables"; export const dynamic = "force-dynamic"; +export const metadata: Metadata = { + title: "Compat Range", + description: "Compat ranges for swc_core", +}; + +type CompatRangePageProps = { + params: { + compatRangeId: string; + }; +}; + +const CompatRangePage: FC = ({ + params: { compatRangeId }, +}) => ( +
+ + +
+); + +export default CompatRangePage; diff --git a/apps/swc-plugins/app/versions/range/components/range-table.tsx b/apps/swc-plugins/app/versions/range/components/range-table.tsx new file mode 100644 index 0000000..1879055 --- /dev/null +++ b/apps/swc-plugins/app/versions/range/components/range-table.tsx @@ -0,0 +1,51 @@ +"use client"; + +import { TableContainer } from "@/components/table-container"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { useRouter } from "next/navigation"; + +type RangeTableProps = { + ranges: { id: bigint; from: string; to: string }[]; +}; + +export const RangeTable = ({ ranges }: RangeTableProps) => { + const router = useRouter(); + + const handleClick = (id: bigint) => { + router.push(`/versions/range/${id}`); + }; + + return ( + + + + + Runtime + Minimum Version + Maximum Version + + + + {ranges.map((range) => ( + handleClick(range.id)} + > + swc_core + {range.from} + {range.to} + + ))} + +
+
+ ); +}; diff --git a/apps/swc-plugins/app/versions/range/page.tsx b/apps/swc-plugins/app/versions/range/page.tsx index 0b91129..ac2ba51 100644 --- a/apps/swc-plugins/app/versions/range/page.tsx +++ b/apps/swc-plugins/app/versions/range/page.tsx @@ -1,26 +1,19 @@ import { createCaller } from "@/lib/server"; -import Link from "next/link"; +import { Metadata } from "next"; +import { RangeTable } from "./components/range-table"; -export default async function Page() { +export const dynamic = "force-dynamic"; +export const fetchCache = "force-no-store"; +export const metadata: Metadata = { + title: "Compat Ranges", + description: "A list of compat ranges for SWC plugins.", +}; + +const RangePage = async () => { const api = await createCaller(); const ranges = await api.compatRange.list(); - return ( -
-

Compat Ranges

-
    - {ranges.map((range) => ( -
  • - - swc_core@{range.from} -{" "} - {range.to} - -
  • - ))} -
-
- ); -} + return ; +}; -export const dynamic = "force-dynamic"; -export const fetchCache = "force-no-store"; +export default RangePage; diff --git a/apps/swc-plugins/components/logo/index.tsx b/apps/swc-plugins/components/logo/index.tsx new file mode 100644 index 0000000..0574529 --- /dev/null +++ b/apps/swc-plugins/components/logo/index.tsx @@ -0,0 +1,15 @@ +import { FC } from "react"; + +import { cn } from "@/lib/utils"; +import Image from "next/image"; +import SWCLogo from "./swc.svg"; + +export const Logo: FC<{ className?: string }> = ({ className }) => ( + SWC Logo +); diff --git a/apps/swc-plugins/components/logo/swc.svg b/apps/swc-plugins/components/logo/swc.svg new file mode 100644 index 0000000..b0ca9e3 --- /dev/null +++ b/apps/swc-plugins/components/logo/swc.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/apps/swc-plugins/components/runtime-version-selector.tsx b/apps/swc-plugins/components/runtime-version-selector.tsx new file mode 100644 index 0000000..ab1071a --- /dev/null +++ b/apps/swc-plugins/components/runtime-version-selector.tsx @@ -0,0 +1,52 @@ +"use client"; + +import { apiClient } from "@/lib/trpc/web-client"; +import { useRouter } from "next/navigation"; +import { FC, useState } from "react"; +import { Select } from "./select"; + +export const RuntimeVersionSelector: FC = () => { + const [runtimes] = apiClient.runtime.list.useSuspenseQuery(); + const [selectedRuntime, setSelectedRuntime] = useState(); + const [selectedVersion, setSelectedVersion] = useState(); + const router = useRouter(); + const versions = apiClient.runtime.listVersions.useQuery({ + runtimeId: selectedRuntime ?? BigInt(0), + }); + + const handleRuntimeChange = (runtimeId: string) => { + setSelectedRuntime(BigInt(runtimeId)); + }; + + const handleVersionChange = (version: string) => { + const selected = versions.data?.find((v) => v.version === version); + setSelectedVersion(version); + router.push(`/versions/range/${selected?.compatRangeId}`); + }; + + return ( +
+ ({ + value: version.version, + label: version.version, + })) ?? [] + } + type="version" + /> +
+ ); +}; diff --git a/apps/swc-plugins/components/select.tsx b/apps/swc-plugins/components/select.tsx new file mode 100644 index 0000000..4582757 --- /dev/null +++ b/apps/swc-plugins/components/select.tsx @@ -0,0 +1,186 @@ +"use client"; + +import { useMeasure } from "@react-hookz/web"; +import { useCommandState } from "cmdk"; +import { CheckIcon, ChevronsUpDown, PlusIcon } from "lucide-react"; +import type { ComponentProps, FC, ReactNode } from "react"; +import { useCallback, useId, useState } from "react"; +import { cn } from "../lib/utils"; +import { Button } from "./ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from "./ui/command"; +import { Label } from "./ui/label"; +import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; + +type SelectProperties = Omit< + ComponentProps, + "open" | "setOpen" +> & { + readonly label?: string; + readonly caption?: string; + readonly value?: string[] | string; + readonly data: readonly { + readonly value: string; + readonly label: string; + }[]; + readonly renderItem?: (item: SelectProperties["data"][number]) => ReactNode; + readonly disabled?: boolean; + readonly type?: string; + readonly trigger?: ReactNode; + readonly onChange?: (value: string) => void; + readonly onCreate?: (value: string) => void; + readonly loading?: boolean; + readonly exactSearch?: boolean; + readonly className?: string; +}; + +const CreateEmptyState = ({ + onCreate, +}: { + readonly onCreate: SelectProperties["onCreate"]; +}) => { + const search = useCommandState((state) => state.search); + + return ( +
+ +
+ ); +}; + +export const Select: FC = ({ + label, + value, + caption, + data, + disabled, + onChange, + type = "item", + renderItem, + trigger, + loading, + onCreate, + exactSearch, + className, + ...properties +}) => { + const id = useId(); + const [open, setOpen] = useState(false); + const selected = data.find((item) => item.value === value); + const [measurements, ref] = useMeasure(); + + const handleSelect = useCallback( + (newValue: string) => { + setOpen(false); + onChange?.(newValue); + }, + [onChange] + ); + + const handleCreate = (newValue: string) => { + setOpen(false); + onCreate?.(newValue); + }; + + return ( + (disabled ? setOpen(false) : setOpen(newOpen))} + > + + {trigger ?? ( +
+ {label ? : null} + + {caption ? ( +

{caption}

+ ) : null} +
+ )} +
+ + + + + {onCreate ? ( + + + + ) : ( + No results found. + )} + + {data.map((item) => { + const active = Array.isArray(value) + ? value.includes(item.value) + : value === item.value; + + return ( + handleSelect(item.value)} + className="flex items-center gap-2" + > +
+ {renderItem ? renderItem(item) : item.label} +
+ +
+ ); + })} +
+
+
+
+
+ ); +}; diff --git a/apps/swc-plugins/components/table-container.tsx b/apps/swc-plugins/components/table-container.tsx new file mode 100644 index 0000000..f9e61f5 --- /dev/null +++ b/apps/swc-plugins/components/table-container.tsx @@ -0,0 +1,29 @@ +import { cn } from "@/lib/utils"; +import type { FC, ReactNode } from "react"; + +type TableContainerProperties = { + readonly title: string; + readonly children: ReactNode; + readonly className?: string; +}; + +export const TableContainer: FC = ({ + title, + children, + className, +}) => ( +
+

+ {title} +

+
+ {children} +
+
+); diff --git a/apps/swc-plugins/lib/fonts.ts b/apps/swc-plugins/lib/fonts.ts new file mode 100644 index 0000000..4542b74 --- /dev/null +++ b/apps/swc-plugins/lib/fonts.ts @@ -0,0 +1,13 @@ +import { Manrope } from "next/font/google"; + +export const fontHeading = Manrope({ + subsets: ["latin"], + display: "swap", + variable: "--font-heading", +}); + +export const fontBody = Manrope({ + subsets: ["latin"], + display: "swap", + variable: "--font-body", +}); diff --git a/apps/swc-plugins/package.json b/apps/swc-plugins/package.json index e8d26f1..52a4761 100644 --- a/apps/swc-plugins/package.json +++ b/apps/swc-plugins/package.json @@ -41,6 +41,7 @@ "@radix-ui/react-toggle": "^1.1.0", "@radix-ui/react-toggle-group": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", + "@react-hookz/web": "^24.0.4", "@simplewebauthn/browser": "9.0.1", "@simplewebauthn/server": "9.0.3", "@tanstack/react-query": "^5.45.1", @@ -60,6 +61,7 @@ "next": "14.2.4", "next-auth": "5.0.0-beta.19", "next-themes": "^0.2.1", + "next-usequerystate": "^1.17.8", "nextjs-toploader": "^1.6.4", "node-fetch": "^3.3.2", "react": "18.2.0", @@ -67,6 +69,7 @@ "react-dom": "18.2.0", "react-hook-form": "^7.52.0", "react-resizable-panels": "^2.1.1", + "react-virtuoso": "^4.10.1", "recharts": "^2.12.7", "semver": "^7.6.3", "sharp": "^0.33.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5467f72..ca46204 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -125,6 +125,9 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.0.7 version: 1.0.7(@types/react-dom@18.2.18)(@types/react@18.3.3)(react-dom@18.2.0)(react@18.2.0) + '@react-hookz/web': + specifier: ^24.0.4 + version: 24.0.4(react-dom@18.2.0)(react@18.2.0) '@simplewebauthn/browser': specifier: 9.0.1 version: 9.0.1 @@ -182,6 +185,9 @@ importers: next-themes: specifier: ^0.2.1 version: 0.2.1(next@14.2.4)(react-dom@18.2.0)(react@18.2.0) + next-usequerystate: + specifier: ^1.17.8 + version: 1.17.8(next@14.2.4) nextjs-toploader: specifier: ^1.6.4 version: 1.6.4(next@14.2.4)(react-dom@18.2.0)(react@18.2.0) @@ -203,6 +209,9 @@ importers: react-resizable-panels: specifier: ^2.1.1 version: 2.1.1(react-dom@18.2.0)(react@18.2.0) + react-virtuoso: + specifier: ^4.10.1 + version: 4.10.1(react-dom@18.2.0)(react@18.2.0) recharts: specifier: ^2.12.7 version: 2.12.7(react-dom@18.2.0)(react@18.2.0) @@ -3641,6 +3650,26 @@ packages: tslib: 2.6.2 dev: false + /@react-hookz/deep-equal@1.0.4: + resolution: {integrity: sha512-N56fTrAPUDz/R423pag+n6TXWbvlBZDtTehaGFjK0InmN+V2OFWLE/WmORhmn6Ce7dlwH5+tQN1LJFw3ngTJVg==} + dev: false + + /@react-hookz/web@24.0.4(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-DcIM6JiZklDyHF6CRD1FTXzuggAkQ+3Ncq2Wln7Kdih8GV6ZIeN9JfS6ZaQxpQUxan8/4n0J2V/R7nMeiSrb2Q==} + engines: {node: '>=18.0.0'} + peerDependencies: + js-cookie: ^3.0.5 + react: ^16.8 || ^17 || ^18 + react-dom: ^16.8 || ^17 || ^18 + peerDependenciesMeta: + js-cookie: + optional: true + dependencies: + '@react-hookz/deep-equal': 1.0.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@rushstack/eslint-patch@1.0.8: resolution: {integrity: sha512-ZK5v4bJwgXldAUA8r3q9YKfCwOqoHTK/ZqRjSeRXQrBXWouoPnS4MQtgC4AXGiiBuUu5wxrRgTlv0ktmM4P1Aw==} dev: true @@ -8270,6 +8299,10 @@ packages: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: false + /mixme@0.5.9: resolution: {integrity: sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==} engines: {node: '>= 8.0.0'} @@ -8366,6 +8399,15 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /next-usequerystate@1.17.8(next@14.2.4): + resolution: {integrity: sha512-9lwrnqFRafi2KGmt9TgnlFP4w0rNSsVtAf+2ufyj/KgQZDv+fIQAGZSCZkmkU1f1Q4tsKvnG94h3prK88mP2sA==} + peerDependencies: + next: '>=13.4 <14.0.2 || ^14.0.3' + dependencies: + mitt: 3.0.1 + next: 14.2.4(react-dom@18.2.0)(react@18.2.0) + dev: false + /next@14.1.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==} engines: {node: '>=18.17.0'} @@ -9287,6 +9329,17 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /react-virtuoso@4.10.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-vDBt9AarmCjPNshw3VxPXW355ZQKSO0p9vrAJ0pi04TB6aXk+qHWTu8NuaQ3ppcd/Ub1r5ryRA4fJ2QGuH0H0g==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16 || >=17 || >= 18' + react-dom: '>=16 || >=17 || >= 18' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'}