diff --git a/.cursor/rules/directory-naming-conventions.mdc b/.cursor/rules/directory-naming-conventions.mdc new file mode 100644 index 00000000..b93c988b --- /dev/null +++ b/.cursor/rules/directory-naming-conventions.mdc @@ -0,0 +1,5 @@ +--- +description: +globs: +alwaysApply: false +--- diff --git a/.cursor/rules/general-typescript-and-react-rules.mdc b/.cursor/rules/general-typescript-and-react-rules.mdc new file mode 100644 index 00000000..ef078edf --- /dev/null +++ b/.cursor/rules/general-typescript-and-react-rules.mdc @@ -0,0 +1,21 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Applies general coding principles and best practices for TypeScript and React development across the project. +globs: **/*.{ts,tsx} +--- +- Write concise, readable TypeScript code. +- Use functional and declarative programming patterns. +- Follow DRY (Don't Repeat Yourself) principle. +- Implement early returns for better readability. +- Structure components logically: exports, subcomponents, helpers, types. +- Use descriptive names with auxiliary verbs (isLoading, hasError). +- Prefix event handlers with 'handle' (handleClick, handleSubmit). +- Use TypeScript for all code. +- Prefer interfaces over types. +- Avoid enums; use const maps instead. +- Implement proper type safety and inference. +- Use `satisfies` operator for type validation. \ No newline at end of file diff --git a/.cursor/rules/next-js-15-async-request-api-rules.mdc b/.cursor/rules/next-js-15-async-request-api-rules.mdc new file mode 100644 index 00000000..301cfd0a --- /dev/null +++ b/.cursor/rules/next-js-15-async-request-api-rules.mdc @@ -0,0 +1,19 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Dictates how asynchronous requests should be handled within Next.js 15, specifically concerning runtime APIs. +globs: app/**/* +--- +- Always use async versions of runtime APIs: + typescript + const cookieStore = await cookies() + const headersList = await headers() + const { isEnabled } = await draftMode() + +- Handle async params in layouts/pages: + typescript + const params = await props.params + const searchParams = await props.searchParams \ No newline at end of file diff --git a/.cursor/rules/next-js-15-component-architecture-rules.mdc b/.cursor/rules/next-js-15-component-architecture-rules.mdc new file mode 100644 index 00000000..14c842ba --- /dev/null +++ b/.cursor/rules/next-js-15-component-architecture-rules.mdc @@ -0,0 +1,15 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Specifies the best practices for building React components within the Next.js 15 App Router structure. +globs: app/**/* +--- +- Favor React Server Components (RSC) where possible. +- Minimize 'use client' directives. +- Implement proper error boundaries. +- Use Suspense for async operations. +- Optimize for performance and Web Vitals. +- Use Shadcn UI whenever there is a component available for the UI goal diff --git a/.cursor/rules/next-js-15-state-management-rules.mdc b/.cursor/rules/next-js-15-state-management-rules.mdc new file mode 100644 index 00000000..03b8d0bf --- /dev/null +++ b/.cursor/rules/next-js-15-state-management-rules.mdc @@ -0,0 +1,13 @@ +--- +description: +globs: +alwaysApply: true +--- +--- +description: Defines the recommended state management strategies for Next.js 15 applications, including server and client contexts. +globs: app/**/* +--- +- Use `useActionState` instead of deprecated `useFormState`. +- Leverage enhanced `useFormStatus` with new properties (data, method, action). +- Implement URL state management with 'nuqs'. +- Minimize client-side state. \ No newline at end of file diff --git a/app/globals.css b/app/globals.css index a2dc41ec..dc98be74 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,26 +1,122 @@ @import "tailwindcss"; +@import "tw-animate-css"; -:root { - --background: #ffffff; - --foreground: #171717; -} +@custom-variant dark (&:is(.dark *)); @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --font-sans: var(--font-geist-sans); --font-mono: var(--font-geist-mono); + --color-sidebar-ring: var(--sidebar-ring); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar: var(--sidebar); + --color-chart-5: var(--chart-5); + --color-chart-4: var(--chart-4); + --color-chart-3: var(--chart-3); + --color-chart-2: var(--chart-2); + --color-chart-1: var(--chart-1); + --color-ring: var(--ring); + --color-input: var(--input); + --color-border: var(--border); + --color-destructive: var(--destructive); + --color-accent-foreground: var(--accent-foreground); + --color-accent: var(--accent); + --color-muted-foreground: var(--muted-foreground); + --color-muted: var(--muted); + --color-secondary-foreground: var(--secondary-foreground); + --color-secondary: var(--secondary); + --color-primary-foreground: var(--primary-foreground); + --color-primary: var(--primary); + --color-popover-foreground: var(--popover-foreground); + --color-popover: var(--popover); + --color-card-foreground: var(--card-foreground); + --color-card: var(--card); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); } -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; } } - -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; -} diff --git a/app/layout.tsx b/app/layout.tsx index f7fa87eb..ebb6d351 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -13,8 +13,8 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "AutoRFP - AI-Powered RFP Response Solution", + description: "Automatically answer RFP questions with AI document agents powered by LlamaIndex", }; export default function RootLayout({ diff --git a/app/page.tsx b/app/page.tsx index 88f0cc9b..14b741ee 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,103 +1,27 @@ -import Image from "next/image"; +import { Navbar } from "@/components/Navbar"; +import { HeroSection } from "@/components/HeroSection"; +import { StatsSection } from "@/components/StatsSection"; +import { FeaturesSection } from "@/components/FeaturesSection"; +import { TestimonialsSection } from "@/components/TestimonialsSection"; +import { AISection } from "@/components/AISection"; +import { ResourcesSection } from "@/components/ResourcesSection"; +import { CTASection } from "@/components/CTASection"; +import { Footer } from "@/components/Footer"; export default function Home() { return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - app/page.tsx - - . -
  2. -
  3. - Save and see your changes instantly. -
  4. -
- -
- - Vercel logomark - Deploy now - - - Read our docs - -
+
+ +
+ + + + + + +
- +
); } diff --git a/components.json b/components.json new file mode 100644 index 00000000..335484f9 --- /dev/null +++ b/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": true, + "tsx": true, + "tailwind": { + "config": "", + "css": "app/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/components/AISection.tsx b/components/AISection.tsx new file mode 100644 index 00000000..d3fa3877 --- /dev/null +++ b/components/AISection.tsx @@ -0,0 +1,133 @@ +import { Button } from "./ui/button"; + +export function AISection() { + return ( +
+
+
+
+
+ POWERED BY LLAMAINDEX +
+

+ Advanced AI that understands your documents +

+

+ Our LlamaIndex-powered document agents read and understand your corporate documentation, knowledge bases, and previous RFP responses to generate accurate, consistent answers. +

+
    +
  • + + + +
    + Document Understanding: Our AI can process Word, PDF, Excel, and PowerPoint files to understand your content +
    +
  • +
  • + + + +
    + Context-Aware Responses: Generates answers that are contextually relevant to the specific RFP question +
    +
  • +
  • + + + +
    + Continuous Learning: Improves over time as it processes more of your content and RFP responses +
    +
  • +
  • + + + +
    + Secure Processing: All your data remains private and secure within your own environment +
    +
  • +
+ +
+
+
+
+
+
+
+
+
+
AI Response Generator
+
+
+
+ Q: What security measures do you have in place to protect customer data? +
+
+

Our platform implements multiple layers of security to protect customer data:

+
    +
  • 256-bit AES encryption for data at rest and in transit
  • +
  • Role-based access controls with multi-factor authentication
  • +
  • Regular penetration testing and vulnerability assessments
  • +
  • SOC 2 Type II and ISO 27001 compliance
  • +
  • Data backup and disaster recovery procedures
  • +
+

Sources: Security_Whitepaper.pdf, ISO27001_Certification.pdf

+
+
+
Response generated in 3.2 seconds from 5 documents
+
+
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/CTASection.tsx b/components/CTASection.tsx new file mode 100644 index 00000000..c24344e8 --- /dev/null +++ b/components/CTASection.tsx @@ -0,0 +1,26 @@ +import { Button } from "./ui/button"; + +export function CTASection() { + return ( +
+
+
+

+ Ready to see AutoRFP in action? +

+

+ Find out why leading response teams across the world turn to AutoRFP for their RFP software needs. +

+
+ + +
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/FeaturesSection.tsx b/components/FeaturesSection.tsx new file mode 100644 index 00000000..7fdfe156 --- /dev/null +++ b/components/FeaturesSection.tsx @@ -0,0 +1,528 @@ +import { Button } from "./ui/button"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs"; + +export function FeaturesSection() { + return ( +
+
+
+

+ The AI platform for every team in your organization +

+

+ Discover how AutoRFP can help different teams in your organization respond to RFPs faster and more effectively. +

+
+ + + + Proposal Managers + Sales + Marketing + IT/Security + Executive Leadership + Legal + + + +
+
+

Proposal & Bid Managers

+

+ AutoRFP AI drafts your answers and manages collaborative workflows so you can deliver winning responses to RFPs, questionnaires, and assessments 80% faster. +

+
    +
  • + + + + Auto-generate responses based on your documents +
  • +
  • + + + + Manage content library with AI assistance +
  • +
  • + + + + Streamline team collaboration +
  • +
+ +
+
+ + + + + + + +
+
+
+ + +
+
+

Sales Teams

+

+ Accelerate your sales cycle by quickly responding to prospect questions and RFPs with accurate, consistent information powered by AI. +

+
    +
  • + + + + Instant answers to prospect questions +
  • +
  • + + + + Reduce response time to RFPs by 80% +
  • +
  • + + + + Increase win rates with better responses +
  • +
+ +
+
+ + + + + + + +
+
+
+ + +
+
+

Marketing Teams

+

+ Ensure consistent messaging and brand voice across all RFP responses while saving time on content creation. +

+
    +
  • + + + + Maintain consistent brand messaging +
  • +
  • + + + + Update content once for all channels +
  • +
  • + + + + Analytics on most-used content pieces +
  • +
+ +
+
+ + + + +
+
+
+ + +
+
+

IT & Security Teams

+

+ Streamline security questionnaires and compliance documentation with AI-powered responses that are accurate and up-to-date. +

+
    +
  • + + + + Automate security questionnaire responses +
  • +
  • + + + + Keep compliance documentation current +
  • +
  • + + + + Secure content access controls +
  • +
+ +
+
+ + + + +
+
+
+ + +
+
+

Executive Leadership

+

+ Gain visibility into your RFP process, optimize win rates, and allocate resources efficiently with data-driven insights. +

+
    +
  • + + + + Win rate analytics and reporting +
  • +
  • + + + + Resource utilization metrics +
  • +
  • + + + + ROI calculations on RFP responses +
  • +
+ +
+
+ + + + + +
+
+
+ + +
+
+

Legal Teams

+

+ Ensure consistent, accurate legal responses while reducing the burden on your legal team for standard RFP questions. +

+
    +
  • + + + + Pre-approved legal language library +
  • +
  • + + + + Compliance tracking for responses +
  • +
  • + + + + Approval workflows for legal content +
  • +
+ +
+
+ + + +
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/Footer.tsx b/components/Footer.tsx new file mode 100644 index 00000000..67c9dcb0 --- /dev/null +++ b/components/Footer.tsx @@ -0,0 +1,144 @@ +import Link from "next/link"; + +export function Footer() { + return ( +
+
+
+
+ + AutoRFP + +

+ The leader in AI-powered RFP response software. +

+
+ + + + + + + LinkedIn + + + + + + Twitter + + + + + + + + Instagram + +
+
+
+

Platform

+
    +
  • + Overview +
  • +
  • + Features +
  • +
  • + Integrations +
  • +
  • + Security +
  • +
  • + Pricing +
  • +
+
+
+

Resources

+
    +
  • + Blog +
  • +
  • + Webinars +
  • +
  • + Case Studies +
  • +
  • + Documentation +
  • +
  • + Support +
  • +
+
+
+

Company

+
    +
  • + About +
  • +
  • + Careers +
  • +
  • + Partners +
  • +
  • + Contact +
  • +
  • + Legal +
  • +
+
+
+
+

+ © 2023 AutoRFP. All rights reserved. +

+
+ Terms + Privacy Policy + Cookies +
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/HeroSection.tsx b/components/HeroSection.tsx new file mode 100644 index 00000000..be1feb4b --- /dev/null +++ b/components/HeroSection.tsx @@ -0,0 +1,60 @@ +import { Button } from "./ui/button"; + +export function HeroSection() { + return ( +
+
+
+
+
+
+ RESPONSIVE AI FOR EVERY RFP +
+

+ AI agents that automate your RFP responses +

+

+ Power your team with insights, accuracy, and speed across bids, questionnaires, and RFP documents with our LlamaIndex-powered AI. +

+
+
+ + +
+
+
+
+
+ + + + + + + + + + +
+
+
+
+
+
+ ); +} \ No newline at end of file diff --git a/components/Navbar.tsx b/components/Navbar.tsx new file mode 100644 index 00000000..5af3d691 --- /dev/null +++ b/components/Navbar.tsx @@ -0,0 +1,56 @@ +import Link from "next/link"; +import { Button } from "./ui/button"; + +export function Navbar() { + return ( +
+
+
+ + AutoRFP + + +
+
+ + +
+
+
+ ); +} \ No newline at end of file diff --git a/components/ResourcesSection.tsx b/components/ResourcesSection.tsx new file mode 100644 index 00000000..9afab6b8 --- /dev/null +++ b/components/ResourcesSection.tsx @@ -0,0 +1,333 @@ +import { Button } from "./ui/button"; +import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "./ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs"; + +export function ResourcesSection() { + return ( +
+
+
+

+ Strategic resources for RFP teams +

+

+ Expert insights and tools to help you succeed with your RFP responses +

+
+ + + + Featured + Webinars + Blog + + + +
+ + + The AI RFP Handbook + Your ultimate guide to harnessing AI for RFP responses + + +
+
+ + + + +
+
+
+ + + +
+ + + + 5 Ways AI Is Transforming RFP Responses + On-demand webinar + + +
+
+ + + + +
+
+
+ + + +
+ + + + Measuring RFP Success: KPIs That Matter + Featured blog post + + +
+
+ + + + + + + +
+
+
+ + + +
+
+
+ + +
+ + + 5 Ways AI Is Transforming RFP Responses + On-demand webinar + + +
+
+ + + + +
+
+
+ + + +
+ + + + Building an Efficient RFP Content Library + Live webinar - June 15, 2023 + + +
+
+ + + + +
+
+
+ + + +
+ + + + RFP Response Metrics: What to Track + On-demand webinar + + +
+
+ + + + +
+
+
+ + + +
+
+
+ + +
+ + + Measuring RFP Success: KPIs That Matter + Featured blog post + + +
+
+ + + + + + + +
+
+
+ + + +
+ + + + 10 Common RFP Mistakes to Avoid + Blog post + + +
+
+ + + + + + + +
+
+
+ + + +
+ + + + How LlamaIndex Powers Better RFP Responses + Blog post + + +
+
+ + + + + + + +
+
+
+ + + +
+
+
+
+ +
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/components/StatsSection.tsx b/components/StatsSection.tsx new file mode 100644 index 00000000..d905e59f --- /dev/null +++ b/components/StatsSection.tsx @@ -0,0 +1,42 @@ +export function StatsSection() { + return ( +
+
+
+

+ Company Performance Metrics +

+
+
+
4.8
+
+ 500+ reviews +
+
+
+
$200M+
+
+ in total opportunities managed +
+
+
+
10+
+
+ of the Fortune 500 use AutoRFP +
+
+
+
1.5M+
+
+ Q&A pairs maintained on the platform +
+
+
+

+ The leader in response intelligence, trusted worldwide +

+
+
+
+ ); +} \ No newline at end of file diff --git a/components/TestimonialsSection.tsx b/components/TestimonialsSection.tsx new file mode 100644 index 00000000..e76c370d --- /dev/null +++ b/components/TestimonialsSection.tsx @@ -0,0 +1,190 @@ +import { Card, CardContent } from "./ui/card"; +import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"; +import { Button } from "./ui/button"; + +export function TestimonialsSection() { + return ( +
+
+
+

+ #1 RFP response software loved by customers +

+

+ See how companies like yours are saving time and winning more deals with AutoRFP +

+
+ +
+ + +
+
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + + + ))} +
+
+ "For every $1 that our company invests in AutoRFP, I estimate a return on investment of $500. We have seen really massive growth over the past few years and we couldn't have done it without AutoRFP." +
+
+
+ + JD + + +
+

Jane Doe

+

+ Global Director of Proposals at TechCorp +

+
+
+
+
+

$5M

+

+ saved in response cost +

+
+
+

15,000

+

+ hours saved in response time +

+
+
+
+
+
+ + + +
+
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + + + ))} +
+
+ "We were able to reduce the time maintaining our content library by 50% through the elimination of writing/editing tasks involved in each RFP response, and AI Assistant has contributed to our increasing win rate." +
+
+
+ + JB + + +
+

John Brown

+

+ Senior Specialist RFx Enablement at SalesForce +

+
+
+
+
+

10x

+

+ return on investment +

+
+
+

50%

+

+ time reduction +

+
+
+
+
+
+ + + +
+
+
+ {[1, 2, 3, 4, 5].map((star) => ( + + + + ))} +
+
+ "It could take 5 to 10 minutes to manually find something in the library or to take two things and merge them together. With AI Assistant, it is actually answering, on average, our questions in 30 seconds." +
+
+
+ + AH + + +
+

Alexander Heart

+

+ Senior Director of Solution Consulting at HealthTech +

+
+
+
+
+

60%

+

+ increase in proposals submitted +

+
+
+

92%

+

+ RFP go-forward rate +

+
+
+
+
+
+
+ +
+ +
+
+
+ ); +} \ No newline at end of file diff --git a/components/ui/accordion.tsx b/components/ui/accordion.tsx new file mode 100644 index 00000000..4a8cca46 --- /dev/null +++ b/components/ui/accordion.tsx @@ -0,0 +1,66 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Accordion({ + ...props +}: React.ComponentProps) { + return +} + +function AccordionItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AccordionTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + + ) +} + +function AccordionContent({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + +
{children}
+
+ ) +} + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/components/ui/alert-dialog.tsx b/components/ui/alert-dialog.tsx new file mode 100644 index 00000000..0863e40d --- /dev/null +++ b/components/ui/alert-dialog.tsx @@ -0,0 +1,157 @@ +"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" + +function AlertDialog({ + ...props +}: React.ComponentProps) { + return +} + +function AlertDialogTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + ) +} + +function AlertDialogHeader({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogFooter({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDialogTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogAction({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AlertDialogCancel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} diff --git a/components/ui/alert.tsx b/components/ui/alert.tsx new file mode 100644 index 00000000..14213546 --- /dev/null +++ b/components/ui/alert.tsx @@ -0,0 +1,66 @@ +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 px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current", + { + variants: { + variant: { + default: "bg-card text-card-foreground", + destructive: + "text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Alert({ + className, + variant, + ...props +}: React.ComponentProps<"div"> & VariantProps) { + return ( +
+ ) +} + +function AlertTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function AlertDescription({ + className, + ...props +}: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { Alert, AlertTitle, AlertDescription } diff --git a/components/ui/aspect-ratio.tsx b/components/ui/aspect-ratio.tsx new file mode 100644 index 00000000..3df3fd02 --- /dev/null +++ b/components/ui/aspect-ratio.tsx @@ -0,0 +1,11 @@ +"use client" + +import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio" + +function AspectRatio({ + ...props +}: React.ComponentProps) { + return +} + +export { AspectRatio } diff --git a/components/ui/avatar.tsx b/components/ui/avatar.tsx new file mode 100644 index 00000000..71e428b4 --- /dev/null +++ b/components/ui/avatar.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as AvatarPrimitive from "@radix-ui/react-avatar" + +import { cn } from "@/lib/utils" + +function Avatar({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarImage({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function AvatarFallback({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { Avatar, AvatarImage, AvatarFallback } diff --git a/components/ui/badge.tsx b/components/ui/badge.tsx new file mode 100644 index 00000000..02054139 --- /dev/null +++ b/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/components/ui/breadcrumb.tsx b/components/ui/breadcrumb.tsx new file mode 100644 index 00000000..eb88f321 --- /dev/null +++ b/components/ui/breadcrumb.tsx @@ -0,0 +1,109 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { ChevronRight, MoreHorizontal } from "lucide-react" + +import { cn } from "@/lib/utils" + +function Breadcrumb({ ...props }: React.ComponentProps<"nav">) { + return