Style Donor/Activist Guide buttons as campaign-style cover cards
The two Help page guide buttons now mirror CampaignCard's structure: a 16:9 cover image on top with a soft hover scale, a rounded icon badge floating in the top-left corner, and title + description in the body. Donor Guide reuses the World Liberty Congress hero image already used on the Donor Guide page; Activist Guide reuses the 'Raised Fists' image that opens the Activist Guide's hero gallery, so each button visually previews its destination.
This commit is contained in:
+56
-18
@@ -1,12 +1,25 @@
|
||||
import { useSeoMeta } from '@unhead/react';
|
||||
import { ChevronRight, HandHeart, HelpCircle, Megaphone, Shield } from 'lucide-react';
|
||||
import { HandHeart, HelpCircle, Megaphone, Shield } from 'lucide-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
import { useLayoutOptions } from '@/contexts/LayoutContext';
|
||||
import { PageHeader } from '@/components/PageHeader';
|
||||
import { TeamSoapboxCard } from '@/components/TeamSoapboxCard';
|
||||
import { HelpFAQSection } from '@/components/HelpFAQSection';
|
||||
import { DEFAULT_ACTION_COVERS } from '@/lib/defaultActionCovers';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/** Cover image used on the Donor Guide button. Mirrors the Donor Guide hero. */
|
||||
const DONOR_GUIDE_COVER = '/hero/wlc-1.webp';
|
||||
|
||||
/**
|
||||
* Cover image used on the Activist Guide button. Picks the same "Raised
|
||||
* Fists" image that opens the Activist Guide's hero gallery, so the button
|
||||
* visually previews the destination.
|
||||
*/
|
||||
const ACTIVIST_GUIDE_COVER = DEFAULT_ACTION_COVERS[0].url;
|
||||
|
||||
export function HelpPage() {
|
||||
const { config } = useAppContext();
|
||||
@@ -21,19 +34,21 @@ export function HelpPage() {
|
||||
<main className="min-h-screen pb-16 sidebar:pb-0">
|
||||
<PageHeader title="Help" icon={<HelpCircle className="size-5" />} />
|
||||
|
||||
{/* Two large guide buttons */}
|
||||
<div className="px-4 pt-4 grid gap-3 sm:grid-cols-2">
|
||||
<GuideButton
|
||||
{/* Two large guide cards */}
|
||||
<div className="px-4 pt-4 grid gap-4 sm:grid-cols-2">
|
||||
<GuideCard
|
||||
to="/help/donors"
|
||||
icon={<HandHeart className="size-6" />}
|
||||
icon={<HandHeart className="size-5" />}
|
||||
title="Donor Guide"
|
||||
description="How to support activists privately and safely."
|
||||
cover={DONOR_GUIDE_COVER}
|
||||
/>
|
||||
<GuideButton
|
||||
<GuideCard
|
||||
to="/help/activists"
|
||||
icon={<Megaphone className="size-6" />}
|
||||
icon={<Megaphone className="size-5" />}
|
||||
title="Activist Guide"
|
||||
description="Receiving donations and cashing out privately."
|
||||
cover={ACTIVIST_GUIDE_COVER}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -65,27 +80,50 @@ export function HelpPage() {
|
||||
);
|
||||
}
|
||||
|
||||
interface GuideButtonProps {
|
||||
interface GuideCardProps {
|
||||
to: string;
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
description: string;
|
||||
cover: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function GuideButton({ to, icon, title, description }: GuideButtonProps) {
|
||||
/**
|
||||
* Visually echoes `CampaignCard` so the Help page's two long-form guides
|
||||
* read like content cards rather than utility buttons.
|
||||
*/
|
||||
function GuideCard({ to, icon, title, description, cover, className }: GuideCardProps) {
|
||||
return (
|
||||
<Link
|
||||
to={to}
|
||||
className="group flex items-center gap-4 rounded-xl border bg-card p-4 text-left shadow-sm transition-colors hover:bg-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
className={cn(
|
||||
'group block rounded-xl overflow-hidden focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background motion-safe:transition-transform motion-safe:duration-200 motion-safe:hover:-translate-y-0.5',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="flex size-12 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary">
|
||||
{icon}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="font-semibold leading-snug">{title}</p>
|
||||
<p className="text-sm text-muted-foreground leading-snug">{description}</p>
|
||||
</div>
|
||||
<ChevronRight className="size-5 shrink-0 text-muted-foreground transition-transform group-hover:translate-x-0.5" />
|
||||
<Card className="overflow-hidden border-border/70 shadow-sm motion-safe:transition-shadow motion-safe:duration-200 group-hover:shadow-lg h-full flex flex-col">
|
||||
{/* Cover image */}
|
||||
<div className="relative w-full aspect-[16/9] bg-gradient-to-br from-primary/15 via-primary/5 to-secondary">
|
||||
<img
|
||||
src={cover}
|
||||
alt=""
|
||||
loading="lazy"
|
||||
className="absolute inset-0 size-full object-cover motion-safe:transition-transform motion-safe:duration-300 group-hover:scale-[1.02]"
|
||||
/>
|
||||
{/* Bottom gradient for legibility of the icon badge */}
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-background/40 via-transparent to-transparent pointer-events-none" />
|
||||
<div className="absolute top-3 left-3 flex size-10 items-center justify-center rounded-full bg-background/90 backdrop-blur text-primary shadow-sm">
|
||||
{icon}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="flex flex-col gap-1.5 p-5 flex-1">
|
||||
<h3 className="font-bold leading-tight tracking-tight text-lg">{title}</h3>
|
||||
<p className="text-sm text-muted-foreground leading-snug">{description}</p>
|
||||
</div>
|
||||
</Card>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user