damus.io

damus.io website
git clone git://jb55.com/damus.io
Log | Files | Refs | README | LICENSE

commit 52250d3192fc882ed92078c7a93a002e314ae4ed
parent ac86a41c0786c8cea6f930faf2875380a1f6f91c
Author: Daniel D’Aquino <daniel@daquino.me>
Date:   Sat, 30 Dec 2023 00:35:39 -0800

Add basic FAQ section

Diffstat:
Mcontent/compiled-locales/en.json | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcontent/locales/en.json | 45+++++++++++++++++++++++++++++++++++++++++++++
Mpackage-lock.json | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpackage.json | 1+
Msrc/components/pages/purple.tsx | 2++
Asrc/components/sections/PurpleFAQ.tsx | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/ui/Accordion.tsx | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtailwind.config.ts | 14++++++++++++++
8 files changed, 333 insertions(+), 0 deletions(-)

diff --git a/content/compiled-locales/en.json b/content/compiled-locales/en.json @@ -299,6 +299,96 @@ "value": "shortName" } ], + "purple.benefits.benefit1.description": [ + { + "type": 0, + "value": "Support Damus development to help build the future of decentralized communication on the web." + } + ], + "purple.benefits.benefit1.name": [ + { + "type": 0, + "value": "Help Build The Future" + } + ], + "purple.benefits.benefit2.description": [ + { + "type": 0, + "value": "Be the first to access upcoming premium features: Automatic translations, longer note storage, and more" + } + ], + "purple.benefits.benefit2.name": [ + { + "type": 0, + "value": "Exclusive features" + } + ], + "purple.benefits.benefit3.description": [ + { + "type": 0, + "value": "Get a special badge on your profile to show everyone your contribution to Freedom tech" + } + ], + "purple.benefits.benefit3.name": [ + { + "type": 0, + "value": "Supporter Badge" + } + ], + "purple.benefits.description": [ + { + "type": 0, + "value": "Help us stay independent in our mission for Freedom tech with our Purple subscription, and look cool doing it!" + } + ], + "purple.benefits.headline": [ + { + "type": 0, + "value": "Get more from Damus." + } + ], + "purple.faq.answer.1.a": [ + { + "type": 0, + "value": "Oh yeah! You can pay with Lightning if you register on the website. For the iOS app, you can pay with Apple Pay." + } + ], + "purple.faq.answer.2.a": [ + { + "type": 0, + "value": "Unfortunately not. Apple doesn’t allow apps to accept Lightning payments. but you can register on the website and pay with Lightning there." + } + ], + "purple.faq.headline": [ + { + "type": 0, + "value": "Frequent Questions" + } + ], + "purple.faq.question.1.q": [ + { + "type": 0, + "value": "Can I pay with Lightning?" + } + ], + "purple.faq.question.2.q": [ + { + "type": 0, + "value": "But can I pay with lightning via the app?" + } + ], + "purple.hero.learn-more": [ + { + "type": 0, + "value": "Learn more" + } + ], + "purple.hero.subscribe": [ + { + "type": 0, + "value": "Subscribe" + } + ], "roles.brand-ambassador": [ { "type": 0, diff --git a/content/locales/en.json b/content/locales/en.json @@ -143,6 +143,51 @@ "meet_the_team.view_profile": { "string": "Follow {shortName}" }, + "purple.benefits.benefit1.description": { + "string": "Support Damus development to help build the future of decentralized communication on the web." + }, + "purple.benefits.benefit1.name": { + "string": "Help Build The Future" + }, + "purple.benefits.benefit2.description": { + "string": "Be the first to access upcoming premium features: Automatic translations, longer note storage, and more" + }, + "purple.benefits.benefit2.name": { + "string": "Exclusive features" + }, + "purple.benefits.benefit3.description": { + "string": "Get a special badge on your profile to show everyone your contribution to Freedom tech" + }, + "purple.benefits.benefit3.name": { + "string": "Supporter Badge" + }, + "purple.benefits.description": { + "string": "Help us stay independent in our mission for Freedom tech with our Purple subscription, and look cool doing it!" + }, + "purple.benefits.headline": { + "string": "Get more from Damus." + }, + "purple.faq.answer.1.a": { + "string": "Oh yeah! You can pay with Lightning if you register on the website. For the iOS app, you can pay with Apple Pay." + }, + "purple.faq.answer.2.a": { + "string": "Unfortunately not. Apple doesn’t allow apps to accept Lightning payments. but you can register on the website and pay with Lightning there." + }, + "purple.faq.headline": { + "string": "Frequent Questions" + }, + "purple.faq.question.1.q": { + "string": "Can I pay with Lightning?" + }, + "purple.faq.question.2.q": { + "string": "But can I pay with lightning via the app?" + }, + "purple.hero.learn-more": { + "string": "Learn more" + }, + "purple.hero.subscribe": { + "string": "Subscribe" + }, "roles.brand-ambassador": { "string": "Brand Ambassador" }, diff --git a/package-lock.json b/package-lock.json @@ -8,6 +8,7 @@ "name": "damus-website", "version": "0.1.0", "dependencies": { + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", @@ -507,6 +508,67 @@ "@babel/runtime": "^7.13.10" } }, + "node_modules/@radix-ui/react-accordion": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.1.2.tgz", + "integrity": "sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-collapsible": "1.0.3", + "@radix-ui/react-collection": "1.0.3", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz", + "integrity": "sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-id": "1.0.1", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-controllable-state": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz", diff --git a/package.json b/package.json @@ -13,6 +13,7 @@ "i18n": "npm run extract:i18n && npm run compile:i18n" }, "dependencies": { + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", diff --git a/src/components/pages/purple.tsx b/src/components/pages/purple.tsx @@ -13,6 +13,7 @@ import { Contribute } from '@/components/sections/Contribute'; import { FinalCTA } from '@/components/sections/FinalCTA'; import { Benefits } from '@/components/sections/Benefits'; import { PurpleBenefits } from '../sections/PurpleBenefits'; +import { PurpleFAQ } from '../sections/PurpleFAQ'; const inter = Inter({ subsets: ['latin'] }) @@ -28,6 +29,7 @@ export function Purple() { <main style={{ scrollBehavior: "smooth" }}> <PurpleHero /> <PurpleBenefits/> + <PurpleFAQ/> <FinalCTA /> <Footer /> </main> diff --git a/src/components/sections/PurpleFAQ.tsx b/src/components/sections/PurpleFAQ.tsx @@ -0,0 +1,61 @@ +import { FormattedMessage, useIntl } from "react-intl"; +import { motion } from "framer-motion"; +import { RoundedContainerWithGradientBorder } from "../ui/RoundedContainerWithGradientBorder"; +import { cn } from "@/lib/utils"; +import { Award, Badge, Heart, Joystick, KeyRound, Scale, Stars, Wallet } from "lucide-react"; +import { MeshGradient3 } from "../effects/MeshGradient.3"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/Accordion" + +const faq = [ + { + questionIntlString: "purple.faq.1.q", + answerIntlString: "purple.faq.1.a", + }, + { + questionIntlString: "purple.faq.2.q", + answerIntlString: "purple.faq.2.a", + } +] + + +export function PurpleFAQ({ className }: { className?: string }) { + const intl = useIntl() + + // This type of structure is necessary in this case to make strings get picked up by `npm run i18n` + const faqIntlStrings: Record<string, string> = { + "purple.faq.1.q": intl.formatMessage({ id: "purple.faq.question.1.q", defaultMessage: "Can I pay with Lightning?" }), + "purple.faq.1.a": intl.formatMessage({ id: "purple.faq.answer.1.a", defaultMessage: "Oh yeah! You can pay with Lightning if you register on the website. For the iOS app, you can pay with Apple Pay." }), + "purple.faq.2.q": intl.formatMessage({ id: "purple.faq.question.2.q", defaultMessage: "But can I pay with lightning via the app?" }), + "purple.faq.2.a": intl.formatMessage({ id: "purple.faq.answer.2.a", defaultMessage: "Unfortunately not. Apple doesn’t allow apps to accept Lightning payments. but you can register on the website and pay with Lightning there." }), + } + + 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.faq.headline", defaultMessage: "Frequent Questions" })} + </motion.h2> + </div> + </div> + <Accordion type="single" collapsible className="w-full text-white max-w-3xl mx-auto"> + {faq.map((item, index) => ( + <AccordionItem value={`item-${index}`} key={index}> + <AccordionTrigger>{faqIntlStrings[item.questionIntlString]}</AccordionTrigger> + <AccordionContent> + {faqIntlStrings[item.answerIntlString]} + </AccordionContent> + </AccordionItem> + ))} + </Accordion> + </div> + </div> + </>) +} diff --git a/src/components/ui/Accordion.tsx b/src/components/ui/Accordion.tsx @@ -0,0 +1,58 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDownIcon } from "lucide-react" + +import { cn } from "@/lib/utils" + +const Accordion = AccordionPrimitive.Root + +const AccordionItem = React.forwardRef< + React.ElementRef<typeof AccordionPrimitive.Item>, + React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item> +>(({ className, ...props }, ref) => ( + <AccordionPrimitive.Item + ref={ref} + className={cn("border-b", className)} + {...props} + /> +)) +AccordionItem.displayName = "AccordionItem" + +const AccordionTrigger = React.forwardRef< + React.ElementRef<typeof AccordionPrimitive.Trigger>, + React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger> +>(({ className, children, ...props }, ref) => ( + <AccordionPrimitive.Header className="flex"> + <AccordionPrimitive.Trigger + ref={ref} + className={cn( + "flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180", + className + )} + {...props} + > + {children} + <ChevronDownIcon className="h-4 w-4 shrink-0 text-white/70 transition-transform duration-200" /> + </AccordionPrimitive.Trigger> + </AccordionPrimitive.Header> +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef<typeof AccordionPrimitive.Content>, + React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content> +>(({ className, children, ...props }, ref) => ( + <AccordionPrimitive.Content + ref={ref} + className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down" + {...props} + > + <div className={cn("pb-4 pt-0", className)}>{children}</div> + </AccordionPrimitive.Content> +)) +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } + diff --git a/tailwind.config.ts b/tailwind.config.ts @@ -14,6 +14,20 @@ const config: Config = { 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', }, + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, }, colors: { ...colors,