diff options
| -rw-r--r-- | apps/browser-extension/components.json | 17 | ||||
| -rw-r--r-- | apps/browser-extension/index.html | 2 | ||||
| -rw-r--r-- | apps/browser-extension/package.json | 17 | ||||
| -rw-r--r-- | apps/browser-extension/public/logo-full-white.png | bin | 0 -> 9041 bytes | |||
| -rw-r--r-- | apps/browser-extension/src/Layout.tsx | 13 | ||||
| -rw-r--r-- | apps/browser-extension/src/Logo.tsx | 8 | ||||
| -rw-r--r-- | apps/browser-extension/src/NotConfiguredPage.tsx | 8 | ||||
| -rw-r--r-- | apps/browser-extension/src/OptionsPage.tsx | 9 | ||||
| -rw-r--r-- | apps/browser-extension/src/SignInPage.tsx | 14 | ||||
| -rw-r--r-- | apps/browser-extension/src/components/ui/button.tsx | 57 | ||||
| -rw-r--r-- | apps/browser-extension/src/components/ui/dialog.tsx | 120 | ||||
| -rw-r--r-- | apps/browser-extension/src/components/ui/input.tsx | 24 | ||||
| -rw-r--r-- | apps/browser-extension/src/index.css | 73 | ||||
| -rw-r--r-- | apps/browser-extension/src/utils/ThemeProvider.tsx | 73 | ||||
| -rw-r--r-- | apps/browser-extension/src/utils/css.ts | 7 | ||||
| -rw-r--r-- | apps/browser-extension/src/utils/providers.tsx | 9 | ||||
| -rw-r--r-- | apps/browser-extension/tailwind.config.js | 1 | ||||
| -rw-r--r-- | pnpm-lock.yaml | 44 |
18 files changed, 396 insertions, 100 deletions
diff --git a/apps/browser-extension/components.json b/apps/browser-extension/components.json new file mode 100644 index 00000000..67eaccb0 --- /dev/null +++ b/apps/browser-extension/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "src/components", + "utils": "src/utils/css" + } +} diff --git a/apps/browser-extension/index.html b/apps/browser-extension/index.html index e4b78eae..3ba58dda 100644 --- a/apps/browser-extension/index.html +++ b/apps/browser-extension/index.html @@ -4,7 +4,7 @@ <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>Vite + React + TS</title> + <title>Hoarder</title> </head> <body> <div id="root"></div> diff --git a/apps/browser-extension/package.json b/apps/browser-extension/package.json index 20cc843c..9b204519 100644 --- a/apps/browser-extension/package.json +++ b/apps/browser-extension/package.json @@ -12,30 +12,39 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@hoarder/trpc": "workspace:^0.1.0", "@hoarder/shared-react": "workspace:^0.1.0", + "@hoarder/trpc": "workspace:^0.1.0", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-slot": "^1.0.2", "@tanstack/react-query": "^5.24.8", "@trpc/client": "11.0.0-next-beta.308", "@trpc/next": "11.0.0-next-beta.308", "@trpc/react-query": "11.0.0-next-beta.308", "@trpc/server": "11.0.0-next-beta.308", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.0", + "cmdk": "^1.0.0", "lucide-react": "^0.330.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.22.0", - "use-chrome-storage": "^1.2.2", "superjson": "^2.2.1", + "tailwind-merge": "^2.2.1", + "tailwindcss-animate": "^1.0.7", + "use-chrome-storage": "^1.2.2", "zod": "^3.22.4" }, "devDependencies": { + "@crxjs/vite-plugin": "^1.0.14", "@hoarder/eslint-config": "workspace:^0.2.0", "@hoarder/prettier-config": "workspace:^0.1.0", "@hoarder/tailwind-config": "workspace:^0.1.0", "@hoarder/tsconfig": "workspace:^0.1.0", - "@crxjs/vite-plugin": "^1.0.14", + "@types/chrome": "^0.0.260", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", - "@types/chrome": "^0.0.260", "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.17", "eslint": "^8.57.0", diff --git a/apps/browser-extension/public/logo-full-white.png b/apps/browser-extension/public/logo-full-white.png Binary files differnew file mode 100644 index 00000000..8d3067c6 --- /dev/null +++ b/apps/browser-extension/public/logo-full-white.png diff --git a/apps/browser-extension/src/Layout.tsx b/apps/browser-extension/src/Layout.tsx index bf760362..0431f550 100644 --- a/apps/browser-extension/src/Layout.tsx +++ b/apps/browser-extension/src/Layout.tsx @@ -1,6 +1,7 @@ import { Home, RefreshCw, Settings, X } from "lucide-react"; import { Outlet, useNavigate } from "react-router-dom"; +import { Button } from "./components/ui/button"; import usePluginSettings from "./utils/settings"; export default function Layout() { @@ -35,16 +36,16 @@ export default function Layout() { </div> <div className="flex space-x-3"> {process.env.NODE_ENV == "development" && ( - <button onClick={() => navigate(0)}> + <Button onClick={() => navigate(0)}> <RefreshCw className="w-4" /> - </button> + </Button> )} - <button onClick={() => navigate("/options")}> + <Button onClick={() => navigate("/options")}> <Settings className="w-4" /> - </button> - <button onClick={() => window.close()}> + </Button> + <Button onClick={() => window.close()}> <X className="w-4" /> - </button> + </Button> </div> </div> </div> diff --git a/apps/browser-extension/src/Logo.tsx b/apps/browser-extension/src/Logo.tsx index 462bbef0..3e2e6444 100644 --- a/apps/browser-extension/src/Logo.tsx +++ b/apps/browser-extension/src/Logo.tsx @@ -1,9 +1,15 @@ +import logoImgWhite from "../public/logo-full-white.png"; import logoImg from "../public/logo-full.png"; export default function Logo() { return ( <span className="flex items-center justify-center"> - <img src={logoImg} alt="hoarder logo" className="h-10" /> + <img src={logoImg} alt="hoarder logo" className="h-10 dark:hidden" /> + <img + src={logoImgWhite} + alt="hoarder logo" + className="hidden h-10 dark:block" + /> </span> ); } diff --git a/apps/browser-extension/src/NotConfiguredPage.tsx b/apps/browser-extension/src/NotConfiguredPage.tsx index 298e9f5e..31d45d6a 100644 --- a/apps/browser-extension/src/NotConfiguredPage.tsx +++ b/apps/browser-extension/src/NotConfiguredPage.tsx @@ -1,6 +1,8 @@ import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; +import { Button } from "./components/ui/button"; +import { Input } from "./components/ui/input"; import Logo from "./Logo"; import usePluginSettings from "./utils/settings"; @@ -33,16 +35,14 @@ export default function NotConfiguredPage() { <p className="text-red-500">{error}</p> <div className="flex gap-2"> <label className="my-auto">Server Address</label> - <input + <Input name="address" value={serverAddress} className="h-8 flex-1 rounded-lg border border-gray-300 p-2" onChange={(e) => setServerAddress(e.target.value)} /> </div> - <button className="bg-black text-white" onClick={onSave}> - Configure - </button> + <Button onClick={onSave}>Configure</Button> </div> ); } diff --git a/apps/browser-extension/src/OptionsPage.tsx b/apps/browser-extension/src/OptionsPage.tsx index 24785857..41b72178 100644 --- a/apps/browser-extension/src/OptionsPage.tsx +++ b/apps/browser-extension/src/OptionsPage.tsx @@ -1,6 +1,7 @@ import React, { useEffect } from "react"; import { useNavigate } from "react-router-dom"; +import { Button } from "./components/ui/button"; import Logo from "./Logo"; import Spinner from "./Spinner"; import usePluginSettings from "./utils/settings"; @@ -55,12 +56,14 @@ export default function OptionsPage() { <span className="text-lg">Settings</span> <hr /> <div className="flex gap-2"> + <span className="my-auto">Server Address:</span> + {settings.address} + </div> + <div className="flex gap-2"> <span className="my-auto">Logged in as:</span> {loggedInMessage} </div> - <button className="rounded-lg border border-gray-200" onClick={onLogout}> - Logout - </button> + <Button onClick={onLogout}>Logout</Button> </div> ); } diff --git a/apps/browser-extension/src/SignInPage.tsx b/apps/browser-extension/src/SignInPage.tsx index aa8699ae..4e846070 100644 --- a/apps/browser-extension/src/SignInPage.tsx +++ b/apps/browser-extension/src/SignInPage.tsx @@ -1,6 +1,8 @@ import { useState } from "react"; import { useNavigate } from "react-router-dom"; +import { Button } from "./components/ui/button"; +import { Input } from "./components/ui/input"; import Logo from "./Logo"; import usePluginSettings from "./utils/settings"; import { api } from "./utils/trpc"; @@ -51,7 +53,7 @@ export default function SignInPage() { <form className="flex flex-col gap-y-2" onSubmit={onSubmit}> <div className="flex flex-col gap-y-1"> <label className="my-auto font-bold">Email</label> - <input + <Input value={formData.email} onChange={(e) => setFormData((f) => ({ ...f, email: e.target.value })) @@ -63,7 +65,7 @@ export default function SignInPage() { </div> <div className="flex flex-col gap-y-1"> <label className="my-auto font-bold">Password</label> - <input + <Input value={formData.password} onChange={(e) => setFormData((f) => ({ @@ -76,13 +78,9 @@ export default function SignInPage() { className="h-8 flex-1 rounded-lg border border-gray-300 p-2" /> </div> - <button - className="bg-black text-white" - type="submit" - disabled={isPending} - > + <Button type="submit" disabled={isPending}> Login - </button> + </Button> </form> </div> ); diff --git a/apps/browser-extension/src/components/ui/button.tsx b/apps/browser-extension/src/components/ui/button.tsx new file mode 100644 index 00000000..1bd3802d --- /dev/null +++ b/apps/browser-extension/src/components/ui/button.tsx @@ -0,0 +1,57 @@ +import type { VariantProps } from "class-variance-authority"; +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva } from "class-variance-authority"; + +import { cn } from "../../utils/css"; + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes<HTMLButtonElement>, + VariantProps<typeof buttonVariants> { + asChild?: boolean; +} + +const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + <Comp + className={cn(buttonVariants({ variant, size, className }))} + ref={ref} + {...props} + /> + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/apps/browser-extension/src/components/ui/dialog.tsx b/apps/browser-extension/src/components/ui/dialog.tsx new file mode 100644 index 00000000..997230bb --- /dev/null +++ b/apps/browser-extension/src/components/ui/dialog.tsx @@ -0,0 +1,120 @@ +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; + +import { cn } from "../../utils/css"; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< + React.ElementRef<typeof DialogPrimitive.Overlay>, + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay> +>(({ className, ...props }, ref) => ( + <DialogPrimitive.Overlay + ref={ref} + className={cn( + "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", + className, + )} + {...props} + /> +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef<typeof DialogPrimitive.Content>, + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> +>(({ className, children, ...props }, ref) => ( + <DialogPortal> + <DialogOverlay /> + <DialogPrimitive.Content + ref={ref} + className={cn( + "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", + className, + )} + {...props} + > + {children} + <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground"> + <X className="h-4 w-4" /> + <span className="sr-only">Close</span> + </DialogPrimitive.Close> + </DialogPrimitive.Content> + </DialogPortal> +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes<HTMLDivElement>) => ( + <div + className={cn( + "flex flex-col space-y-1.5 text-center sm:text-left", + className, + )} + {...props} + /> +); +DialogHeader.displayName = "DialogHeader"; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes<HTMLDivElement>) => ( + <div + className={cn( + "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", + className, + )} + {...props} + /> +); +DialogFooter.displayName = "DialogFooter"; + +const DialogTitle = React.forwardRef< + React.ElementRef<typeof DialogPrimitive.Title>, + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title> +>(({ className, ...props }, ref) => ( + <DialogPrimitive.Title + ref={ref} + className={cn( + "text-lg font-semibold leading-none tracking-tight", + className, + )} + {...props} + /> +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef<typeof DialogPrimitive.Description>, + React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description> +>(({ className, ...props }, ref) => ( + <DialogPrimitive.Description + ref={ref} + className={cn("text-sm text-muted-foreground", className)} + {...props} + /> +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/apps/browser-extension/src/components/ui/input.tsx b/apps/browser-extension/src/components/ui/input.tsx new file mode 100644 index 00000000..5751b004 --- /dev/null +++ b/apps/browser-extension/src/components/ui/input.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; + +import { cn } from "../../utils/css"; + +export type InputProps = React.InputHTMLAttributes<HTMLInputElement>; + +const Input = React.forwardRef<HTMLInputElement, InputProps>( + ({ className, type, ...props }, ref) => { + return ( + <input + type={type} + className={cn( + "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50", + className, + )} + ref={ref} + {...props} + /> + ); + }, +); +Input.displayName = "Input"; + +export { Input }; diff --git a/apps/browser-extension/src/index.css b/apps/browser-extension/src/index.css index e7d4bb2f..d5c92220 100644 --- a/apps/browser-extension/src/index.css +++ b/apps/browser-extension/src/index.css @@ -1,72 +1 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; - line-height: 1.5; - font-weight: 400; - - color-scheme: light dark; - color: rgba(255, 255, 255, 0.87); - background-color: #242424; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} -a:hover { - color: #535bf2; -} - -body { - margin: 0; - display: flex; - place-items: center; - min-width: 320px; - min-height: 100vh; -} - -h1 { - font-size: 3.2em; - line-height: 1.1; -} - -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - background-color: #1a1a1a; - cursor: pointer; - transition: border-color 0.25s; -} -button:hover { - border-color: #646cff; -} -button:focus, -button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; -} - -@media (prefers-color-scheme: light) { - :root { - color: #213547; - background-color: #ffffff; - } - a:hover { - color: #747bff; - } - button { - background-color: #f9f9f9; - } -} +@import "@hoarder/tailwind-config/globals.css"; diff --git a/apps/browser-extension/src/utils/ThemeProvider.tsx b/apps/browser-extension/src/utils/ThemeProvider.tsx new file mode 100644 index 00000000..79a0b32f --- /dev/null +++ b/apps/browser-extension/src/utils/ThemeProvider.tsx @@ -0,0 +1,73 @@ +import { createContext, useContext, useEffect, useState } from "react"; + +type Theme = "dark" | "light" | "system"; + +interface ThemeProviderProps { + children: React.ReactNode; + defaultTheme?: Theme; + storageKey?: string; +} + +interface ThemeProviderState { + theme: Theme; + setTheme: (theme: Theme) => void; +} + +const initialState: ThemeProviderState = { + theme: "system", + setTheme: () => null, +}; + +const ThemeProviderContext = createContext<ThemeProviderState>(initialState); + +export function ThemeProvider({ + children, + defaultTheme = "system", + storageKey = "vite-ui-theme", + ...props +}: ThemeProviderProps) { + const [theme, setTheme] = useState<Theme>( + () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, + ); + + useEffect(() => { + const root = window.document.documentElement; + + root.classList.remove("light", "dark"); + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light"; + + root.classList.add(systemTheme); + return; + } + + root.classList.add(theme); + }, [theme]); + + const value = { + theme, + setTheme: (theme: Theme) => { + localStorage.setItem(storageKey, theme); + setTheme(theme); + }, + }; + + return ( + <ThemeProviderContext.Provider {...props} value={value}> + {children} + </ThemeProviderContext.Provider> + ); +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext); + + if (context === undefined) + throw new Error("useTheme must be used within a ThemeProvider"); + + return context; +}; diff --git a/apps/browser-extension/src/utils/css.ts b/apps/browser-extension/src/utils/css.ts new file mode 100644 index 00000000..88283f01 --- /dev/null +++ b/apps/browser-extension/src/utils/css.ts @@ -0,0 +1,7 @@ +import type { ClassValue } from "clsx"; +import { clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/apps/browser-extension/src/utils/providers.tsx b/apps/browser-extension/src/utils/providers.tsx index 4ca17016..4b571254 100644 --- a/apps/browser-extension/src/utils/providers.tsx +++ b/apps/browser-extension/src/utils/providers.tsx @@ -1,9 +1,16 @@ import { TRPCProvider } from "@hoarder/shared-react/providers/trpc-provider"; import usePluginSettings from "./settings"; +import { ThemeProvider } from "./ThemeProvider"; export function Providers({ children }: { children: React.ReactNode }) { const { settings } = usePluginSettings(); - return <TRPCProvider settings={settings}>{children}</TRPCProvider>; + return ( + <TRPCProvider settings={settings}> + <ThemeProvider defaultTheme="system" storageKey="vite-ui-theme"> + {children} + </ThemeProvider> + </TRPCProvider> + ); } diff --git a/apps/browser-extension/tailwind.config.js b/apps/browser-extension/tailwind.config.js index e8f2d639..7300649a 100644 --- a/apps/browser-extension/tailwind.config.js +++ b/apps/browser-extension/tailwind.config.js @@ -1,6 +1,7 @@ import web from "@hoarder/tailwind-config/web"; const config = { + darkMode: "media", content: web.content, presets: [web], }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0e64f565..e5b7aec5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -49,6 +49,18 @@ importers: '@hoarder/trpc': specifier: workspace:^0.1.0 version: link:../../packages/trpc + '@radix-ui/react-dialog': + specifier: ^1.0.5 + version: 1.0.5(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-popover': + specifier: ^1.0.7 + version: 1.0.7(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-select': + specifier: ^2.0.0 + version: 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.58)(react@18.2.0) '@tanstack/react-query': specifier: ^5.24.8 version: 5.24.8(react@18.2.0) @@ -64,6 +76,15 @@ importers: '@trpc/server': specifier: 11.0.0-next-beta.308 version: 11.0.0-next-beta.308 + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.0 + version: 2.1.0 + cmdk: + specifier: ^1.0.0 + version: 1.0.0(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) lucide-react: specifier: ^0.330.0 version: 0.330.0(react@18.2.0) @@ -79,6 +100,12 @@ importers: superjson: specifier: ^2.2.1 version: 2.2.1 + tailwind-merge: + specifier: ^2.2.1 + version: 2.2.1 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.1) use-chrome-storage: specifier: ^1.2.2 version: 1.3.0(react@18.2.0) @@ -5261,6 +5288,12 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + cmdk@1.0.0: + resolution: {integrity: sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + collapse-white-space@2.1.0: resolution: {integrity: sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==} @@ -19589,6 +19622,17 @@ snapshots: cluster-key-slot@1.1.2: dev: false + cmdk@1.0.0(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0): + dependencies: + '@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + dev: false + collapse-white-space@2.1.0: {} color-convert@1.9.3: |
