Add animated verify-campaign tutorial after publishing statement
Once an organization publishes its verifier statement on /organizations, show an interactive walkthrough demonstrating how to verify a campaign: a looping three-step animation on a mock campaign card where a cursor opens the three-dots menu and selects 'Verify this campaign'. Step list is clickable to scrub; motion is gated behind prefers-reduced-motion.
This commit is contained in:
@@ -0,0 +1,337 @@
|
||||
import { useEffect, useReducer, useRef } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
BadgeCheck,
|
||||
MoreHorizontal,
|
||||
MousePointer2,
|
||||
} from 'lucide-react';
|
||||
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/**
|
||||
* An animated, interactive tutorial shown on /organizations once an
|
||||
* organization has published its verifier statement. It demonstrates the
|
||||
* exact gesture a verifier uses to vouch for a campaign: tapping the
|
||||
* three-dots (kebab) button on a campaign card and choosing
|
||||
* "Verify this campaign".
|
||||
*
|
||||
* The component renders a faithful mock campaign card and drives a small
|
||||
* three-step state machine that mimics a cursor opening the kebab menu and
|
||||
* clicking the verify item. It auto-advances on a timer, loops, and exposes
|
||||
* clickable step dots so users can scrub. Motion is fully gated behind
|
||||
* `motion-safe:` / a `prefers-reduced-motion` check — with reduced motion the
|
||||
* cursor and looping are disabled and the final state is shown statically.
|
||||
*/
|
||||
|
||||
type Phase = 'idle' | 'menuOpen' | 'verified';
|
||||
|
||||
const PHASE_ORDER: Phase[] = ['idle', 'menuOpen', 'verified'];
|
||||
|
||||
// How long each phase is held before auto-advancing (ms).
|
||||
const PHASE_DURATION: Record<Phase, number> = {
|
||||
idle: 2200,
|
||||
menuOpen: 2600,
|
||||
verified: 3000,
|
||||
};
|
||||
|
||||
interface State {
|
||||
phase: Phase;
|
||||
/** Bumps on every manual interaction to pause autoplay briefly. */
|
||||
paused: boolean;
|
||||
}
|
||||
|
||||
type Action =
|
||||
| { type: 'advance' }
|
||||
| { type: 'goto'; phase: Phase };
|
||||
|
||||
function reducer(state: State, action: Action): State {
|
||||
switch (action.type) {
|
||||
case 'advance': {
|
||||
const idx = PHASE_ORDER.indexOf(state.phase);
|
||||
const next = PHASE_ORDER[(idx + 1) % PHASE_ORDER.length];
|
||||
return { phase: next, paused: false };
|
||||
}
|
||||
case 'goto':
|
||||
return { phase: action.phase, paused: true };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
function usePrefersReducedMotion(): boolean {
|
||||
const ref = useRef(false);
|
||||
if (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {
|
||||
ref.current = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
}
|
||||
return ref.current;
|
||||
}
|
||||
|
||||
export function VerifyTutorial({ className }: { className?: string }) {
|
||||
const { t } = useTranslation();
|
||||
const reducedMotion = usePrefersReducedMotion();
|
||||
|
||||
const [state, dispatch] = useReducer(reducer, {
|
||||
phase: (reducedMotion ? 'verified' : 'idle') as Phase,
|
||||
paused: false,
|
||||
});
|
||||
|
||||
// Autoplay timer. Disabled under reduced motion, or while paused after a
|
||||
// manual interaction (resumes on the next phase change).
|
||||
useEffect(() => {
|
||||
if (reducedMotion || state.paused) return;
|
||||
const id = window.setTimeout(
|
||||
() => dispatch({ type: 'advance' }),
|
||||
PHASE_DURATION[state.phase],
|
||||
);
|
||||
return () => window.clearTimeout(id);
|
||||
}, [state.phase, state.paused, reducedMotion]);
|
||||
|
||||
// When a user scrubs (paused), resume autoplay after a grace period.
|
||||
useEffect(() => {
|
||||
if (!state.paused || reducedMotion) return;
|
||||
const id = window.setTimeout(
|
||||
() => dispatch({ type: 'advance' }),
|
||||
PHASE_DURATION[state.phase] + 1500,
|
||||
);
|
||||
return () => window.clearTimeout(id);
|
||||
}, [state.paused, state.phase, reducedMotion]);
|
||||
|
||||
const phaseIndex = PHASE_ORDER.indexOf(state.phase);
|
||||
const menuVisible = state.phase === 'menuOpen' || state.phase === 'verified';
|
||||
const verified = state.phase === 'verified';
|
||||
|
||||
const stepCopy = [
|
||||
{
|
||||
title: t('organizations.tutorial.steps.open.title'),
|
||||
body: t('organizations.tutorial.steps.open.body'),
|
||||
},
|
||||
{
|
||||
title: t('organizations.tutorial.steps.verify.title'),
|
||||
body: t('organizations.tutorial.steps.verify.body'),
|
||||
},
|
||||
{
|
||||
title: t('organizations.tutorial.steps.confirm.title'),
|
||||
body: t('organizations.tutorial.steps.confirm.body'),
|
||||
},
|
||||
];
|
||||
|
||||
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',
|
||||
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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-8 lg:grid-cols-2 lg:items-center">
|
||||
{/* ── Left: animated mock campaign card ───────────────────────── */}
|
||||
<DemoStage
|
||||
phaseIndex={phaseIndex}
|
||||
menuVisible={menuVisible}
|
||||
verified={verified}
|
||||
reducedMotion={reducedMotion}
|
||||
/>
|
||||
|
||||
{/* ── Right: step list, synced to the animation ───────────────── */}
|
||||
<ol className="space-y-3">
|
||||
{stepCopy.map((step, i) => {
|
||||
const active = i === phaseIndex;
|
||||
const done = i < phaseIndex;
|
||||
return (
|
||||
<li key={step.title}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => dispatch({ type: 'goto', phase: PHASE_ORDER[i] })}
|
||||
aria-current={active ? 'step' : undefined}
|
||||
className={cn(
|
||||
'group flex w-full items-start gap-4 rounded-xl border p-4 text-left transition-all',
|
||||
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/60',
|
||||
active
|
||||
? 'border-primary/40 bg-primary/5 shadow-sm'
|
||||
: 'border-border/60 bg-background hover:border-primary/30 hover:bg-muted/40',
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
'flex size-8 shrink-0 items-center justify-center rounded-full text-sm font-bold transition-colors',
|
||||
done
|
||||
? 'bg-primary text-primary-foreground'
|
||||
: active
|
||||
? 'bg-primary/15 text-primary ring-2 ring-primary/40'
|
||||
: 'bg-muted text-muted-foreground',
|
||||
)}
|
||||
>
|
||||
{done ? <BadgeCheck className="size-4" /> : i + 1}
|
||||
</span>
|
||||
<span className="space-y-1">
|
||||
<span
|
||||
className={cn(
|
||||
'block text-sm font-semibold leading-snug',
|
||||
active ? 'text-foreground' : 'text-foreground/90',
|
||||
)}
|
||||
>
|
||||
{step.title}
|
||||
</span>
|
||||
<span className="block text-sm text-muted-foreground leading-relaxed">
|
||||
{step.body}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
// ── The animated mock card ───────────────────────────────────────────────
|
||||
|
||||
interface DemoStageProps {
|
||||
phaseIndex: number;
|
||||
menuVisible: boolean;
|
||||
verified: boolean;
|
||||
reducedMotion: boolean;
|
||||
}
|
||||
|
||||
function DemoStage({
|
||||
phaseIndex,
|
||||
menuVisible,
|
||||
verified,
|
||||
reducedMotion,
|
||||
}: DemoStageProps) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<div className="relative mx-auto w-full max-w-sm select-none" aria-hidden="true">
|
||||
{/* Mock campaign card */}
|
||||
<div className="overflow-hidden rounded-2xl border border-border/60 bg-card shadow-md">
|
||||
{/* Banner */}
|
||||
<div className="relative h-40 bg-gradient-to-br from-sky-500/80 via-cyan-500/70 to-emerald-500/80">
|
||||
<div
|
||||
aria-hidden
|
||||
className="absolute inset-0 opacity-30 mix-blend-overlay"
|
||||
style={{
|
||||
backgroundImage:
|
||||
'radial-gradient(circle at 30% 30%, rgba(255,255,255,0.5), transparent 45%)',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Verified badge (top-left) — appears in the final phase */}
|
||||
<div
|
||||
className={cn(
|
||||
'absolute left-3 top-3 flex items-center gap-1.5 rounded-full bg-background/90 px-2.5 py-1 text-xs font-semibold text-foreground shadow-sm backdrop-blur transition-all duration-500',
|
||||
verified
|
||||
? 'opacity-100 translate-y-0'
|
||||
: 'opacity-0 -translate-y-1 pointer-events-none',
|
||||
)}
|
||||
>
|
||||
<BadgeCheck className="size-4 text-primary" />
|
||||
{t('organizations.tutorial.demo.verifiedBadge')}
|
||||
</div>
|
||||
|
||||
{/* Three-dots button (top-right) */}
|
||||
<div className="absolute right-3 top-3">
|
||||
<div
|
||||
className={cn(
|
||||
'flex size-8 items-center justify-center rounded-md bg-background/80 text-muted-foreground backdrop-blur transition-all duration-300',
|
||||
phaseIndex === 0 &&
|
||||
!reducedMotion &&
|
||||
'motion-safe:animate-pulse ring-2 ring-primary/60',
|
||||
menuVisible && 'bg-background text-foreground ring-2 ring-primary/50',
|
||||
)}
|
||||
>
|
||||
<MoreHorizontal className="size-4" />
|
||||
</div>
|
||||
|
||||
{/* Dropdown menu */}
|
||||
<div
|
||||
className={cn(
|
||||
'absolute right-0 top-10 z-20 w-52 origin-top-right rounded-md border bg-popover p-1 text-popover-foreground shadow-lg transition-all duration-200',
|
||||
menuVisible
|
||||
? 'scale-100 opacity-100'
|
||||
: 'pointer-events-none scale-95 opacity-0',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center gap-2 rounded-sm px-2 py-2 text-sm font-medium transition-colors',
|
||||
phaseIndex >= 1
|
||||
? 'bg-primary/10 text-primary'
|
||||
: 'text-foreground',
|
||||
)}
|
||||
>
|
||||
<BadgeCheck className="size-4 shrink-0" />
|
||||
{t('organizations.tutorial.demo.menuVerify')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Card body */}
|
||||
<div className="space-y-3 p-4">
|
||||
<div>
|
||||
<p className="font-semibold leading-snug">
|
||||
{t('organizations.tutorial.demo.campaignTitle')}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t('organizations.tutorial.demo.campaignOrganizer')}
|
||||
</p>
|
||||
</div>
|
||||
{/* Fake progress bar */}
|
||||
<div className="space-y-1.5">
|
||||
<div className="h-2 w-full overflow-hidden rounded-full bg-muted">
|
||||
<div className="h-full w-2/3 rounded-full bg-primary" />
|
||||
</div>
|
||||
<div className="flex justify-between text-xs text-muted-foreground">
|
||||
<span>0.45 BTC</span>
|
||||
<span>67%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Animated cursor — hidden under reduced motion */}
|
||||
{!reducedMotion && (
|
||||
<div
|
||||
className={cn(
|
||||
'pointer-events-none absolute z-30 transition-all duration-700 ease-out',
|
||||
// idle → hover the kebab (top-right); menuOpen/verified → hover the verify item
|
||||
phaseIndex === 0
|
||||
? 'right-4 top-5'
|
||||
: 'right-8 top-[4.5rem]',
|
||||
)}
|
||||
>
|
||||
<MousePointer2
|
||||
className={cn(
|
||||
'size-6 fill-foreground text-background drop-shadow-md transition-transform',
|
||||
'motion-safe:animate-tutorial-tap',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default VerifyTutorial;
|
||||
+17
-1
@@ -1076,7 +1076,23 @@
|
||||
"lede": "سجّل الدخول بملف منظّمتك الشخصي لنشر بيان التحقق الخاص بك أو تحديثه أو سحبه."
|
||||
},
|
||||
"loginGateTitle": "سجّل الدخول بملف منظّمتك الشخصي",
|
||||
"loginGateBody": "سجّل الدخول بملف منظّمتك الشخصي على Nostr، أو أنشئ واحداً، للبدء. بمجرد تسجيل دخولك، يمكنك نشر بيان التحقق الخاص بك هنا."
|
||||
"loginGateBody": "سجّل الدخول بملف منظّمتك الشخصي على Nostr، أو أنشئ واحداً، للبدء. بمجرد تسجيل دخولك، يمكنك نشر بيان التحقق الخاص بك هنا.",
|
||||
"tutorial": {
|
||||
"eyebrow": "أنت الآن مُوثِّق",
|
||||
"title": "كيفية توثيق حملة",
|
||||
"lede": "بيانك منشور الآن. إليك كيف توثّق حملة تثق بها — يكفي نقرتان من أي بطاقة حملة.",
|
||||
"steps": {
|
||||
"open": { "title": "افتح القائمة", "body": "في أي بطاقة حملة، انقر على زر النقاط الثلاث في الزاوية العلوية اليمنى من اللافتة." },
|
||||
"verify": { "title": "اختر \"وثّق هذه الحملة\"", "body": "تكشف القائمة عن إجراء التوثيق — وهو مرئي فقط للمشرفين والمُوثِّقين مثلك." },
|
||||
"confirm": { "title": "أكِّد وانتهيت", "body": "أقرّ بأن الحملة أصلية. تنضم شارتك إلى البطاقة ليعلم المتبرعون أنك تقف خلفها." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "مياه نظيفة لموانزا",
|
||||
"campaignOrganizer": "بواسطة مؤسسة Mradi",
|
||||
"menuVerify": "وثّق هذه الحملة",
|
||||
"verifiedBadge": "موثّقة بواسطتك"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "تعيين منظّم",
|
||||
|
||||
+26
-1
@@ -1539,7 +1539,32 @@
|
||||
"lede": "Sign in with your organization's profile to publish, update, or withdraw your verification statement."
|
||||
},
|
||||
"loginGateTitle": "Sign in with your organization's profile",
|
||||
"loginGateBody": "Log in with your organization's Nostr profile, or create one, to get started. Once you're signed in, you can publish your verification statement here."
|
||||
"loginGateBody": "Log in with your organization's Nostr profile, or create one, to get started. Once you're signed in, you can publish your verification statement here.",
|
||||
"tutorial": {
|
||||
"eyebrow": "You're a verifier now",
|
||||
"title": "How to verify a campaign",
|
||||
"lede": "Your statement is live. Here's how to vouch for a campaign you trust — it takes two taps from any campaign card.",
|
||||
"steps": {
|
||||
"open": {
|
||||
"title": "Open the menu",
|
||||
"body": "On any campaign card, tap the three-dots button in the top-right corner of the banner."
|
||||
},
|
||||
"verify": {
|
||||
"title": "Choose \"Verify this campaign\"",
|
||||
"body": "The menu reveals a verify action — visible only to moderators and verifiers like you."
|
||||
},
|
||||
"confirm": {
|
||||
"title": "Confirm & you're done",
|
||||
"body": "Attest the campaign is authentic. Your badge joins the card so donors know you stand behind it."
|
||||
}
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Clean Water for Mwanza",
|
||||
"campaignOrganizer": "by Mradi Foundation",
|
||||
"menuVerify": "Verify this campaign",
|
||||
"verifiedBadge": "Verified by you"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Appoint Organizer",
|
||||
|
||||
+26
-1
@@ -1086,7 +1086,32 @@
|
||||
"lede": "Inicia sesión con el perfil de tu organización para publicar, actualizar o retirar tu declaración de verificación."
|
||||
},
|
||||
"loginGateTitle": "Inicia sesión con el perfil de tu organización",
|
||||
"loginGateBody": "Inicia sesión con el perfil de Nostr de tu organización, o crea uno, para empezar. Una vez que hayas iniciado sesión, podrás publicar aquí tu declaración de verificación."
|
||||
"loginGateBody": "Inicia sesión con el perfil de Nostr de tu organización, o crea uno, para empezar. Una vez que hayas iniciado sesión, podrás publicar aquí tu declaración de verificación.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Ahora eres verificador",
|
||||
"title": "Cómo verificar una campaña",
|
||||
"lede": "Tu declaración ya está publicada. Así puedes respaldar una campaña en la que confías: solo dos toques desde cualquier tarjeta de campaña.",
|
||||
"steps": {
|
||||
"open": {
|
||||
"title": "Abre el menú",
|
||||
"body": "En cualquier tarjeta de campaña, toca el botón de tres puntos en la esquina superior derecha del banner."
|
||||
},
|
||||
"verify": {
|
||||
"title": "Elige \"Verificar esta campaña\"",
|
||||
"body": "El menú muestra una acción de verificación, visible solo para moderadores y verificadores como tú."
|
||||
},
|
||||
"confirm": {
|
||||
"title": "Confirma y listo",
|
||||
"body": "Da fe de que la campaña es auténtica. Tu insignia se une a la tarjeta para que los donantes sepan que la respaldas."
|
||||
}
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Agua limpia para Mwanza",
|
||||
"campaignOrganizer": "de la Fundación Mradi",
|
||||
"menuVerify": "Verificar esta campaña",
|
||||
"verifiedBadge": "Verificada por ti"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Designar Organizador",
|
||||
|
||||
+17
-1
@@ -1086,7 +1086,23 @@
|
||||
"lede": "با نمایهٔ سازمان خود وارد شوید تا بیانیهٔ تأیید خود را منتشر، بهروزرسانی یا حذف کنید."
|
||||
},
|
||||
"loginGateTitle": "با نمایهٔ سازمان خود وارد شوید",
|
||||
"loginGateBody": "برای شروع، با نمایهٔ Nostr سازمان خود وارد شوید یا یکی بسازید. پس از ورود، میتوانید بیانیهٔ تأیید خود را اینجا منتشر کنید."
|
||||
"loginGateBody": "برای شروع، با نمایهٔ Nostr سازمان خود وارد شوید یا یکی بسازید. پس از ورود، میتوانید بیانیهٔ تأیید خود را اینجا منتشر کنید.",
|
||||
"tutorial": {
|
||||
"eyebrow": "اکنون شما یک تأییدکننده هستید",
|
||||
"title": "چگونه یک کمپین را تأیید کنیم",
|
||||
"lede": "بیانیهٔ شما فعال است. در اینجا میبینید که چگونه کمپینی را که به آن اعتماد دارید تأیید کنید — تنها با دو ضربه از روی هر کارت کمپین انجام میشود.",
|
||||
"steps": {
|
||||
"open": { "title": "منو را باز کنید", "body": "روی هر کارت کمپین، دکمهٔ سهنقطه را در گوشهٔ بالا سمت راست بنر لمس کنید." },
|
||||
"verify": { "title": "گزینهٔ \"این کمپین را تأیید کنید\" را انتخاب کنید", "body": "منو یک کنش تأیید را نمایش میدهد — که فقط برای ناظران و تأییدکنندگانی مانند شما قابل مشاهده است." },
|
||||
"confirm": { "title": "تأیید کنید و کار تمام است", "body": "گواهی دهید که کمپین معتبر است. نشان شما به کارت افزوده میشود تا اهداکنندگان بدانند که شما پشتیبان آن هستید." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "آب پاکیزه برای Mwanza",
|
||||
"campaignOrganizer": "توسط بنیاد Mradi",
|
||||
"menuVerify": "این کمپین را تأیید کنید",
|
||||
"verifiedBadge": "تأییدشده توسط شما"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "تعیین سازماندهنده",
|
||||
|
||||
+26
-1
@@ -1525,7 +1525,32 @@
|
||||
"lede": "Connectez-vous avec le profil de votre organisation pour publier, mettre à jour ou retirer votre déclaration de vérification."
|
||||
},
|
||||
"loginGateTitle": "Connectez-vous avec le profil de votre organisation",
|
||||
"loginGateBody": "Connectez-vous avec le profil Nostr de votre organisation, ou créez-en un, pour commencer. Une fois connecté, vous pourrez publier votre déclaration de vérification ici."
|
||||
"loginGateBody": "Connectez-vous avec le profil Nostr de votre organisation, ou créez-en un, pour commencer. Une fois connecté, vous pourrez publier votre déclaration de vérification ici.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Vous êtes désormais vérificateur",
|
||||
"title": "Comment vérifier une campagne",
|
||||
"lede": "Votre déclaration est en ligne. Voici comment vous porter garant d'une campagne en laquelle vous avez confiance — deux clics suffisent depuis n'importe quelle carte de campagne.",
|
||||
"steps": {
|
||||
"open": {
|
||||
"title": "Ouvrez le menu",
|
||||
"body": "Sur n'importe quelle carte de campagne, appuyez sur le bouton à trois points dans le coin supérieur droit de la bannière."
|
||||
},
|
||||
"verify": {
|
||||
"title": "Choisissez \"Vérifier cette campagne\"",
|
||||
"body": "Le menu révèle une action de vérification — visible uniquement par les modérateurs et les vérificateurs comme vous."
|
||||
},
|
||||
"confirm": {
|
||||
"title": "Confirmez, et c'est terminé",
|
||||
"body": "Attestez que la campagne est authentique. Votre badge rejoint la carte afin que les donateurs sachent que vous la soutenez."
|
||||
}
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "De l'eau potable pour Mwanza",
|
||||
"campaignOrganizer": "par la Fondation Mradi",
|
||||
"menuVerify": "Vérifier cette campagne",
|
||||
"verifiedBadge": "Vérifié par vous"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Désigner un organisateur",
|
||||
|
||||
+17
-1
@@ -1528,7 +1528,23 @@
|
||||
"lede": "अपने सत्यापन वक्तव्य को प्रकाशित करने, अपडेट करने या वापस लेने के लिए अपने संगठन की प्रोफ़ाइल से साइन इन करें।"
|
||||
},
|
||||
"loginGateTitle": "अपने संगठन की प्रोफ़ाइल से साइन इन करें",
|
||||
"loginGateBody": "शुरू करने के लिए अपने संगठन की Nostr प्रोफ़ाइल से लॉग इन करें, या एक बनाएँ। साइन इन करने के बाद, आप यहाँ अपना सत्यापन वक्तव्य प्रकाशित कर सकते हैं।"
|
||||
"loginGateBody": "शुरू करने के लिए अपने संगठन की Nostr प्रोफ़ाइल से लॉग इन करें, या एक बनाएँ। साइन इन करने के बाद, आप यहाँ अपना सत्यापन वक्तव्य प्रकाशित कर सकते हैं।",
|
||||
"tutorial": {
|
||||
"eyebrow": "अब आप एक सत्यापनकर्ता हैं",
|
||||
"title": "किसी अभियान को कैसे सत्यापित करें",
|
||||
"lede": "आपका वक्तव्य लाइव है। जिस अभियान पर आप भरोसा करते हैं उसकी पुष्टि करने का तरीका यहाँ है — किसी भी अभियान कार्ड से बस दो टैप में हो जाता है।",
|
||||
"steps": {
|
||||
"open": { "title": "मेनू खोलें", "body": "किसी भी अभियान कार्ड पर, बैनर के ऊपरी-दाएँ कोने में तीन-बिंदु वाले बटन पर टैप करें।" },
|
||||
"verify": { "title": "\"इस अभियान को सत्यापित करें\" चुनें", "body": "मेनू एक सत्यापन क्रिया दिखाता है — जो केवल आपके जैसे मॉडरेटर और सत्यापनकर्ताओं को ही दिखती है।" },
|
||||
"confirm": { "title": "पुष्टि करें और हो गया", "body": "प्रमाणित करें कि अभियान प्रामाणिक है। आपका बैज कार्ड में जुड़ जाता है ताकि दानदाताओं को पता चले कि आप इसके पीछे खड़े हैं।" }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Mwanza के लिए स्वच्छ जल",
|
||||
"campaignOrganizer": "Mradi Foundation द्वारा",
|
||||
"menuVerify": "इस अभियान को सत्यापित करें",
|
||||
"verifiedBadge": "आपके द्वारा सत्यापित"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "ऑर्गनाइज़र नियुक्त करें",
|
||||
|
||||
+17
-1
@@ -1528,7 +1528,23 @@
|
||||
"lede": "Masuk dengan profil organisasi Anda untuk menerbitkan, memperbarui, atau menarik kembali pernyataan verifikasi Anda."
|
||||
},
|
||||
"loginGateTitle": "Masuk dengan profil organisasi Anda",
|
||||
"loginGateBody": "Masuk dengan profil Nostr organisasi Anda, atau buat satu, untuk memulai. Setelah masuk, Anda dapat menerbitkan pernyataan verifikasi Anda di sini."
|
||||
"loginGateBody": "Masuk dengan profil Nostr organisasi Anda, atau buat satu, untuk memulai. Setelah masuk, Anda dapat menerbitkan pernyataan verifikasi Anda di sini.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Anda kini seorang verifikator",
|
||||
"title": "Cara memverifikasi kampanye",
|
||||
"lede": "Pernyataan Anda sudah aktif. Berikut cara menjamin kampanye yang Anda percaya — cukup dua ketukan dari kartu kampanye mana pun.",
|
||||
"steps": {
|
||||
"open": { "title": "Buka menu", "body": "Pada kartu kampanye mana pun, ketuk tombol tiga titik di sudut kanan atas banner." },
|
||||
"verify": { "title": "Pilih \"Verifikasi kampanye ini\"", "body": "Menu menampilkan aksi verifikasi — hanya terlihat oleh moderator dan verifikator seperti Anda." },
|
||||
"confirm": { "title": "Konfirmasi & selesai", "body": "Tegaskan bahwa kampanye ini autentik. Lencana Anda akan muncul di kartu sehingga para donatur tahu Anda mendukungnya." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Air Bersih untuk Mwanza",
|
||||
"campaignOrganizer": "oleh Mradi Foundation",
|
||||
"menuVerify": "Verifikasi kampanye ini",
|
||||
"verifiedBadge": "Diverifikasi oleh Anda"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Tunjuk Organizer",
|
||||
|
||||
+17
-1
@@ -1086,7 +1086,23 @@
|
||||
"lede": "ចូលគណនីដោយប្រើប្រវត្តិរូបអង្គការរបស់អ្នក ដើម្បីផ្សព្វផ្សាយ ធ្វើបច្ចុប្បន្នភាព ឬដកសេចក្តីថ្លែងការណ៍ផ្ទៀងផ្ទាត់របស់អ្នកចេញ។"
|
||||
},
|
||||
"loginGateTitle": "ចូលគណនីដោយប្រើប្រវត្តិរូបអង្គការរបស់អ្នក",
|
||||
"loginGateBody": "ចូលគណនីដោយប្រើប្រវត្តិរូប Nostr របស់អង្គការអ្នក ឬបង្កើតមួយ ដើម្បីចាប់ផ្តើម។ នៅពេលអ្នកបានចូលគណនីហើយ អ្នកអាចផ្សព្វផ្សាយសេចក្តីថ្លែងការណ៍ផ្ទៀងផ្ទាត់របស់អ្នកនៅទីនេះ។"
|
||||
"loginGateBody": "ចូលគណនីដោយប្រើប្រវត្តិរូប Nostr របស់អង្គការអ្នក ឬបង្កើតមួយ ដើម្បីចាប់ផ្តើម។ នៅពេលអ្នកបានចូលគណនីហើយ អ្នកអាចផ្សព្វផ្សាយសេចក្តីថ្លែងការណ៍ផ្ទៀងផ្ទាត់របស់អ្នកនៅទីនេះ។",
|
||||
"tutorial": {
|
||||
"eyebrow": "ឥឡូវនេះអ្នកជាអ្នកផ្ទៀងផ្ទាត់ហើយ",
|
||||
"title": "របៀបផ្ទៀងផ្ទាត់យុទ្ធនាការ",
|
||||
"lede": "សេចក្តីថ្លែងការណ៍របស់អ្នកកំពុងដំណើរការ។ នេះជារបៀបធានាដល់យុទ្ធនាការដែលអ្នកទុកចិត្ត — វាត្រូវការតែការប៉ះពីរដងពីកាតយុទ្ធនាការណាមួយប៉ុណ្ណោះ។",
|
||||
"steps": {
|
||||
"open": { "title": "បើកម៉ឺនុយ", "body": "នៅលើកាតយុទ្ធនាការណាមួយ សូមប៉ះប៊ូតុងចំណុចបីនៅជ្រុងខាងស្តាំផ្នែកខាងលើនៃផ្ទាំងបដា។" },
|
||||
"verify": { "title": "ជ្រើសរើស \"ផ្ទៀងផ្ទាត់យុទ្ធនាការនេះ\"", "body": "ម៉ឺនុយនឹងបង្ហាញសកម្មភាពផ្ទៀងផ្ទាត់ — មើលឃើញតែសម្រាប់អ្នកសម្របសម្រួល និងអ្នកផ្ទៀងផ្ទាត់ដូចជាអ្នកប៉ុណ្ណោះ។" },
|
||||
"confirm": { "title": "បញ្ជាក់ ហើយអ្នកបានបញ្ចប់", "body": "បញ្ជាក់ថាយុទ្ធនាការនេះពិតប្រាកដ។ ផ្លាកសញ្ញារបស់អ្នកនឹងភ្ជាប់ទៅកាត ដើម្បីឱ្យអ្នកបរិច្ចាគដឹងថាអ្នកគាំទ្រវា។" }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "ទឹកស្អាតសម្រាប់ Mwanza",
|
||||
"campaignOrganizer": "ដោយ Mradi Foundation",
|
||||
"menuVerify": "ផ្ទៀងផ្ទាត់យុទ្ធនាការនេះ",
|
||||
"verifiedBadge": "បានផ្ទៀងផ្ទាត់ដោយអ្នក"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "តែងតាំងអ្នករៀបចំ",
|
||||
|
||||
+17
-1
@@ -1088,7 +1088,23 @@
|
||||
"lede": "د خپل سازمان د پروفایل سره ننوځئ ترڅو خپل د تصدیق بیان خپور، تازه، یا وباسئ."
|
||||
},
|
||||
"loginGateTitle": "د خپل سازمان د پروفایل سره ننوځئ",
|
||||
"loginGateBody": "د پیل لپاره د خپل سازمان د Nostr پروفایل سره ننوځئ، یا یو جوړ کړئ. کله چې ننوتلي اوسئ، تاسو کولی شئ خپل د تصدیق بیان دلته خپور کړئ."
|
||||
"loginGateBody": "د پیل لپاره د خپل سازمان د Nostr پروفایل سره ننوځئ، یا یو جوړ کړئ. کله چې ننوتلي اوسئ، تاسو کولی شئ خپل د تصدیق بیان دلته خپور کړئ.",
|
||||
"tutorial": {
|
||||
"eyebrow": "اوس تاسو تصدیق کوونکی یاست",
|
||||
"title": "د کمپاین تصدیق کولو څرنګوالی",
|
||||
"lede": "ستاسو بیان فعال دی. دلته دا دی چې څنګه د هغه کمپاین ضمانت وکړئ چې تاسو پرې باور لرئ — دا د هر کمپاین له کارت څخه دوه ټک نیسي.",
|
||||
"steps": {
|
||||
"open": { "title": "مینو پرانیځئ", "body": "د هر کمپاین په کارت کې، د بینر په پورتنۍ ښۍ کونج کې د درې ټکو تڼۍ ټک کړئ." },
|
||||
"verify": { "title": "\"دا کمپاین تصدیق کړئ\" غوره کړئ", "body": "مینو د تصدیق کړنه ښکاره کوي — یوازې تاسو په څېر اعتدال کوونکو او تصدیق کوونکو ته ښکاري." },
|
||||
"confirm": { "title": "تایید کړئ او کار مو پای ته ورسېد", "body": "تصدیق کړئ چې کمپاین اصلي دی. ستاسو نښان د کارت سره یوځای کېږي ترڅو بسپنه ورکوونکي پوه شي چې تاسو یې ملاتړ کوئ." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "د موانزا لپاره پاکې اوبه",
|
||||
"campaignOrganizer": "د Mradi بنسټ لخوا",
|
||||
"menuVerify": "دا کمپاین تصدیق کړئ",
|
||||
"verifiedBadge": "ستاسو لخوا تصدیق شوی"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "تنظیموونکی ټاکل",
|
||||
|
||||
+26
-1
@@ -1530,7 +1530,32 @@
|
||||
"lede": "Entre com o perfil da sua organização para publicar, atualizar ou retirar sua declaração de verificação."
|
||||
},
|
||||
"loginGateTitle": "Entre com o perfil da sua organização",
|
||||
"loginGateBody": "Entre com o perfil Nostr da sua organização, ou crie um, para começar. Depois de entrar, você pode publicar sua declaração de verificação aqui."
|
||||
"loginGateBody": "Entre com o perfil Nostr da sua organização, ou crie um, para começar. Depois de entrar, você pode publicar sua declaração de verificação aqui.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Agora você é um verificador",
|
||||
"title": "Como verificar uma campanha",
|
||||
"lede": "Sua declaração está no ar. Veja como avalizar uma campanha em que você confia — bastam dois toques a partir de qualquer cartão de campanha.",
|
||||
"steps": {
|
||||
"open": {
|
||||
"title": "Abra o menu",
|
||||
"body": "Em qualquer cartão de campanha, toque no botão de três pontos no canto superior direito do banner."
|
||||
},
|
||||
"verify": {
|
||||
"title": "Escolha \"Verificar esta campanha\"",
|
||||
"body": "O menu revela uma ação de verificação — visível apenas para moderadores e verificadores como você."
|
||||
},
|
||||
"confirm": {
|
||||
"title": "Confirme e pronto",
|
||||
"body": "Ateste que a campanha é autêntica. Seu selo se une ao cartão para que os doadores saibam que você a apoia."
|
||||
}
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Água Limpa para Mwanza",
|
||||
"campaignOrganizer": "por Mradi Foundation",
|
||||
"menuVerify": "Verificar esta campanha",
|
||||
"verifiedBadge": "Verificado por você"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Nomear organizador",
|
||||
|
||||
+26
-1
@@ -1530,7 +1530,32 @@
|
||||
"lede": "Войдите с профилем вашей организации, чтобы опубликовать, обновить или отозвать своё заявление о верификации."
|
||||
},
|
||||
"loginGateTitle": "Войдите с профилем вашей организации",
|
||||
"loginGateBody": "Войдите с профилем Nostr вашей организации или создайте его, чтобы начать. После входа вы сможете опубликовать здесь своё заявление о верификации."
|
||||
"loginGateBody": "Войдите с профилем Nostr вашей организации или создайте его, чтобы начать. После входа вы сможете опубликовать здесь своё заявление о верификации.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Теперь вы верификатор",
|
||||
"title": "Как верифицировать кампанию",
|
||||
"lede": "Ваше заявление опубликовано. Вот как поручиться за кампанию, которой вы доверяете, — это всего два касания на любой карточке кампании.",
|
||||
"steps": {
|
||||
"open": {
|
||||
"title": "Откройте меню",
|
||||
"body": "На любой карточке кампании нажмите кнопку с тремя точками в правом верхнем углу баннера."
|
||||
},
|
||||
"verify": {
|
||||
"title": "Выберите «Проверить эту кампанию»",
|
||||
"body": "В меню появится действие верификации — оно видно только модераторам и верификаторам, таким как вы."
|
||||
},
|
||||
"confirm": {
|
||||
"title": "Подтвердите — и готово",
|
||||
"body": "Подтвердите подлинность кампании. Ваш значок появится на карточке, чтобы доноры знали, что вы за неё ручаетесь."
|
||||
}
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Чистая вода для Mwanza",
|
||||
"campaignOrganizer": "от Mradi Foundation",
|
||||
"menuVerify": "Проверить эту кампанию",
|
||||
"verifiedBadge": "Проверено вами"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Назначить организатора",
|
||||
|
||||
+17
-1
@@ -1088,7 +1088,23 @@
|
||||
"lede": "Pinda nepurofairi yesangano rako kuti uburitse, ugadziridze, kana kubvisa chirevo chako chekusimbisa."
|
||||
},
|
||||
"loginGateTitle": "Pinda nepurofairi yesangano rako",
|
||||
"loginGateBody": "Pinda nepurofairi yeNostr yesangano rako, kana kuti gadzira imwe, kuti utange. Kana wapinda, unogona kuburitsa chirevo chako chekusimbisa pano."
|
||||
"loginGateBody": "Pinda nepurofairi yeNostr yesangano rako, kana kuti gadzira imwe, kuti utange. Kana wapinda, unogona kuburitsa chirevo chako chekusimbisa pano.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Iwe zvino uri muongorori",
|
||||
"title": "Mashandisirwo ekusimbisa mushandirapamwe",
|
||||
"lede": "Chirevo chako chava pachena. Heano matanho ekutsigira mushandirapamwe waunovimba nawo — zvinotora kubata kaviri chete kubva pakadhi rapi nerapi remushandirapamwe.",
|
||||
"steps": {
|
||||
"open": { "title": "Vhura menyu", "body": "Pakadhi ripi neripi remushandirapamwe, baya bhatani remadhoti matatu kona yekumusoro kurudyi kwebhanga." },
|
||||
"verify": { "title": "Sarudza \"Simbisa mushandirapamwe uyu\"", "body": "Menyu inoratidza chiito chekusimbisa — chinoonekwa chete nevatariri nevaongorori sewe." },
|
||||
"confirm": { "title": "Simbisa uye wapedza", "body": "Pupura kuti mushandirapamwe ndewechokwadi. Bheji rako rinobatana nekadhi kuti vanopa vazive kuti unowutsigira." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Mvura Yakachena yeMwanza",
|
||||
"campaignOrganizer": "naMradi Foundation",
|
||||
"menuVerify": "Simbisa mushandirapamwe uyu",
|
||||
"verifiedBadge": "Yasimbiswa newe"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Sarudza Mugadziri",
|
||||
|
||||
+17
-1
@@ -1527,7 +1527,23 @@
|
||||
"lede": "Ingia kwa wasifu wa shirika lako ili kuchapisha, kusasisha, au kuondoa taarifa yako ya uthibitishaji."
|
||||
},
|
||||
"loginGateTitle": "Ingia kwa wasifu wa shirika lako",
|
||||
"loginGateBody": "Ingia kwa wasifu wa Nostr wa shirika lako, au tengeneza mmoja, ili kuanza. Mara tu unapoingia, unaweza kuchapisha taarifa yako ya uthibitishaji hapa."
|
||||
"loginGateBody": "Ingia kwa wasifu wa Nostr wa shirika lako, au tengeneza mmoja, ili kuanza. Mara tu unapoingia, unaweza kuchapisha taarifa yako ya uthibitishaji hapa.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Sasa wewe ni mthibitishaji",
|
||||
"title": "Jinsi ya kuthibitisha kampeni",
|
||||
"lede": "Taarifa yako iko hewani. Hivi ndivyo unavyoweza kuiunga mkono kampeni unayoiamini \u2014 inachukua mibofyo miwili kutoka kwa kadi yoyote ya kampeni.",
|
||||
"steps": {
|
||||
"open": { "title": "Fungua menyu", "body": "Kwenye kadi yoyote ya kampeni, gusa kitufe cha nukta tatu kwenye kona ya juu kulia ya bango." },
|
||||
"verify": { "title": "Chagua \"Thibitisha kampeni hii\"", "body": "Menyu hufunua kitendo cha kuthibitisha \u2014 kinachoonekana kwa wasimamizi na wathibitishaji kama wewe pekee." },
|
||||
"confirm": { "title": "Thibitisha na umemaliza", "body": "Shuhudia kuwa kampeni ni halisi. Beji yako huungana na kadi ili wafadhili wajue unaiunga mkono." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Maji Safi kwa Mwanza",
|
||||
"campaignOrganizer": "na Mradi Foundation",
|
||||
"menuVerify": "Thibitisha kampeni hii",
|
||||
"verifiedBadge": "Imethibitishwa na wewe"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Teua Mratibu",
|
||||
|
||||
+17
-1
@@ -1529,7 +1529,23 @@
|
||||
"lede": "Doğrulama beyanınızı yayımlamak, güncellemek veya geri çekmek için organizasyonunuzun profiliyle giriş yapın."
|
||||
},
|
||||
"loginGateTitle": "Organizasyonunuzun profiliyle giriş yapın",
|
||||
"loginGateBody": "Başlamak için organizasyonunuzun Nostr profiliyle giriş yapın ya da bir tane oluşturun. Giriş yaptıktan sonra doğrulama beyanınızı buradan yayımlayabilirsiniz."
|
||||
"loginGateBody": "Başlamak için organizasyonunuzun Nostr profiliyle giriş yapın ya da bir tane oluşturun. Giriş yaptıktan sonra doğrulama beyanınızı buradan yayımlayabilirsiniz.",
|
||||
"tutorial": {
|
||||
"eyebrow": "Artık bir doğrulayıcısınız",
|
||||
"title": "Bir kampanya nasıl doğrulanır",
|
||||
"lede": "Beyanınız yayında. Güvendiğiniz bir kampanyaya nasıl kefil olacağınız işte burada — herhangi bir kampanya kartından iki dokunuşla yapılır.",
|
||||
"steps": {
|
||||
"open": { "title": "Menüyü açın", "body": "Herhangi bir kampanya kartında, afişin sağ üst köşesindeki üç nokta düğmesine dokunun." },
|
||||
"verify": { "title": "\"Bu kampanyayı doğrula\" seçeneğini seçin", "body": "Menüde bir doğrulama işlemi belirir — yalnızca sizin gibi moderatörler ve doğrulayıcılar tarafından görülebilir." },
|
||||
"confirm": { "title": "Onaylayın ve işlem tamam", "body": "Kampanyanın gerçek olduğunu teyit edin. Rozetiniz kartta yerini alır, böylece bağışçılar arkasında durduğunuzu bilir." }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "Mwanza için Temiz Su",
|
||||
"campaignOrganizer": "Mradi Vakfı tarafından",
|
||||
"menuVerify": "Bu kampanyayı doğrula",
|
||||
"verifiedBadge": "Sizin tarafınızdan doğrulandı"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "Organizatör Ata",
|
||||
|
||||
@@ -1088,7 +1088,23 @@
|
||||
"lede": "使用組織的個人資料登入,即可發布、更新或撤回你的驗證聲明。"
|
||||
},
|
||||
"loginGateTitle": "使用你組織的個人資料登入",
|
||||
"loginGateBody": "使用你組織的 Nostr 個人資料登入,或建立一個,即可開始。登入後,你可以在這裡發布你的驗證聲明。"
|
||||
"loginGateBody": "使用你組織的 Nostr 個人資料登入,或建立一個,即可開始。登入後,你可以在這裡發布你的驗證聲明。",
|
||||
"tutorial": {
|
||||
"eyebrow": "你現在是驗證者了",
|
||||
"title": "如何驗證一個專案",
|
||||
"lede": "你的聲明已上線。以下說明如何為你信任的專案背書——從任何專案卡片只需點兩下即可完成。",
|
||||
"steps": {
|
||||
"open": { "title": "開啟選單", "body": "在任何專案卡片上,點選橫幅右上角的三點按鈕。" },
|
||||
"verify": { "title": "選擇「驗證此活動」", "body": "選單會顯示驗證操作——只有像你這樣的版主和驗證者才看得到。" },
|
||||
"confirm": { "title": "確認後即完成", "body": "證明這個專案是真實的。你的徽章會加入卡片,讓捐款者知道你為它背書。" }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "為姆萬扎提供潔淨用水",
|
||||
"campaignOrganizer": "由 Mradi 基金會發起",
|
||||
"menuVerify": "驗證此活動",
|
||||
"verifiedBadge": "已由你驗證"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "任命組織者",
|
||||
|
||||
+17
-1
@@ -1088,7 +1088,23 @@
|
||||
"lede": "使用组织的个人资料登录,即可发布、更新或撤回你的验证声明。"
|
||||
},
|
||||
"loginGateTitle": "使用你组织的个人资料登录",
|
||||
"loginGateBody": "使用你组织的 Nostr 个人资料登录,或创建一个,即可开始。登录后,你可以在这里发布你的验证声明。"
|
||||
"loginGateBody": "使用你组织的 Nostr 个人资料登录,或创建一个,即可开始。登录后,你可以在这里发布你的验证声明。",
|
||||
"tutorial": {
|
||||
"eyebrow": "你现在是验证者了",
|
||||
"title": "如何验证一个活动",
|
||||
"lede": "你的声明已生效。下面教你如何为信任的活动背书——从任意活动卡片只需两步即可完成。",
|
||||
"steps": {
|
||||
"open": { "title": "打开菜单", "body": "在任意活动卡片上,点击横幅右上角的三点按钮。" },
|
||||
"verify": { "title": "选择\"验证此活动\"", "body": "菜单会显示一个验证操作——仅对你这样的版主和验证者可见。" },
|
||||
"confirm": { "title": "确认即可完成", "body": "证明该活动真实可信。你的徽章会出现在卡片上,让捐赠者知道你为它背书。" }
|
||||
},
|
||||
"demo": {
|
||||
"campaignTitle": "为 Mwanza 提供清洁饮水",
|
||||
"campaignOrganizer": "由 Mradi 基金会发起",
|
||||
"menuVerify": "验证此活动",
|
||||
"verifiedBadge": "已由你验证"
|
||||
}
|
||||
}
|
||||
},
|
||||
"organizers": {
|
||||
"appoint": "任命组织者",
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
import { MilkdownEditor } from '@/components/markdown/MilkdownEditor';
|
||||
import { LoginArea } from '@/components/auth/LoginArea';
|
||||
import { VerifyTutorial } from '@/components/organizations/VerifyTutorial';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
@@ -262,6 +263,7 @@ function VerifierEditor() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<Card className="border-border/60 shadow-sm">
|
||||
<CardContent className="p-6 sm:p-8 space-y-6">
|
||||
{/* Prompt */}
|
||||
@@ -321,6 +323,11 @@ function VerifierEditor() {
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Once the org's statement is live, teach them the actual
|
||||
verify gesture: the three-dots menu on any campaign card. */}
|
||||
{isPublished && <VerifyTutorial />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -138,6 +138,12 @@ export default {
|
||||
// an organic audio indicator.
|
||||
'0%, 100%': { transform: 'scaleY(0.35)' },
|
||||
'50%': { transform: 'scaleY(1)' }
|
||||
},
|
||||
'tutorial-tap': {
|
||||
// A soft "press" pulse for the demo cursor in the
|
||||
// verifier tutorial — shrinks briefly to read as a tap.
|
||||
'0%, 70%, 100%': { transform: 'scale(1)' },
|
||||
'80%': { transform: 'scale(0.78)' }
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
@@ -149,7 +155,8 @@ export default {
|
||||
'collapsible-down': 'collapsible-down 0.2s ease-out',
|
||||
'collapsible-up': 'collapsible-up 0.2s ease-out',
|
||||
'accent-glow': 'accent-glow 2s ease-in-out infinite',
|
||||
'equaliser-bar': 'equaliser-bar 0.9s ease-in-out infinite'
|
||||
'equaliser-bar': 'equaliser-bar 0.9s ease-in-out infinite',
|
||||
'tutorial-tap': 'tutorial-tap 2.4s ease-in-out infinite'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user