diff --git a/.eslintrc.json b/.eslintrc.json index 229d9961..e9d9fe37 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -5,7 +5,6 @@ "next", "next/core-web-vitals", "prettier", - "plugin:tailwindcss/recommended", "plugin:tailwindcss/recommended" ], "plugins": ["tailwindcss"], diff --git a/.vscode/settings.json b/.vscode/settings.json index 48a495a6..3f24cee9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,9 @@ ], "tailwindCSS.experimental.classRegex": [ ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], - ["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] + ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], + ["cn\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"], + // ["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] ], "vitest.debugExclude": [ "/**", diff --git a/apps/prepare/package.json b/apps/prepare/package.json index 9daa44a1..6707bdbb 100644 --- a/apps/prepare/package.json +++ b/apps/prepare/package.json @@ -14,14 +14,26 @@ "dependencies": { "@astrojs/react": "^3.6.2", "@astrojs/tailwind": "^5.1.2", + "@fontsource-variable/fustat": "^5.1.0", + "@fontsource/ibm-plex-mono": "^5.1.0", + "@hookform/resolvers": "^3.1.0", + "@motionone/utils": "^10.18.0", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/themes": "3.1.6", + "class-variance-authority": "0.7.1", "@types/node": "^22.9.1", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", "astro": "5.0.0-beta.8", + "framer-motion": ">=11.5.6", "lucide-react": "0.359.0", + "next-themes": "^0.4.3", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-hook-form": "^7.44.2", "tailwindcss": "3.4.6", - "www": "workspace:*" + "tailwindcss-motion": "0.4.3-beta", + "www": "workspace:*", + "zod": "^3.23.8" } } diff --git a/apps/prepare/public/images/prodkt/bryanfunk_hero__personal-landing-bg-alpha.avif b/apps/prepare/public/images/prodkt/bryanfunk_hero__personal-landing-bg-alpha.avif new file mode 100644 index 00000000..8582d03f Binary files /dev/null and b/apps/prepare/public/images/prodkt/bryanfunk_hero__personal-landing-bg-alpha.avif differ diff --git a/apps/prepare/public/images/prodkt/bryanfunk_hero__personal-landing-bg-nonAlpha.avif b/apps/prepare/public/images/prodkt/bryanfunk_hero__personal-landing-bg-nonAlpha.avif new file mode 100644 index 00000000..2101902d Binary files /dev/null and b/apps/prepare/public/images/prodkt/bryanfunk_hero__personal-landing-bg-nonAlpha.avif differ diff --git a/apps/prepare/public/images/prodkt/landing/component-examples.avif b/apps/prepare/public/images/prodkt/landing/component-examples.avif new file mode 100644 index 00000000..d2e19908 Binary files /dev/null and b/apps/prepare/public/images/prodkt/landing/component-examples.avif differ diff --git a/apps/prepare/public/images/prodkt/landing/planfoundry-screenshot.avif b/apps/prepare/public/images/prodkt/landing/planfoundry-screenshot.avif new file mode 100644 index 00000000..94879184 Binary files /dev/null and b/apps/prepare/public/images/prodkt/landing/planfoundry-screenshot.avif differ diff --git a/apps/prepare/public/images/prodkt/landing/prodkt-flows-screenshot.avif b/apps/prepare/public/images/prodkt/landing/prodkt-flows-screenshot.avif new file mode 100644 index 00000000..25794ac6 Binary files /dev/null and b/apps/prepare/public/images/prodkt/landing/prodkt-flows-screenshot.avif differ diff --git a/apps/prepare/public/images/sparkstack/bg_lighting-test_1.avif b/apps/prepare/public/images/sparkstack/bg_lighting-test_1.avif new file mode 100644 index 00000000..5d5c15e3 Binary files /dev/null and b/apps/prepare/public/images/sparkstack/bg_lighting-test_1.avif differ diff --git a/apps/prepare/public/images/sparkstack/noise.webp b/apps/prepare/public/images/sparkstack/noise.webp new file mode 100644 index 00000000..6677c824 Binary files /dev/null and b/apps/prepare/public/images/sparkstack/noise.webp differ diff --git a/apps/prepare/src/assets/prodkt/logo.tsx b/apps/prepare/src/assets/prodkt/logo.tsx new file mode 100644 index 00000000..a360f4cc --- /dev/null +++ b/apps/prepare/src/assets/prodkt/logo.tsx @@ -0,0 +1,26 @@ +import * as React from "react" +import { SVGProps } from "react" + +export default function Logo(props: SVGProps) { + return ( + + Prodkt - Home of Bryan Funk + + + +) +} diff --git a/apps/prepare/src/assets/prodkt/logomark.tsx b/apps/prepare/src/assets/prodkt/logomark.tsx new file mode 100644 index 00000000..b6aa8828 --- /dev/null +++ b/apps/prepare/src/assets/prodkt/logomark.tsx @@ -0,0 +1,21 @@ +import * as React from "react" +import { SVGProps } from "react" + +export default function Logomark(props: SVGProps) { + return ( + + + + ) +} diff --git a/apps/prepare/src/assets/prodkt/logotype.tsx b/apps/prepare/src/assets/prodkt/logotype.tsx new file mode 100644 index 00000000..8c1dd4a6 --- /dev/null +++ b/apps/prepare/src/assets/prodkt/logotype.tsx @@ -0,0 +1,28 @@ +import * as React from "react" +import { SVGProps } from "react" + +export default function Logotype(props: SVGProps) { + return ( + + + + + + + + + + + +) +} diff --git a/apps/prepare/src/components/effect-ripple.tsx b/apps/prepare/src/components/effect-ripple.tsx new file mode 100644 index 00000000..bb4ee959 --- /dev/null +++ b/apps/prepare/src/components/effect-ripple.tsx @@ -0,0 +1,61 @@ +import React, { type CSSProperties } from "react"; + +import { cn } from '@/lib/utils'; + +interface RippleProps { + mainCircleSize?: number; + mainCircleOpacity?: number; + numCircles?: number; + className?: string; +} + +const Ripple = React.memo(function Ripple({ + mainCircleSize = 45, + mainCircleOpacity = 0.08, + numCircles = 8, + className, +}: RippleProps) { + return ( +
+ {Array.from({ length: numCircles }, (_, i) => { + const size = mainCircleSize + i * 8; + const opacity = mainCircleOpacity - i * 0.012; + const animationDelay = `${i * 0.1}s`; + const borderStyle = i === numCircles - 1 ? "dashed" : "solid"; + const borderOpacity = 5 + i * 4; + const borderRadius = 1 + i * 0.15; + + return ( +
+ ); + })} +
+ ); +}); + +Ripple.displayName = "Ripple"; + +export default Ripple; diff --git a/apps/prepare/src/components/flow-cards/index.tsx b/apps/prepare/src/components/flow-cards/index.tsx new file mode 100644 index 00000000..dbc8702b --- /dev/null +++ b/apps/prepare/src/components/flow-cards/index.tsx @@ -0,0 +1,285 @@ +import * as React from "react" +import { cn } from "@/lib/utils" +import { Button } from "@/registry/default/ui/button" +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/registry/default/ui/card" +import { Input } from "@/registry/default/ui/input" +import { Label } from "@/registry/default/ui/label" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/registry/default/ui/select" + +const FlowModalMenu = { + "base": { + "title": "Base", + "description": "Base primitive components", + }, + "headers": { + "title": "Headers", + "description": "Header components", + }, + "posts": { + "title": "Posts", + "description": "Post components", + }, + "articles": { + "title": "Articles", + "description": "Article components", + }, + "catalogs": { + "title": "Catalogs", + "description": "Catalog components", + }, + "testimonials": { + "title": "Testimonials", + "description": "Testimonial components", + }, + "call-to-action": { + "title": "Call to action", + "description": "Call to action components", + }, + "footer": { + "title": "Footer", + "description": "Footer components", + }, + "landing-page": { + "title": "Landing page", + "description": "Landing page components", + }, + "product-grid": { + "title": "Product grid", + "description": "Product grid components", + }, + "product-page": { + "title": "Product page", + "description": "Product page components", + }, + "shop-page": { + "title": "Shop page", + "description": "Shop page components", + }, + "checkout-page": { + "title": "Checkout page", + "description": "Checkout page components", + }, + "cart-page": { + "title": "Cart page", + "description": "Cart page components", + }, + "account-page": { + "title": "Account page", + "description": "Account page components", + }, + "404-page": { + "title": "404 page", + "description": "404 page components", + }, + "500-page": { + "title": "500 page", + "description": "500 page components", + }, + "blog-page": { + "title": "Blog page", + "description": "Blog page components", + }, + "blog-post-page": { + "title": "Blog post page", + "description": "Blog post page components", + }, + "contact-page": { + "title": "Contact page", + "description": "Contact page components", + }, + "faq-page": { + "title": "FAQ page", + "description": "FAQ page components", + }, + "pricing-page": { + "title": "Pricing page", + "description": "Pricing page components", + }, + "search-page": { + "title": "Search page", + "description": "Search page components", + }, + "checkout-success-page": { + "title": "Checkout success page", + "description": "Checkout success page components", + }, + "checkout-cancel-page": { + "title": "Checkout cancel page", + "description": "Checkout cancel page components", + }, + "checkout-error-page": { + "title": "Checkout error page", + "description": "Checkout error page components", + }, + "checkout-payment-page": { + "title": "Checkout payment page", + "description": "Checkout payment page components", + }, + "checkout-review-page": { + "title": "Checkout review page", + "description": "Checkout review page components", + }, + "checkout-shipping-page": { + "title": "Checkout shipping page", + "description": "Checkout shipping page components", + }, + "checkout-thank-you-page": { + "title": "Checkout thank you page", + "description": "Checkout thank you page components", + }, +} + +export function FlowCard() { + return ( + +
+
+ + { + Object.entries(FlowModalMenu).map(([key, value]) => ( + + )) + } + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + ) +} + + +export function FlowCardBrowser({ children, className, ...props }: { children: React.ReactNode, className?: string }) { + return ( +
+
+
+
+
+
+
+
+ {children} +
+
+
+ ) +} + +export const FullContainer = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+ ) +} +export const TwoColumns = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+
+ ) +} +export const ThreeColumns = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+
+
+ ) +} +export const FourColumns = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+
+
+
+ ) +} +export const TwoRows = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+
+ ) +} +export const ThreeRows = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+
+
+ ) +} +export const FourRows = ({ className, ...props }: { className?: string }) => { + return ( +
+
+
+
+
+
+ ) +} +export const TwoRowsTwoColumns = ({ className, ...props }: { className?: string }) => { + return ( + <> +
+
+
+
+
+
+
+
+
+
+ + ) +} diff --git a/apps/prepare/src/components/landing-page/cta-button.tsx b/apps/prepare/src/components/landing-page/cta-button.tsx new file mode 100644 index 00000000..b141ce73 --- /dev/null +++ b/apps/prepare/src/components/landing-page/cta-button.tsx @@ -0,0 +1,26 @@ +import { forwardRef } from 'react'; + +import { cn } from '@/lib/utils'; +import { Button } from '@/registry/default/ui/button'; + +export const CtaButton = forwardRef< + HTMLButtonElement, + React.ComponentProps +>(function CtaButtonComponent({ className, children, ...props }, ref) { + return ( + + ); +}); diff --git a/apps/prepare/src/components/landing-page/footer.tsx b/apps/prepare/src/components/landing-page/footer.tsx new file mode 100644 index 00000000..37e74a0b --- /dev/null +++ b/apps/prepare/src/components/landing-page/footer.tsx @@ -0,0 +1,95 @@ +import { forwardRef } from 'react'; + +import { cn } from '@/lib/utils'; + +interface FooterSection { + heading: React.ReactNode; + links: Array<{ + href: string; + label: React.ReactNode; + }>; +} + +interface FooterProps extends React.HTMLAttributes { + logo: React.ReactNode; + description: React.ReactNode; + copyright: React.ReactNode; + sections: FooterSection[]; +} + +export const Footer = forwardRef( + function MarketingFooterComponent( + { className, logo, description, copyright, sections, ...props }, + ref, + ) { + return ( +
+
+
+
+
+
{logo}
+
+
+

+ {description} +

+
+
+

{copyright}

+
+
+
+
+ +
+ {sections.map((section, index) => ( +
+
+ + {section.heading} + + + + {section.links.map((link, linkIndex) => ( + + {link.label} + + ))} + +
+
+ ))} +
+
+
+
+ ); + }, +); + +function FooterSectionHeading(props: React.PropsWithChildren) { + return {props.children}; +} + +function FooterSectionList(props: React.PropsWithChildren) { + return
    {props.children}
; +} + +function FooterLink({ + href, + children, +}: React.PropsWithChildren<{ href: string }>) { + return ( +
  • + {children} +
  • + ); +} diff --git a/apps/prepare/src/components/landing-page/gradient-secondary-text.tsx b/apps/prepare/src/components/landing-page/gradient-secondary-text.tsx new file mode 100644 index 00000000..c830c290 --- /dev/null +++ b/apps/prepare/src/components/landing-page/gradient-secondary-text.tsx @@ -0,0 +1,27 @@ +import { forwardRef } from 'react'; + +import { Slot, Slottable } from '@radix-ui/react-slot'; + +import { cn } from '@/lib/utils'; + +export const GradientSecondaryText = forwardRef< + HTMLSpanElement, + React.HTMLAttributes & { + asChild?: boolean; + } +>(function GradientSecondaryTextComponent({ className, ...props }, ref) { + const Comp = props.asChild ? Slot : 'span'; + + return ( + + {props.children} + + ); +}); diff --git a/apps/prepare/src/components/landing-page/gradient-text.tsx b/apps/prepare/src/components/landing-page/gradient-text.tsx new file mode 100644 index 00000000..a5edb58d --- /dev/null +++ b/apps/prepare/src/components/landing-page/gradient-text.tsx @@ -0,0 +1,22 @@ +import type React from 'react'; +import { forwardRef } from 'react'; + +import { cn } from '@/lib/utils'; + +export const GradientText = forwardRef< + HTMLSpanElement, + React.HTMLAttributes +>(function GradientTextComponent({ className, children, ...props }, ref) { + return ( + + {children} + + ); +}); diff --git a/apps/prepare/src/components/landing-page/header.tsx b/apps/prepare/src/components/landing-page/header.tsx new file mode 100644 index 00000000..e1447a4e --- /dev/null +++ b/apps/prepare/src/components/landing-page/header.tsx @@ -0,0 +1,37 @@ +import { forwardRef } from 'react'; + +import { cn } from '@/lib/utils'; + +interface HeaderProps extends React.HTMLAttributes { + logo?: React.ReactNode; + navigation?: React.ReactNode; + actions?: React.ReactNode; +} + +export const Header = forwardRef( + function MarketingHeaderComponent( + { className, logo, navigation, actions, ...props }, + ref, + ) { + return ( +
    +
    +
    +
    {logo}
    +
    {navigation}
    +
    + {actions} +
    +
    +
    +
    + ); + }, +); diff --git a/apps/prepare/src/components/landing-page/hero-title.tsx b/apps/prepare/src/components/landing-page/hero-title.tsx new file mode 100644 index 00000000..33bdd829 --- /dev/null +++ b/apps/prepare/src/components/landing-page/hero-title.tsx @@ -0,0 +1,27 @@ +import { forwardRef } from 'react'; + +import { Slot, Slottable } from '@radix-ui/react-slot'; + +import { cn } from '@/lib/utils'; + +export const HeroTitle = forwardRef< + HTMLHeadingElement, + React.HTMLAttributes & { + asChild?: boolean; + } +>(function HeroTitleComponent({ children, className, ...props }, ref) { + const Comp = props.asChild ? Slot : 'h1'; + + return ( + + {children} + + ); +}); diff --git a/apps/prepare/src/components/landing-page/hero.tsx b/apps/prepare/src/components/landing-page/hero.tsx new file mode 100644 index 00000000..9984721b --- /dev/null +++ b/apps/prepare/src/components/landing-page/hero.tsx @@ -0,0 +1,91 @@ +import React from 'react'; + +import { cn } from '@/lib/utils'; +import { Heading } from '@/registry/default/prodkt/heading'; +import { HeroTitle } from './hero-title'; + +interface HeroProps { + pill?: React.ReactNode; + title: React.ReactNode; + subtitle?: React.ReactNode; + cta?: React.ReactNode; + image?: React.ReactNode; + className?: string; + animate?: boolean; +} + +export function Hero({ + pill, + title, + subtitle, + cta, + image, + className, + animate = true, +}: HeroProps) { + return ( +
    +
    +
    + {pill && ( +
    + {pill} +
    + )} + +
    + {title} + + {subtitle && ( +
    + + {subtitle} + +
    + )} +
    + + {cta && ( +
    + {cta} +
    + )} +
    +
    + + {image && ( +
    + {image} +
    + )} +
    + ); +} diff --git a/apps/prepare/src/components/landing-page/index.tsx b/apps/prepare/src/components/landing-page/index.tsx new file mode 100644 index 00000000..78c91f2b --- /dev/null +++ b/apps/prepare/src/components/landing-page/index.tsx @@ -0,0 +1,15 @@ +export * from './hero-title'; +export * from './pill'; +export * from './gradient-secondary-text'; +export * from './gradient-text'; +export * from './hero'; +export * from './secondary-hero'; +export * from './cta-button'; +export * from './header'; +export * from './footer'; +export * from 'www/registry/default/prodkt/bento-grid-uno/feature-showcase'; +export * from 'www/registry/default/prodkt/bento-grid-uno/feature-grid'; +export * from 'www/registry/default/prodkt/bento-grid-uno/feature-card'; +export * from './newsletter-signup'; +export * from './newsletter-signup-container'; +export * from 'www/registry/default/prodkt/bento-grid-uno/page'; diff --git a/apps/prepare/src/components/landing-page/newsletter-signup-container.tsx b/apps/prepare/src/components/landing-page/newsletter-signup-container.tsx new file mode 100644 index 00000000..62cbd5fe --- /dev/null +++ b/apps/prepare/src/components/landing-page/newsletter-signup-container.tsx @@ -0,0 +1,86 @@ +'use client'; + +import { useCallback, useState } from 'react'; + +import { cn } from '@/lib/utils'; +import { Alert, AlertDescription, AlertTitle } from '@/registry/default/ui/alert'; +import { Heading } from '@/registry/default/prodkt/heading'; +import { Spinner } from '@/registry/default/prodkt/spinner'; +import { NewsletterSignup } from './newsletter-signup'; + +interface NewsletterSignupContainerProps + extends React.HTMLAttributes { + onSignup: (email: string) => Promise; + heading?: string; + description?: string; + successMessage?: string; + errorMessage?: string; +} + +export function NewsletterSignupContainer({ + onSignup, + heading = 'Subscribe to our newsletter', + description = 'Get the latest updates and offers directly to your inbox.', + successMessage = 'Thank you for subscribing!', + errorMessage = 'An error occurred. Please try again.', + className, + ...props +}: NewsletterSignupContainerProps) { + const [status, setStatus] = useState< + 'idle' | 'loading' | 'success' | 'error' + >('idle'); + + const handleSubmit = useCallback( + async (data: { email: string }) => { + setStatus('loading'); + + try { + await onSignup(data.email); + + setStatus('success'); + } catch (error) { + console.error('Newsletter signup error:', error); + setStatus('error'); + } + }, + [onSignup], + ); + + return ( +
    +
    + {heading} +

    {description}

    +
    + + {status === 'idle' && } + + {status === 'loading' && ( +
    + +
    + )} + + {status === 'success' && ( +
    + + Success! + {successMessage} + +
    + )} + + {status === 'error' && ( +
    + + Error + {errorMessage} + +
    + )} +
    + ); +} diff --git a/apps/prepare/src/components/landing-page/newsletter-signup.tsx b/apps/prepare/src/components/landing-page/newsletter-signup.tsx new file mode 100644 index 00000000..8bd86ae0 --- /dev/null +++ b/apps/prepare/src/components/landing-page/newsletter-signup.tsx @@ -0,0 +1,71 @@ +'use client'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; + +import { cn } from '@/lib/utils'; +import { Button } from '@/registry/default/ui/button'; +import { + Form, + FormControl, + FormField, + FormItem, + FormMessage, +} from '@/registry/default/ui/form'; +import { Input } from '@/registry/default/ui/input'; + +const NewsletterFormSchema = z.object({ + email: z.string().email('Please enter a valid email address'), +}); + +type NewsletterFormValues = z.infer; + +interface NewsletterSignupProps extends React.HTMLAttributes { + onSignup: (data: NewsletterFormValues) => void; + buttonText?: string; + placeholder?: string; +} + +export function NewsletterSignup({ + onSignup, + buttonText = 'Subscribe', + placeholder = 'Enter your email', + className, + ...props +}: NewsletterSignupProps) { + const form = useForm({ + resolver: zodResolver(NewsletterFormSchema), + defaultValues: { + email: '', + }, + }); + + return ( +
    +
    + + ( + + + + + + + )} + /> + + + + +
    + ); +} diff --git a/apps/prepare/src/components/landing-page/pill.tsx b/apps/prepare/src/components/landing-page/pill.tsx new file mode 100644 index 00000000..d77b32b7 --- /dev/null +++ b/apps/prepare/src/components/landing-page/pill.tsx @@ -0,0 +1,40 @@ +import { forwardRef } from 'react'; + +import { Slot, Slottable } from '@radix-ui/react-slot'; + +import { cn } from '@/lib/utils'; +import { GradientSecondaryText } from './gradient-secondary-text'; + +export const Pill = forwardRef< + HTMLHeadingElement, + React.HTMLAttributes & { + label?: string; + asChild?: boolean; + } +>(function PillComponent({ className, asChild, ...props }, ref) { + const Comp = asChild ? Slot : 'h3'; + + return ( + + {props.label && ( + + {props.label} + + )} + + {props.children} + + + ); +}); diff --git a/apps/prepare/src/components/landing-page/secondary-hero.tsx b/apps/prepare/src/components/landing-page/secondary-hero.tsx new file mode 100644 index 00000000..69992ae5 --- /dev/null +++ b/apps/prepare/src/components/landing-page/secondary-hero.tsx @@ -0,0 +1,45 @@ +import { forwardRef } from 'react'; + +import { cn } from '@/lib/utils'; +import { Heading } from '@/registry/default/prodkt/heading'; + +interface SecondaryHeroProps extends React.HTMLAttributes { + pill?: React.ReactNode; + heading: React.ReactNode; + subheading: React.ReactNode; +} + +export const SecondaryHero = forwardRef( + function SecondaryHeroComponent( + { className, pill, heading, subheading, children, ...props }, + ref, + ) { + return ( +
    + {pill} + +
    + + {heading} + + + + {subheading} + +
    + + {children} +
    + ); + }, +); diff --git a/apps/prepare/src/components/marquee/marquee.tsx b/apps/prepare/src/components/marquee/marquee.tsx new file mode 100644 index 00000000..47cef904 --- /dev/null +++ b/apps/prepare/src/components/marquee/marquee.tsx @@ -0,0 +1,51 @@ +import { cn } from '@/lib/utils' + +interface MarqueeProps { + className?: string + reverse?: boolean + pauseOnHover?: boolean + children?: React.ReactNode + vertical?: boolean + repeat?: number + [key: string]: any +} + +export function Marquee({ + className, + reverse, + pauseOnHover = false, + children, + vertical = false, + repeat = 4, + ...props +}: MarqueeProps) { + return ( +
    + {Array(repeat) + .fill(0) + .map((_, i) => ( +
    + {children} +
    + ))} +
    + ) +} diff --git a/apps/prepare/src/components/prodkt-grid/index.tsx b/apps/prepare/src/components/prodkt-grid/index.tsx new file mode 100644 index 00000000..eca46479 --- /dev/null +++ b/apps/prepare/src/components/prodkt-grid/index.tsx @@ -0,0 +1,81 @@ +import Ripple from '@/registry/default/prodkt/effect-ripple' + +export default function ProdktGrid() { + return ( +
    +
    +

    Deploy faster

    +

    + Everything you need to deploy your app +

    +
    +
    +
    + +
    +

    Releases

    +

    Push to deploy

    +

    + Lorem ipsum dolor sit amet, consectetur adipiscing elit. In gravida justo et nulla efficitur, maximus + egestas sem pellentesque. +

    +
    +
    +
    +
    +
    + +
    +

    Integrations

    +

    Connect your favorite tools

    +

    + Curabitur auctor, ex quis auctor venenatis, eros arcu rhoncus massa. +

    +
    +
    +
    +
    +
    + +
    +
    +

    Security

    +

    Advanced access control

    +

    + Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia. +

    +
    +
    +
    +
    +
    + +
    +

    Performance

    +

    Lightning-fast builds

    +

    + Sed congue eros non finibus molestie. Vestibulum euismod augue vel commodo vulputate. Maecenas at + augue sed elit dictum vulputate. +

    +
    +
    +
    +
    +
    +
    + ) +} diff --git a/apps/prepare/src/components/site-header/auth-button.tsx b/apps/prepare/src/components/site-header/auth-button.tsx new file mode 100644 index 00000000..d90d7462 --- /dev/null +++ b/apps/prepare/src/components/site-header/auth-button.tsx @@ -0,0 +1,35 @@ +import { forwardRef } from 'react'; + +import { cn } from '@/lib/utils'; +import { Button } from '@/registry/default/ui/button'; + +export const AuthButton = forwardRef< + HTMLButtonElement, + React.ComponentProps +>(function CtaButtonComponent({ className, children, ...props }, ref) { + return ( + //
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + ); +}); diff --git a/apps/prepare/src/components/site-header/data.tsx b/apps/prepare/src/components/site-header/data.tsx new file mode 100644 index 00000000..1a74ec1e --- /dev/null +++ b/apps/prepare/src/components/site-header/data.tsx @@ -0,0 +1,115 @@ + +import { + HomeIcon, + ProjectsIcon, + ChangelogIcon, + AboutIcon, + CodeblocksIcon, + ContactIcon, + BlogIcon, +} from "@/registry/icons/prodkt-navigation" + +export const components: { title: string; href: string; description: string; icon: React.ReactNode }[] = [ + { + title: "Alert Dialog", + href: "/docs/primitives/alert-dialog", + description: + "A modal dialog that interrupts the user with important content and expects a response.", + icon: ( ), + }, + { + title: "Hover Card", + href: "/docs/primitives/hover-card", + description: + "For sighted users to preview content available behind a link.", + icon: ( ), + }, + { + title: "Progress", + href: "/docs/primitives/progress", + description: + "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.", + icon: ( ), + }, + { + title: "Scroll-area", + href: "/docs/primitives/scroll-area", + description: "Visually or semantically separates content.", + icon: ( ), + }, + { + title: "Tabs", + href: "/docs/primitives/tabs", + description: + "A set of layered sections of content—known as tab panels—that are displayed one at a time.", + icon: ( ), + }, + { + title: "Tooltip", + href: "/docs/primitives/tooltip", + description: + "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.", + icon: ( ), + }, +] + + + +export const actions = [ + { + title: 'Home', + href: '/', + icon: (