commit ac86a41c0786c8cea6f930faf2875380a1f6f91c
parent ae285a22f40600aa8642fd9c5e9acd69576dcdcc
Author: Daniel D’Aquino <daniel@daquino.me>
Date: Sat, 30 Dec 2023 00:01:52 -0800
Damus Purple landing page first draft
Diffstat:
9 files changed, 217 insertions(+), 2 deletions(-)
diff --git a/public/logo-icon-dark.png b/public/logo-icon-dark.png
Binary files differ.
diff --git a/public/stars-bg.png b/public/stars-bg.png
Binary files differ.
diff --git a/public/stars-bg.webp b/public/stars-bg.webp
Binary files differ.
diff --git a/src/components/pages/purple.tsx b/src/components/pages/purple.tsx
@@ -0,0 +1,35 @@
+import Image from 'next/image'
+import { Inter } from 'next/font/google'
+import { PurpleHero } from '@/components/sections/PurpleHero'
+import Head from "next/head";
+import { useIntl } from 'react-intl'
+import { BannedInChina } from '@/components/sections/BannedInChina'
+import { DamusOnMedia } from '@/components/sections/DamusOnMedia';
+import { MeetTheTeam } from '@/components/sections/MeetTheTeam';
+import { DamusAroundTheWorld } from '@/components/sections/DamusAroundTheWorld';
+import { Footer } from '@/components/sections/Footer';
+import { DamusLiveEvents } from '@/components/sections/DamusLiveEvents';
+import { Contribute } from '@/components/sections/Contribute';
+import { FinalCTA } from '@/components/sections/FinalCTA';
+import { Benefits } from '@/components/sections/Benefits';
+import { PurpleBenefits } from '../sections/PurpleBenefits';
+
+const inter = Inter({ subsets: ['latin'] })
+
+export function Purple() {
+ const intl = useIntl()
+
+ return (<>
+ <Head>
+ <title>Damus</title>
+ <meta name="description" content={intl.formatMessage({ id: "home.meta_description", defaultMessage: "Damus is a new social network that you control. Available now on iOS, iPad and macOS (M1/M2)" })} />
+ <meta name="apple-itunes-app" content="app-id=1628663131" />
+ </Head>
+ <main style={{ scrollBehavior: "smooth" }}>
+ <PurpleHero />
+ <PurpleBenefits/>
+ <FinalCTA />
+ <Footer />
+ </main>
+ </>)
+}
diff --git a/src/components/sections/PurpleBenefits.tsx b/src/components/sections/PurpleBenefits.tsx
@@ -0,0 +1,68 @@
+import { MeshGradient2 } from "../effects/MeshGradient.2";
+import { Button } from "../ui/Button";
+import { FormattedMessage, useIntl } from "react-intl";
+import Link from "next/link";
+import { motion } from "framer-motion";
+import { RoundedContainerWithGradientBorder } from "../ui/RoundedContainerWithGradientBorder";
+import { cn } from "@/lib/utils";
+import Image from "next/image";
+import { Award, Badge, Heart, Joystick, KeyRound, Scale, Stars, Wallet } from "lucide-react";
+import { MeshGradient4 } from "../effects/MeshGradient.4";
+import { MeshGradient3 } from "../effects/MeshGradient.3";
+
+export function PurpleBenefits({ className }: { className?: string }) {
+ const intl = useIntl()
+
+ const benefits = [
+ {
+ icon: <Heart className="h-12 w-12 text-white opacity-80"/>,
+ headline: intl.formatMessage({ id: "purple.benefits.benefit1.name", defaultMessage: "Help Build The Future" }),
+ description: intl.formatMessage({ id: "purple.benefits.benefit1.description", defaultMessage: "Support Damus development to help build the future of decentralized communication on the web." }),
+ },
+ {
+ icon: <Stars className="text-white h-12 w-12 opacity-80"/>,
+ headline: intl.formatMessage({ id: "purple.benefits.benefit2.name", defaultMessage: "Exclusive features" }),
+ description: intl.formatMessage({ id: "purple.benefits.benefit2.description", defaultMessage: "Be the first to access upcoming premium features: Automatic translations, longer note storage, and more" }),
+ },
+ {
+ icon: <Award className="h-12 w-12 text-white opacity-80"/>,
+ headline: intl.formatMessage({ id: "purple.benefits.benefit3.name", defaultMessage: "Supporter Badge" }),
+ description: intl.formatMessage({ id: "purple.benefits.benefit3.description", defaultMessage: "Get a special badge on your profile to show everyone your contribution to Freedom tech" }),
+ },
+ ]
+
+ return (<>
+ <div className={cn("bg-black overflow-hidden relative", className)}>
+ <MeshGradient3 className="absolute top-0 left-0 pointer-events-none translate-y-3/4 overflow-visible scale-150"/>
+ <div className="container mx-auto px-6 pb-32 pt-20">
+ <div className="flex flex-col items-center justify-center mt-32 lg:mt-16">
+ <div className="relative mb-32 flex flex-col items-center">
+ <motion.h2 className="text-4xl md:text-8xl text-center text-transparent bg-clip-text bg-gradient-to-r from-damuspink-500 from-30% to-damuspink-600 to-100% font-semibold pb-8 break-keep">
+ { intl.formatMessage({ id: "purple.benefits.headline", defaultMessage: "Get more from Damus." }) }
+ </motion.h2>
+ <motion.div className="text-white/60 text-xl text-center max-w-2xl mb-6 mt-6 break-keep">
+ { intl.formatMessage({ id: "purple.benefits.description", defaultMessage: "Help us stay independent in our mission for Freedom tech with our Purple subscription, and look cool doing it!" }) }
+ </motion.div>
+ </div>
+ {(intl.locale != "ja" || process.env.FORCE_LOAD_ALL_JA_SECTIONS) && (
+ <div className="flex flex-wrap gap-x-8 gap-y-16 items-stretch justify-center">
+ {benefits.map((item, index) => (
+ <div key={index} className="max-w-xs flex flex-col items-center justify-between">
+ <RoundedContainerWithGradientBorder className="">
+ {item.icon}
+ </RoundedContainerWithGradientBorder>
+ <h3 className="text-xl font-semibold text-transparent bg-clip-text bg-gradient-to-br from-white from-30% to-cyan-200 to-100% text-center text-normal mt-6">
+ {item.headline}
+ </h3>
+ <p className="text-white/80 text-center text-normal mt-4">
+ {item.description}
+ </p>
+ </div>
+ ))}
+ </div>
+ )}
+ </div>
+ </div>
+ </div>
+ </>)
+}
diff --git a/src/components/sections/PurpleHero.tsx b/src/components/sections/PurpleHero.tsx
@@ -0,0 +1,56 @@
+import { ArrowUpRight, ChevronRight, Globe2 } from "lucide-react";
+import { MeshGradient1 } from "../effects/MeshGradient.1";
+import { TopMenu } from "./TopMenu";
+import { Button } from "../ui/Button";
+import { FormattedMessage, useIntl } from "react-intl";
+import Link from "next/link";
+import { DAMUS_APP_STORE_URL, DAMUS_TESTFLIGHT_URL } from "@/lib/constants";
+import { motion } from "framer-motion";
+import Image from "next/image";
+import { RoundedContainerWithColorGradientBorder } from "../ui/RoundedContainerWithGradientBorder";
+
+export function PurpleHero() {
+ const intl = useIntl()
+
+ return (<>
+ <div
+ className="bg-black overflow-hidden relative min-h-screen"
+ >
+ <div className="absolute z-0 w-full h-full pointer-events-none">
+ <Image src="/stars-bg.webp" fill className="absolute top-0 left-0 object-contain object-center w-full h-full" alt="" aria-hidden="true" />
+ <MeshGradient1 className="-translate-x-1/3" />
+ </div>
+ <div className="container z-10 mx-auto px-6 pb-32 pt-12">
+ <TopMenu className="w-full" />
+ <div className="relative mb-32 flex flex-col items-center justify-center min-h-screen">
+ <div className="flex gap-x-4 items-center mb-6">
+ <RoundedContainerWithColorGradientBorder className="w-24 h-24 p-[1px]">
+ <Image src="logo-icon-dark.png" fill className="overflow-hidden w-full h-full object-fill shadow-xl rounded-2xl" alt="Damus Purple logo" />
+ </RoundedContainerWithColorGradientBorder>
+ <motion.h2 className="text-4xl md:text-8xl text-center text-transparent bg-clip-text bg-gradient-to-r from-damuspink-500 from-30% to-damuspink-600 to-100% font-semibold break-keep tracking-tight">
+ Purple
+ </motion.h2>
+ </div>
+ <motion.div
+ className="mt-10 md:mt-6 flex flex-col md:flex-row items-center md:items-center gap-y-4 gap-x-6"
+ style={{ opacity: 0 }}
+ animate={{ opacity: 1, transition: { delay: 1.5, duration: 1 } }}
+ >
+ <Link href={DAMUS_APP_STORE_URL} target="_blank">
+ <Button variant="default" className="w-full md:w-auto">
+ {intl.formatMessage({ id: "purple.hero.subscribe", defaultMessage: "Subscribe" })}
+ <ArrowUpRight className="ml-2" />
+ </Button>
+ </Link>
+ <Link href={DAMUS_TESTFLIGHT_URL} target="_blank">
+ <Button variant="link" className="w-full md:w-auto">
+ {intl.formatMessage({ id: "purple.hero.learn-more", defaultMessage: "Learn more" })}
+ <ArrowUpRight className="text-damuspink-600 ml-2" />
+ </Button>
+ </Link>
+ </motion.div>
+ </div>
+ </div>
+ </div>
+ </>)
+}
diff --git a/src/components/ui/RoundedContainerWithGradientBorder.tsx b/src/components/ui/RoundedContainerWithGradientBorder.tsx
@@ -11,4 +11,17 @@ export function RoundedContainerWithGradientBorder({ className, allItemsClassNam
</div>
</div>
)
-}-
\ No newline at end of file
+}
+
+export function RoundedContainerWithColorGradientBorder({ className, allItemsClassName, children }: { className?: string, allItemsClassName?: string, children: React.ReactNode }) {
+ return (
+ <div className={cn("relative w-24 h-24 flex justify-center items-center backdrop-blur-sm", allItemsClassName, className)}>
+ <div className="z-10 relative p-6 w-full h-full">
+ {children}
+ </div>
+ <div className={cn("absolute z-0 w-full h-full p-[1px] rounded-2xl bg-gradient-to-br from-damuspink-500 via-damuspink-500/20 to-deeppurple-700 opacity-40 shadow-lg", allItemsClassName)}>
+ <div className={cn("w-full h-full flex justify-center items-center rounded-2xl bg-gray-900", allItemsClassName)}/>
+ </div>
+ </div>
+ )
+}
diff --git a/src/pages/purple/index.tsx b/src/pages/purple/index.tsx
@@ -0,0 +1,41 @@
+import { Inter } from 'next/font/google'
+import { IntlProvider, useIntl } from 'react-intl'
+import English from "@/../content/compiled-locales/en.json";
+import Japanese from "@/../content/compiled-locales/ja.json";
+import { useEffect } from 'react';
+import { useState } from 'react';
+import { Purple } from '@/components/pages/purple';
+
+export default function HomePage() {
+ // Automatically detect the user's locale based on their browser settings
+ const [language, setLanguage] = useState("en");
+ const [messages, setMessages] = useState(English);
+
+ useEffect(() => {
+ setLanguage(navigator.language);
+ }, []);
+
+ useEffect(() => {
+ switch (language) {
+ case "en":
+ setMessages(English);
+ break;
+ case "ja":
+ setMessages(Japanese);
+ break;
+ default:
+ setMessages(English);
+ break;
+ }
+ }, [language]);
+
+ return (<>
+ <IntlProvider
+ locale={language}
+ messages={messages}
+ onError={() => null}>
+ <Purple />
+ </IntlProvider>
+ </>)
+}
+
diff --git a/tailwind.config.ts b/tailwind.config.ts
@@ -21,6 +21,9 @@ const config: Config = {
600: "#D34CD9",
500: "#F869B6",
},
+ "deeppurple": {
+ 700: "#BF25ED",
+ }
},
},
plugins: [],