Skip to content

Commit

Permalink
feat(www): New landing page
Browse files Browse the repository at this point in the history
  • Loading branch information
alifarooq9 committed Apr 7, 2024
1 parent 786a399 commit 14b5702
Show file tree
Hide file tree
Showing 15 changed files with 664 additions and 22 deletions.
9 changes: 8 additions & 1 deletion apps/www/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ await import("./src/env.js");

/** @type {import("next").NextConfig} */
const config = {
transpilePackages: ["@rapidlaunch/ui"],
images: {
remotePatterns: [
{
protocol: "https",
hostname: "utfs.io",
},
],
},
};

export default config;
4 changes: 4 additions & 0 deletions apps/www/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
"dependencies": {
"@hookform/resolvers": "^3.3.4",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@t3-oss/env-nextjs": "^0.9.2",
"@tanstack/react-query": "^5.24.1",
"@vercel/analytics": "^1.2.2",
Expand All @@ -28,6 +31,7 @@
"react-dom": "18.2.0",
"react-hook-form": "^7.50.1",
"react-wrap-balancer": "^1.1.0",
"sharp": "^0.33.3",
"sonner": "^1.4.2",
"tailwind-merge": "^2.2.1",
"tailwindcss-animate": "^1.0.7",
Expand Down
4 changes: 2 additions & 2 deletions apps/www/prettier.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
const config = {
plugins: ["prettier-plugin-tailwindcss"],
tabWidth: 4,
plugins: ["prettier-plugin-tailwindcss"],
tabWidth: 4,
};

export default config;
68 changes: 68 additions & 0 deletions apps/www/src/app/(app)/_components/highlight-tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { cn } from "@/lib/utils";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import type { TabsProps } from "@radix-ui/react-tabs";
import { SaasStarterkitHighlight } from "@/app/(app)/_components/saas-startkit-highlight";

const highlights = [
{
id: "saas-starterkit",
title: "SaaS Starterkit",
description:
"Auth, Dashboard, Landing Pages, billing and more — everything you need to launch your MVP faster.",
badge: "Almost Ready",
},
{
id: "blocks",
title: "Blocks",
description:
"Auth forms, modals, hero sections, pricing tables, and more — all customizable and open source.",
disabled: true,
badge: "Coming Soon",
},
{
id: "guides",
title: "Guides",
description:
"Authenticating users, setting up billing, and more — all the guides you need to launch your app.",
disabled: true,
badge: "Coming Soon",
},
];

type HighlightNavProps = TabsProps;

export function HighlightTabs({ className, ...props }: HighlightNavProps) {
return (
<Tabs
className={cn("space-y-10", className)}
defaultValue={highlights[0]?.id}
{...props}
>
<TabsList className="grid h-auto grid-cols-3 items-start bg-transparent p-0">
{highlights.map((highlight) => (
<TabsTrigger
value={highlight.id}
key={highlight.id}
disabled={highlight.disabled}
className="group flex flex-col items-start justify-start gap-2 whitespace-normal rounded-none border-t py-6 text-start data-[state=active]:border-primary data-[state=active]:shadow-none"
>
<div className="flex items-center gap-2">
<h2 className="font-medium">{highlight.title}</h2>
{highlight?.badge && (
<span className="rounded-sm bg-secondary px-2 py-0.5 text-xs font-medium text-primary">
{highlight.badge}
</span>
)}
</div>
<p className="font-normal text-muted-foreground transition-all">
{highlight.description}
</p>
</TabsTrigger>
))}
</TabsList>
<TabsContent value="saas-starterkit">
<SaasStarterkitHighlight />
</TabsContent>
</Tabs>
);
}
112 changes: 112 additions & 0 deletions apps/www/src/app/(app)/_components/saas-startkit-highlight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { badgeVariants } from "@/components/ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { siteUrls } from "@/config/urls";
import Image from "next/image";
import Link from "next/link";
import { ArrowRightIcon } from "lucide-react";
import { buttonVariants } from "@/components/ui/button";

const saasStarterkitHighlights = [
{
id: "user-dashboard",
title: "User Dashboard",
imageLight:
"https://utfs.io/f/43bbc3c8-cf3c-4fae-a0eb-9183f1779489-294m81.png",
imageDark:
"https://utfs.io/f/fddea366-51c6-45f4-bd54-84d273ad9fb9-1ly324.png",
},
{
id: "auth",
title: "Authentication",
imageLight:
"https://utfs.io/f/805616c1-22b8-4508-9890-9ba9e2867a41-p24dnn.png",
imageDark:
"https://utfs.io/f/9074c0de-d9ea-4c0b-9d49-55dca1253a3f-6ig3yq.png",
},
{
id: "user-settings",
title: "User Settings",
imageLight:
"https://utfs.io/f/da560e34-84ca-4283-8060-65d727def753-eqmy3s.png",
imageDark:
"https://utfs.io/f/e365451e-1a36-43a7-8d1c-7315e5aae430-63u1th.png",
},
{
id: "Users-management",
title: "Users Management",
imageLight:
"https://utfs.io/f/72a2c035-69e0-46ca-84a8-446e4dabf77c-3koi6e.png",
imageDark:
"https://utfs.io/f/89099112-4273-4375-9e44-1b3394600e21-c6ikq1.png",
},
];

export function SaasStarterkitHighlight() {
return (
<div className="space-y-4">
<div>
<p className="text-sm">
For more information, Visit the{" "}
<Link
href={siteUrls.saasStarterkit}
className={badgeVariants({
variant: "secondary",
className: "ml-1 gap-0.5",
})}
>
SaaS Starterkit
<ArrowRightIcon className="h-3 w-3" />
</Link>
</p>
</div>
<Tabs defaultValue="user-dashboard">
<TabsList className="gap-2 bg-transparent p-0">
{saasStarterkitHighlights.map((tab) => (
<TabsTrigger
key={tab.id}
value={tab.id}
className="data-[state=active]:bg-secondary"
>
{tab.title}
</TabsTrigger>
))}

<Link
href={siteUrls.saasStarterkit}
className={buttonVariants({
variant: "ghost",
size: "sm",
className: "gap-1",
})}
>
<span>View all</span>
<ArrowRightIcon className="h-4 w-4" />
</Link>
</TabsList>
{saasStarterkitHighlights.map((tab) => (
<TabsContent
className="relative aspect-video rounded-md bg-muted"
key={tab.id}
value={tab.id}
>
<Image
src={tab.imageLight}
alt={tab.title}
fill
className="block rounded-md border border-border dark:hidden"
priority
/>

<Image
src={tab.imageDark}
alt={tab.title}
fill
className="hidden rounded-md border border-border dark:block"
priority
/>
</TabsContent>
))}
</Tabs>
</div>
);
}
2 changes: 1 addition & 1 deletion apps/www/src/app/(app)/_components/side-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Icons } from "@/components/icons";

export function SiteHeader() {
return (
<header className="sticky top-0 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-14 max-w-screen-2xl items-center justify-between">
<div className="flex items-center gap-5">
<Link href={siteUrls.home} className="left-4 z-10">
Expand Down
66 changes: 52 additions & 14 deletions apps/www/src/app/(app)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,68 @@
import { Badge } from "@/components/ui/badge";
import Balance from "react-wrap-balancer";
import { EarlyAccessForm } from "@/components/early-access-form";
import { ExternalLinkIcon } from "lucide-react";
import Link from "next/link";
import { siteUrls } from "@/config/urls";
import { buttonVariants } from "@/components/ui/button";
import { Icons } from "@/components/icons";
import { HighlightTabs } from "@/app/(app)/_components/highlight-tabs";
import { getRepoStars } from "@/server/actions/github";

export default async function HomePage() {
const repoStars = await getRepoStars();

export default function HomePage() {
return (
<main className="container flex flex-col items-center justify-center gap-4 py-20">
<Badge variant="secondary" className="gap-2">
<span>🎉</span>{" "}
<p>Open Source SaaS Starterkits and components</p>
</Badge>
<div className="container flex flex-col items-center justify-center gap-4 py-20">
<Link
href={siteUrls.twitter}
className="flex items-center space-x-2 rounded-md bg-secondary px-3 py-2 text-sm hover:bg-secondary/80"
>
<span>🎉</span>
<span className="font-medium">
RapidLaunch is in development. Follow our progress on 𝕏
(formally Twitter)
</span>
<ExternalLinkIcon className="h-4 w-4" />
</Link>
<Balance
as="h1"
className="text-center text-3xl font-semibold sm:text-4xl md:text-6xl"
className="text-center font-heading text-3xl font-bold sm:text-4xl sm:leading-tight md:text-5xl md:leading-tight"
>
Launch 🚀 in days with beautiful SaaS starterkits and components
Rapidly launch your MVP with Beautiful Starterkits, Blocks, and
more.
</Balance>
<Balance
as="p"
className="text-center text-muted-foreground sm:text-xl"
>
Elevate your development game with Rapidlaunch! Launch your apps
faster with our SaaS starterkits, components, building blocks.
Customizable. Open Source
faster with our SaaS starterkits, components, building guides,
and more. Customizable. Open Source.
</Balance>
<div className="flex items-center gap-4">
<Link
href={siteUrls.docs}
className={buttonVariants({
className: "flex items-center gap-2",
})}
>
Get Early Access
</Link>
<Link
href={siteUrls.github}
className={buttonVariants({
className: "flex items-center",
variant: "outline",
})}
>
<Icons.gitHub className="mr-2 h-4 w-4" />
Github -
<span className="ml-1 flex items-center font-normal text-muted-foreground">
{repoStars}
</span>
</Link>
</div>

<EarlyAccessForm />
</main>
<HighlightTabs className="mt-36" />
</div>
);
}
6 changes: 4 additions & 2 deletions apps/www/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import "@/styles/globals.css";
import type { Metadata } from "next";
import { siteConfig } from "@/config/site";
import { Analytics } from "@vercel/analytics/react";
import { fontSans } from "@/lib/fonts";
import { fontSans, fontHeading } from "@/lib/fonts";

const TITLE =
"Rapidlaunch | Open Source Nextjs SaaS Starterkits and Components";
Expand Down Expand Up @@ -49,7 +49,9 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body className={`${fontSans.className}`}>
<body
className={`${fontSans.variable} ${fontHeading.variable} font-sans`}
>
<Providers>
{children}
<Toaster position="top-center" />
Expand Down
48 changes: 48 additions & 0 deletions apps/www/src/components/ui/scroll-area.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use client"

import * as React from "react"
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"

import { cn } from "@/lib/utils"

const ScrollArea = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
>(({ className, children, ...props }, ref) => (
<ScrollAreaPrimitive.Root
ref={ref}
className={cn("relative overflow-hidden", className)}
{...props}
>
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
{children}
</ScrollAreaPrimitive.Viewport>
<ScrollBar />
<ScrollAreaPrimitive.Corner />
</ScrollAreaPrimitive.Root>
))
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName

const ScrollBar = React.forwardRef<
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
>(({ className, orientation = "vertical", ...props }, ref) => (
<ScrollAreaPrimitive.ScrollAreaScrollbar
ref={ref}
orientation={orientation}
className={cn(
"flex touch-none select-none transition-colors",
orientation === "vertical" &&
"h-full w-2.5 border-l border-l-transparent p-[1px]",
orientation === "horizontal" &&
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
className
)}
{...props}
>
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
</ScrollAreaPrimitive.ScrollAreaScrollbar>
))
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName

export { ScrollArea, ScrollBar }
Loading

0 comments on commit 14b5702

Please sign in to comment.