commit ad1b86abf81554c0e80f863e8696e8d6cb0c9317
parent 4a18875581def6ce69a0c93a0a3426e91b850edd
Author: William Casarin <jb55@jb55.com>
Date: Tue, 27 Feb 2024 11:04:21 -0800
Merge remote-tracking branch 'github/master'
Diffstat:
9 files changed, 315 insertions(+), 37 deletions(-)
diff --git a/content/compiled-locales/en.json b/content/compiled-locales/en.json
@@ -253,12 +253,6 @@
"value": "Download now"
}
],
- "home.hero.follow-us-on-nostr": [
- {
- "type": 0,
- "value": "Follow us on Nostr"
- }
- ],
"home.hero.headline": [
{
"type": 0,
@@ -338,7 +332,7 @@
"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!"
+ "value": "Help us stay independent in our mission for Freedom tech with our Purple membership, and look cool doing it!"
}
],
"purple.benefits.headline": [
@@ -347,6 +341,90 @@
"value": "Get more from Damus."
}
],
+ "purple.checkout.back": [
+ {
+ "type": 0,
+ "value": "Go back"
+ }
+ ],
+ "purple.checkout.continue": [
+ {
+ "type": 0,
+ "value": "Continue in the app to set it up"
+ }
+ ],
+ "purple.checkout.continue.hide-qr": [
+ {
+ "type": 0,
+ "value": "Hide QR code"
+ }
+ ],
+ "purple.checkout.continue.show-qr": [
+ {
+ "type": 0,
+ "value": "Show QR code"
+ }
+ ],
+ "purple.checkout.open-in-app": [
+ {
+ "type": 0,
+ "value": "Open in Damus"
+ }
+ ],
+ "purple.checkout.open-in-wallet": [
+ {
+ "type": 0,
+ "value": "Open in wallet"
+ }
+ ],
+ "purple.checkout.payment-received": [
+ {
+ "type": 0,
+ "value": "Payment received"
+ }
+ ],
+ "purple.checkout.purchased-for": [
+ {
+ "type": 0,
+ "value": "Purchased Damus Purple for:"
+ }
+ ],
+ "purple.checkout.purchasing-for": [
+ {
+ "type": 0,
+ "value": "Verified. Purchasing Damus Purple for:"
+ }
+ ],
+ "purple.checkout.step-1": [
+ {
+ "type": 0,
+ "value": "Choose your plan"
+ }
+ ],
+ "purple.checkout.step-2": [
+ {
+ "type": 0,
+ "value": "Verify your npub"
+ }
+ ],
+ "purple.checkout.step-3": [
+ {
+ "type": 0,
+ "value": "Lightning payment"
+ }
+ ],
+ "purple.checkout.title": [
+ {
+ "type": 0,
+ "value": "Checkout"
+ }
+ ],
+ "purple.checkout.waiting-for-payment": [
+ {
+ "type": 0,
+ "value": "Waiting for payment"
+ }
+ ],
"purple.faq.1.a": [
{
"type": 0,
@@ -374,7 +452,7 @@
"purple.faq.3.a": [
{
"type": 0,
- "value": "Damus Purple is a paid subscription to Damus that gives you access to exclusive features, and helps us fund the project"
+ "value": "Damus Purple is a paid membership to Damus that gives you access to exclusive features, and helps us fund the project"
}
],
"purple.faq.3.q": [
@@ -449,6 +527,12 @@
"value": "Frequent Questions"
}
],
+ "purple.final_cta.become-a-member": [
+ {
+ "type": 0,
+ "value": "Become a member"
+ }
+ ],
"purple.final_cta.headline": [
{
"type": 0,
@@ -464,31 +548,31 @@
"purple.final_cta.subheadline": [
{
"type": 0,
- "value": "for as little as U$6.99/month"
+ "value": "for as little as 15k sats/month"
}
],
- "purple.final_cta.subscribe": [
+ "purple.final_cta.text": [
{
"type": 0,
- "value": "Subscribe"
+ "value": "Contribute to the future of the free internet, access exclusive features, and look cool doing it."
}
],
- "purple.final_cta.text": [
+ "purple.hero.become-a-member": [
{
"type": 0,
- "value": "Contribute to the future of the free internet, access exclusive features, and look cool doing it."
+ "value": "Become a member"
}
],
- "purple.hero.learn-more": [
+ "purple.hero.description": [
{
"type": 0,
- "value": "Learn more"
+ "value": "For free-speech maximalists"
}
],
- "purple.hero.subscribe": [
+ "purple.hero.learn-more": [
{
"type": 0,
- "value": "Subscribe"
+ "value": "Learn more"
}
],
"roles.brand-ambassador": [
diff --git a/content/locales/en.json b/content/locales/en.json
@@ -122,9 +122,6 @@
"home.hero.download_now": {
"string": "Download now"
},
- "home.hero.follow-us-on-nostr": {
- "string": "Follow us on Nostr"
- },
"home.hero.headline": {
"string": "The social network you control"
},
@@ -162,11 +159,53 @@
"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!"
+ "string": "Help us stay independent in our mission for Freedom tech with our Purple membership, and look cool doing it!"
},
"purple.benefits.headline": {
"string": "Get more from Damus."
},
+ "purple.checkout.back": {
+ "string": "Go back"
+ },
+ "purple.checkout.continue": {
+ "string": "Continue in the app to set it up"
+ },
+ "purple.checkout.continue.hide-qr": {
+ "string": "Hide QR code"
+ },
+ "purple.checkout.continue.show-qr": {
+ "string": "Show QR code"
+ },
+ "purple.checkout.open-in-app": {
+ "string": "Open in Damus"
+ },
+ "purple.checkout.open-in-wallet": {
+ "string": "Open in wallet"
+ },
+ "purple.checkout.payment-received": {
+ "string": "Payment received"
+ },
+ "purple.checkout.purchased-for": {
+ "string": "Purchased Damus Purple for:"
+ },
+ "purple.checkout.purchasing-for": {
+ "string": "Verified. Purchasing Damus Purple for:"
+ },
+ "purple.checkout.step-1": {
+ "string": "Choose your plan"
+ },
+ "purple.checkout.step-2": {
+ "string": "Verify your npub"
+ },
+ "purple.checkout.step-3": {
+ "string": "Lightning payment"
+ },
+ "purple.checkout.title": {
+ "string": "Checkout"
+ },
+ "purple.checkout.waiting-for-payment": {
+ "string": "Waiting for payment"
+ },
"purple.faq.1.a": {
"string": "Yes! You can pay with Lightning if you register on the website. For the iOS app, you can pay with Apple Pay."
},
@@ -180,7 +219,7 @@
"string": "Can I pay with lightning via the app?"
},
"purple.faq.3.a": {
- "string": "Damus Purple is a paid subscription to Damus that gives you access to exclusive features, and helps us fund the project"
+ "string": "Damus Purple is a paid membership to Damus that gives you access to exclusive features, and helps us fund the project"
},
"purple.faq.3.q": {
"string": "What is Damus Purple?"
@@ -218,6 +257,9 @@
"purple.faq.headline": {
"string": "Frequent Questions"
},
+ "purple.final_cta.become-a-member": {
+ "string": "Become a member"
+ },
"purple.final_cta.headline": {
"string": "Get Purple today!"
},
@@ -225,20 +267,20 @@
"string": "Open in Damus"
},
"purple.final_cta.subheadline": {
- "string": "for as little as U$6.99/month"
- },
- "purple.final_cta.subscribe": {
- "string": "Subscribe"
+ "string": "for as little as 15k sats/month"
},
"purple.final_cta.text": {
"string": "Contribute to the future of the free internet, access exclusive features, and look cool doing it."
},
+ "purple.hero.become-a-member": {
+ "string": "Become a member"
+ },
+ "purple.hero.description": {
+ "string": "For free-speech maximalists"
+ },
"purple.hero.learn-more": {
"string": "Learn more"
},
- "purple.hero.subscribe": {
- "string": "Subscribe"
- },
"roles.brand-ambassador": {
"string": "Brand Ambassador"
},
diff --git a/src/components/sections/PurpleBanner.tsx b/src/components/sections/PurpleBanner.tsx
@@ -37,7 +37,7 @@ export function PurpleBanner() {
</div>
<div className="text-purple-200/70 text-md md:text-lg text-center max-w-2xl mb-2 break-keep">
{/* TODO: Localize */}
- Help us stay independent in our mission for Freedom tech with our Purple subscription, get exclusive benefits, and look cool doing it!
+ Help us stay independent in our mission for Freedom tech with our Purple membership, get exclusive benefits, and look cool doing it!
</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 w-full md:w-auto"
@@ -46,7 +46,7 @@ export function PurpleBanner() {
>
<Link href="/purple/checkout" className="w-full md:w-auto">
<Button variant="default" className="w-full">
- {intl.formatMessage({ id: "purple.hero.subscribe", defaultMessage: "Subscribe" })}
+ {intl.formatMessage({ id: "purple.hero.become-a-member", defaultMessage: "Become a member" })}
</Button>
</Link>
<Link href="/purple" className="w-full md:w-auto">
diff --git a/src/components/sections/PurpleBenefits.tsx b/src/components/sections/PurpleBenefits.tsx
@@ -41,7 +41,7 @@ export function PurpleBenefits({ className }: { className?: string }) {
{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!" })}
+ {intl.formatMessage({ id: "purple.benefits.description", defaultMessage: "Help us stay independent in our mission for Freedom tech with our Purple membership, and look cool doing it!" })}
</motion.div>
</div>
{(intl.locale != "ja" || process.env.FORCE_LOAD_ALL_JA_SECTIONS) && (
diff --git a/src/components/sections/PurpleCheckout.tsx b/src/components/sections/PurpleCheckout.tsx
@@ -312,10 +312,18 @@ export function PurpleCheckout() {
{productTemplates ? Object.entries(productTemplates).map(([name, productTemplate]) => (
<button
key={name}
- className={`flex flex-col items-center justify-center p-3 border rounded-lg ${name == lnCheckout?.product_template_name ? "border-green-500" : "border-purple-200/50"} disabled:opacity-50 disabled:cursor-not-allowed`}
+ className={`relative flex flex-col items-center justify-center p-3 pt-4 border rounded-lg ${name == lnCheckout?.product_template_name ? "border-green-500" : "border-purple-200/50"} disabled:opacity-50 disabled:cursor-not-allowed`}
onClick={() => selectProduct(name)}
disabled={lnCheckout?.verified_pubkey != null}
>
+ {productTemplate.special_label && (
+ <div className="absolute top-0 right-0 -mt-4 -mr-2 bg-gradient-to-r from-damuspink-500 to-damuspink-600 rounded-full p-1 px-3">
+ <div className="text-white text-xs font-semibold">
+ {productTemplate.special_label}
+ </div>
+ </div>
+ )}
+
<div className="text-purple-200/50 font-normal text-sm">
{productTemplate.description}
</div>
@@ -374,7 +382,7 @@ export function PurpleCheckout() {
/>
{lnCheckout?.invoice?.bolt11 && !lnCheckout?.invoice?.paid &&
<>
- <QRCodeSVG value={"lightning:" + lnCheckout.invoice.bolt11} className="mt-6 w-[300px] h-[300px] max-w-full max-h-full mx-auto mb-6" />
+ <QRCodeSVG value={"lightning:" + lnCheckout.invoice.bolt11} className="mt-6 w-[300px] h-[300px] max-w-full max-h-full mx-auto mb-6 border-[5px] border-white" />
{/* Shows the bolt11 in for copy-paste with a copy and paste button */}
<div className="flex items-center justify-between rounded-md bg-purple-200/20">
<div className="w-full text-sm text-purple-200/50 font-normal px-4 py-2 overflow-x-scroll">
@@ -482,6 +490,7 @@ interface LNCheckout {
interface ProductTemplate {
description: string,
+ special_label?: string | null,
amount_msat: number,
expiry: number,
}
diff --git a/src/components/sections/PurpleFAQ.tsx b/src/components/sections/PurpleFAQ.tsx
@@ -17,7 +17,7 @@ export function PurpleFAQ({ className }: { className?: string }) {
const faq = [
{
question: intl.formatMessage({ id: "purple.faq.3.q", defaultMessage: "What is Damus Purple?" }),
- answer: intl.formatMessage({ id: "purple.faq.3.a", defaultMessage: "Damus Purple is a paid subscription to Damus that gives you access to exclusive features, and helps us fund the project" }),
+ answer: intl.formatMessage({ id: "purple.faq.3.a", defaultMessage: "Damus Purple is a paid membership to Damus that gives you access to exclusive features, and helps us fund the project" }),
},
{
question: intl.formatMessage({ id: "purple.faq.4.q", defaultMessage: "What are the exclusive features?" }),
diff --git a/src/components/sections/PurpleFinalCTA.tsx b/src/components/sections/PurpleFinalCTA.tsx
@@ -41,7 +41,7 @@ export function PurpleFinalCTA({ className }: { className?: string }) {
>
<Link href="/purple/checkout" className="w-full md:w-auto">
<Button variant="default" className="w-full">
- {intl.formatMessage({ id: "purple.final_cta.subscribe", defaultMessage: "Subscribe" })}
+ {intl.formatMessage({ id: "purple.final_cta.become-a-member", defaultMessage: "Become a member" })}
</Button>
</Link>
<Link href="damus:purple:landing" target="_blank" className="w-full md:w-auto">
diff --git a/src/components/sections/PurpleHero.tsx b/src/components/sections/PurpleHero.tsx
@@ -39,7 +39,7 @@ export function PurpleHero() {
>
<Link href="/purple/checkout" className="w-full md:w-auto">
<Button variant="default" className="w-full">
- {intl.formatMessage({ id: "purple.hero.subscribe", defaultMessage: "Subscribe" })}
+ {intl.formatMessage({ id: "purple.hero.become-a-member", defaultMessage: "Become a member" })}
</Button>
</Link>
<Link href="#benefits" className="w-full md:w-auto">
diff --git a/src/components/ui/AlertDialog.tsx b/src/components/ui/AlertDialog.tsx
@@ -0,0 +1,143 @@
+// Based on https://ui.shadcn.com and MIT licensed.
+
+"use client"
+
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "./Button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
+>(({ className, ...props }, ref) => (
+ <AlertDialogPrimitive.Overlay
+ className={cn(
+ "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
+ className
+ )}
+ {...props}
+ ref={ref}
+ />
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef<typeof AlertDialogPrimitive.Content>,
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
+>(({ className, ...props }, ref) => (
+ <AlertDialogPortal>
+ <AlertDialogOverlay />
+ <AlertDialogPrimitive.Content
+ ref={ref}
+ className={cn(
+ "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-white p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
+ className
+ )}
+ {...props}
+ />
+ </AlertDialogPortal>
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes<HTMLDivElement>) => (
+ <div
+ className={cn(
+ "flex flex-col space-y-2 text-center sm:text-left",
+ className
+ )}
+ {...props}
+ />
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes<HTMLDivElement>) => (
+ <div
+ className={cn(
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
+ className
+ )}
+ {...props}
+ />
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef<typeof AlertDialogPrimitive.Title>,
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
+>(({ className, ...props }, ref) => (
+ <AlertDialogPrimitive.Title
+ ref={ref}
+ className={cn("text-lg font-semibold", className)}
+ {...props}
+ />
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef<typeof AlertDialogPrimitive.Description>,
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
+>(({ className, ...props }, ref) => (
+ <AlertDialogPrimitive.Description
+ ref={ref}
+ className={cn("text-sm text-gray-500", className)}
+ {...props}
+ />
+))
+AlertDialogDescription.displayName =
+ AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef<typeof AlertDialogPrimitive.Action>,
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
+>(({ className, ...props }, ref) => (
+ <AlertDialogPrimitive.Action
+ ref={ref}
+ className={cn(buttonVariants(), className)}
+ {...props}
+ />
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
+ React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
+>(({ className, ...props }, ref) => (
+ <AlertDialogPrimitive.Cancel
+ ref={ref}
+ className={cn(
+ buttonVariants({ variant: "default" }),
+ "mt-2 sm:mt-0",
+ className
+ )}
+ {...props}
+ />
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}