mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
right before packages, env, db, and auth refactor
removing env validation, moving db and auth to each app
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.9.1",
|
||||
"@opencut/env": "workspace:*",
|
||||
"@opencut/ui": "workspace:*",
|
||||
"@radix-ui/react-separator": "^1.1.7",
|
||||
"@upstash/ratelimit": "^2.0.6",
|
||||
"@upstash/redis": "^1.35.4",
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
import { Hero } from "@/components/landing/hero";
|
||||
import { Header } from "@/components/header";
|
||||
import { Footer } from "@/components/footer";
|
||||
import type { Metadata } from "next";
|
||||
import { SITE_URL } from "@/constants/site-constants";
|
||||
|
||||
@@ -13,9 +10,7 @@ export const metadata: Metadata = {
|
||||
export default async function Home() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Hero />
|
||||
<Footer />
|
||||
<h1>Hello World</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import Link from "next/link";
|
||||
import { RiDiscordFill, RiTwitterXLine } from "react-icons/ri";
|
||||
import { FaGithub } from "react-icons/fa6";
|
||||
import Image from "next/image";
|
||||
import { DEFAULT_LOGO_URL, SOCIAL_LINKS } from "@/constants/site-constants";
|
||||
import { capitalizeFirstLetter } from "@/lib/utils";
|
||||
|
||||
type Category = "resources" | "company";
|
||||
|
||||
interface Link {
|
||||
label: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
type CategoryLinks = Record<Category, Link[]>;
|
||||
|
||||
const links: CategoryLinks = {
|
||||
resources: [
|
||||
{ label: "Roadmap", href: "/roadmap" },
|
||||
{ label: "Blog", href: "/blog" },
|
||||
{ label: "Privacy", href: "/privacy" },
|
||||
{ label: "Terms of use", href: "/terms" },
|
||||
],
|
||||
company: [
|
||||
{ label: "Contributors", href: "/contributors" },
|
||||
{ label: "Sponsors", href: "/sponsors" },
|
||||
{ label: "Branding", href: "/branding" },
|
||||
{ label: "About", href: `${SOCIAL_LINKS.github}/blob/main/README.md` },
|
||||
],
|
||||
};
|
||||
|
||||
export function Footer() {
|
||||
return (
|
||||
<footer className="bg-background border-t">
|
||||
<div className="mx-auto max-w-5xl px-8 py-10">
|
||||
<div className="mb-8 grid grid-cols-1 gap-12 md:grid-cols-2">
|
||||
{/* Brand Section */}
|
||||
<div className="max-w-sm md:col-span-1">
|
||||
<div className="mb-4 flex items-center justify-start gap-2">
|
||||
<Image
|
||||
src={DEFAULT_LOGO_URL}
|
||||
alt="OpenCut"
|
||||
width={24}
|
||||
height={24}
|
||||
className="invert dark:invert-0"
|
||||
/>
|
||||
<span className="text-lg font-bold">OpenCut</span>
|
||||
</div>
|
||||
<p className="text-muted-foreground mb-5 text-sm md:text-left">
|
||||
The open source video editor that gets the job done. Simple,
|
||||
powerful, and works on any platform.
|
||||
</p>
|
||||
<div className="flex justify-start gap-3">
|
||||
<Link
|
||||
href={SOCIAL_LINKS.github}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<FaGithub className="h-5 w-5" />
|
||||
</Link>
|
||||
<Link
|
||||
href={SOCIAL_LINKS.x}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<RiTwitterXLine className="h-5 w-5" />
|
||||
</Link>
|
||||
<Link
|
||||
href={SOCIAL_LINKS.discord}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<RiDiscordFill className="h-5 w-5" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start justify-start gap-12 py-2">
|
||||
{(Object.keys(links) as Category[]).map((category) => (
|
||||
<div key={category} className="flex flex-col gap-2">
|
||||
<h3 className="text-foreground font-semibold">{capitalizeFirstLetter({ string: category })}</h3>
|
||||
<ul className="space-y-2 text-sm">
|
||||
{links[category].map((link) => (
|
||||
<li key={link.href}>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="text-muted-foreground hover:text-foreground transition-colors"
|
||||
target={link.href.startsWith("http") ? "_blank" : undefined}
|
||||
rel={link.href.startsWith("http") ? "noopener noreferrer" : undefined}
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bottom Section */}
|
||||
<div className="flex flex-col items-start justify-between gap-4 pt-2 md:flex-row">
|
||||
<div className="text-muted-foreground flex items-center gap-4 text-sm">
|
||||
<span>© 2025 OpenCut, All Rights Reserved</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { motion } from "motion/react";
|
||||
import { Button } from "./ui/button";
|
||||
import { ArrowRight } from "lucide-react";
|
||||
import Image from "next/image";
|
||||
import { ThemeToggle } from "./theme-toggle";
|
||||
import { GithubIcon, MenuIcon } from "@opencut/ui/icons";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { DEFAULT_LOGO_URL, SOCIAL_LINKS } from "@/constants/site-constants";
|
||||
|
||||
export function Header() {
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
|
||||
const links = [
|
||||
{
|
||||
label: "Contributors",
|
||||
href: "/contributors",
|
||||
},
|
||||
{
|
||||
label: "Sponsors",
|
||||
href: "/sponsors",
|
||||
},
|
||||
{
|
||||
label: "Blog",
|
||||
href: "/blog",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<header className="bg-background shadow-background/85 sticky top-0 z-10 shadow-[0_30px_35px_15px_rgba(0,0,0,1)]">
|
||||
<div className="relative flex w-full items-center justify-between px-6 pt-4">
|
||||
<div className="relative z-10 flex items-center gap-6">
|
||||
<Link href="/" className="flex items-center gap-3">
|
||||
<Image
|
||||
src={DEFAULT_LOGO_URL}
|
||||
alt="OpenCut Logo"
|
||||
className="invert dark:invert-0"
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
</Link>
|
||||
<nav className="hidden items-center gap-4 md:flex">
|
||||
{links.map((link) => (
|
||||
<Link key={link.href} href={link.href}>
|
||||
<Button variant="text" className="p-0 text-sm">
|
||||
{link.label}
|
||||
</Button>
|
||||
</Link>
|
||||
))}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<div className="relative z-10">
|
||||
<div className="flex items-center gap-3 md:hidden">
|
||||
<Button
|
||||
variant="text"
|
||||
size="icon"
|
||||
className="flex items-center justify-center p-0"
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
>
|
||||
<MenuIcon size={30} />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="hidden items-center gap-3 md:flex">
|
||||
<Link href={SOCIAL_LINKS.github}>
|
||||
<Button className="bg-background text-sm" variant="outline">
|
||||
<GithubIcon className="h-4 w-4" />
|
||||
31k+
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/projects">
|
||||
<Button className="text-sm">
|
||||
Projects
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<ThemeToggle />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"bg-background/20 pointer-events-none fixed inset-0 opacity-0 backdrop-blur-3xl",
|
||||
"transition-opacity duration-150",
|
||||
isMenuOpen && "pointer-events-auto opacity-100",
|
||||
)}
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
>
|
||||
<div className="relative h-full">
|
||||
<nav className="flex flex-col gap-3 px-6 pt-[5rem]">
|
||||
{links.map((link, index) => (
|
||||
<motion.div
|
||||
key={link.href}
|
||||
initial={{ scale: 0.98, opacity: 0 }}
|
||||
animate={{
|
||||
scale: isMenuOpen ? 1 : 0.98,
|
||||
opacity: isMenuOpen ? 1 : 0,
|
||||
}}
|
||||
transition={{
|
||||
duration: 0.4,
|
||||
delay: isMenuOpen ? index * 0.1 : 0,
|
||||
ease: [0.25, 0.46, 0.45, 0.94],
|
||||
}}
|
||||
>
|
||||
<Link
|
||||
href={link.href}
|
||||
className="text-2xl font-semibold"
|
||||
onClick={() => setIsMenuOpen(false)}
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
</motion.div>
|
||||
))}
|
||||
</nav>
|
||||
<ThemeToggle
|
||||
className="absolute bottom-8 right-8 size-10"
|
||||
iconClassName="!size-[1.2rem]"
|
||||
onToggle={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user