diff options
Diffstat (limited to 'apps/web/src/app')
| -rw-r--r-- | apps/web/src/app/contributors/page.tsx | 100 | ||||
| -rw-r--r-- | apps/web/src/app/favicon.ico | bin | 4286 -> 0 bytes | |||
| -rw-r--r-- | apps/web/src/app/globals.css | 2 | ||||
| -rw-r--r-- | apps/web/src/app/layout.tsx | 39 | ||||
| -rw-r--r-- | apps/web/src/app/metadata.ts | 66 | ||||
| -rw-r--r-- | apps/web/src/app/page.tsx | 8 |
6 files changed, 132 insertions, 83 deletions
diff --git a/apps/web/src/app/contributors/page.tsx b/apps/web/src/app/contributors/page.tsx index f5fa0755..67957c32 100644 --- a/apps/web/src/app/contributors/page.tsx +++ b/apps/web/src/app/contributors/page.tsx @@ -6,6 +6,7 @@ import { Button } from "@/components/ui/button"; import { ExternalLink } from "lucide-react";
import Link from "next/link";
import { GithubIcon } from "@/components/icons";
+import { Badge } from "@/components/ui/badge";
export const metadata: Metadata = {
title: "Contributors - OpenCut",
@@ -49,7 +50,7 @@ async function getContributors(): Promise<Contributor[]> { const contributors = await response.json();
const filteredContributors = contributors.filter(
- (contributor: any) => contributor.type === "User"
+ (contributor: Contributor) => contributor.type === "User"
);
return filteredContributors;
@@ -61,8 +62,8 @@ async function getContributors(): Promise<Contributor[]> { export default async function ContributorsPage() {
const contributors = await getContributors();
- const topContributor = contributors[0];
- const otherContributors = contributors.slice(1);
+ const topContributors = contributors.slice(0, 2);
+ const otherContributors = contributors.slice(2);
return (
<div className="min-h-screen bg-background">
@@ -77,10 +78,10 @@ export default async function ContributorsPage() { <div className="relative container mx-auto px-4 py-16">
<div className="max-w-6xl mx-auto">
<div className="text-center mb-20">
- <div className="inline-flex items-center gap-2 bg-muted/50 text-muted-foreground px-3 py-1 rounded-full text-sm mb-6">
+ <Badge variant="secondary" className="gap-2 mb-6">
<GithubIcon className="h-3 w-3" />
Open Source
- </div>
+ </Badge>
<h1 className="text-5xl md:text-6xl font-bold tracking-tight mb-6">
Contributors
</h1>
@@ -105,54 +106,59 @@ export default async function ContributorsPage() { </div>
</div>
- {topContributor && (
+ {topContributors.length > 0 && (
<div className="mb-20">
<div className="text-center mb-12">
<h2 className="text-2xl font-semibold mb-2">
- Top Contributor
+ Top Contributors
</h2>
<p className="text-muted-foreground">
Leading the way in contributions
</p>
</div>
- <Link
- href={topContributor.html_url}
- target="_blank"
- rel="noopener noreferrer"
- className="group block"
- >
- <div className="relative mx-auto max-w-md">
- <div className="absolute inset-0 bg-gradient-to-r from-muted/50 to-muted/30 rounded-2xl blur group-hover:blur-md transition-all duration-300" />
- <Card className="relative bg-background/80 backdrop-blur-sm border-2 group-hover:border-muted-foreground/20 transition-all duration-300 group-hover:shadow-xl">
- <CardContent className="p-8 text-center">
- <div className="relative mb-6">
- <Avatar className="h-24 w-24 mx-auto ring-4 ring-background shadow-2xl">
- <AvatarImage
- src={topContributor.avatar_url}
- alt={`${topContributor.login}'s avatar`}
- />
- <AvatarFallback className="text-lg font-semibold">
- {topContributor.login.charAt(0).toUpperCase()}
- </AvatarFallback>
- </Avatar>
- <div className="absolute -top-2 -right-2 bg-foreground text-background rounded-full w-8 h-8 flex items-center justify-center text-sm font-bold">
- 1
- </div>
- </div>
- <h3 className="text-xl font-semibold mb-2 group-hover:text-foreground/80 transition-colors">
- {topContributor.login}
- </h3>
- <div className="flex items-center justify-center gap-2 text-muted-foreground">
- <span className="font-medium text-foreground">
- {topContributor.contributions}
- </span>
- <span>contributions</span>
- </div>
- </CardContent>
- </Card>
- </div>
- </Link>
+ <div className="flex flex-col md:flex-row gap-6 justify-center max-w-4xl mx-auto">
+ {topContributors.map((contributor, index) => (
+ <Link
+ key={contributor.id}
+ href={contributor.html_url}
+ target="_blank"
+ rel="noopener noreferrer"
+ className="group block flex-1"
+ >
+ <div className="relative mx-auto max-w-md">
+ <div className="absolute inset-0 bg-gradient-to-r from-muted/50 to-muted/30 rounded-2xl blur group-hover:blur-md transition-all duration-300" />
+ <Card className="relative bg-background/80 backdrop-blur-sm border-2 group-hover:border-muted-foreground/20 transition-all duration-300 group-hover:shadow-xl">
+ <CardContent className="p-8 text-center">
+ <div className="relative mb-6">
+ <Avatar className="h-24 w-24 mx-auto ring-4 ring-background shadow-2xl">
+ <AvatarImage
+ src={contributor.avatar_url}
+ alt={`${contributor.login}'s avatar`}
+ />
+ <AvatarFallback className="text-lg font-semibold">
+ {contributor.login.charAt(0).toUpperCase()}
+ </AvatarFallback>
+ </Avatar>
+ <div className="absolute -top-2 -right-2 bg-foreground text-background rounded-full w-8 h-8 flex items-center justify-center text-sm font-bold">
+ {index + 1}
+ </div>
+ </div>
+ <h3 className="text-xl font-semibold mb-2 group-hover:text-foreground/80 transition-colors">
+ {contributor.login}
+ </h3>
+ <div className="flex items-center justify-center gap-2 text-muted-foreground">
+ <span className="font-medium text-foreground">
+ {contributor.contributions}
+ </span>
+ <span>contributions</span>
+ </div>
+ </CardContent>
+ </Card>
+ </div>
+ </Link>
+ ))}
+ </div>
</div>
)}
@@ -167,7 +173,7 @@ export default async function ContributorsPage() { </p>
</div>
- <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-4">
+ <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-6">
{otherContributors.map((contributor, index) => (
<Link
key={contributor.id}
@@ -179,8 +185,8 @@ export default async function ContributorsPage() { animationDelay: `${index * 50}ms`,
}}
>
- <div className="text-center p-4 rounded-xl hover:bg-muted/50 transition-all duration-300 group-hover:scale-105">
- <Avatar className="h-16 w-16 mx-auto mb-3 ring-2 ring-transparent group-hover:ring-muted-foreground/20 transition-all duration-300">
+ <div className="text-center p-2 rounded-xl transition-all duration-300 hover:opacity-50">
+ <Avatar className="h-16 w-16 mx-auto mb-3">
<AvatarImage
src={contributor.avatar_url}
alt={`${contributor.login}'s avatar`}
diff --git a/apps/web/src/app/favicon.ico b/apps/web/src/app/favicon.ico Binary files differdeleted file mode 100644 index cb20127b..00000000 --- a/apps/web/src/app/favicon.ico +++ /dev/null diff --git a/apps/web/src/app/globals.css b/apps/web/src/app/globals.css index 2169dbbc..1c8a7887 100644 --- a/apps/web/src/app/globals.css +++ b/apps/web/src/app/globals.css @@ -39,7 +39,7 @@ --sidebar-ring: 0 0% 3.9%; } .dark { - --background: 0 0% 8%; + --background: 0 0% 6%; --foreground: 0 0% 98%; --card: 0 0% 3.9%; --card-foreground: 0 0% 98%; diff --git a/apps/web/src/app/layout.tsx b/apps/web/src/app/layout.tsx index 5d33100d..8188d31b 100644 --- a/apps/web/src/app/layout.tsx +++ b/apps/web/src/app/layout.tsx @@ -1,4 +1,3 @@ -import type { Metadata } from "next"; import { Inter } from "next/font/google"; import { ThemeProvider } from "next-themes"; import { Analytics } from "@vercel/analytics/react"; @@ -6,46 +5,15 @@ import Script from "next/script"; import "./globals.css"; import { Toaster } from "../components/ui/sonner"; import { TooltipProvider } from "../components/ui/tooltip"; +import { DevelopmentDebug } from "../components/development-debug"; +import { baseMetaData } from "./metadata"; const inter = Inter({ subsets: ["latin"], variable: "--font-inter", }); -export const metadata: Metadata = { - title: "OpenCut", - description: - "A simple but powerful video editor that gets the job done. In your browser.", - openGraph: { - title: "OpenCut", - description: - "A simple but powerful video editor that gets the job done. In your browser.", - url: "https://opencut.app", - siteName: "OpenCut", - locale: "en_US", - type: "website", - images: [ - { - url: "https://opencut.app/opengraph-image.jpg", - width: 1200, - height: 630, - alt: "OpenCut", - }, - ], - }, - twitter: { - card: "summary_large_image", - title: "OpenCut", - description: - "A simple but powerful video editor that gets the job done. In your browser.", - creator: "@opencutapp", - images: ["/opengraph-image.jpg"], - }, - robots: { - index: true, - follow: true, - }, -}; +export const metadata = baseMetaData; export default function RootLayout({ children, @@ -60,6 +28,7 @@ export default function RootLayout({ {children} <Analytics /> <Toaster /> + <DevelopmentDebug /> <Script src="https://app.databuddy.cc/databuddy.js" strategy="afterInteractive" diff --git a/apps/web/src/app/metadata.ts b/apps/web/src/app/metadata.ts new file mode 100644 index 00000000..4e387014 --- /dev/null +++ b/apps/web/src/app/metadata.ts @@ -0,0 +1,66 @@ +import { Metadata } from "next"; + +const title = "OpenCut"; +const description = "A simple but powerful video editor that gets the job done. In your browser."; +const openGraphImageUrl = "https://opencut.app/opengraph-image.jpg"; +const twitterImageUrl = "/opengraph-image.jpg"; + +export const baseMetaData: Metadata = { + title: title, + description: description, + openGraph: { + title: title, + description: description, + url: "https://opencut.app", + siteName: "OpenCut", + locale: "en_US", + type: "website", + images: [ + { + url: openGraphImageUrl, + width: 1200, + height: 630, + alt: "OpenCut", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: title, + description: description, + creator: "@opencutapp", + images: [twitterImageUrl], + }, + robots: { + index: true, + follow: true, + }, + icons: { + icon: [ + { url: "/favicon.ico" }, + { url: "/icons/favicon-16x16.png", sizes: "16x16", type: "image/png" }, + { url: "/icons/favicon-32x32.png", sizes: "32x32", type: "image/png" }, + { url: "/icons/favicon-96x96.png", sizes: "96x96", type: "image/png" }, + ], + apple: [ + { url: "/icons/apple-icon-57x57.png", sizes: "57x57", type: "image/png" }, + { url: "/icons/apple-icon-60x60.png", sizes: "60x60", type: "image/png" }, + { url: "/icons/apple-icon-72x72.png", sizes: "72x72", type: "image/png" }, + { url: "/icons/apple-icon-76x76.png", sizes: "76x76", type: "image/png" }, + { url: "/icons/apple-icon-114x114.png", sizes: "114x114", type: "image/png" }, + { url: "/icons/apple-icon-120x120.png", sizes: "120x120", type: "image/png" }, + { url: "/icons/apple-icon-144x144.png", sizes: "144x144", type: "image/png" }, + { url: "/icons/apple-icon-152x152.png", sizes: "152x152", type: "image/png" }, + { url: "/icons/apple-icon-180x180.png", sizes: "180x180", type: "image/png" }, + ], + shortcut: ["/favicon.ico"] + }, + appleWebApp: { + capable: true, + title: title, + }, + manifest: "/manifest.json", + other: { + "msapplication-config": "/browserconfig.xml" + } +}; diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx index dcedab32..e9957e1b 100644 --- a/apps/web/src/app/page.tsx +++ b/apps/web/src/app/page.tsx @@ -1,6 +1,7 @@ import { Hero } from "@/components/landing/hero";
import { Header } from "@/components/header";
import { getWaitlistCount } from "@/lib/waitlist";
+import Image from "next/image";
// Force dynamic rendering so waitlist count updates in real-time
export const dynamic = "force-dynamic";
@@ -10,6 +11,13 @@ export default async function Home() { return (
<div>
+ <Image
+ className="fixed top-0 left-0 -z-50 size-full object-cover"
+ src="/landing-page-bg.png"
+ height={1903.5}
+ width={1269}
+ alt="landing-page.bg"
+ />
<Header />
<Hero signupCount={signupCount} />
</div>
|
