diff options
Diffstat (limited to 'apps/web/src')
| -rw-r--r-- | apps/web/src/components/development-debug.tsx | 3 | ||||
| -rw-r--r-- | apps/web/src/components/footer.tsx | 272 | ||||
| -rw-r--r-- | apps/web/src/components/header.tsx | 3 | ||||
| -rw-r--r-- | apps/web/src/env.ts | 27 | ||||
| -rw-r--r-- | apps/web/src/lib/rate-limit.ts | 5 | ||||
| -rw-r--r-- | apps/web/src/middleware.ts | 3 |
6 files changed, 176 insertions, 137 deletions
diff --git a/apps/web/src/components/development-debug.tsx b/apps/web/src/components/development-debug.tsx index 3b891e38..62e606ff 100644 --- a/apps/web/src/components/development-debug.tsx +++ b/apps/web/src/components/development-debug.tsx @@ -7,9 +7,10 @@ import { usePlaybackStore } from "@/stores/playback-store"; import { Button } from "@/components/ui/button";
import { useState } from "react";
import type { TimelineElement } from "@/types/timeline";
+import { env } from "@/env";
// Only show in development
-const SHOW_DEBUG_INFO = process.env.NODE_ENV === "development";
+const SHOW_DEBUG_INFO = env.NODE_ENV === "development";
interface ActiveElement {
element: TimelineElement;
diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx index 43a9db0e..81505d4a 100644 --- a/apps/web/src/components/footer.tsx +++ b/apps/web/src/components/footer.tsx @@ -1,132 +1,140 @@ -"use client";
-
-import { motion } from "motion/react";
-import Link from "next/link";
-import { useEffect, useState } from "react";
-import { RiGithubLine, RiTwitterXLine } from "react-icons/ri";
-import { getStars } from "@/lib/fetch-github-stars";
-import Image from "next/image";
-
-export function Footer() {
- const [star, setStar] = useState<string>();
-
- useEffect(() => {
- const fetchStars = async () => {
- try {
- const data = await getStars();
- setStar(data);
- } catch (err) {
- console.error("Failed to fetch GitHub stars", err);
- }
- };
-
- fetchStars();
- }, []);
-
- return (
- <motion.footer
- className="bg-background border-t"
- initial={{ opacity: 0 }}
- animate={{ opacity: 1 }}
- transition={{ delay: 0.8, duration: 0.8 }}
- >
- <div className="max-w-5xl mx-auto px-8 py-10">
- <div className="grid grid-cols-1 md:grid-cols-2 gap-12 mb-8">
- {/* Brand Section */}
- <div className="md:col-span-1 max-w-sm">
- <div className="flex items-center gap-2 mb-4">
- <Image src="/logo.svg" alt="OpenCut" width={24} height={24} />
- <span className="font-bold text-lg">OpenCut</span>
- </div>
- <p className="text-sm text-muted-foreground mb-5">
- The open source video editor that gets the job done. Simple,
- powerful, and works on any platform.
- </p>
- <div className="flex gap-3">
- <Link
- href="https://github.com/OpenCut-app/OpenCut"
- className="text-muted-foreground hover:text-foreground transition-colors"
- target="_blank"
- rel="noopener noreferrer"
- >
- <RiGithubLine className="h-5 w-5" />
- </Link>
- <Link
- href="https://x.com/OpenCutApp"
- className="text-muted-foreground hover:text-foreground transition-colors"
- target="_blank"
- rel="noopener noreferrer"
- >
- <RiTwitterXLine className="h-5 w-5" />
- </Link>
- </div>
- </div>
-
- <div className="flex gap-12 justify-end items-start py-2">
- <div>
- <h3 className="font-semibold text-foreground mb-4">Resources</h3>
- <ul className="space-y-2 text-sm">
- <li>
- <Link
- href="/roadmap"
- className="text-muted-foreground hover:text-foreground transition-colors"
- >
- Roadmap
- </Link>
- </li>
- <li>
- <Link
- href="/privacy"
- className="text-muted-foreground hover:text-foreground transition-colors"
- >
- Privacy policy
- </Link>
- </li>
- <li>
- <Link
- href="/terms"
- className="text-muted-foreground hover:text-foreground transition-colors"
- >
- Terms of use
- </Link>
- </li>
- </ul>
- </div>
-
- {/* Company Links */}
- <div>
- <h3 className="font-semibold text-foreground mb-4">Company</h3>
- <ul className="space-y-2 text-sm">
- <li>
- <Link
- href="/contributors"
- className="text-muted-foreground hover:text-foreground transition-colors"
- >
- Contributors
- </Link>
- </li>
- <li>
- <Link
- href="https://github.com/OpenCut-app/OpenCut/blob/main/README.md"
- className="text-muted-foreground hover:text-foreground transition-colors"
- target="_blank"
- rel="noopener noreferrer"
- >
- About
- </Link>
- </li>
- </ul>
- </div>
- </div>
- </div>
-
- {/* Bottom Section */}
- <div className="pt-2 flex flex-col md:flex-row justify-between items-center gap-4">
- <div className="flex items-center gap-4 text-sm text-muted-foreground">
- <span>© 2025 OpenCut, All Rights Reserved</span>
- </div>
- </div>
- </div>
- </motion.footer>
- );
-}
+"use client"; + +import { motion } from "motion/react"; +import Link from "next/link"; +import { useEffect, useState } from "react"; +import { RiDiscordFill, RiGithubLine, RiTwitterXLine } from "react-icons/ri"; +import { getStars } from "@/lib/fetch-github-stars"; +import Image from "next/image"; + +export function Footer() { + const [star, setStar] = useState<string>(); + + useEffect(() => { + const fetchStars = async () => { + try { + const data = await getStars(); + setStar(data); + } catch (err) { + console.error("Failed to fetch GitHub stars", err); + } + }; + + fetchStars(); + }, []); + + return ( + <motion.footer + className="bg-background border-t" + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + transition={{ delay: 0.8, duration: 0.8 }} + > + <div className="max-w-5xl mx-auto px-8 py-10"> + <div className="grid grid-cols-1 md:grid-cols-2 gap-12 mb-8"> + {/* Brand Section */} + <div className="md:col-span-1 max-w-sm"> + <div className="flex items-center gap-2 mb-4"> + <Image src="/logo.svg" alt="OpenCut" width={24} height={24} /> + <span className="font-bold text-lg">OpenCut</span> + </div> + <p className="text-sm text-muted-foreground mb-5"> + The open source video editor that gets the job done. Simple, + powerful, and works on any platform. + </p> + <div className="flex gap-3"> + <Link + href="https://github.com/OpenCut-app/OpenCut" + className="text-muted-foreground hover:text-foreground transition-colors" + target="_blank" + rel="noopener noreferrer" + > + <RiGithubLine className="h-5 w-5" /> + </Link> + <Link + href="https://x.com/OpenCutApp" + className="text-muted-foreground hover:text-foreground transition-colors" + target="_blank" + rel="noopener noreferrer" + > + <RiTwitterXLine className="h-5 w-5" /> + </Link> + <Link + href="https://discord.com/invite/Mu3acKZvCp" + 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 gap-12 justify-end items-start py-2"> + <div> + <h3 className="font-semibold text-foreground mb-4">Resources</h3> + <ul className="space-y-2 text-sm"> + <li> + <Link + href="/roadmap" + className="text-muted-foreground hover:text-foreground transition-colors" + > + Roadmap + </Link> + </li> + <li> + <Link + href="/privacy" + className="text-muted-foreground hover:text-foreground transition-colors" + > + Privacy policy + </Link> + </li> + <li> + <Link + href="/terms" + className="text-muted-foreground hover:text-foreground transition-colors" + > + Terms of use + </Link> + </li> + </ul> + </div> + + {/* Company Links */} + <div> + <h3 className="font-semibold text-foreground mb-4">Company</h3> + <ul className="space-y-2 text-sm"> + <li> + <Link + href="/contributors" + className="text-muted-foreground hover:text-foreground transition-colors" + > + Contributors + </Link> + </li> + <li> + <Link + href="https://github.com/OpenCut-app/OpenCut/blob/main/README.md" + className="text-muted-foreground hover:text-foreground transition-colors" + target="_blank" + rel="noopener noreferrer" + > + About + </Link> + </li> + </ul> + </div> + </div> + </div> + + {/* Bottom Section */} + <div className="pt-2 flex flex-col md:flex-row justify-between items-center gap-4"> + <div className="flex items-center gap-4 text-sm text-muted-foreground"> + <span>© 2025 OpenCut, All Rights Reserved</span> + </div> + </div> + </div> + </motion.footer> + ); +} diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index bfe314d6..455e0140 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -8,6 +8,7 @@ import { useSession } from "@opencut/auth/client"; import { getStars } from "@/lib/fetch-github-stars";
import { useEffect, useState } from "react";
import Image from "next/image";
+import { env } from "@/env";
export function Header() {
const { data: session } = useSession();
@@ -40,7 +41,7 @@ export function Header() { Contributors
</Button>
</Link>
- {process.env.NODE_ENV === "development" ? (
+ {env.NODE_ENV === "development" ? (
<Link href="/projects">
<Button size="sm" className="text-sm ml-4">
Projects
diff --git a/apps/web/src/env.ts b/apps/web/src/env.ts new file mode 100644 index 00000000..8071107e --- /dev/null +++ b/apps/web/src/env.ts @@ -0,0 +1,27 @@ +import { vercel } from "@t3-oss/env-core/presets-zod"; +import { createEnv } from "@t3-oss/env-nextjs"; +import { z } from "zod"; +import { keys as auth } from "@opencut/auth/keys"; +import { keys as db } from "@opencut/db/keys"; + +export const env = createEnv({ + extends: [vercel(), auth(), db()], + server: { + ANALYZE: z.string().optional(), + // Added by Vercel + NEXT_RUNTIME: z.enum(["nodejs", "edge"]).optional(), + NODE_ENV: z + .enum(["development", "production", "test"]) + .default("development"), + UPSTASH_REDIS_REST_URL: z.string().url(), + UPSTASH_REDIS_REST_TOKEN: z.string(), + }, + client: {}, + runtimeEnv: { + ANALYZE: process.env.ANALYZE, + NEXT_RUNTIME: process.env.NEXT_RUNTIME, + NODE_ENV: process.env.NODE_ENV, + UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL, + UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN, + }, +}); diff --git a/apps/web/src/lib/rate-limit.ts b/apps/web/src/lib/rate-limit.ts index bf1cce02..92e78e74 100644 --- a/apps/web/src/lib/rate-limit.ts +++ b/apps/web/src/lib/rate-limit.ts @@ -1,10 +1,11 @@ // lib/rate-limit.ts
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
+import { env } from "@/env";
const redis = new Redis({
- url: process.env.UPSTASH_REDIS_REST_URL!,
- token: process.env.UPSTASH_REDIS_REST_TOKEN!,
+ url: env.UPSTASH_REDIS_REST_URL,
+ token: env.UPSTASH_REDIS_REST_TOKEN,
});
export const waitlistRateLimit = new Ratelimit({
diff --git a/apps/web/src/middleware.ts b/apps/web/src/middleware.ts index bdce5cc1..57e1e808 100644 --- a/apps/web/src/middleware.ts +++ b/apps/web/src/middleware.ts @@ -1,5 +1,6 @@ import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
+import { env } from "./env";
export async function middleware(request: NextRequest) {
// Handle fuckcapcut.com domain redirect
@@ -9,7 +10,7 @@ export async function middleware(request: NextRequest) { const path = request.nextUrl.pathname;
- if (path === "/editor" && process.env.NODE_ENV === "production") {
+ if (path === "/editor" && env.NODE_ENV === "production") {
const homeUrl = new URL("/", request.url);
homeUrl.searchParams.set("redirect", request.url);
return NextResponse.redirect(homeUrl);
|
