diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e47f58c..e45fd89d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,8 @@ "editor.formatOnSave": true, "[typescriptreact]": { "editor.defaultFormatter": "biomejs.biome" + }, + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" } } diff --git a/apps/hub/src/routeTree.gen.ts b/apps/hub/src/routeTree.gen.ts index 0a92f85e..ed5c9632 100644 --- a/apps/hub/src/routeTree.gen.ts +++ b/apps/hub/src/routeTree.gen.ts @@ -39,6 +39,7 @@ import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdIndexImpo import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdVersionsImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/versions' import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdTokensImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/tokens' import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdServersImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/servers' +import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdModulesImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/modules' import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdMatchmakerImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/matchmaker' import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdLobbiesImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/lobbies' import { Route as AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdCdnImport } from './routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/cdn' @@ -222,6 +223,13 @@ const AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdServersRoute = AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdRoute, } as any) +const AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdModulesRoute = + AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdModulesImport.update({ + path: '/modules', + getParentRoute: () => + AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdRoute, + } as any) + const AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdMatchmakerRoute = AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdMatchmakerImport.update({ path: '/matchmaker', @@ -522,6 +530,13 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdMatchmakerImport parentRoute: typeof AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdImport } + '/_authenticated/_layout/games/$gameId/environments/$namespaceId/modules': { + id: '/_authenticated/_layout/games/$gameId/environments/$namespaceId/modules' + path: '/modules' + fullPath: '/games/$gameId/environments/$namespaceId/modules' + preLoaderRoute: typeof AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdModulesImport + parentRoute: typeof AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdImport + } '/_authenticated/_layout/games/$gameId/environments/$namespaceId/servers': { id: '/_authenticated/_layout/games/$gameId/environments/$namespaceId/servers' path: '/servers' @@ -661,6 +676,7 @@ export const routeTree = rootRoute.addChildren({ }, ), AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdMatchmakerRoute, + AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdModulesRoute, AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdServersRoute: AuthenticatedLayoutGamesGameIdEnvironmentsNamespaceIdServersRoute.addChildren( { @@ -819,6 +835,7 @@ export const routeTree = rootRoute.addChildren({ "/_authenticated/_layout/games/$gameId/environments/$namespaceId/cdn", "/_authenticated/_layout/games/$gameId/environments/$namespaceId/lobbies", "/_authenticated/_layout/games/$gameId/environments/$namespaceId/matchmaker", + "/_authenticated/_layout/games/$gameId/environments/$namespaceId/modules", "/_authenticated/_layout/games/$gameId/environments/$namespaceId/servers", "/_authenticated/_layout/games/$gameId/environments/$namespaceId/tokens", "/_authenticated/_layout/games/$gameId/environments/$namespaceId/versions", @@ -859,6 +876,10 @@ export const routeTree = rootRoute.addChildren({ "filePath": "_authenticated/_layout/games/$gameId_/environments/$namespaceId/matchmaker.tsx", "parent": "/_authenticated/_layout/games/$gameId/environments/$namespaceId" }, + "/_authenticated/_layout/games/$gameId/environments/$namespaceId/modules": { + "filePath": "_authenticated/_layout/games/$gameId_/environments/$namespaceId/modules.tsx", + "parent": "/_authenticated/_layout/games/$gameId/environments/$namespaceId" + }, "/_authenticated/_layout/games/$gameId/environments/$namespaceId/servers": { "filePath": "_authenticated/_layout/games/$gameId_/environments/$namespaceId/servers.tsx", "parent": "/_authenticated/_layout/games/$gameId/environments/$namespaceId", diff --git a/apps/hub/src/routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/modules.tsx b/apps/hub/src/routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/modules.tsx new file mode 100644 index 00000000..576dbd80 --- /dev/null +++ b/apps/hub/src/routes/_authenticated/_layout/games/$gameId_/environments/$namespaceId/modules.tsx @@ -0,0 +1,23 @@ +import { ModulesStore, loadModuleCategories } from "@rivet-gg/components"; +import { createFileRoute } from "@tanstack/react-router"; + +function GameIdModules() { + const { categories } = Route.useLoaderData(); + return ( + <> + + > + ); +} + +export const Route = createFileRoute( + "/_authenticated/_layout/games/$gameId/environments/$namespaceId/modules", +)({ + component: GameIdModules, + loader: async () => { + const categories = await loadModuleCategories(); + return { + categories, + }; + }, +}); diff --git a/packages/components/package.json b/packages/components/package.json index 4df67955..ba7ef19b 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -64,7 +64,7 @@ "input-otp": "^1.2.3", "lucide-react": "^0.439.0", "react": "^18.2.0", - "react-day-picker": "^8.10.1", + "react-day-picker": "^9.0.9", "react-dom": "^18.2.0", "react-hook-form": "^7.51.1", "react-resizable-panels": "^2.0.19", diff --git a/packages/components/src/action-card.tsx b/packages/components/src/action-card.tsx index aeee8f49..c8ab330e 100644 --- a/packages/components/src/action-card.tsx +++ b/packages/components/src/action-card.tsx @@ -1,3 +1,4 @@ +"use client"; import type { ReactNode } from "react"; import { Card, diff --git a/packages/components/src/animated-currency.tsx b/packages/components/src/animated-currency.tsx index cc9ffe5c..8040dcc2 100644 --- a/packages/components/src/animated-currency.tsx +++ b/packages/components/src/animated-currency.tsx @@ -1,3 +1,4 @@ +"use client"; import { LazyMotion, animate, diff --git a/packages/components/src/asset-image.tsx b/packages/components/src/asset-image.tsx index 095e8d02..61e9f4b9 100644 --- a/packages/components/src/asset-image.tsx +++ b/packages/components/src/asset-image.tsx @@ -1,3 +1,4 @@ +"use client"; import { useConfig } from "./lib/config"; export function AssetImage( diff --git a/packages/components/src/auto-form/fields/file.tsx b/packages/components/src/auto-form/fields/file.tsx index 6f2390c7..a9c0925c 100644 --- a/packages/components/src/auto-form/fields/file.tsx +++ b/packages/components/src/auto-form/fields/file.tsx @@ -1,3 +1,4 @@ +"use client"; import { faTrash } from "@fortawesome/pro-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { type ChangeEvent, useState } from "react"; diff --git a/packages/components/src/auto-form/fields/union.tsx b/packages/components/src/auto-form/fields/union.tsx index 5a9db4b0..bec891a2 100644 --- a/packages/components/src/auto-form/fields/union.tsx +++ b/packages/components/src/auto-form/fields/union.tsx @@ -1,3 +1,4 @@ +"use client"; import { useState } from "react"; import type * as z from "zod"; import { FormControl, FormItem, FormMessage } from "../../ui/form"; diff --git a/packages/components/src/auto-form/index.tsx b/packages/components/src/auto-form/index.tsx index ee0136a7..2f830883 100644 --- a/packages/components/src/auto-form/index.tsx +++ b/packages/components/src/auto-form/index.tsx @@ -1,3 +1,4 @@ +"use client"; import React from "react"; import { type DefaultValues, type FormState, useForm } from "react-hook-form"; import type { z } from "zod"; diff --git a/packages/components/src/copy-area.tsx b/packages/components/src/copy-area.tsx index cc0719ee..9bce293e 100644 --- a/packages/components/src/copy-area.tsx +++ b/packages/components/src/copy-area.tsx @@ -1,3 +1,4 @@ +"use client"; import { faCopy } from "@fortawesome/pro-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Slot } from "@radix-ui/react-slot"; diff --git a/packages/components/src/datepicker.tsx b/packages/components/src/datepicker.tsx index 4935698e..fdffff0f 100644 --- a/packages/components/src/datepicker.tsx +++ b/packages/components/src/datepicker.tsx @@ -69,12 +69,7 @@ export function DatePicker({ ) : null} - + ); @@ -143,7 +138,6 @@ export function RangeDatePicker({ ) : null} + + + Docs + + + + + Support + + + + ), }: HeaderProps) { return ( @@ -43,43 +58,20 @@ export function Header({ Toggle navigation menu - - - - - - - + + + + + {logo} + + {mobileBreadcrumbs} - + + {support} - - - - Docs - - - - - Support - - - diff --git a/packages/components/src/header/nav-item.tsx b/packages/components/src/header/nav-item.tsx index d7bdbb93..9c806b8e 100644 --- a/packages/components/src/header/nav-item.tsx +++ b/packages/components/src/header/nav-item.tsx @@ -12,7 +12,7 @@ export function NavItem({ className, asChild, ...props }: NavItemProps) { diff --git a/packages/components/src/hooks/use-dialog.tsx b/packages/components/src/hooks/use-dialog.tsx index e19c02a9..af2cd4f7 100644 --- a/packages/components/src/hooks/use-dialog.tsx +++ b/packages/components/src/hooks/use-dialog.tsx @@ -1,3 +1,4 @@ +"use client"; import { type ComponentProps, type ComponentType, diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 71dc84d9..15fca40c 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -22,6 +22,9 @@ export * from "./animated-currency"; export * from "./live-badge"; export * from "./relative-time"; export * from "./code"; +export * from "./modules-store"; +export * from "./module-icon"; +export * from "./module-card"; export * from "./ui/typography"; export * from "./ui/skeleton"; export * from "./ui/sheet"; @@ -68,6 +71,7 @@ export * from "./lib/formatter"; export * from "./lib/exit-signals"; export * from "./lib/config"; export * from "./lib/create-schema-form"; +export * from "./lib/modules"; export * from "./auto-form"; export * from "./hooks"; export * as styleHelpers from "./ui/helpers/index"; diff --git a/packages/components/src/lib/config.ts b/packages/components/src/lib/config.ts index 335286c5..e3e22366 100644 --- a/packages/components/src/lib/config.ts +++ b/packages/components/src/lib/config.ts @@ -1,3 +1,4 @@ +"use client"; import { createContext, useContext } from "react"; interface Config { @@ -10,30 +11,30 @@ interface Config { sentry?: { dsn: string; projectId: string; - } - outerbaseProviderToken: string, + }; + outerbaseProviderToken: string; } export const ConfigContext = createContext({ apiUrl: "", assetsUrl: "", - outerbaseProviderToken: '', + outerbaseProviderToken: "", }); export const useConfig = () => useContext(ConfigContext); export const ConfigProvider = ConfigContext.Provider; const getApiEndpoint = (apiEndpoint: string) => { - if (apiEndpoint == '__AUTO__') { - if (location.hostname.startsWith('hub.')) { + if (apiEndpoint == "__AUTO__") { + if (location.hostname.startsWith("hub.")) { // Connect to the corresponding API endpoint - return 'https://' + location.hostname.replace('hub.', 'api.'); + return "https://" + location.hostname.replace("hub.", "api."); } else { // Default to staging servers for all other endpoints - return 'https://api.staging2.gameinc.io'; + return "https://api.staging2.gameinc.io"; } } return apiEndpoint; -} +}; export const getConfig = (): Config => { const el = document.getElementById("RIVET_CONFIG"); @@ -46,5 +47,5 @@ export const getConfig = (): Config => { return { ...parsed, apiUrl: getApiEndpoint(parsed.apiUrl), - } + }; }; diff --git a/packages/components/src/lib/create-schema-form.tsx b/packages/components/src/lib/create-schema-form.tsx index 30194263..3d5388bc 100644 --- a/packages/components/src/lib/create-schema-form.tsx +++ b/packages/components/src/lib/create-schema-form.tsx @@ -1,3 +1,4 @@ +'use client'; import { Button, type ButtonProps, Form } from "@rivet-gg/components"; import { zodResolver } from "@hookform/resolvers/zod"; import { type ComponentProps, type ReactNode, useEffect } from "react"; diff --git a/packages/components/src/lib/modules.ts b/packages/components/src/lib/modules.ts new file mode 100644 index 00000000..2ac5e713 --- /dev/null +++ b/packages/components/src/lib/modules.ts @@ -0,0 +1,141 @@ +const CATEGORIES = [ + { + name: 'Multiplayer', + description: 'Engage players with live multiplayer gameplay, fostering competition and cooperation.', + slug: 'multiplayer' + }, + { + name: 'Authentication', + description: 'Secure and manage user accounts to personalize and safeguard the player experience.', + slug: 'auth' + }, + { + name: 'Social', + description: 'Facilitate player interaction and community-building to boost engagement and retention.', + slug: 'social' + }, + { + name: 'Economy', + description: 'Drive player progression and monetization with virtual goods and currencies.', + slug: 'economy' + }, + // { + // name: "Monetization", + // description: "TODO", + // slug: "monetization", + // }, + { + name: 'Competitive', + description: 'Motivate and reward skilled play with rankings, tournaments, and leagues.', + slug: 'competitive' + }, + { + name: 'Analytics', + description: 'Gain actionable insights to optimize game design, balance, and monetization.', + slug: 'analytics' + }, + // { + // name: "Monitoring", + // description: "TODO", + // slug: "monitoring", + // }, + { + name: 'Security', + description: 'Protect your game and players from cheating, hacking, and disruptive behavior.', + slug: 'security' + }, + { + name: 'Utility', + description: 'Streamline development with foundational tools and reusable components.', + slug: 'utility' + }, + { + name: 'Platform', + description: "Extend your game's reach and engage players across popular gaming platforms.", + slug: 'platform' + }, + // { + // name: "Infrastructure", + // description: "Extend and integrate your game with custom backend services and third-party APIs.", + // slug: "infra", + // }, + { + name: 'Service', + description: 'Integrate third-party services to enhance functionality and streamline operations.', + slug: 'service' + } +]; + +export async function loadModulesMeta() { + const versionMetaResponse = await fetch('https://releases.rivet.gg/backend/index.json'); + const { latestVersion } = await versionMetaResponse.json(); + const modulesMetaResponse = await fetch(`https://releases.rivet.gg/backend/${latestVersion}/index.json`); + return await modulesMetaResponse.json(); +} + +export async function loadModuleMeta(module: string) { + const meta = await loadModulesMeta(); + const moduleMeta = meta.modules[module]; + return { + ...moduleMeta, + category: CATEGORIES.find(category => moduleMeta.config.tags.indexOf(category.slug) !== -1) ?? {name: "Uncategorized", slug: "uncategorized", description: ""}, + config: { + ...moduleMeta.config, + dependencies: Object.fromEntries( + Object.keys(moduleMeta.config.dependencies || {}).map(dep => [dep, meta.modules[dep]]) + ) + } + }; +} + + +export interface Category { + name: string; + slug: string; + description: string; + modules: { id: string; module: any }[]; +} + +export async function loadModuleCategories() { + const meta = await loadModulesMeta(); + const unsortedModules = new Set(Object.keys(meta.modules)); + const allCategories: Category[] = []; + for (let categoryConfig of CATEGORIES) { + const category: Category = { + ...categoryConfig, + modules: [] + }; + allCategories.push(category); + + // Find modules + for (const moduleId of new Set(unsortedModules)) { + const mod = meta.modules[moduleId]!; + if (mod.config.tags?.indexOf('internal') != -1) { + unsortedModules.delete(moduleId); + continue; + } + + if (mod.config.tags.indexOf(category.slug) == -1) continue; + + // Add to category + unsortedModules.delete(moduleId); + category.modules.push({ id: moduleId, module: mod }); + } + + // Sort modules + category.modules = category.modules.sort((a, b) => { + // Sink 'coming_soon' modules to the bottom + if (a.module.config.status === 'coming_soon' && b.module.config.status !== 'coming_soon') return 1; + if (a.module.config.status !== 'coming_soon' && b.module.config.status === 'coming_soon') return -1; + // For modules with the same status, sort alphabetically + return a.module.config.name!.localeCompare(b.module.config.name!); + }); + } + + // Check for unsorted modules + if (unsortedModules.size !== 0) { + throw new Error(`Modules do no have tag matching a category: ${[...unsortedModules].join(', ')}`); + } + + return allCategories; +} \ No newline at end of file diff --git a/packages/components/src/logs-view.tsx b/packages/components/src/logs-view.tsx index 40e8cf43..9a529ba1 100644 --- a/packages/components/src/logs-view.tsx +++ b/packages/components/src/logs-view.tsx @@ -1,3 +1,4 @@ +"use client"; import { faArrowDownToLine } from "@fortawesome/pro-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import type { Virtualizer } from "@tanstack/react-virtual"; diff --git a/packages/components/src/module-card.tsx b/packages/components/src/module-card.tsx new file mode 100644 index 00000000..b0a0c52d --- /dev/null +++ b/packages/components/src/module-card.tsx @@ -0,0 +1,106 @@ +"use client"; +import type { IconProp } from "@fortawesome/fontawesome-svg-core"; +import { faExternalLink } from "@fortawesome/pro-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { motion } from "framer-motion"; +import { Suspense, lazy } from "react"; +import { Card, CardDescription, CardHeader, CardTitle } from "./ui/card"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, + SheetTrigger, +} from "./ui/sheet"; +import { Link, Text } from "./ui/typography"; + +const ModuleIcon = lazy(async () => ({ + default: (await import("./module-icon")).ModuleIcon, +})); + +const animationProps = { + initial: { opacity: 0 }, + animate: { opacity: 1 }, + exit: { opacity: 0 }, +}; + +interface ModuleCardProps { + id: string; + name: string; + description: string; + status: string; + icon: string; + layoutAnimation?: boolean; + onClick?: () => void; +} + +export function ModuleCard({ + id, + name, + icon, + description, + layoutAnimation = true, + onClick, +}: ModuleCardProps) { + const moduleCard = ( + + + + + + + + {name} + + + {description} + + + + + ); + + if (onClick) { + return moduleCard; + } + + return ( + + {moduleCard} + + + {name} + + + Open in New Tab + + + + + + + + + + + ); +} diff --git a/packages/components/src/module-icon.tsx b/packages/components/src/module-icon.tsx new file mode 100644 index 00000000..800491a4 --- /dev/null +++ b/packages/components/src/module-icon.tsx @@ -0,0 +1,26 @@ +import { + type IconPack, + type IconProp, + library, +} from "@fortawesome/fontawesome-svg-core"; +import { fab } from "@fortawesome/free-brands-svg-icons"; +import { fas } from "@fortawesome/pro-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +const fasFab: IconPack = Object.fromEntries( + Object.entries(fab).map(([iconName, icon]) => [ + iconName, + { ...icon, prefix: "fas" }, + ]), +); + +library.add(fasFab, fas); + +interface ModuleIconProps { + className?: string; + icon: IconProp; +} + +export function ModuleIcon({ className, icon }: ModuleIconProps) { + return ; +} diff --git a/packages/components/src/modules-store.tsx b/packages/components/src/modules-store.tsx new file mode 100644 index 00000000..204fc191 --- /dev/null +++ b/packages/components/src/modules-store.tsx @@ -0,0 +1,193 @@ +"use client"; +import { + faBellConcierge, + faHammer, + faPlus, +} from "@fortawesome/pro-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { LayoutGroup, motion } from "framer-motion"; +import { useState } from "react"; +import type { Category } from "./lib/modules"; +import { cn } from "./lib/utils"; +import { ModuleCard } from "./module-card"; +import { SidebarNavigation } from "./sidebar-navigation"; +import { SidebarPage } from "./sidebar-page"; +import { Button } from "./ui/button"; +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "./ui/card"; +import { Flex } from "./ui/flex"; +import { Grid } from "./ui/grid"; +import { Input } from "./ui/input"; +import { H1, H2, Lead } from "./ui/typography"; + +interface ModulesStoreProps { + categories: Category[]; + onModuleClick?: (module: Category["modules"][number]) => void; +} + +export function ModulesStore({ categories, onModuleClick }: ModulesStoreProps) { + const [query, setQuery] = useState(""); + + const filteredCategories = categories + .map((category) => { + const modules = category.modules.filter( + ({ module }) => + module.config.name + .toLowerCase() + .includes((query || "").toLowerCase()) || + module.config.description + .toLowerCase() + .includes((query || "").toLowerCase()), + ); + return { ...category, modules }; + }) + .filter((category) => category.modules.length > 0); + + return ( + <> + + Backend Modules + + Build your game's backend with open-source modules. + + + + + + { + setQuery(e.target.value); + }} + placeholder="Search..." + className="bg-transparent border-transparent h-full w-full placeholder:text-muted-foreground focus-visible:outline-none" + /> + + + + + {categories.map((category) => ( + c.slug === category.slug) + ? "text-foreground" + : "opacity-50", + )} + > + {category.name} + + ))} + + } + > + + Build Your Own + + + + } + > + + + {filteredCategories.length === 0 ? ( + + + + + + No modules found + + + + If you can't find a module that fits your needs, you + can request a module to be created or build your own module. + + + } + > + + Request Module + + + } + > + + Build Your Own Module + + + + + + ) : null} + {filteredCategories.map((category) => ( + + {category.name} + + {category.description} + + + {category.modules.map(({ id, module }) => ( + onModuleClick?.(module) : null + } + {...module.config} + /> + ))} + + + ))} + + + + > + ); +} diff --git a/packages/components/src/tailwind-base.ts b/packages/components/src/tailwind-base.ts index 10fd2d58..b493398b 100644 --- a/packages/components/src/tailwind-base.ts +++ b/packages/components/src/tailwind-base.ts @@ -45,6 +45,9 @@ const config = { active: 'status~="active"', }, extend: { + aria: { + "current-page": "current='page'", + }, colors: { border: "hsl(var(--border))", input: "hsl(var(--input))", diff --git a/packages/components/src/ui/button.tsx b/packages/components/src/ui/button.tsx index a64deee3..6b2139de 100644 --- a/packages/components/src/ui/button.tsx +++ b/packages/components/src/ui/button.tsx @@ -30,6 +30,7 @@ const buttonVariants = cva( }, size: { default: "h-10 px-4 py-2", + xs: "h-5 rounded-md px-2 text-xs", sm: "h-9 rounded-md px-3 text-xs", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", diff --git a/packages/components/src/ui/calendar.tsx b/packages/components/src/ui/calendar.tsx index 62525b76..21b5bfb3 100644 --- a/packages/components/src/ui/calendar.tsx +++ b/packages/components/src/ui/calendar.tsx @@ -1,10 +1,5 @@ +"use client"; import { DayPicker } from "react-day-picker"; - -import { - faChevronLeft, - faChevronRight, -} from "@fortawesome/pro-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { cn } from "../lib/utils"; import { buttonVariants } from "./button"; @@ -54,14 +49,14 @@ function Calendar({ day_hidden: "invisible", ...classNames, }} - components={{ - IconLeft: () => ( - - ), - IconRight: () => ( - - ), - }} + // components={{ + // IconLeft: () => ( + // + // ), + // IconRight: () => ( + // + // ), + // }} {...props} /> ); diff --git a/packages/components/src/ui/card.tsx b/packages/components/src/ui/card.tsx index eac37e06..4fdcc169 100644 --- a/packages/components/src/ui/card.tsx +++ b/packages/components/src/ui/card.tsx @@ -10,18 +10,22 @@ import { const Card = React.forwardRef< HTMLDivElement, - React.HTMLAttributes & Partial ->(({ className, ...props }, ref) => ( - -)); + React.HTMLAttributes & + Partial & { asChild?: boolean } +>(({ className, asChild, ...props }, ref) => { + const Comp = asChild ? Slot : "div"; + return ( + + ); +}); Card.displayName = "Card"; const CardHeader = React.forwardRef< diff --git a/packages/components/src/ui/date-picker.tsx b/packages/components/src/ui/date-picker.tsx index 309efef6..514cfba0 100644 --- a/packages/components/src/ui/date-picker.tsx +++ b/packages/components/src/ui/date-picker.tsx @@ -30,12 +30,7 @@ export const DatePicker = forwardRef< - + ); diff --git a/packages/components/src/ui/file-input.tsx b/packages/components/src/ui/file-input.tsx index d4f69535..42876bb5 100644 --- a/packages/components/src/ui/file-input.tsx +++ b/packages/components/src/ui/file-input.tsx @@ -1,3 +1,4 @@ +"use client"; import { faTrash } from "@fortawesome/pro-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { type ChangeEvent, useState } from "react"; diff --git a/packages/components/src/ui/form.tsx b/packages/components/src/ui/form.tsx index e65ab4af..6d1d2d24 100644 --- a/packages/components/src/ui/form.tsx +++ b/packages/components/src/ui/form.tsx @@ -1,3 +1,4 @@ +"use client"; import type * as LabelPrimitive from "@radix-ui/react-label"; import { Slot } from "@radix-ui/react-slot"; import * as React from "react"; diff --git a/packages/components/src/ui/resizable.tsx b/packages/components/src/ui/resizable.tsx index 640cb9ee..5fd42510 100644 --- a/packages/components/src/ui/resizable.tsx +++ b/packages/components/src/ui/resizable.tsx @@ -1,3 +1,4 @@ +"use client"; import * as ResizablePrimitive from "react-resizable-panels"; import { faGripVertical } from "@fortawesome/pro-solid-svg-icons"; diff --git a/packages/components/src/uptime.tsx b/packages/components/src/uptime.tsx index 7e21ac46..cd3fd6df 100644 --- a/packages/components/src/uptime.tsx +++ b/packages/components/src/uptime.tsx @@ -1,3 +1,4 @@ +"use client"; import { useEffect, useState } from "react"; import { type DurationOptions, formatDuration } from "./lib/formatter"; diff --git a/packages/components/src/virtual-scroll-area.tsx b/packages/components/src/virtual-scroll-area.tsx index 38b97f21..4aba1e73 100644 --- a/packages/components/src/virtual-scroll-area.tsx +++ b/packages/components/src/virtual-scroll-area.tsx @@ -1,3 +1,4 @@ +"use client"; import { type Virtualizer, type VirtualizerOptions, diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index 21124c68..d9eaa901 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -7,7 +7,8 @@ "noEmit": true, "moduleResolution": "bundler", "jsx": "react-jsx", - "baseUrl": "." + "baseUrl": ".", + "module": "Preserve" }, "include": ["src"] } diff --git a/yarn.lock b/yarn.lock index 2e81ce74..f7e25718 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4091,7 +4091,7 @@ __metadata: lucide-react: "npm:^0.439.0" postcss: "npm:^8.4.38" react: "npm:^18.2.0" - react-day-picker: "npm:^8.10.1" + react-day-picker: "npm:^9.0.9" react-dom: "npm:^18.2.0" react-hook-form: "npm:^7.51.1" react-resizable-panels: "npm:^2.0.19" @@ -11751,13 +11751,14 @@ __metadata: languageName: node linkType: hard -"react-day-picker@npm:^8.10.1": - version: 8.10.1 - resolution: "react-day-picker@npm:8.10.1" +"react-day-picker@npm:^9.0.9": + version: 9.0.9 + resolution: "react-day-picker@npm:9.0.9" + dependencies: + date-fns: "npm:^3.6.0" peerDependencies: - date-fns: ^2.28.0 || ^3.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - checksum: 10c0/a0ff28c4b61b3882e6a825b19e5679e2fdf3256cf1be8eb0a0c028949815c1ae5a6561474c2c19d231c010c8e0e0b654d3a322610881e0655abca05a2e03d9df + react: ">=16.8.0" + checksum: 10c0/cbbc537f766b9c6329a5645ea4ecac8e7f7e9e19e04b9219961d3cbd36bc61e2376aef12f975093ecb931e4a6a463e0ec5726ec0f0fcfa04296422635de960ee languageName: node linkType: hard
+ {category.description} +