-
Notifications
You must be signed in to change notification settings - Fork 85
chore: new landing page #2369
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: new landing page #2369
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,69 @@ | ||||||||||||||||||||||||||||||||||||||||||
"use client"; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
import { useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||
import { Icon, faCheck } from "@rivet-gg/icons"; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
// Command Center section | ||||||||||||||||||||||||||||||||||||||||||
export const CommandCenterSection = () => { | ||||||||||||||||||||||||||||||||||||||||||
const [activeTab, setActiveTab] = useState("monitoring"); | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
const tabs = [ | ||||||||||||||||||||||||||||||||||||||||||
{ id: "monitoring", title: "Monitoring", }, | ||||||||||||||||||||||||||||||||||||||||||
{ id: "logs", title: "Logs", }, | ||||||||||||||||||||||||||||||||||||||||||
{ id: "local-dev", title: "Local Dev", }, | ||||||||||||||||||||||||||||||||||||||||||
{ id: "collaboration", title: "Collaboration", }, | ||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
const features = [ | ||||||||||||||||||||||||||||||||||||||||||
"Live Logs", "Crash Reporting", "Log Retention", "Error Tracing", "Performance Metrics", "Alerts" | ||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||
<div className="mx-auto max-w-7xl px-6 py-28 lg:py-44 lg:px-8 mt-16"> | ||||||||||||||||||||||||||||||||||||||||||
<div className="text-center mb-12"> | ||||||||||||||||||||||||||||||||||||||||||
<h2 className="text-3xl font-bold tracking-tight text-white">The command center your backend is missing</h2> | ||||||||||||||||||||||||||||||||||||||||||
<p className="mt-4 text-lg text-white/70">Complete visibility and control over your serverless infrastructure</p> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
<div className="flex justify-center mb-12"> | ||||||||||||||||||||||||||||||||||||||||||
<div className="inline-flex space-x-1"> | ||||||||||||||||||||||||||||||||||||||||||
{tabs.map((tab) => ( | ||||||||||||||||||||||||||||||||||||||||||
<button | ||||||||||||||||||||||||||||||||||||||||||
key={tab.id} | ||||||||||||||||||||||||||||||||||||||||||
className={`px-6 py-3 rounded-md text-base font-medium transition-all duration-200 border ${ | ||||||||||||||||||||||||||||||||||||||||||
activeTab === tab.id | ||||||||||||||||||||||||||||||||||||||||||
? "bg-zinc-900 text-white border-zinc-700" | ||||||||||||||||||||||||||||||||||||||||||
: "text-white/60 hover:text-white hover:bg-black/10 border-transparent" | ||||||||||||||||||||||||||||||||||||||||||
}`} | ||||||||||||||||||||||||||||||||||||||||||
onClick={() => setActiveTab(tab.id)} | ||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||
{tab.title} | ||||||||||||||||||||||||||||||||||||||||||
</button> | ||||||||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
<div className="flex justify-center mb-12"> | ||||||||||||||||||||||||||||||||||||||||||
<div className="flex space-x-12"> | ||||||||||||||||||||||||||||||||||||||||||
{features.map((feature, index) => ( | ||||||||||||||||||||||||||||||||||||||||||
<div key={index} className="flex items-center"> | ||||||||||||||||||||||||||||||||||||||||||
<div className="text-white/40 mr-2"> | ||||||||||||||||||||||||||||||||||||||||||
<Icon icon={faCheck} className="text-sm" /> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
<span className="text-sm text-white/80">{feature}</span> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+47
to
+56
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: features list lacks mobile responsiveness - will overflow on small screens
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
<div className="flex justify-center"> | ||||||||||||||||||||||||||||||||||||||||||
<div className="w-full max-w-4xl h-[480px] bg-zinc-900 border border-white/5 rounded-xl overflow-hidden"> | ||||||||||||||||||||||||||||||||||||||||||
{/* Placeholder for hub screenshot */} | ||||||||||||||||||||||||||||||||||||||||||
<div className="w-full h-full flex items-center justify-center text-white/40"> | ||||||||||||||||||||||||||||||||||||||||||
Hub Screenshot Placeholder | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,114 @@ | ||||||||||||||||||||||||||||||
"use client"; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
import Link from "next/link"; | ||||||||||||||||||||||||||||||
import { Icon, faDiscord, faGithub, faTwitter, faBluesky } from "@rivet-gg/icons"; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Community section | ||||||||||||||||||||||||||||||
export const CommunitySection = () => { | ||||||||||||||||||||||||||||||
const platforms = [ | ||||||||||||||||||||||||||||||
{ name: "Discord", icon: faDiscord, href: "https://discord.gg/rivet" }, | ||||||||||||||||||||||||||||||
{ name: "Discussions", icon: faGithub, href: "https://github.com/rivet-gg/discussions" }, | ||||||||||||||||||||||||||||||
{ name: "X", icon: faTwitter, href: "https://x.com/rivet_gg" }, | ||||||||||||||||||||||||||||||
{ name: "Bluesky", icon: faBluesky, href: "https://bsky.app/profile/rivet.gg" } | ||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
// Tweets for each column | ||||||||||||||||||||||||||||||
const columnTweets = [ | ||||||||||||||||||||||||||||||
// Column 1 | ||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Jane Doe", | ||||||||||||||||||||||||||||||
handle: "@janedoe", | ||||||||||||||||||||||||||||||
content: "Just deployed my first stateful job with @rivet_gg and I'm blown away by how simple it was. The documentation is excellent!" | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Mike Williams", | ||||||||||||||||||||||||||||||
handle: "@mikew", | ||||||||||||||||||||||||||||||
content: "As someone new to serverless, Rivet made the learning curve much smoother. Their tutorials are super straightforward." | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Sara Chen", | ||||||||||||||||||||||||||||||
handle: "@sarac", | ||||||||||||||||||||||||||||||
content: "Been using @rivet_gg for our AI agents and the performance is incredible. Self-hosting was a breeze too!" | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||
// Column 2 | ||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "John Smith", | ||||||||||||||||||||||||||||||
handle: "@johnsmith", | ||||||||||||||||||||||||||||||
content: "Rivet has completely changed how we handle our functions. Our team's productivity has doubled since we made the switch." | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Emma Rodriguez", | ||||||||||||||||||||||||||||||
handle: "@emmar", | ||||||||||||||||||||||||||||||
content: "The desktop sandbox feature in @rivet_gg is a game changer for our GUI-based applications. Nothing else comes close." | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "David Kim", | ||||||||||||||||||||||||||||||
handle: "@davidk", | ||||||||||||||||||||||||||||||
content: "Our entire backend is running on Rivet now. The monitoring tools make my job 10x easier as a DevOps engineer." | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||||
// Column 3 | ||||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Alex Johnson", | ||||||||||||||||||||||||||||||
handle: "@alexj", | ||||||||||||||||||||||||||||||
content: "I've tried all the serverless platforms out there, and @rivet_gg is hands down the best one for my needs. The open-source aspect sealed the deal for me." | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Taylor Morgan", | ||||||||||||||||||||||||||||||
handle: "@taylorm", | ||||||||||||||||||||||||||||||
content: "Moving from AWS to self-hosted @rivet_gg cut our costs by 70% while improving performance. Best decision we made this year." | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
user: "Jordan Lee", | ||||||||||||||||||||||||||||||
handle: "@jordanl", | ||||||||||||||||||||||||||||||
content: "The Rivet community is amazing! Got help with my implementation within minutes of posting a question." | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
] | ||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||
<div className="mx-auto max-w-7xl px-6 py-28 lg:py-44 lg:px-8 mt-16"> | ||||||||||||||||||||||||||||||
<div className="text-center mb-10"> | ||||||||||||||||||||||||||||||
<h2 className="text-3xl font-bold tracking-tight text-white">Join the community</h2> | ||||||||||||||||||||||||||||||
<p className="mt-4 text-lg text-white/70">Connect with thousands of developers building with Rivet</p> | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
<div className="flex justify-center space-x-3 mb-16"> | ||||||||||||||||||||||||||||||
{platforms.map((platform, index) => ( | ||||||||||||||||||||||||||||||
<Link key={index} href={platform.href} className="group"> | ||||||||||||||||||||||||||||||
<div className="flex items-center justify-center h-10 px-5 rounded-md border border-zinc-700 bg-zinc-900 group-hover:bg-zinc-800 group-hover:border-zinc-600 transition-all"> | ||||||||||||||||||||||||||||||
<Icon icon={platform.icon} className="text-white/60 group-hover:text-white/90 mr-2 transition-colors" /> | ||||||||||||||||||||||||||||||
<span className="text-sm text-white/60 group-hover:text-white/90 transition-colors">{platform.name}</span> | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
</Link> | ||||||||||||||||||||||||||||||
Comment on lines
+81
to
+87
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Missing rel="noopener noreferrer" for external links and target="_blank" attributes for better security and UX
Suggested change
|
||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8"> | ||||||||||||||||||||||||||||||
{columnTweets.map((column, columnIndex) => ( | ||||||||||||||||||||||||||||||
<div key={columnIndex} className="flex flex-col space-y-6"> | ||||||||||||||||||||||||||||||
{column.map((tweet, tweetIndex) => ( | ||||||||||||||||||||||||||||||
<div | ||||||||||||||||||||||||||||||
key={`${columnIndex}-${tweetIndex}`} | ||||||||||||||||||||||||||||||
className="rounded-xl p-6 bg-black/20 border border-white/5 flex flex-col hover:bg-black/30 hover:border-white/10 transition-all" | ||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||
<div className="flex items-center mb-4"> | ||||||||||||||||||||||||||||||
<div className="w-10 h-10 rounded-full bg-zinc-700 mr-3"></div> | ||||||||||||||||||||||||||||||
<div> | ||||||||||||||||||||||||||||||
<div className="text-white font-medium">{tweet.user}</div> | ||||||||||||||||||||||||||||||
<div className="text-white/50 text-sm">{tweet.handle}</div> | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
<p className="text-white/80">{tweet.content}</p> | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Tweet content should have a role="article" for better screen reader support |
||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
))} | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,33 @@ | ||||||||||||||||
"use client"; | ||||||||||||||||
|
||||||||||||||||
import { Icon, faCopy, faCheck } from "@rivet-gg/icons"; | ||||||||||||||||
import { useState } from "react"; | ||||||||||||||||
|
||||||||||||||||
// Copy command component with clipboard functionality | ||||||||||||||||
export const CopyCommand = ({ command }: { command: string }) => { | ||||||||||||||||
const [copied, setCopied] = useState(false); | ||||||||||||||||
|
||||||||||||||||
const handleCopy = () => { | ||||||||||||||||
// Copy the command without the $ symbol | ||||||||||||||||
navigator.clipboard.writeText(command); | ||||||||||||||||
setCopied(true); | ||||||||||||||||
setTimeout(() => setCopied(false), 1000); | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Consider using useEffect cleanup to clear timeout on unmount to prevent memory leaks. |
||||||||||||||||
}; | ||||||||||||||||
|
||||||||||||||||
return ( | ||||||||||||||||
<div | ||||||||||||||||
onClick={handleCopy} | ||||||||||||||||
className="inline-flex items-center bg-black/40 rounded-md border border-white/10 px-4 py-2.5 font-mono text-sm group relative cursor-pointer active:scale-[0.98] active:bg-black/60 transition-all" | ||||||||||||||||
Comment on lines
+18
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Use button element instead of div for better accessibility. Add role="button" and keyboard handlers (onKeyDown) to support keyboard interaction.
Suggested change
|
||||||||||||||||
> | ||||||||||||||||
<span className="text-gray-500 mr-2 font-mono">$</span> | ||||||||||||||||
<span className="text-white/90 font-mono">{command}</span> | ||||||||||||||||
<div | ||||||||||||||||
className="ml-3 text-gray-400 group-hover:text-[#FF5C00] transition-colors" | ||||||||||||||||
aria-label={copied ? "Copied!" : "Copy to clipboard"} | ||||||||||||||||
> | ||||||||||||||||
<Icon icon={copied ? faCheck : faCopy} className={`${copied ? "text-[#FF5C00]" : ""} transition-all`} /> | ||||||||||||||||
</div> | ||||||||||||||||
<div className="absolute inset-0 bg-white/5 opacity-0 group-hover:opacity-100 group-active:opacity-0 transition-opacity rounded-md pointer-events-none"></div> | ||||||||||||||||
</div> | ||||||||||||||||
); | ||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
"use client"; | ||
|
||
import Link from "next/link"; | ||
import { Button } from "@rivet-gg/components"; | ||
import { Icon, faArrowRight } from "@rivet-gg/icons"; | ||
|
||
// CTA section | ||
export const CtaSection = () => { | ||
return ( | ||
<div className="mx-auto max-w-7xl px-6 py-36 lg:py-52 lg:px-8 border-t border-white/5 mt-24"> | ||
<div className="text-center"> | ||
<h2 className="text-4xl font-bold tracking-tight text-white">Get building today</h2> | ||
<p className="mt-6 text-xl text-white/70 max-w-2xl mx-auto"> | ||
Start for free, no credit card required. Deploy your first serverless project in minutes. | ||
</p> | ||
|
||
<div className="mt-12 flex items-center justify-center gap-x-6"> | ||
<Button | ||
size="lg" | ||
asChild | ||
className="px-4 pr-6 py-3 text-base bg-gradient-to-b from-[#FF5C00] to-[#FF5C00]/90 border border-[#FF5C00]/30 hover:border-[#FF5C00]/60 transition-all duration-200 group" | ||
> | ||
<Link href="#deploy" className="flex items-center justify-center relative"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: href='#deploy' points to a non-existent anchor. Should likely point to an actual deployment page route |
||
<span>Deploy in 1 Minute</span> | ||
<Icon icon={faArrowRight} className="absolute right-2 text-sm opacity-0 group-hover:opacity-100 group-hover:translate-x-1 transition-all duration-200" /> | ||
</Link> | ||
</Button> | ||
<Button | ||
variant="outline" | ||
size="lg" | ||
asChild | ||
className="px-4 pr-6 py-3 text-base border-white/10 hover:border-white/30 transition-all duration-200 group" | ||
> | ||
<Link href="#demo" className="flex items-center justify-center relative"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: href='#demo' points to a non-existent anchor. Should likely point to an actual demo booking page route |
||
<span>Book Demo</span> | ||
<Icon icon={faArrowRight} className="absolute right-2 text-sm opacity-0 group-hover:opacity-100 group-hover:translate-x-1 transition-all duration-200" /> | ||
</Link> | ||
</Button> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,93 @@ | ||||||
"use client"; | ||||||
|
||||||
import Link from "next/link"; | ||||||
import { Icon, faCode, faLayerGroup, faTerminal, faDesktop, faListCheck, faArrowsToCircle, faArrowRight, faDatabase } from "@rivet-gg/icons"; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: faListCheck is imported but never used in the component
Suggested change
|
||||||
|
||||||
// Tutorials section | ||||||
export const TutorialsSection = () => { | ||||||
const tutorials = [ | ||||||
{ | ||||||
title: "Deploy your first function", | ||||||
description: "Get started with serverless functions in minutes", | ||||||
icons: [faCode], | ||||||
href: "/docs/tutorials/first-function", | ||||||
useCases: ["APIs", "Webhooks", "Edge computing"] | ||||||
}, | ||||||
{ | ||||||
title: "Create a stateful actor", | ||||||
description: "Build services that maintain state between requests", | ||||||
icons: [faLayerGroup], | ||||||
href: "/docs/tutorials/stateful-actor", | ||||||
useCases: ["AI agents", "Stateful workers", "Long-running processes"] | ||||||
}, | ||||||
{ | ||||||
title: "Build a workflow", | ||||||
description: "Orchestrate complex multi-step processes", | ||||||
icons: [faArrowsToCircle], | ||||||
href: "/docs/tutorials/workflows", | ||||||
useCases: ["Multi-agent systems", "Business logic", "ETL pipelines"] | ||||||
}, | ||||||
{ | ||||||
title: "Run AI generated code in a sandbox", | ||||||
description: "Execute untrusted code safely with isolation", | ||||||
icons: [faTerminal], | ||||||
href: "/docs/tutorials/ai-sandbox", | ||||||
useCases: ["LLM code execution", "User code execution", "AI agents"] | ||||||
}, | ||||||
{ | ||||||
title: "Access desktop sandbox", | ||||||
description: "Run GUI applications in an isolated environment", | ||||||
icons: [faDesktop], | ||||||
href: "/docs/tutorials/desktop-sandbox", | ||||||
useCases: ["Remote desktops", "Browser automation", "Visual apps"] | ||||||
}, | ||||||
{ | ||||||
title: "Store agent memory", | ||||||
description: "Persist and retrieve AI agent context and knowledge", | ||||||
icons: [faDatabase], | ||||||
href: "/docs/tutorials/agent-memory", | ||||||
useCases: ["RAG", "Vector embeddings", "AI agent state"] | ||||||
} | ||||||
]; | ||||||
|
||||||
return ( | ||||||
<div className="mx-auto max-w-7xl px-6 py-28 lg:py-44 lg:px-8 mt-16"> | ||||||
<div className="text-center mb-12"> | ||||||
<h2 className="text-3xl font-bold tracking-tight text-white">Start building in seconds</h2> | ||||||
<p className="mt-4 text-lg text-white/70">Follow our step-by-step tutorials to deploy your first project quickly</p> | ||||||
</div> | ||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> | ||||||
{tutorials.map((tutorial, index) => ( | ||||||
<Link key={index} href={tutorial.href} className="group"> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: using array index as key could cause issues with React reconciliation if tutorials are reordered - consider using a unique id |
||||||
<div className="rounded-xl h-[280px] bg-[#121212] group-hover:bg-zinc-800/90 border border-white/5 group-hover:border-white/20 shadow-sm transition-all duration-200 flex flex-col overflow-hidden"> | ||||||
{/* Top section with icons */} | ||||||
<div className="bg-black/40 p-4 flex items-center justify-center h-[120px] w-full"> | ||||||
<div className="flex space-x-4"> | ||||||
{tutorial.icons.map((icon, iconIndex) => ( | ||||||
<div key={iconIndex} className="flex items-center justify-center w-14 h-14"> | ||||||
<Icon | ||||||
icon={icon} | ||||||
className="text-4xl text-white/50 group-hover:text-[#FF5C00] transition-colors duration-200" | ||||||
/> | ||||||
</div> | ||||||
))} | ||||||
</div> | ||||||
</div> | ||||||
|
||||||
{/* Bottom section with content */} | ||||||
<div className="p-5 flex flex-col flex-1"> | ||||||
<h3 className="text-xl font-semibold text-white mb-2">{tutorial.title}</h3> | ||||||
<p className="text-white/60 text-sm">{tutorial.description}</p> | ||||||
|
||||||
<div className="flex items-center mt-auto pt-3 text-[#FF5C00] opacity-0 group-hover:opacity-100 transition-opacity"> | ||||||
<span className="text-sm font-medium">View tutorial</span> | ||||||
<Icon icon={faArrowRight} className="ml-2 text-xs group-hover:translate-x-0.5 transition-all" /> | ||||||
</div> | ||||||
</div> | ||||||
</div> | ||||||
</Link> | ||||||
))} | ||||||
</div> | ||||||
</div> | ||||||
); | ||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { FancyHeader } from "@/components/v2/FancyHeader"; | ||
|
||
export default function Layout({ children }: { children: React.ReactNode }) { | ||
return ( | ||
<> | ||
<FancyHeader /> | ||
{children} | ||
</> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: activeTab state is set but no content changes based on tab selection