diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 0312b760..00000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env sh -. "$(dirname -- "$0")/_/husky.sh" - -npx lint-staged \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 23fd35f0..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.formatOnSave": true -} \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f7f09b6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,109 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of authorship +and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +("Commons") that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute to +the Commons to promote the ideal of a free culture and the further production of +creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a Work +(the "Affirmer"), to the extent that he or she is an owner of Copyright and +Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights ("Copyright and + Related Rights"). Copyright and Related Rights include, but are not limited + to, the following: + +i. the right to reproduce, adapt, distribute, perform, display, communicate, and +translate a Work; ii. moral rights retained by the original author(s) and/or +performer(s); iii. publicity and privacy rights pertaining to a person's image +or likeness depicted in a Work; iv. rights protecting against unfair competition +in regards to a Work, subject to the limitations in paragraph 4(a), below; v. +rights protecting the extraction, dissemination, use and reuse of data in a +Work; vi. database rights (such as those arising under Directive 96/9/EC of the +European Parliament and of the Council of 11 March 1996 on the legal protection +of databases, and under any national implementation thereof, including any +amended or successor version of such directive); and vii. other similar, +equivalent or corresponding rights throughout the world based on applicable law +or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer's Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the "Waiver"). Affirmer + makes the Waiver for the benefit of each member of the public at large and to + the detriment of Affirmer's heirs and successors, fully intending that such + Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer's express . + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer's express . In addition, to the extent the Waiver is so judged + Affirmer hereby grants to each affected person a royalty-free, non + transferable, non sublicensable, non exclusive, irrevocable and unconditional + license to exercise Affirmer's Copyright and Related Rights in the Work (i) + in all territories worldwide, (ii) for the maximum duration provided by + applicable law or treaty (including future time extensions), (iii) in any + current or future medium and for any number of copies, and (iv) for any + purpose whatsoever, including without limitation commercial, advertising or + promotional purposes (the "License"). The License shall be deemed effective + as of the date CC0 was applied by Affirmer to the Work. Should any part of + the License for any reason be judged legally invalid or ineffective under + applicable law, such partial invalidity or ineffectiveness shall not + invalidate the remainder of the License, and in such case Affirmer hereby + affirms that he or she will not (i) exercise any of his or her remaining + Copyright and Related Rights in the Work or (ii) assert any associated claims + and causes of action with respect to the Work, in either case contrary to + +4. Limitations and Disclaimers. + +a. No trademark or patent rights held by Affirmer are waived, abandoned, +surrendered, licensed or otherwise affected by this document. b. Affirmer offers +the Work as-is and makes no representations or warranties of any kind concerning +the Work, express, implied, statutory or otherwise, including without limitation +warranties of title, merchantability, fitness for a particular purpose, non +infringement, or the absence of latent or other defects, accuracy, or the +present or absence of errors, whether or not discoverable, all to the greatest +extent permissible under applicable law. c. Affirmer disclaims responsibility +for clearing rights of other persons that may apply to the Work or any use +thereof, including without limitation any person's Copyright and Related Rights +in the Work. Further, Affirmer disclaims responsibility for obtaining any +necessary consents, permissions or other rights required for any use of the +Work. d. Affirmer understands and acknowledges that Creative Commons is not a +party to this document and has no duty or obligation with respect to this CC0 or +use of the Work. diff --git a/README.md b/README.md deleted file mode 100644 index 49587d9a..00000000 --- a/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# SWC Website - -## Built Using - -- [Next.js](https://nextjs.org?utm_source=swc) -- [Nextra](https://nextra.vercel.app) -- [Vercel](https://vercel.com?utm_source=swc) - -[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fswc-project%2Fwebsite) diff --git a/apps/plugins/.eslintignore b/apps/plugins/.eslintignore deleted file mode 100644 index 7eaeda27..00000000 --- a/apps/plugins/.eslintignore +++ /dev/null @@ -1,3 +0,0 @@ -*.d.ts -/lib/generated -/components/ui diff --git a/apps/plugins/.eslintrc.json b/apps/plugins/.eslintrc.json deleted file mode 100644 index 4ea74466..00000000 --- a/apps/plugins/.eslintrc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "next/core-web-vitals", - "rules": { - "@typescript-eslint/no-unused-vars": "off", - "@next/next/no-server-import-in-page": "off", - "@typescript-eslint/ban-types": "off" - } -} diff --git a/apps/plugins/.gitignore b/apps/plugins/.gitignore index 08318f37..289f7928 100644 --- a/apps/plugins/.gitignore +++ b/apps/plugins/.gitignore @@ -1,43 +1,43 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts - -# scripts -.cache/ - - -generated/ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# scripts +.cache/ + + +generated/ .turbo/ \ No newline at end of file diff --git a/apps/plugins/README.md b/apps/plugins/README.md deleted file mode 100644 index 5ce4a7c6..00000000 --- a/apps/plugins/README.md +++ /dev/null @@ -1,36 +0,0 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -## Getting Started - -First, run the development server: - -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` - -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. - -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/apps/plugins/app/(home)/page.tsx b/apps/plugins/app/(home)/page.tsx index 7deb1d12..1fb6c612 100644 --- a/apps/plugins/app/(home)/page.tsx +++ b/apps/plugins/app/(home)/page.tsx @@ -1,33 +1,33 @@ -import { Logo } from "@/components/logo"; -import { RuntimeVersionSelector } from "@/components/runtime-version-selector"; -import { Button } from "@/components/ui/button"; -import { Metadata } from "next"; -import Link from "next/link"; -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. -

-
- - -
-
-); - -export default Home; +import { Logo } from "@/components/logo"; +import { RuntimeVersionSelector } from "@/components/runtime-version-selector"; +import { Button } from "@/components/ui/button"; +import { Metadata } from "next"; +import Link from "next/link"; +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. +

+
+ + +
+
+); + +export default Home; diff --git a/apps/plugins/app/api-client-provider.tsx b/apps/plugins/app/api-client-provider.tsx index 59802691..fbefe211 100644 --- a/apps/plugins/app/api-client-provider.tsx +++ b/apps/plugins/app/api-client-provider.tsx @@ -1,38 +1,38 @@ -"use client"; - -import { apiClient } from "@/lib/trpc/web-client"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { httpBatchLink } from "@trpc/client"; -import { PropsWithChildren, useState } from "react"; -import superjson from "superjson"; - -export function ApiClientProvider({ children }: PropsWithChildren<{}>) { - const [queryClient] = useState( - () => - new QueryClient({ - defaultOptions: { - queries: { - queryKeyHashFn: (queryKey) => - superjson.stringify(queryKey), - }, - }, - }) - ); - const [trpcClient] = useState(() => - apiClient.createClient({ - links: [ - httpBatchLink({ - url: "/api/trpc", - transformer: superjson, - }), - ], - }) - ); - return ( - - - {children} - - - ); -} +"use client"; + +import { apiClient } from "@/lib/trpc/web-client"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { httpBatchLink } from "@trpc/client"; +import { PropsWithChildren, useState } from "react"; +import superjson from "superjson"; + +export function ApiClientProvider({ children }: PropsWithChildren<{}>) { + const [queryClient] = useState( + () => + new QueryClient({ + defaultOptions: { + queries: { + queryKeyHashFn: (queryKey) => + superjson.stringify(queryKey), + }, + }, + }) + ); + const [trpcClient] = useState(() => + apiClient.createClient({ + links: [ + httpBatchLink({ + url: "/api/trpc", + transformer: superjson, + }), + ], + }) + ); + return ( + + + {children} + + + ); +} diff --git a/apps/plugins/app/api/auth/[...nextauth]/route.ts b/apps/plugins/app/api/auth/[...nextauth]/route.ts index 73228a09..db57ba32 100644 --- a/apps/plugins/app/api/auth/[...nextauth]/route.ts +++ b/apps/plugins/app/api/auth/[...nextauth]/route.ts @@ -1,2 +1,3 @@ -import { handlers } from "@/lib/auth"; -export const { GET, POST } = handlers; +import { handlers } from "@/lib/auth"; + +export const { GET, POST } = handlers; diff --git a/apps/plugins/app/api/trpc/[trpc]/route.ts b/apps/plugins/app/api/trpc/[trpc]/route.ts index 50095b43..7e3ea39b 100644 --- a/apps/plugins/app/api/trpc/[trpc]/route.ts +++ b/apps/plugins/app/api/trpc/[trpc]/route.ts @@ -1,6 +1,3 @@ -import { handler } from "@/lib/api/server"; - -export { - handler as GET, - handler as POST -}; +import { handler } from "@/lib/api/server"; + +export { handler as GET, handler as POST }; diff --git a/apps/plugins/app/api/update/runtimes/route.ts b/apps/plugins/app/api/update/runtimes/route.ts index ad3c950a..15bbd848 100644 --- a/apps/plugins/app/api/update/runtimes/route.ts +++ b/apps/plugins/app/api/update/runtimes/route.ts @@ -1,13 +1,13 @@ -import { UpdateRuntimesInputSchema } from "@/lib/api/updater/router"; -import { createCaller } from "@/lib/server"; -import { NextRequest, NextResponse } from "next/server"; - -export const POST = async (req: NextRequest) => { - const body = UpdateRuntimesInputSchema.parse(await req.json()); - - const api = await createCaller(); - - await api.updater.updateRuntimes(body); - - return NextResponse.json({ ok: true }); -}; +import { UpdateRuntimesInputSchema } from "@/lib/api/updater/router"; +import { createCaller } from "@/lib/server"; +import { NextRequest, NextResponse } from "next/server"; + +export const POST = async (req: NextRequest) => { + const body = UpdateRuntimesInputSchema.parse(await req.json()); + + const api = await createCaller(); + + await api.updater.updateRuntimes(body); + + return NextResponse.json({ ok: true }); +}; diff --git a/apps/plugins/app/api/update/wasm-plugins/route.ts b/apps/plugins/app/api/update/wasm-plugins/route.ts index c0e5fa15..aefe4637 100644 --- a/apps/plugins/app/api/update/wasm-plugins/route.ts +++ b/apps/plugins/app/api/update/wasm-plugins/route.ts @@ -1,13 +1,13 @@ -import { UpdateWasmPluginsInputSchema } from "@/lib/api/updater/router"; -import { createCaller } from "@/lib/server"; -import { NextRequest, NextResponse } from "next/server"; - -export const POST = async (req: NextRequest) => { - const body = UpdateWasmPluginsInputSchema.parse(await req.json()); - - const api = await createCaller(); - - await api.updater.updateWasmPlugins(body); - - return NextResponse.json({ ok: true }); -}; +import { UpdateWasmPluginsInputSchema } from "@/lib/api/updater/router"; +import { createCaller } from "@/lib/server"; +import { NextRequest, NextResponse } from "next/server"; + +export const POST = async (req: NextRequest) => { + const body = UpdateWasmPluginsInputSchema.parse(await req.json()); + + const api = await createCaller(); + + await api.updater.updateWasmPlugins(body); + + return NextResponse.json({ ok: true }); +}; diff --git a/apps/plugins/app/client-providers.tsx b/apps/plugins/app/client-providers.tsx index 578a672b..ae464515 100644 --- a/apps/plugins/app/client-providers.tsx +++ b/apps/plugins/app/client-providers.tsx @@ -1,13 +1,13 @@ -"use client"; - -import { ThemeProvider } from "next-themes"; -import { PropsWithChildren } from "react"; -import { ApiClientProvider } from "./api-client-provider"; - -export function ClientProviders({ children }: PropsWithChildren) { - return ( - - {children} - - ); -} +"use client"; + +import { ThemeProvider } from "next-themes"; +import { PropsWithChildren } from "react"; +import { ApiClientProvider } from "./api-client-provider"; + +export function ClientProviders({ children }: PropsWithChildren) { + return ( + + {children} + + ); +} diff --git a/apps/plugins/app/import/ranges/page.tsx b/apps/plugins/app/import/ranges/page.tsx index f4dcc59f..619801b7 100644 --- a/apps/plugins/app/import/ranges/page.tsx +++ b/apps/plugins/app/import/ranges/page.tsx @@ -1,45 +1,45 @@ -import { db } from "@/lib/prisma"; -import fs from "node:fs/promises"; - -export default async function Page() { - if (process.env.NODE_ENV === "production") { - return
Not allowed
; - } - - const ranges: { min: string; max: string }[] = JSON.parse( - await fs.readFile("./data/ranges.json", "utf8") - ); - - for (const { min, max } of ranges) { - await db.compatRange.upsert({ - where: { - from: min, - }, - update: { - to: max, - }, - create: { - from: min, - to: max, - }, - }); - } - - const runtimes = ["@swc/core", "next", "rspack", "farm"]; - - for (const runtime of runtimes) { - await db.swcRuntime.upsert({ - where: { - name: runtime, - }, - update: {}, - create: { - name: runtime, - }, - }); - } - - return
Done
; -} - -export const dynamic = "force-dynamic"; +import { db } from "@/lib/prisma"; +import fs from "node:fs/promises"; + +export default async function Page() { + if (process.env.NODE_ENV === "production") { + return
Not allowed
; + } + + const ranges: { min: string; max: string }[] = JSON.parse( + await fs.readFile("./data/ranges.json", "utf8") + ); + + for (const { min, max } of ranges) { + await db.compatRange.upsert({ + where: { + from: min, + }, + update: { + to: max, + }, + create: { + from: min, + to: max, + }, + }); + } + + const runtimes = ["@swc/core", "next", "rspack", "farm"]; + + for (const runtime of runtimes) { + await db.swcRuntime.upsert({ + where: { + name: runtime, + }, + update: {}, + create: { + name: runtime, + }, + }); + } + + return
Done
; +} + +export const dynamic = "force-dynamic"; diff --git a/apps/plugins/app/import/runtime/route.ts b/apps/plugins/app/import/runtime/route.ts index c3763d79..915b58b4 100644 --- a/apps/plugins/app/import/runtime/route.ts +++ b/apps/plugins/app/import/runtime/route.ts @@ -1,76 +1,80 @@ -import { db } from "@/lib/prisma"; -import { createCaller } from "@/lib/server"; -import { NextRequest, NextResponse } from "next/server"; -import { z } from "zod"; - -const VersionSchema = z.object({ - version: z.string(), - swcCoreVersion: z.string(), -}); - -const BodySchema = z.object({ - runtime: z.enum(["@swc/core", "next", "rspack"]), - versions: z.array(VersionSchema), -}); - -export async function POST(req: NextRequest) { - if (process.env.NODE_ENV === "production") { - return NextResponse.json( - { - error: "Not allowed", - }, - { - status: 403, - } - ); - } - - const { runtime, versions } = BodySchema.parse(await req.json()); - - const rt = await db.swcRuntime.findUniqueOrThrow({ - where: { - name: runtime, - }, - }); - const api = await createCaller(); - - for (const version of versions) { - const compatRange = await api.compatRange.byCoreVersion({ - version: version.swcCoreVersion, - }); - if (!compatRange) { - console.log(`No compat range found for ${version.swcCoreVersion}`); - continue; - } - - try { - await db.swcRuntimeVersion.upsert({ - where: { - runtimeId_version: { - runtimeId: rt.id, - version: version.version.replace("v", ""), - }, - }, - update: { - compatRangeId: compatRange.id, - swcCoreVersion: version.swcCoreVersion.replace("v", ""), - }, - create: { - runtimeId: rt.id, - version: version.version.replace("v", ""), - compatRangeId: compatRange.id, - swcCoreVersion: version.swcCoreVersion.replace("v", ""), - }, - }); - } catch (e) { - console.error( - `Failed to create compat range for ${version.swcCoreVersion}: ${e}` - ); - continue; - } - } - - return NextResponse.json({ - ok: true, - }); -} +import { db } from "@/lib/prisma"; +import { createCaller } from "@/lib/server"; +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; + +const VersionSchema = z.object({ + version: z.string(), + swcCoreVersion: z.string(), +}); + +const BodySchema = z.object({ + runtime: z.enum(["@swc/core", "next", "rspack"]), + versions: z.array(VersionSchema), +}); + +export async function POST(req: NextRequest) { + if (process.env.NODE_ENV === "production") { + return NextResponse.json( + { + error: "Not allowed", + }, + { + status: 403, + }, + ); + } + + const { runtime, versions } = BodySchema.parse(await req.json()); + + const rt = await db.swcRuntime.findUniqueOrThrow({ + where: { + name: runtime, + }, + }); + + const api = await createCaller(); + + for (const version of versions) { + const compatRange = await api.compatRange.byCoreVersion({ + version: version.swcCoreVersion, + }); + + if (!compatRange) { + console.log(`No compat range found for ${version.swcCoreVersion}`); + + continue; + } + + try { + await db.swcRuntimeVersion.upsert({ + where: { + runtimeId_version: { + runtimeId: rt.id, + version: version.version.replace("v", ""), + }, + }, + update: { + compatRangeId: compatRange.id, + swcCoreVersion: version.swcCoreVersion.replace("v", ""), + }, + create: { + runtimeId: rt.id, + version: version.version.replace("v", ""), + compatRangeId: compatRange.id, + swcCoreVersion: version.swcCoreVersion.replace("v", ""), + }, + }); + } catch (e) { + console.error( + `Failed to create compat range for ${version.swcCoreVersion}: ${e}`, + ); + + continue; + } + } + + return NextResponse.json({ + ok: true, + }); +} diff --git a/apps/plugins/app/import/swc_core/route.ts b/apps/plugins/app/import/swc_core/route.ts index 19431064..d9f6bdb6 100644 --- a/apps/plugins/app/import/swc_core/route.ts +++ b/apps/plugins/app/import/swc_core/route.ts @@ -1,29 +1,30 @@ -import { createCaller } from "@/lib/server"; -import { NextRequest, NextResponse } from "next/server"; -import { z } from "zod"; - -const CoreVersionSchema = z.object({ - version: z.string(), - pluginRunnerReq: z.string(), -}); - -const BodySchema = z.object({ - coreVersions: z.array(CoreVersionSchema), - pluginRunnerVersions: z.array(z.string()), -}); - -export async function POST(req: NextRequest) { - const api = await createCaller(); - const { coreVersions, pluginRunnerVersions } = BodySchema.parse( - await req.json() - ); - - await api.compatRange.addCacheForCrates({ - coreVersions, - pluginRunnerVersions, - }); - - return NextResponse.json({ - ok: true, - }); -} +import { createCaller } from "@/lib/server"; +import { NextRequest, NextResponse } from "next/server"; +import { z } from "zod"; + +const CoreVersionSchema = z.object({ + version: z.string(), + pluginRunnerReq: z.string(), +}); + +const BodySchema = z.object({ + coreVersions: z.array(CoreVersionSchema), + pluginRunnerVersions: z.array(z.string()), +}); + +export async function POST(req: NextRequest) { + const api = await createCaller(); + + const { coreVersions, pluginRunnerVersions } = BodySchema.parse( + await req.json(), + ); + + await api.compatRange.addCacheForCrates({ + coreVersions, + pluginRunnerVersions, + }); + + return NextResponse.json({ + ok: true, + }); +} diff --git a/apps/plugins/app/layout.tsx b/apps/plugins/app/layout.tsx index c1649eac..1c453342 100644 --- a/apps/plugins/app/layout.tsx +++ b/apps/plugins/app/layout.tsx @@ -1,31 +1,31 @@ -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 NextTopLoader from "nextjs-toploader"; -import { FC, PropsWithChildren } from "react"; -import { ClientProviders } from "./client-providers"; -import "./globals.css"; - -const RootLayout: FC = ({ children }) => ( - - - - - - {children} - - - - - -); - -export default RootLayout; +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 NextTopLoader from "nextjs-toploader"; +import { FC, PropsWithChildren } from "react"; +import { ClientProviders } from "./client-providers"; +import "./globals.css"; + +const RootLayout: FC = ({ children }) => ( + + + + + + {children} + + + + + +); + +export default RootLayout; diff --git a/apps/plugins/app/loading.tsx b/apps/plugins/app/loading.tsx index 10e0561a..83b42ce4 100644 --- a/apps/plugins/app/loading.tsx +++ b/apps/plugins/app/loading.tsx @@ -1,7 +1,7 @@ -export default function Loading() { - return ( -
-
Loading...
-
- ); -} +export default function Loading() { + return ( +
+
Loading...
+
+ ); +} diff --git a/apps/plugins/app/robots.ts b/apps/plugins/app/robots.ts index ace613c7..c4e19496 100644 --- a/apps/plugins/app/robots.ts +++ b/apps/plugins/app/robots.ts @@ -1,11 +1,11 @@ -import { MetadataRoute } from "next"; - -export default function robots(): MetadataRoute.Robots { - return { - rules: { - userAgent: "*", - allow: "/", - }, - // sitemap: `${BASE_URL}/sitemap.xml`, - }; -} +import { MetadataRoute } from "next"; + +export default function robots(): MetadataRoute.Robots { + return { + rules: { + userAgent: "*", + allow: "/", + }, + // sitemap: `${BASE_URL}/sitemap.xml`, + }; +} diff --git a/apps/plugins/app/versions/from-core/[version]/page.tsx b/apps/plugins/app/versions/from-core/[version]/page.tsx index 04b64d4d..e2c8c6c4 100644 --- a/apps/plugins/app/versions/from-core/[version]/page.tsx +++ b/apps/plugins/app/versions/from-core/[version]/page.tsx @@ -1,25 +1,25 @@ -import { createCaller } from "@/lib/server"; -import { redirect } from "next/navigation"; - -export default async function Page( - props: { - params: Promise<{ version: string }>; - } -) { - const params = await props.params; - - const { - version - } = params; - - const api = await createCaller(); - const compatRange = await api.compatRange.byCoreVersion({ - version, - }); - - if (compatRange) { - return redirect(`/versions/range/${compatRange.id}`); - } - - return
No compat range found for swc_core@{version}
; -} +import { createCaller } from "@/lib/server"; +import { redirect } from "next/navigation"; + +export default async function Page( + props: { + params: Promise<{ version: string }>; + } +) { + const params = await props.params; + + const { + version + } = params; + + const api = await createCaller(); + const compatRange = await api.compatRange.byCoreVersion({ + version, + }); + + if (compatRange) { + return redirect(`/versions/range/${compatRange.id}`); + } + + return
No compat range found for swc_core@{version}
; +} diff --git a/apps/plugins/app/versions/from-plugin-runner/[version]/page.tsx b/apps/plugins/app/versions/from-plugin-runner/[version]/page.tsx index bcfc6ba1..6b097a79 100644 --- a/apps/plugins/app/versions/from-plugin-runner/[version]/page.tsx +++ b/apps/plugins/app/versions/from-plugin-runner/[version]/page.tsx @@ -1,25 +1,25 @@ -import { createCaller } from "@/lib/server"; -import { redirect } from "next/navigation"; - -export default async function Page( - props: { - params: Promise<{ version: string }>; - } -) { - const params = await props.params; - - const { - version - } = params; - - const api = await createCaller(); - const compatRange = await api.compatRange.byPluginRunnerVersion({ - version, - }); - - if (compatRange) { - return redirect(`/versions/range/${compatRange.id}`); - } - - return
No compat range found for swc_plugin_runner@{version}
; -} +import { createCaller } from "@/lib/server"; +import { redirect } from "next/navigation"; + +export default async function Page( + props: { + params: Promise<{ version: string }>; + } +) { + const params = await props.params; + + const { + version + } = params; + + const api = await createCaller(); + const compatRange = await api.compatRange.byPluginRunnerVersion({ + version, + }); + + if (compatRange) { + return redirect(`/versions/range/${compatRange.id}`); + } + + return
No compat range found for swc_plugin_runner@{version}
; +} diff --git a/apps/plugins/app/versions/layout.tsx b/apps/plugins/app/versions/layout.tsx index 9b6370c6..5de07db8 100644 --- a/apps/plugins/app/versions/layout.tsx +++ b/apps/plugins/app/versions/layout.tsx @@ -1,28 +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; +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/plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx b/apps/plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx index 873872c0..ae390f62 100644 --- a/apps/plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx +++ b/apps/plugins/app/versions/range/[compatRangeId]/components/compat-range-header.tsx @@ -1,47 +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} - -

- -
- - -
-
- ); -}; +"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/plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx b/apps/plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx index a4d2d6bc..c85af70c 100644 --- a/apps/plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx +++ b/apps/plugins/app/versions/range/[compatRangeId]/components/compat-range-tables.tsx @@ -1,97 +1,97 @@ -"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} - - - ))} - -
-
- - ); -}; +"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/plugins/app/versions/range/[compatRangeId]/page.tsx b/apps/plugins/app/versions/range/[compatRangeId]/page.tsx index c519f10c..50d417a2 100644 --- a/apps/plugins/app/versions/range/[compatRangeId]/page.tsx +++ b/apps/plugins/app/versions/range/[compatRangeId]/page.tsx @@ -1,29 +1,29 @@ -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: Promise<{ - compatRangeId: string; - }>; -}; - -const CompatRangePage: FC = async ({ params }) => { - const { compatRangeId } = await params; - - return ( -
- - -
- ); -}; - -export default CompatRangePage; +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: Promise<{ + compatRangeId: string; + }>; +}; + +const CompatRangePage: FC = async ({ params }) => { + const { compatRangeId } = await params; + + return ( +
+ + +
+ ); +}; + +export default CompatRangePage; diff --git a/apps/plugins/app/versions/range/components/range-table.tsx b/apps/plugins/app/versions/range/components/range-table.tsx index 3490a483..bdf3255d 100644 --- a/apps/plugins/app/versions/range/components/range-table.tsx +++ b/apps/plugins/app/versions/range/components/range-table.tsx @@ -1,61 +1,61 @@ -"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} - - - ))} - -
-
- ); -}; +"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/plugins/app/versions/range/page.tsx b/apps/plugins/app/versions/range/page.tsx index af7627f0..933ddcfc 100644 --- a/apps/plugins/app/versions/range/page.tsx +++ b/apps/plugins/app/versions/range/page.tsx @@ -1,19 +1,19 @@ -import { createCaller } from "@/lib/server"; -import { Metadata } from "next"; -import { RangeTable } from "./components/range-table"; - -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 ; -}; - -export default RangePage; +import { createCaller } from "@/lib/server"; +import { Metadata } from "next"; +import { RangeTable } from "./components/range-table"; + +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 ; +}; + +export default RangePage; diff --git a/apps/plugins/components.json b/apps/plugins/components.json index 835bc876..5da5653a 100644 --- a/apps/plugins/components.json +++ b/apps/plugins/components.json @@ -1,17 +1,17 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "default", - "rsc": true, - "tsx": true, - "tailwind": { - "config": "tailwind.config.ts", - "css": "app/globals.css", - "baseColor": "slate", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils" - } -} +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "tailwind.config.ts", + "css": "app/globals.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} diff --git a/apps/plugins/components/dynamic.tsx b/apps/plugins/components/dynamic.tsx index a3c18323..68dfec44 100644 --- a/apps/plugins/components/dynamic.tsx +++ b/apps/plugins/components/dynamic.tsx @@ -1,17 +1,17 @@ -"use client"; - -import { ReactNode, useEffect, useState } from "react"; - -export const Dynamic = ({ children }: { children: ReactNode }) => { - const [hasMounted, setHasMounted] = useState(false); - - useEffect(() => { - setHasMounted(true); - }, []); - - if (!hasMounted) { - return null; - } - - return <>{children} ; -}; +"use client"; + +import { ReactNode, useEffect, useState } from "react"; + +export const Dynamic = ({ children }: { children: ReactNode }) => { + const [hasMounted, setHasMounted] = useState(false); + + useEffect(() => { + setHasMounted(true); + }, []); + + if (!hasMounted) { + return null; + } + + return <>{children} ; +}; diff --git a/apps/plugins/components/logo/index.tsx b/apps/plugins/components/logo/index.tsx index 102fea65..de66074c 100644 --- a/apps/plugins/components/logo/index.tsx +++ b/apps/plugins/components/logo/index.tsx @@ -1,15 +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 -); +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/plugins/components/logo/swc.svg b/apps/plugins/components/logo/swc.svg index b0ca9e35..01aef532 100644 --- a/apps/plugins/components/logo/swc.svg +++ b/apps/plugins/components/logo/swc.svg @@ -1,12 +1,12 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/apps/plugins/components/runtime-version-selector.tsx b/apps/plugins/components/runtime-version-selector.tsx index 272fffd2..b5d8b35e 100644 --- a/apps/plugins/components/runtime-version-selector.tsx +++ b/apps/plugins/components/runtime-version-selector.tsx @@ -1,52 +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" - /> -
- ); -}; +"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/plugins/components/select.tsx b/apps/plugins/components/select.tsx index 2090da4a..3ca02a65 100644 --- a/apps/plugins/components/select.tsx +++ b/apps/plugins/components/select.tsx @@ -1,196 +1,196 @@ -"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} -
- -
- ); - })} -
-
-
-
-
- ); -}; +"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/plugins/components/ui/accordion.tsx b/apps/plugins/components/ui/accordion.tsx index b1e2db38..83d74916 100644 --- a/apps/plugins/components/ui/accordion.tsx +++ b/apps/plugins/components/ui/accordion.tsx @@ -1,58 +1,58 @@ -"use client"; - -import * as React from "react"; -import * as AccordionPrimitive from "@radix-ui/react-accordion"; -import { ChevronDown } from "lucide-react"; - -import { cn } from "@/lib/utils"; - -const Accordion = AccordionPrimitive.Root; - -const AccordionItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AccordionItem.displayName = "AccordionItem"; - -const AccordionTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - svg]:rotate-180", - className - )} - {...props} - > - {children} - - - -)); -AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; - -const AccordionContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - -
{children}
-
-)); - -AccordionContent.displayName = AccordionPrimitive.Content.displayName; - -export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; +"use client"; + +import * as React from "react"; +import * as AccordionPrimitive from "@radix-ui/react-accordion"; +import { ChevronDown } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +const Accordion = AccordionPrimitive.Root; + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AccordionItem.displayName = "AccordionItem"; + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + +)); +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)); + +AccordionContent.displayName = AccordionPrimitive.Content.displayName; + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/apps/plugins/components/ui/alert-dialog.tsx b/apps/plugins/components/ui/alert-dialog.tsx index e9799b53..d4abe1a9 100644 --- a/apps/plugins/components/ui/alert-dialog.tsx +++ b/apps/plugins/components/ui/alert-dialog.tsx @@ -1,141 +1,141 @@ -"use client"; - -import * as React from "react"; -import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; - -import { cn } from "@/lib/utils"; -import { buttonVariants } from "@/components/ui/button"; - -const AlertDialog = AlertDialogPrimitive.Root; - -const AlertDialogTrigger = AlertDialogPrimitive.Trigger; - -const AlertDialogPortal = AlertDialogPrimitive.Portal; - -const AlertDialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; - -const AlertDialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - - - - -)); -AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; - -const AlertDialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-); -AlertDialogHeader.displayName = "AlertDialogHeader"; - -const AlertDialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-); -AlertDialogFooter.displayName = "AlertDialogFooter"; - -const AlertDialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; - -const AlertDialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogDescription.displayName = - AlertDialogPrimitive.Description.displayName; - -const AlertDialogAction = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; - -const AlertDialogCancel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; - -export { - AlertDialog, - AlertDialogPortal, - AlertDialogOverlay, - AlertDialogTrigger, - AlertDialogContent, - AlertDialogHeader, - AlertDialogFooter, - AlertDialogTitle, - AlertDialogDescription, - AlertDialogAction, - AlertDialogCancel, -}; +"use client"; + +import * as React from "react"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; + +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; + +const AlertDialog = AlertDialogPrimitive.Root; + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; + +const AlertDialogPortal = AlertDialogPrimitive.Portal; + +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; + +const AlertDialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +AlertDialogHeader.displayName = "AlertDialogHeader"; + +const AlertDialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +AlertDialogFooter.displayName = "AlertDialogFooter"; + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogDescription.displayName = + AlertDialogPrimitive.Description.displayName; + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +}; diff --git a/apps/plugins/components/ui/alert.tsx b/apps/plugins/components/ui/alert.tsx index 2d6922cd..34160af2 100644 --- a/apps/plugins/components/ui/alert.tsx +++ b/apps/plugins/components/ui/alert.tsx @@ -1,62 +1,62 @@ -import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; - -import { cn } from "@/lib/utils"; - -const alertVariants = cva( - "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", - { - variants: { - variant: { - default: "bg-background text-foreground", - destructive: - "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", - }, - }, - defaultVariants: { - variant: "default", - }, - } -); - -const Alert = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes & VariantProps ->(({ className, variant, ...props }, ref) => ( -
-)); -Alert.displayName = "Alert"; - -const AlertTitle = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -AlertTitle.displayName = "AlertTitle"; - -const AlertDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); -AlertDescription.displayName = "AlertDescription"; - -export { Alert, AlertTitle, AlertDescription }; +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const alertVariants = cva( + "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", + { + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +const Alert = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & VariantProps +>(({ className, variant, ...props }, ref) => ( +
+)); +Alert.displayName = "Alert"; + +const AlertTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +AlertTitle.displayName = "AlertTitle"; + +const AlertDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +AlertDescription.displayName = "AlertDescription"; + +export { Alert, AlertTitle, AlertDescription }; diff --git a/apps/plugins/components/ui/aspect-ratio.tsx b/apps/plugins/components/ui/aspect-ratio.tsx index 359bc940..e7de2dd7 100644 --- a/apps/plugins/components/ui/aspect-ratio.tsx +++ b/apps/plugins/components/ui/aspect-ratio.tsx @@ -1,7 +1,7 @@ -"use client"; - -import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"; - -const AspectRatio = AspectRatioPrimitive.Root; - -export { AspectRatio }; +"use client"; + +import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"; + +const AspectRatio = AspectRatioPrimitive.Root; + +export { AspectRatio }; diff --git a/apps/plugins/components/ui/avatar.tsx b/apps/plugins/components/ui/avatar.tsx index 8d1b7db7..d0ed29e4 100644 --- a/apps/plugins/components/ui/avatar.tsx +++ b/apps/plugins/components/ui/avatar.tsx @@ -1,50 +1,50 @@ -"use client"; - -import * as React from "react"; -import * as AvatarPrimitive from "@radix-ui/react-avatar"; - -import { cn } from "@/lib/utils"; - -const Avatar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -Avatar.displayName = AvatarPrimitive.Root.displayName; - -const AvatarImage = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AvatarImage.displayName = AvatarPrimitive.Image.displayName; - -const AvatarFallback = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; - -export { Avatar, AvatarImage, AvatarFallback }; +"use client"; + +import * as React from "react"; +import * as AvatarPrimitive from "@radix-ui/react-avatar"; + +import { cn } from "@/lib/utils"; + +const Avatar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Avatar.displayName = AvatarPrimitive.Root.displayName; + +const AvatarImage = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarImage.displayName = AvatarPrimitive.Image.displayName; + +const AvatarFallback = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName; + +export { Avatar, AvatarImage, AvatarFallback }; diff --git a/apps/plugins/components/ui/breadcrumb.tsx b/apps/plugins/components/ui/breadcrumb.tsx index 1725e067..4b60c0fc 100644 --- a/apps/plugins/components/ui/breadcrumb.tsx +++ b/apps/plugins/components/ui/breadcrumb.tsx @@ -1,115 +1,115 @@ -import * as React from "react"; -import { Slot } from "@radix-ui/react-slot"; -import { ChevronRight, MoreHorizontal } from "lucide-react"; - -import { cn } from "@/lib/utils"; - -const Breadcrumb = React.forwardRef< - HTMLElement, - React.ComponentPropsWithoutRef<"nav"> & { - separator?: React.ReactNode; - } ->(({ ...props }, ref) =>