diff options
Diffstat (limited to 'apps/web/src/components')
| -rw-r--r-- | apps/web/src/components/editor/onboarding.tsx | 5 | ||||
| -rw-r--r-- | apps/web/src/components/footer.tsx | 53 | ||||
| -rw-r--r-- | apps/web/src/components/header.tsx | 6 | ||||
| -rw-r--r-- | apps/web/src/components/landing/handlebars.tsx | 203 | ||||
| -rw-r--r-- | apps/web/src/components/landing/hero.tsx | 41 |
5 files changed, 28 insertions, 280 deletions
diff --git a/apps/web/src/components/editor/onboarding.tsx b/apps/web/src/components/editor/onboarding.tsx index bc5533ce..08ef3318 100644 --- a/apps/web/src/components/editor/onboarding.tsx +++ b/apps/web/src/components/editor/onboarding.tsx @@ -3,7 +3,6 @@ import { ArrowRightIcon } from "lucide-react"; import { useState } from "react"; import ReactMarkdown from "react-markdown"; -import { SOCIAL_LINKS } from "@/site/social"; import { useLocalStorage } from "@/services/storage/use-local-storage"; import { Button } from "../ui/button"; import { Dialog, DialogBody, DialogContent, DialogTitle } from "../ui/dialog"; @@ -67,9 +66,7 @@ export function Onboarding() { <div className="space-y-5"> <div className="space-y-3"> <Title title={getStepTitle()} /> - <Description - description={`Join our [Discord](${SOCIAL_LINKS.discord}), chat with cool people and share feedback to help make OpenCut the best editor ever.`} - /> + <Description description="Have fun testing! Your projects and media stay local in your browser." /> </div> <NextButton onClick={handleClose}>Finish</NextButton> </div> diff --git a/apps/web/src/components/footer.tsx b/apps/web/src/components/footer.tsx index b56f8c6c..e7a8fc39 100644 --- a/apps/web/src/components/footer.tsx +++ b/apps/web/src/components/footer.tsx @@ -1,5 +1,5 @@ import Link from "next/link";
-import { RiDiscordFill, RiTwitterXLine } from "react-icons/ri";
+import { RiTwitterXLine } from "react-icons/ri";
import { FaGithub } from "react-icons/fa6";
import Image from "next/image";
import { DEFAULT_LOGO_URL } from "@/site/brand";
@@ -13,23 +13,30 @@ interface FooterLink { href: string;
}
-type CategoryLinks = Record<Category, FooterLink[]>;
+interface LinkCategory {
+ category: Category;
+ links: FooterLink[];
+}
-const links: CategoryLinks = {
- resources: [
- { label: "Roadmap", href: "/roadmap" },
- { label: "Changelog", href: "/changelog" },
- { label: "Blog", href: "/blog" },
- { label: "Privacy", href: "/privacy" },
- { label: "Terms of use", href: "/terms" },
- ],
- company: [
- { label: "Contributors", href: "/contributors" },
- { label: "Sponsors", href: "/sponsors" },
- { label: "Brand", href: "/brand" },
- { label: "About", href: `${SOCIAL_LINKS.github}/blob/main/README.md` },
- ],
-};
+const linkCategories: LinkCategory[] = [
+ {
+ category: "resources",
+ links: [
+ { label: "Roadmap", href: "/roadmap" },
+ { label: "Privacy", href: "/privacy" },
+ { label: "Terms of use", href: "/terms" },
+ ],
+ },
+ {
+ category: "company",
+ links: [
+ { label: "Contributors", href: "/contributors" },
+ { label: "Sponsors", href: "/sponsors" },
+ { label: "Brand", href: "/brand" },
+ { label: "About", href: `${SOCIAL_LINKS.github}/blob/main/README.md` },
+ ],
+ },
+];
export function Footer() {
return (
@@ -68,25 +75,17 @@ export function Footer() { >
<RiTwitterXLine className="size-5" />
</Link>
- <Link
- href={SOCIAL_LINKS.discord}
- className="text-muted-foreground hover:text-foreground transition-colors"
- target="_blank"
- rel="noopener noreferrer"
- >
- <RiDiscordFill className="size-5" />
- </Link>
</div>
</div>
<div className="flex items-start justify-start gap-12 py-2">
- {(Object.keys(links) as Category[]).map((category) => (
+ {linkCategories.map(({ category, links: categoryLinks }) => (
<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) => (
+ {categoryLinks.map((link) => (
<li key={link.href}>
<Link
href={link.href}
diff --git a/apps/web/src/components/header.tsx b/apps/web/src/components/header.tsx index 99ba1730..44a2864f 100644 --- a/apps/web/src/components/header.tsx +++ b/apps/web/src/components/header.tsx @@ -16,7 +16,7 @@ import { } from "@hugeicons/core-free-icons";
import { HugeiconsIcon } from "@hugeicons/react";
import { cn } from "@/utils/ui";
-import { DEFAULT_LOGO_URL, SITE_URL } from "@/site/brand";
+import { DEFAULT_LOGO_URL } from "@/site/brand";
import { SOCIAL_LINKS } from "@/site/social";
import {
ContextMenu,
@@ -42,10 +42,6 @@ export function Header() { label: "Sponsors",
href: "/sponsors",
},
- {
- label: "Blog",
- href: "/blog",
- },
];
return (
diff --git a/apps/web/src/components/landing/handlebars.tsx b/apps/web/src/components/landing/handlebars.tsx deleted file mode 100644 index 4a81cdba..00000000 --- a/apps/web/src/components/landing/handlebars.tsx +++ /dev/null @@ -1,203 +0,0 @@ -"use client"; - -import { - type PropsWithChildren, - useEffect, - useLayoutEffect, - useRef, - useState, -} from "react"; - -type HandlebarsProps = PropsWithChildren; - -const MIN_HANDLE_SEPARATION_PX = 60; -const MASK_GRADIENT_EDGE_PADDING_PX = 10; -const HANDLEBARS_ROTATE_DEG = 2.76; -const RIGHT_HANDLE_LEFT_OFFSET_PX = -30; - -export function Handlebars({ children }: HandlebarsProps) { - const containerRef = useRef<HTMLDivElement>(null); - const leftHandleRef = useRef<HTMLDivElement>(null); - const rightHandleRef = useRef<HTMLDivElement>(null); - - const [width, setWidth] = useState(0); - const [leftHandle, setLeftHandle] = useState(0); - const [rightHandle, setRightHandle] = useState(0); - - const widthRef = useRef(0); - const leftHandlePositionRef = useRef(0); - const rightHandlePositionRef = useRef(0); - - const dragRef = useRef<{ - isDragging: boolean; - side: "left" | "right" | null; - pointerId: number | null; - startX: number; - initialPosition: number; - }>({ - isDragging: false, - side: null, - pointerId: null, - startX: 0, - initialPosition: 0, - }); - - useLayoutEffect(() => { - const container = containerRef.current; - if (!container) return; - - const updateWidth = () => { - const newWidth = container.offsetWidth; - setWidth(newWidth); - setRightHandle(newWidth); - }; - - const observer = new ResizeObserver(updateWidth); - observer.observe(container); - updateWidth(); - - return () => observer.disconnect(); - }, []); - - useEffect(() => { - widthRef.current = width; - leftHandlePositionRef.current = leftHandle; - rightHandlePositionRef.current = rightHandle; - }, [leftHandle, rightHandle, width]); - - useEffect(() => { - const handlePointerMove = (event: PointerEvent) => { - const { isDragging, side, pointerId, startX, initialPosition } = - dragRef.current; - - if (!isDragging) return; - if (pointerId !== null && event.pointerId !== pointerId) return; - if (!side) return; - - const deltaX = event.clientX - startX; - - if (side === "left") { - const maxLeft = Math.max( - 0, - rightHandlePositionRef.current - MIN_HANDLE_SEPARATION_PX, - ); - const nextLeftHandle = Math.max( - 0, - Math.min(maxLeft, initialPosition + deltaX), - ); - setLeftHandle(nextLeftHandle); - return; - } - - const minRight = Math.min( - widthRef.current, - leftHandlePositionRef.current + MIN_HANDLE_SEPARATION_PX, - ); - const nextRightHandle = Math.max( - minRight, - Math.min(widthRef.current, initialPosition + deltaX), - ); - setRightHandle(nextRightHandle); - }; - - const handlePointerEnd = (event: PointerEvent) => { - const { pointerId } = dragRef.current; - if (pointerId !== null && event.pointerId !== pointerId) return; - - dragRef.current.isDragging = false; - dragRef.current.side = null; - dragRef.current.pointerId = null; - }; - - window.addEventListener("pointermove", handlePointerMove); - window.addEventListener("pointerup", handlePointerEnd); - window.addEventListener("pointercancel", handlePointerEnd); - - return () => { - window.removeEventListener("pointermove", handlePointerMove); - window.removeEventListener("pointerup", handlePointerEnd); - window.removeEventListener("pointercancel", handlePointerEnd); - }; - }, []); - - const hasMeasuredWidth = width > 0; - const leftGradientPercent = hasMeasuredWidth - ? (leftHandle / (width - MASK_GRADIENT_EDGE_PADDING_PX)) * 100 - : 0; - const rightGradientPercent = hasMeasuredWidth - ? (rightHandle / (width + MASK_GRADIENT_EDGE_PADDING_PX)) * 100 - : 100; - const textMask = hasMeasuredWidth - ? `linear-gradient(90deg, - rgba(255, 255, 255, 0) 0%, - rgba(255, 255, 255, 0) ${leftGradientPercent}%, - rgba(0, 0, 0) ${leftGradientPercent}%, - rgba(0, 0, 0) ${rightGradientPercent}%, - rgba(255, 255, 255, 0) ${rightGradientPercent}%, - rgba(255, 255, 255, 0) 100%)` - : undefined; - - return ( - <div className="flex justify-center gap-4 leading-16"> - <div - ref={containerRef} - className="relative mt-0.5" - style={{ transform: `rotate(-${HANDLEBARS_ROTATE_DEG}deg)` }} - > - <div className="absolute inset-0 z-10 flex size-full justify-between rounded-2xl border border-yellow-500"> - <div - ref={leftHandleRef} - className="bg-background absolute left-0 z-20 flex h-full w-7 cursor-ew-resize touch-none items-center justify-center rounded-full border border-yellow-500 select-none" - style={{ - translate: `${leftHandle}px 0`, - }} - onPointerDown={(event) => { - event.preventDefault(); - leftHandleRef.current?.setPointerCapture(event.pointerId); - dragRef.current.isDragging = true; - dragRef.current.side = "left"; - dragRef.current.pointerId = event.pointerId; - dragRef.current.startX = event.clientX; - dragRef.current.initialPosition = leftHandlePositionRef.current; - }} - > - <div className="h-8 w-2 rounded-full bg-yellow-500" /> - </div> - - <div - ref={rightHandleRef} - className="bg-background absolute z-20 flex h-full w-7 cursor-ew-resize touch-none items-center justify-center rounded-full border border-yellow-500 select-none" - style={{ - left: hasMeasuredWidth - ? `${RIGHT_HANDLE_LEFT_OFFSET_PX}px` - : undefined, - right: hasMeasuredWidth ? undefined : "0px", - translate: hasMeasuredWidth ? `${rightHandle}px 0` : undefined, - }} - onPointerDown={(event) => { - event.preventDefault(); - rightHandleRef.current?.setPointerCapture(event.pointerId); - dragRef.current.isDragging = true; - dragRef.current.side = "right"; - dragRef.current.pointerId = event.pointerId; - dragRef.current.startX = event.clientX; - dragRef.current.initialPosition = rightHandlePositionRef.current; - }} - > - <div className="h-8 w-2 rounded-full bg-yellow-500" /> - </div> - </div> - - <span - className="relative z-0 inline-flex size-full items-center justify-center rounded-2xl px-9 will-change-auto" - style={{ - mask: textMask, - WebkitMask: textMask, - }} - > - {children} - </span> - </div> - </div> - ); -} diff --git a/apps/web/src/components/landing/hero.tsx b/apps/web/src/components/landing/hero.tsx deleted file mode 100644 index ac49e4be..00000000 --- a/apps/web/src/components/landing/hero.tsx +++ /dev/null @@ -1,41 +0,0 @@ -"use client";
-
-import { Button } from "../ui/button";
-import { ArrowRight } from "lucide-react";
-import Image from "next/image";
-import { Handlebars } from "./handlebars";
-import Link from "next/link";
-
-export function Hero() {
- return (
- <div className="flex min-h-[calc(100svh-4.5rem)] flex-col items-center justify-between px-4 text-center">
- <Image
- className="absolute top-0 left-0 -z-50 size-full object-cover opacity-85 invert dark:invert-0"
- src="/landing-page-dark.png"
- height={1903.5}
- width={1269}
- alt="OpenCut video editor landing page background"
- />
- <div className="mx-auto flex w-full max-w-3xl flex-1 flex-col justify-center">
- <div className="inline-block text-4xl font-bold tracking-tighter md:text-[4rem]">
- <h1>The open source</h1>
- <Handlebars>Video editor</Handlebars>
- </div>
-
- <p className="text-muted-foreground mx-auto mt-10 max-w-xl text-base font-light tracking-wide sm:text-xl">
- A simple but powerful video editor that gets the job done. Works on
- any platform.
- </p>
-
- <div className="mt-8 flex justify-center gap-8">
- <Link href="/projects">
- <Button type="submit" size="lg" className="h-11 text-base">
- Try early beta
- <ArrowRight className="ml-0.5" />
- </Button>
- </Link>
- </div>
- </div>
- </div>
- );
-}
|
