Blend the verify tutorial into the step; remove it from /organizations
Add hideHeader, bare, and stacked props to VerifyTutorial. The how-to step now renders it borderless with the header hidden (single step header) and the demo card stacked full-width above the step list so it matches the button width below. Remove the tutorial from /organizations, leaving just the 'Start verifying' CTA card.
This commit is contained in:
@@ -512,7 +512,7 @@ function VerifierHowtoStep({ onFinish }: { onFinish: () => void }) {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<VerifyTutorial />
|
||||
<VerifyTutorial hideHeader bare stacked />
|
||||
|
||||
<Button onClick={onFinish} className="w-full h-12 text-base rounded-full">
|
||||
{t('onboarding.verifier.howto.finish')}
|
||||
|
||||
@@ -66,7 +66,24 @@ function usePrefersReducedMotion(): boolean {
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
export function VerifyTutorial({ className }: { className?: string }) {
|
||||
interface VerifyTutorialProps {
|
||||
className?: string;
|
||||
/** Hide the component's internal eyebrow/title/lede header (when the host
|
||||
* already provides one). */
|
||||
hideHeader?: boolean;
|
||||
/** Drop the bordered card chrome so it blends into the surrounding page. */
|
||||
bare?: boolean;
|
||||
/** Stack the demo full-width above the step list instead of the
|
||||
* side-by-side two-column layout. */
|
||||
stacked?: boolean;
|
||||
}
|
||||
|
||||
export function VerifyTutorial({
|
||||
className,
|
||||
hideHeader = false,
|
||||
bare = false,
|
||||
stacked = false,
|
||||
}: VerifyTutorialProps) {
|
||||
const { t } = useTranslation();
|
||||
const reducedMotion = usePrefersReducedMotion();
|
||||
|
||||
@@ -118,40 +135,50 @@ export function VerifyTutorial({ className }: { className?: string }) {
|
||||
return (
|
||||
<section
|
||||
className={cn(
|
||||
'rounded-2xl border border-primary/20 bg-gradient-to-br from-primary/[0.07] via-background to-background p-6 sm:p-8 shadow-sm',
|
||||
!bare &&
|
||||
'rounded-2xl border border-primary/20 bg-gradient-to-br from-primary/[0.07] via-background to-background p-6 sm:p-8 shadow-sm',
|
||||
className,
|
||||
)}
|
||||
aria-labelledby="verify-tutorial-title"
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex flex-wrap items-start justify-between gap-4 mb-8">
|
||||
<div className="max-w-md">
|
||||
<p className="inline-flex items-center gap-1.5 text-xs font-semibold tracking-widest uppercase text-primary mb-2">
|
||||
<BadgeCheck className="size-4" />
|
||||
{t('organizations.tutorial.eyebrow')}
|
||||
</p>
|
||||
<h3
|
||||
id="verify-tutorial-title"
|
||||
className="text-xl sm:text-2xl font-bold tracking-tight mb-2"
|
||||
>
|
||||
{t('organizations.tutorial.title')}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
{t('organizations.tutorial.lede')}
|
||||
</p>
|
||||
{!hideHeader && (
|
||||
<div className="flex flex-wrap items-start justify-between gap-4 mb-8">
|
||||
<div className="max-w-md">
|
||||
<p className="inline-flex items-center gap-1.5 text-xs font-semibold tracking-widest uppercase text-primary mb-2">
|
||||
<BadgeCheck className="size-4" />
|
||||
{t('organizations.tutorial.eyebrow')}
|
||||
</p>
|
||||
<h3
|
||||
id="verify-tutorial-title"
|
||||
className="text-xl sm:text-2xl font-bold tracking-tight mb-2"
|
||||
>
|
||||
{t('organizations.tutorial.title')}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
{t('organizations.tutorial.lede')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid gap-8 lg:grid-cols-2 lg:items-center">
|
||||
{/* ── Left: animated mock campaign card ───────────────────────── */}
|
||||
<div
|
||||
className={cn(
|
||||
stacked
|
||||
? 'space-y-6'
|
||||
: 'grid gap-8 lg:grid-cols-2 lg:items-center',
|
||||
)}
|
||||
>
|
||||
{/* ── Animated mock campaign card ──────────────────────────────── */}
|
||||
<DemoStage
|
||||
phaseIndex={phaseIndex}
|
||||
menuVisible={menuVisible}
|
||||
verified={verified}
|
||||
reducedMotion={reducedMotion}
|
||||
fullWidth={stacked}
|
||||
/>
|
||||
|
||||
{/* ── Right: step list, synced to the animation ───────────────── */}
|
||||
{/* ── Step list, synced to the animation ──────────────────────── */}
|
||||
<ol className="space-y-3">
|
||||
{stepCopy.map((step, i) => {
|
||||
const active = i === phaseIndex;
|
||||
@@ -212,6 +239,8 @@ interface DemoStageProps {
|
||||
menuVisible: boolean;
|
||||
verified: boolean;
|
||||
reducedMotion: boolean;
|
||||
/** Span the full container width instead of the narrow `max-w-sm` card. */
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
|
||||
function DemoStage({
|
||||
@@ -219,11 +248,18 @@ function DemoStage({
|
||||
menuVisible,
|
||||
verified,
|
||||
reducedMotion,
|
||||
fullWidth = false,
|
||||
}: DemoStageProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="relative mx-auto w-full max-w-sm select-none" aria-hidden="true">
|
||||
<div
|
||||
className={cn(
|
||||
'relative w-full select-none',
|
||||
fullWidth ? 'mx-0' : 'mx-auto max-w-sm',
|
||||
)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Mock campaign card */}
|
||||
<div className="overflow-hidden rounded-2xl border border-border/60 bg-card shadow-md">
|
||||
{/* Banner */}
|
||||
|
||||
@@ -8,13 +8,10 @@ import {
|
||||
ShieldCheck,
|
||||
} from 'lucide-react';
|
||||
|
||||
import { VerifyTutorial } from '@/components/organizations/VerifyTutorial';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
import { useCurrentUser } from '@/hooks/useCurrentUser';
|
||||
import { useOnboarding } from '@/contexts/onboardingContextDef';
|
||||
import { useVerifierStatement } from '@/hooks/useVerifierStatement';
|
||||
|
||||
/**
|
||||
* The /organizations page. A landing-style document modeled on the
|
||||
@@ -181,40 +178,32 @@ export function OrganizationsPage() {
|
||||
*/
|
||||
function VerifierEditor() {
|
||||
const { t } = useTranslation();
|
||||
const { user } = useCurrentUser();
|
||||
const { isVerifier } = useVerifierStatement(user?.pubkey);
|
||||
const { startSignup } = useOnboarding();
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<Card className="border-border/60 shadow-sm">
|
||||
<CardContent className="py-12 px-8 flex flex-col items-center gap-6 text-center">
|
||||
<div className="p-4 rounded-full bg-primary/10">
|
||||
<Building2 className="size-8 text-primary" />
|
||||
</div>
|
||||
<div className="space-y-2 max-w-sm">
|
||||
<h3 className="text-xl font-bold tracking-tight">
|
||||
{t('organizations.getStartedCard.title')}
|
||||
</h3>
|
||||
<p className="text-muted-foreground text-sm leading-relaxed">
|
||||
{t('organizations.getStartedCard.body')}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
size="lg"
|
||||
className="gap-2"
|
||||
onClick={() => startSignup({ role: 'verifier' })}
|
||||
>
|
||||
<BadgeCheck className="size-5" />
|
||||
{t('organizations.getStartedCard.cta')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Once the org's statement is live, teach them the actual
|
||||
verify gesture: the three-dots menu on any campaign card. */}
|
||||
{isVerifier && <VerifyTutorial />}
|
||||
</div>
|
||||
<Card className="border-border/60 shadow-sm">
|
||||
<CardContent className="py-12 px-8 flex flex-col items-center gap-6 text-center">
|
||||
<div className="p-4 rounded-full bg-primary/10">
|
||||
<Building2 className="size-8 text-primary" />
|
||||
</div>
|
||||
<div className="space-y-2 max-w-sm">
|
||||
<h3 className="text-xl font-bold tracking-tight">
|
||||
{t('organizations.getStartedCard.title')}
|
||||
</h3>
|
||||
<p className="text-muted-foreground text-sm leading-relaxed">
|
||||
{t('organizations.getStartedCard.body')}
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
size="lg"
|
||||
className="gap-2"
|
||||
onClick={() => startSignup({ role: 'verifier' })}
|
||||
>
|
||||
<BadgeCheck className="size-5" />
|
||||
{t('organizations.getStartedCard.cta')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user