mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add copy button to terminal, expand Why Choose, add pricing section, reorder nav
This commit is contained in:
@@ -5,6 +5,7 @@ import { Hero } from "@/components/hero";
|
||||
import { HowItWorks } from "@/components/how-it-works";
|
||||
import { Navbar } from "@/components/navbar";
|
||||
import { OpenSource } from "@/components/open-source";
|
||||
import { Pricing } from "@/components/pricing";
|
||||
import { WhyChoose } from "@/components/why-choose";
|
||||
|
||||
export default function Home() {
|
||||
@@ -17,6 +18,7 @@ export default function Home() {
|
||||
<WhyChoose />
|
||||
<BentoGrid />
|
||||
<Enterprise />
|
||||
<Pricing />
|
||||
<OpenSource />
|
||||
</main>
|
||||
<Footer />
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
"use client";
|
||||
|
||||
import { Check, Copy } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { FadeIn } from "./fade-in";
|
||||
|
||||
const command = "docker run -d -p 1349:1349 ghcr.io/ashim-hq/ashim";
|
||||
|
||||
export function HowItWorks() {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
function copyCommand() {
|
||||
navigator.clipboard.writeText(command);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
}
|
||||
|
||||
return (
|
||||
<section id="how-it-works" className="bg-background-alt px-6 py-20 md:py-28">
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
@@ -13,17 +28,25 @@ export function HowItWorks() {
|
||||
|
||||
<FadeIn delay={0.1}>
|
||||
<div className="mt-8 overflow-hidden rounded-xl border border-border bg-[#1e1e1e] shadow-lg">
|
||||
<div className="flex items-center gap-2 border-b border-white/10 px-4 py-2.5">
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#ff5f57]" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#febc2e]" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#28c840]" />
|
||||
<div className="flex items-center justify-between border-b border-white/10 px-4 py-2.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#ff5f57]" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#febc2e]" />
|
||||
<div className="h-2.5 w-2.5 rounded-full bg-[#28c840]" />
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={copyCommand}
|
||||
className="text-white/40 transition-colors hover:text-white/80"
|
||||
aria-label="Copy command"
|
||||
>
|
||||
{copied ? <Check size={14} /> : <Copy size={14} />}
|
||||
</button>
|
||||
</div>
|
||||
<div className="px-5 py-4 text-left font-mono text-sm">
|
||||
<div className="overflow-x-auto whitespace-nowrap px-5 py-4 text-left font-mono text-sm">
|
||||
<p className="text-white">
|
||||
<span className="text-green-400">$</span>{" "}
|
||||
<span className="select-all">
|
||||
docker run -d -p 1349:1349 -v snapotter-data:/data ghcr.io/ashim-hq/ashim:latest
|
||||
</span>
|
||||
<span className="select-all">{command}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,9 @@ import { Github, Menu, Star, X } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
const links = [
|
||||
{ label: "Features", href: "#features" },
|
||||
{ label: "Download", href: "#how-it-works" },
|
||||
{ label: "Pricing", href: "#enterprise" },
|
||||
{ label: "Features", href: "#features" },
|
||||
{ label: "Pricing", href: "#pricing" },
|
||||
{ label: "Docs", href: "https://docs.snapotter.com" },
|
||||
{ label: "Contact", href: "/contact" },
|
||||
];
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Check } from "lucide-react";
|
||||
|
||||
import { FadeIn } from "./fade-in";
|
||||
|
||||
const plans = [
|
||||
{
|
||||
name: "Free",
|
||||
price: "Free",
|
||||
subtitle: "For everyone",
|
||||
features: [
|
||||
"All 40+ tools included",
|
||||
"Unlimited usage",
|
||||
"Self-host anywhere",
|
||||
"Community support",
|
||||
"Open source (AGPL-3.0)",
|
||||
],
|
||||
cta: "Get Started",
|
||||
href: "#how-it-works",
|
||||
highlighted: false,
|
||||
},
|
||||
{
|
||||
name: "Enterprise",
|
||||
price: "Custom",
|
||||
subtitle: "For organizations",
|
||||
features: [
|
||||
"Everything in Free",
|
||||
"Commercial license (no AGPL)",
|
||||
"Priority support",
|
||||
"Deployment assistance",
|
||||
"Custom integrations",
|
||||
],
|
||||
cta: "Contact Us",
|
||||
href: "/contact",
|
||||
highlighted: true,
|
||||
},
|
||||
];
|
||||
|
||||
export function Pricing() {
|
||||
return (
|
||||
<section id="pricing" className="bg-background-alt px-6 py-24 md:py-36">
|
||||
<div className="mx-auto max-w-4xl">
|
||||
<FadeIn>
|
||||
<h2 className="text-center text-3xl font-bold tracking-tight md:text-4xl">
|
||||
Simple pricing
|
||||
</h2>
|
||||
<p className="mx-auto mt-4 max-w-xl text-center text-lg text-muted">
|
||||
Free for everyone. Enterprise support when you need it.
|
||||
</p>
|
||||
</FadeIn>
|
||||
|
||||
<div className="mt-16 grid gap-6 md:grid-cols-2">
|
||||
{plans.map((plan, i) => (
|
||||
<FadeIn key={plan.name} delay={i * 0.1}>
|
||||
<div className="flex h-full flex-col rounded-2xl border border-border bg-background p-8">
|
||||
<p className="text-sm font-medium text-muted">{plan.subtitle}</p>
|
||||
<p className="mt-2 text-3xl font-bold">{plan.price}</p>
|
||||
|
||||
<ul className="mt-8 flex-1 space-y-3">
|
||||
{plan.features.map((feature) => (
|
||||
<li key={feature} className="flex items-center gap-2 text-sm">
|
||||
<Check size={16} className="shrink-0 text-accent" />
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<a
|
||||
href={plan.href}
|
||||
className={`mt-8 block rounded-lg px-4 py-2.5 text-center text-sm font-medium transition-colors ${
|
||||
plan.highlighted
|
||||
? "bg-accent text-accent-foreground hover:bg-accent-hover"
|
||||
: "border border-border hover:bg-background-alt"
|
||||
}`}
|
||||
>
|
||||
{plan.cta}
|
||||
</a>
|
||||
</div>
|
||||
</FadeIn>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,15 @@
|
||||
import { BadgeCheck, CircleDollarSign, Layers, ShieldCheck, UserRoundX, Zap } from "lucide-react";
|
||||
import {
|
||||
BadgeCheck,
|
||||
CircleDollarSign,
|
||||
Code,
|
||||
Layers,
|
||||
Plug,
|
||||
ShieldCheck,
|
||||
UserRoundX,
|
||||
Workflow,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
|
||||
import { FadeIn } from "./fade-in";
|
||||
|
||||
const benefits = [
|
||||
@@ -32,6 +43,21 @@ const benefits = [
|
||||
description: "Powered by Sharp. Process images instantly.",
|
||||
icon: Zap,
|
||||
},
|
||||
{
|
||||
title: "Open Source",
|
||||
description: "AGPL-3.0 licensed. Inspect every line of code.",
|
||||
icon: Code,
|
||||
},
|
||||
{
|
||||
title: "REST API",
|
||||
description: "Every tool accessible via HTTP. Full OpenAPI docs.",
|
||||
icon: Plug,
|
||||
},
|
||||
{
|
||||
title: "Pipeline Automation",
|
||||
description: "Chain tools together. Automate your workflows.",
|
||||
icon: Workflow,
|
||||
},
|
||||
];
|
||||
|
||||
export function WhyChoose() {
|
||||
|
||||
Reference in New Issue
Block a user