refactor: eslint and prettier conflict will be resolved and formatted

This commit is contained in:
Enes Köksal
2026-04-23 17:05:43 +03:00
parent 385b61f29b
commit 3cfea40fbd
219 changed files with 16638 additions and 13663 deletions
+314 -87
View File
@@ -26,10 +26,9 @@ import {
CheckCircle,
Upload,
Share2,
Check
Check,
} from 'lucide-react';
interface LandingPageProps {
isLoggedIn: boolean;
}
@@ -55,7 +54,8 @@ const coreWorkflowFeatures = [
},
{
title: 'Approval Workflow',
description: 'Assign specific team members or clients to review and sign off on a cut. Get an exact \"Approved\" status.',
description:
'Assign specific team members or clients to review and sign off on a cut. Get an exact \"Approved\" status.',
icon: CheckCircle,
},
];
@@ -73,7 +73,8 @@ const workflowAcceleratorFeatures = [
},
{
title: 'Real-time Webhooks',
description: 'Get instant Telegram alerts the second a comment is dropped. More integrations coming soon.',
description:
'Get instant Telegram alerts the second a comment is dropped. More integrations coming soon.',
icon: BellRing,
},
{
@@ -121,7 +122,9 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
const updateNavbar = () => {
const hasScrolled = window.scrollY > 20;
gsap.to(nav, {
backgroundColor: hasScrolled ? 'color-mix(in oklab, var(--background) 85%, transparent)' : 'transparent',
backgroundColor: hasScrolled
? 'color-mix(in oklab, var(--background) 85%, transparent)'
: 'transparent',
backdropFilter: hasScrolled ? 'blur(16px)' : 'blur(0px)',
borderBottomColor: hasScrolled ? 'var(--border)' : 'transparent',
duration: 0.3,
@@ -141,27 +144,50 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
}, []);
return (
<div ref={rootRef} className="min-h-screen overflow-x-hidden bg-background text-foreground font-sans selection:bg-primary/20">
<div
ref={rootRef}
className="min-h-screen overflow-x-hidden bg-background text-foreground font-sans selection:bg-primary/20"
>
{/* Header */}
<header ref={navbarRef} className="fixed inset-x-0 top-0 z-50 border-b border-transparent bg-transparent transition-colors duration-300">
<header
ref={navbarRef}
className="fixed inset-x-0 top-0 z-50 border-b border-transparent bg-transparent transition-colors duration-300"
>
<div className="mx-auto flex h-14 w-full max-w-[1200px] items-center justify-between px-4 sm:h-16 sm:px-6 lg:px-10">
<Link href="/" className="group relative isolate inline-flex items-center gap-2 overflow-hidden border border-border bg-background px-3 py-2">
<Link
href="/"
className="group relative isolate inline-flex items-center gap-2 overflow-hidden border border-border bg-background px-3 py-2"
>
<span className="pointer-events-none absolute inset-0 -translate-x-[101%] bg-primary/10 transition-transform duration-300 group-hover:translate-x-0" />
<Video className="relative z-10 h-4 w-4 text-primary" />
<span className="relative z-10 text-xs font-semibold tracking-[0.12em]">OPENFRAME</span>
</Link>
<nav className="hidden items-center gap-6 text-[11px] font-medium uppercase tracking-[0.14em] md:flex">
<Link className="text-muted-foreground transition-colors hover:text-foreground" href="#features">
<Link
className="text-muted-foreground transition-colors hover:text-foreground"
href="#features"
>
Features
</Link>
<Link className="text-muted-foreground transition-colors hover:text-foreground" href="#pricing">
<Link
className="text-muted-foreground transition-colors hover:text-foreground"
href="#pricing"
>
Pricing
</Link>
<a className="text-muted-foreground transition-colors hover:text-foreground" href="https://github.com/yusufipk/OpenFrame" target="_blank" rel="noreferrer">
<a
className="text-muted-foreground transition-colors hover:text-foreground"
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
>
GitHub
</a>
<a className="text-muted-foreground transition-colors hover:text-foreground" href="mailto:[email protected]">
<a
className="text-muted-foreground transition-colors hover:text-foreground"
href="mailto:[email protected]"
>
Contact
</a>
</nav>
@@ -177,7 +203,10 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
</Link>
) : (
<>
<Link href="/login" className="text-xs font-medium text-muted-foreground hover:text-foreground hidden sm:block mr-4">
<Link
href="/login"
className="text-xs font-medium text-muted-foreground hover:text-foreground hidden sm:block mr-4"
>
Log in
</Link>
<Link href="/register" className={controlButtonClass}>
@@ -196,7 +225,10 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<div className="pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_top,_var(--tw-gradient-stops))] from-primary/5 via-background to-background" />
<div className="relative z-10 mx-auto max-w-[1000px] space-y-8">
<div data-hero-copy className="inline-flex items-center gap-2 border border-border/50 bg-secondary/30 px-3 py-1.5 text-xs text-muted-foreground backdrop-blur-md">
<div
data-hero-copy
className="inline-flex items-center gap-2 border border-border/50 bg-secondary/30 px-3 py-1.5 text-xs text-muted-foreground backdrop-blur-md"
>
<span className="relative flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-primary opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-primary"></span>
@@ -204,16 +236,26 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<span className="font-mono tracking-wide uppercase">Open Source Video Review</span>
</div>
<h1 data-hero-copy className="text-4xl font-semibold leading-[0.95] tracking-[-0.03em] sm:text-5xl md:text-6xl lg:text-7xl">
<h1
data-hero-copy
className="text-4xl font-semibold leading-[0.95] tracking-[-0.03em] sm:text-5xl md:text-6xl lg:text-7xl"
>
Cut Video Approval Time in Half. <br className="hidden md:block" />
<span className="text-muted-foreground">Stop Chasing Timecodes.</span>
</h1>
<p data-hero-copy className="mx-auto max-w-2xl text-base text-muted-foreground md:text-xl">
OpenFrame puts comments, voice notes, and annotations on a single timeline so clients say &quot;yes&quot; faster and your team stops guessing.
<p
data-hero-copy
className="mx-auto max-w-2xl text-base text-muted-foreground md:text-xl"
>
OpenFrame puts comments, voice notes, and annotations on a single timeline so clients
say &quot;yes&quot; faster and your team stops guessing.
</p>
<div data-hero-copy className="mx-auto flex max-w-md flex-col items-center justify-center gap-2">
<div
data-hero-copy
className="mx-auto flex max-w-md flex-col items-center justify-center gap-2"
>
<Link
href={hostedCtaHref}
className="group relative isolate inline-flex h-12 min-w-max items-center justify-center overflow-hidden border border-primary bg-primary px-10 text-sm font-medium whitespace-nowrap text-primary-foreground transition-transform duration-300 hover:scale-[1.02]"
@@ -222,7 +264,10 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<MoveRight className="ml-2 h-4 w-4 transition-transform group-hover:translate-x-1" />
</Link>
<a href="#pricing" className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground">
<a
href="#pricing"
className="text-sm font-medium text-muted-foreground transition-colors hover:text-foreground"
>
Prefer self-hosting? <ArrowRight className="ml-1 inline h-3.5 w-3.5" />
</a>
</div>
@@ -252,7 +297,6 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<Mic className="h-4 w-4" />
</button>
</div>
</div>
</div>
</section>
@@ -261,7 +305,9 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<section className="border-y border-border bg-card/10 px-4 py-16 sm:px-6 lg:px-8">
<div className="mx-auto w-full max-w-[1200px]">
<div className="mx-auto max-w-4xl">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">Feedback chaos looks like this:</h2>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Feedback chaos looks like this:
</h2>
<ul className="mt-8 space-y-4 text-base text-muted-foreground md:text-lg">
<li className="flex items-start gap-3">
<XCircle className="mt-1 h-5 w-5 shrink-0 text-red-500/80" />
@@ -293,7 +339,9 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<section className="border-b border-border bg-background px-4 py-20 sm:px-6 lg:px-8">
<div className="mx-auto w-full max-w-[1200px]">
<div className="mb-16 text-center">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">From upload to approval in one flow.</h2>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
From upload to approval in one flow.
</h2>
</div>
<div className="grid gap-4 md:grid-cols-4 relative">
@@ -301,7 +349,7 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
{ label: 'Upload a cut', icon: Upload },
{ label: 'Share a review link', icon: Share2 },
{ label: 'Get timestamped feedback', icon: MessageSquare },
{ label: 'Mark approved and move on', icon: Check }
{ label: 'Mark approved and move on', icon: Check },
].map((step, idx, arr) => (
<div key={step.label} className="group relative flex flex-col items-center">
<div className="flex flex-col items-center justify-center w-full min-h-[100px] md:aspect-[4/3] border border-border bg-card/20 px-4 py-6 md:p-6 text-center relative z-10 transition-all duration-300 group-hover:border-primary/40 group-hover:bg-card/40">
@@ -334,22 +382,31 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
{/* 4) FEATURES */}
<section id="features" className="scroll-mt-20 border-t border-border bg-card/10">
{/* Feature 1 */}
<div className="border-b border-border">
<div className="mx-auto flex w-full max-w-[1200px] flex-col-reverse items-center justify-between gap-12 px-4 py-20 sm:px-6 lg:flex-row lg:px-8 lg:py-32">
<div data-reveal className="w-full lg:w-1/2 relative">
<div className="relative aspect-[16/10] w-full border border-border/50 bg-background overflow-hidden">
<Image src="/landing/compare-v2.webp" alt="Comparison Mode" fill className="object-cover object-left-top" sizes="(min-width: 1024px) 50vw, 100vw" />
<Image
src="/landing/compare-v2.webp"
alt="Comparison Mode"
fill
className="object-cover object-left-top"
sizes="(min-width: 1024px) 50vw, 100vw"
/>
<div className="absolute inset-0 bg-background/5" />
</div>
</div>
<div data-reveal className="w-full lg:w-1/2 space-y-6">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">Compare versions side-by-side. End &quot;which cut is this?&quot;</h2>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Compare versions side-by-side. End &quot;which cut is this?&quot;
</h2>
<p className="text-base text-muted-foreground md:text-lg">
See what actually changed between versions then approve with confidence.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">Cuts revision cycles.</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">
Cuts revision cycles.
</p>
</div>
</div>
</div>
@@ -358,20 +415,29 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<div className="border-b border-border bg-background">
<div className="mx-auto flex w-full max-w-[1200px] flex-col items-center justify-between gap-12 px-4 py-20 sm:px-6 lg:flex-row lg:px-8 lg:py-32">
<div data-reveal className="w-full lg:w-1/2 space-y-6">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">Explain it better with Voice.</h2>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Explain it better with Voice.
</h2>
<p className="text-base text-muted-foreground md:text-lg">
No more &quot;What did you mean by this?&quot; emails. Every note lands at the exact moment in the video.
No more &quot;What did you mean by this?&quot; emails. Every note lands at the
exact moment in the video.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">
Faster feedback. Fewer misunderstandings.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">Faster feedback. Fewer misunderstandings.</p>
</div>
<div data-reveal className="w-full lg:w-1/2">
<div className="border border-border bg-card p-6">
<div className="border border-border/50 bg-background p-6">
<div className="flex items-start justify-between">
<div className="flex items-center gap-3">
<div className="flex h-8 w-8 items-center justify-center bg-secondary font-mono text-xs">Y</div>
<div className="flex h-8 w-8 items-center justify-center bg-secondary font-mono text-xs">
Y
</div>
<div className="space-y-1">
<p className="font-mono text-[11px] font-medium leading-none">Yusuf İpek</p>
<p className="font-mono text-[11px] font-medium leading-none">
Yusuf İpek
</p>
<p className="font-mono text-[10px] text-muted-foreground">00:03:45</p>
</div>
</div>
@@ -382,7 +448,13 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<Play className="h-3 w-3" />
</button>
{Array.from({ length: 40 }).map((_, i) => (
<span key={i} className="voice-bar w-full flex-1 bg-primary/60" style={{ height: `${[30, 80, 50, 90, 40, 70, 60, 45, 85, 55, 65, 35, 95, 75, 25, 40, 80, 50, 90, 30][i % 20]}%` }} />
<span
key={i}
className="voice-bar w-full flex-1 bg-primary/60"
style={{
height: `${[30, 80, 50, 90, 40, 70, 60, 45, 85, 55, 65, 35, 95, 75, 25, 40, 80, 50, 90, 30][i % 20]}%`,
}}
/>
))}
</div>
</div>
@@ -394,12 +466,37 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
{/* Feature 3 */}
<div className="border-b border-border">
<div className="mx-auto flex w-full max-w-[1200px] flex-col-reverse items-center justify-between gap-12 px-4 py-20 sm:px-6 lg:flex-row lg:px-8 lg:py-32">
<div data-reveal className="w-full lg:w-1/2 relative aspect-video bg-card border border-border p-4">
<div
data-reveal
className="w-full lg:w-1/2 relative aspect-video bg-card border border-border p-4"
>
<div className="relative h-full w-full border border-border/50 overflow-hidden bg-background">
<Image src="https://images.unsplash.com/photo-1542204165-65bf26472b9b?auto=format&fit=crop&w=800&q=80" alt="Annotate" fill className="object-cover opacity-70" />
<svg className="absolute inset-0 h-full w-full pointer-events-none" viewBox="0 0 800 450" fill="none">
<circle cx="500" cy="225" r="80" stroke="#06b6d4" strokeWidth="4" className="opacity-90 drop-shadow-[0_0_8px_rgba(6,182,212,0.8)]" />
<path d="M500 145 Q550 80 620 120" stroke="#06b6d4" strokeWidth="4" className="opacity-90" strokeLinecap="round" />
<Image
src="https://images.unsplash.com/photo-1542204165-65bf26472b9b?auto=format&fit=crop&w=800&q=80"
alt="Annotate"
fill
className="object-cover opacity-70"
/>
<svg
className="absolute inset-0 h-full w-full pointer-events-none"
viewBox="0 0 800 450"
fill="none"
>
<circle
cx="500"
cy="225"
r="80"
stroke="#06b6d4"
strokeWidth="4"
className="opacity-90 drop-shadow-[0_0_8px_rgba(6,182,212,0.8)]"
/>
<path
d="M500 145 Q550 80 620 120"
stroke="#06b6d4"
strokeWidth="4"
className="opacity-90"
strokeLinecap="round"
/>
</svg>
{/* Circle Editor UI mock */}
@@ -423,11 +520,16 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
</div>
</div>
<div data-reveal className="w-full lg:w-1/2 space-y-6">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">Point. Draw. Done.</h2>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Point. Draw. Done.
</h2>
<p className="text-base text-muted-foreground md:text-lg">
Precise feedback that leaves zero room for error. Circle, sketch, and point directly on the video frame.
Precise feedback that leaves zero room for error. Circle, sketch, and point
directly on the video frame.
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">
Stops &quot;I thought you meant...&quot;
</p>
<p className="text-xs uppercase tracking-[0.14em] text-primary">Stops &quot;I thought you meant...&quot;</p>
</div>
</div>
</div>
@@ -437,16 +539,29 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<section className="border-b border-border px-4 py-20 sm:px-6 lg:px-8 lg:py-32 bg-background">
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mb-12 flex flex-col items-center text-center">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">Everything a real production workflow needs.</h2>
<p className="mt-4 max-w-2xl text-base text-muted-foreground">The core tools teams expect without the complexity that slows clients down.</p>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Everything a real production workflow needs.
</h2>
<p className="mt-4 max-w-2xl text-base text-muted-foreground">
The core tools teams expect without the complexity that slows clients down.
</p>
</div>
<div className="space-y-10">
<div>
<p data-reveal className="mb-4 text-xs uppercase tracking-[0.14em] text-muted-foreground">Core workflow</p>
<p
data-reveal
className="mb-4 text-xs uppercase tracking-[0.14em] text-muted-foreground"
>
Core workflow
</p>
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{coreWorkflowFeatures.map((feat) => (
<div key={feat.title} data-reveal className="group border border-border bg-card p-6 transition-colors hover:border-primary/50 hover:bg-card/80">
<div
key={feat.title}
data-reveal
className="group border border-border bg-card p-6 transition-colors hover:border-primary/50 hover:bg-card/80"
>
<feat.icon className="mb-4 h-6 w-6 text-primary" />
<h3 className="mb-2 text-lg font-medium">{feat.title}</h3>
<p className="text-sm text-muted-foreground">{feat.description}</p>
@@ -456,10 +571,19 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
</div>
<div>
<p data-reveal className="mb-4 text-xs uppercase tracking-[0.14em] text-muted-foreground">Workflow Accelerators</p>
<p
data-reveal
className="mb-4 text-xs uppercase tracking-[0.14em] text-muted-foreground"
>
Workflow Accelerators
</p>
<div className="grid gap-4 sm:grid-cols-2">
{workflowAcceleratorFeatures.map((feat) => (
<div key={feat.title} data-reveal className="group border border-border bg-card p-6 transition-colors hover:border-primary/50 hover:bg-card/80">
<div
key={feat.title}
data-reveal
className="group border border-border bg-card p-6 transition-colors hover:border-primary/50 hover:bg-card/80"
>
<feat.icon className="mb-4 h-6 w-6 text-primary" />
<h3 className="mb-2 text-lg font-medium">{feat.title}</h3>
<p className="text-sm text-muted-foreground">{feat.description}</p>
@@ -475,8 +599,13 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<section className="border-b border-border bg-card/20 px-4 py-20 sm:px-6 lg:px-8 lg:py-32">
<div className="mx-auto flex w-full max-w-[1200px] flex-col lg:flex-row gap-12 lg:items-center">
<div data-reveal className="lg:w-1/2 space-y-6">
<h2 className="text-4xl font-semibold tracking-[-0.02em] md:text-5xl">Clients don&apos;t need an account. They just review.</h2>
<p className="text-lg text-muted-foreground">If clients can&apos;t adopt the tool, approvals don&apos;t happen. OpenFrame keeps it frictionless.</p>
<h2 className="text-4xl font-semibold tracking-[-0.02em] md:text-5xl">
Clients don&apos;t need an account. They just review.
</h2>
<p className="text-lg text-muted-foreground">
If clients can&apos;t adopt the tool, approvals don&apos;t happen. OpenFrame keeps
it frictionless.
</p>
</div>
<div data-reveal className="lg:w-1/2 space-y-4">
<div className="flex items-start gap-4 border border-border bg-background p-6 transition-transform hover:-translate-y-1">
@@ -494,7 +623,9 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<div className="flex items-start gap-4 border border-border bg-background p-6 transition-transform hover:-translate-y-1">
<MessageSquare className="mt-1 h-6 w-6 shrink-0 text-primary" />
<div>
<h3 className="text-lg font-semibold">Timestamped notes that are impossible to miss.</h3>
<h3 className="text-lg font-semibold">
Timestamped notes that are impossible to miss.
</h3>
</div>
</div>
</div>
@@ -502,41 +633,73 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
</section>
{/* 7) PRICING */}
<section id="pricing" className="border-b border-border bg-[#0a0a0a] px-4 py-20 sm:px-6 lg:px-8 lg:py-32">
<section
id="pricing"
className="border-b border-border bg-[#0a0a0a] px-4 py-20 sm:px-6 lg:px-8 lg:py-32"
>
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mb-16">
<h2 className="text-3xl font-semibold md:text-5xl text-foreground" style={{ fontFamily: 'monospace', letterSpacing: '-0.02em' }}>
<h2
className="text-3xl font-semibold md:text-5xl text-foreground"
style={{ fontFamily: 'monospace', letterSpacing: '-0.02em' }}
>
Deploy it yourself - or let us run it for you.
</h2>
</div>
<div className="grid gap-6 md:grid-cols-3">
{/* Card 1: Open Source */}
<div data-reveal className="relative flex flex-col border border-border/40 bg-[#141414] p-8">
<div
data-reveal
className="relative flex flex-col border border-border/40 bg-[#141414] p-8"
>
<div className="mb-6">
<h3 className="text-xl font-semibold text-foreground">Open Source (Self-hosted)</h3>
<h3 className="text-xl font-semibold text-foreground">
Open Source (Self-hosted)
</h3>
</div>
<div className="mb-8 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">Free</span>
</div>
<p className="mb-8 text-sm text-muted-foreground">For teams who want full control and can run their own infrastructure.</p>
<p className="mb-8 text-sm text-muted-foreground">
For teams who want full control and can run their own infrastructure.
</p>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-center gap-3"><CheckSquare className="h-4 w-4 text-[#06b6d4]" />Full codebase access</li>
<li className="flex items-center gap-3"><CheckSquare className="h-4 w-4 text-[#06b6d4]" />Self-hosted infrastructure control</li>
<li className="flex items-center gap-3"><CheckSquare className="h-4 w-4 text-[#06b6d4]" />Manual update cadence</li>
<li className="flex items-center gap-3">
<CheckSquare className="h-4 w-4 text-[#06b6d4]" />
Full codebase access
</li>
<li className="flex items-center gap-3">
<CheckSquare className="h-4 w-4 text-[#06b6d4]" />
Self-hosted infrastructure control
</li>
<li className="flex items-center gap-3">
<CheckSquare className="h-4 w-4 text-[#06b6d4]" />
Manual update cadence
</li>
</ul>
<a href="https://github.com/yusufipk/OpenFrame" target="_blank" rel="noreferrer" className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden border border-border/50 bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 text-sm">
<a
href="https://github.com/yusufipk/OpenFrame"
target="_blank"
rel="noreferrer"
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden border border-border/50 bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 text-sm"
>
<Github className="mr-2 h-4 w-4" /> View on GitHub
</a>
</div>
{/* Card 2: Hosted Cloud */}
<div data-reveal className="relative flex flex-col border border-[#06b6d4]/40 bg-[#141414] p-8">
<div
data-reveal
className="relative flex flex-col border border-[#06b6d4]/40 bg-[#141414] p-8"
>
<div className="mb-6">
<p className="font-mono text-[10px] uppercase font-semibold text-muted-foreground tracking-widest mb-4">Best for teams who want zero setup.</p>
<p className="font-mono text-[10px] uppercase font-semibold text-muted-foreground tracking-widest mb-4">
Best for teams who want zero setup.
</p>
<h3 className="text-xl font-semibold text-foreground">Hosted Cloud</h3>
</div>
@@ -546,40 +709,77 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
</div>
<ul className="mb-8 flex-1 space-y-4 text-sm text-foreground/80">
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Unlimited collaborators</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Timestamped comments + voice notes</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Annotations + version compare</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Share links with permissions</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Exports (PDF/CSV)</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Unlimited YouTube Video Imports</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Download original uploaded video</span></li>
<li className="flex items-start gap-3"><CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" /><span>Includes: 200 GB Storage</span></li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Unlimited collaborators</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Timestamped comments + voice notes</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Annotations + version compare</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Share links with permissions</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Exports (PDF/CSV)</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Unlimited YouTube Video Imports</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Download original uploaded video</span>
</li>
<li className="flex items-start gap-3">
<CheckSquare className="mt-0.5 shrink-0 h-4 w-4 text-[#06b6d4]" />
<span>Includes: 200 GB Storage</span>
</li>
</ul>
<p className="mb-8 text-sm text-muted-foreground">Need more storage? Add 100 GB for $5/mo.</p>
<p className="mb-8 text-sm text-muted-foreground">
Need more storage? Add 100 GB for $5/mo.
</p>
<Link href={hostedCtaHref} className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#06b6d4] font-medium text-black transition-colors hover:bg-[#06b6d4]/90 text-sm">
<Link
href={hostedCtaHref}
className="mt-auto group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#06b6d4] font-medium text-black transition-colors hover:bg-[#06b6d4]/90 text-sm"
>
Start free
</Link>
</div>
{/* Card 3: Studio & Agency */}
<div data-reveal className="relative flex flex-col border border-border/40 bg-[#141414] p-8">
<div
data-reveal
className="relative flex flex-col border border-border/40 bg-[#141414] p-8"
>
<div className="mb-6">
<h3 className="text-xl font-semibold text-foreground">Need more than the standard limits?</h3>
<h3 className="text-xl font-semibold text-foreground">
Need more than the standard limits?
</h3>
</div>
<div className="mb-6 flex items-baseline gap-2">
<span className="text-3xl font-semibold text-[#06b6d4]">Let&apos;s talk</span>
</div>
<p className="mb-8 text-sm text-foreground/80 leading-relaxed">
Custom capacity and setup help for high-volume production teams. Tell us your storage, usage, and workflow - we&apos;ll recommend the right approach.
Custom capacity and setup help for high-volume production teams. Tell us your
storage, usage, and workflow - we&apos;ll recommend the right approach.
</p>
<a href="mailto:[email protected]" className="group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 border border-border/50 text-sm">
<a
href="mailto:[email protected]"
className="group relative isolate inline-flex h-12 w-full items-center justify-center overflow-hidden bg-[#0a0a0a] font-medium text-foreground transition-colors hover:bg-white/5 border border-border/50 text-sm"
>
Contact us
</a>
</div>
</div>
</div>
</section>
@@ -588,7 +788,9 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<section className="border-b border-border bg-background px-4 py-20 sm:px-6 lg:px-8 lg:py-24">
<div className="mx-auto w-full max-w-[1200px]">
<div data-reveal className="mx-auto max-w-4xl">
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">Security & privacy, by design.</h2>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-5xl">
Security & privacy, by design.
</h2>
<ul className="mt-8 space-y-4 text-base text-muted-foreground md:text-lg">
<li>- Permissioned share links (control who can view/comment)</li>
<li>- Private-by-default projects</li>
@@ -612,7 +814,7 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
},
{
q: 'What happens if I exceed my storage?',
a: 'You can add 100 GB for $5/mo. If you need much more, contact us at [email protected] and we\'ll help you choose the best setup.',
a: "You can add 100 GB for $5/mo. If you need much more, contact us at [email protected] and we'll help you choose the best setup.",
},
{
q: 'How is YouTube unlimited?',
@@ -655,10 +857,17 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
{/* 10) FINAL CTA STRIP */}
<section className="border-b border-border bg-background px-4 py-16 sm:px-6 lg:px-8">
<div data-reveal className="mx-auto flex w-full max-w-[1200px] flex-col items-center justify-between gap-4 text-center md:flex-row md:text-left">
<div
data-reveal
className="mx-auto flex w-full max-w-[1200px] flex-col items-center justify-between gap-4 text-center md:flex-row md:text-left"
>
<div>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-4xl">Stop chasing feedback. Start getting approvals.</h2>
<p className="mt-2 text-sm text-muted-foreground">Your first review link takes minutes.</p>
<h2 className="text-3xl font-semibold tracking-[-0.02em] md:text-4xl">
Stop chasing feedback. Start getting approvals.
</h2>
<p className="mt-2 text-sm text-muted-foreground">
Your first review link takes minutes.
</p>
</div>
<Link
href={hostedCtaHref}
@@ -674,14 +883,32 @@ export function LandingPage({ isLoggedIn }: LandingPageProps) {
<div className="mx-auto flex max-w-[1200px] flex-col items-center justify-between gap-4 sm:flex-row">
<div className="flex items-center gap-2">
<Video className="h-4 w-4 text-primary" />
<span className="font-mono text-xs text-muted-foreground">© 2026 IPEK TECH LLC. All rights reserved.</span>
<span className="font-mono text-xs text-muted-foreground">
© 2026 IPEK TECH LLC. All rights reserved.
</span>
</div>
<div className="flex flex-wrap justify-center gap-4">
<a href="mailto:[email protected]" className="text-xs text-muted-foreground hover:text-foreground">info@open-frame.net</a>
<a href="https://github.com/yusufipk/OpenFrame" className="text-xs text-muted-foreground hover:text-foreground">GitHub</a>
<Link href="/terms" className="text-xs text-muted-foreground hover:text-foreground">Terms</Link>
<Link href="/privacy" className="text-xs text-muted-foreground hover:text-foreground">Privacy</Link>
<Link href="/refund" className="text-xs text-muted-foreground hover:text-foreground">Refund Policy</Link>
<a
href="mailto:info@open-frame.net"
className="text-xs text-muted-foreground hover:text-foreground"
>
info@open-frame.net
</a>
<a
href="https://github.com/yusufipk/OpenFrame"
className="text-xs text-muted-foreground hover:text-foreground"
>
GitHub
</a>
<Link href="/terms" className="text-xs text-muted-foreground hover:text-foreground">
Terms
</Link>
<Link href="/privacy" className="text-xs text-muted-foreground hover:text-foreground">
Privacy
</Link>
<Link href="/refund" className="text-xs text-muted-foreground hover:text-foreground">
Refund Policy
</Link>
</div>
</div>
</footer>