Add Venezuela earthquake relief banner to home page
Pin a full-bleed emergency relief banner to the top of the home page during the Venezuela earthquake response. It rotates through news photographs from Caracas via the shared HeroBanner (slow crossfade + Ken-Burns pan), with a humanitarian headline and two CTAs: Donate to relief (deep-links to /campaigns?country=VE) and Raise funds for Venezuela (auth-gated campaign creation). Also fix a latent HeroBanner crossfade bug where new layers mounted at their final opacity, making transitions snap instead of fade; layers now mount hidden and flip visible on the next animation frame. Copy lives under campaigns.home.venezuelaRelief.* and is translated across all 16 locales.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 226 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 257 KiB |
@@ -38,6 +38,14 @@ interface Layer {
|
||||
id: number;
|
||||
/** URL of the image rendered on this layer. */
|
||||
url: string;
|
||||
/**
|
||||
* Whether this layer has been flipped to its visible opacity. A new
|
||||
* layer mounts with `entered: false` (opacity 0) and is flipped to
|
||||
* `true` on the next animation frame so the CSS opacity transition
|
||||
* actually fires — without this two-step the browser paints the layer
|
||||
* straight at its final opacity and the crossfade looks instant.
|
||||
*/
|
||||
entered: boolean;
|
||||
}
|
||||
|
||||
const FADE_MS = 1500;
|
||||
@@ -61,7 +69,7 @@ export function HeroBanner({
|
||||
const [index, setIndex] = useState(0);
|
||||
const idRef = useRef(0);
|
||||
const [layers, setLayers] = useState<Layer[]>(() =>
|
||||
images.length > 0 ? [{ id: 0, url: images[0] }] : [],
|
||||
images.length > 0 ? [{ id: 0, url: images[0], entered: true }] : [],
|
||||
);
|
||||
|
||||
// Honor the user's reduced-motion preference. We freeze the rotation
|
||||
@@ -90,17 +98,34 @@ export function HeroBanner({
|
||||
return () => window.clearInterval(id);
|
||||
}, [images, intervalMs]);
|
||||
|
||||
// Whenever the active index changes, push a new layer on top. Old
|
||||
// layers are reaped after the crossfade completes.
|
||||
// Whenever the active index changes, push a new layer on top. The
|
||||
// layer mounts hidden (`entered: false`) and is flipped visible on the
|
||||
// next animation frame so the opacity transition animates instead of
|
||||
// snapping. Old layers are reaped after the crossfade completes.
|
||||
useEffect(() => {
|
||||
if (images.length === 0) return;
|
||||
const url = images[index % images.length];
|
||||
const id = ++idRef.current;
|
||||
setLayers((prev) => [...prev, { id, url }]);
|
||||
setLayers((prev) => [...prev, { id, url, entered: false }]);
|
||||
|
||||
const raf = window.requestAnimationFrame(() => {
|
||||
// Second frame guarantees the browser has painted the layer at
|
||||
// opacity 0 before we transition it to 1.
|
||||
window.requestAnimationFrame(() => {
|
||||
setLayers((prev) =>
|
||||
prev.map((l) => (l.id === id ? { ...l, entered: true } : l)),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
const timeout = window.setTimeout(() => {
|
||||
setLayers((prev) => prev.filter((l) => l.id === id));
|
||||
}, FADE_MS + 50);
|
||||
return () => window.clearTimeout(timeout);
|
||||
|
||||
return () => {
|
||||
window.cancelAnimationFrame(raf);
|
||||
window.clearTimeout(timeout);
|
||||
};
|
||||
}, [index, images]);
|
||||
|
||||
// Preload the next image during idle time so the next crossfade
|
||||
@@ -119,14 +144,13 @@ export function HeroBanner({
|
||||
className={cn('absolute inset-0 overflow-hidden', className)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{layers.map((layer, i) => {
|
||||
const isTop = i === layers.length - 1;
|
||||
{layers.map((layer) => {
|
||||
return (
|
||||
<div
|
||||
key={layer.id}
|
||||
className="absolute inset-0"
|
||||
style={{
|
||||
opacity: isTop ? 1 : 0,
|
||||
opacity: layer.entered ? 1 : 0,
|
||||
transition: `opacity ${FADE_MS}ms ease-in-out`,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { HeartHandshake, PlusCircle } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { HeroBanner } from '@/components/HeroBanner';
|
||||
import { StartCampaignLink } from '@/components/StartCampaignLink';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
/**
|
||||
* Ordered set of news photographs from the Venezuela earthquake that
|
||||
* rotate behind the relief banner. They live in `/public/hero/` and use
|
||||
* the shared {@link HeroBanner} crossfade + slow-pan treatment, the same
|
||||
* animation as the site's other page heroes. Photo attributions are
|
||||
* surfaced generically in the `credit` copy beneath the banner.
|
||||
*/
|
||||
const VENEZUELA_RELIEF_IMAGES: readonly string[] = [
|
||||
'/hero/ve-quake-1.jpg', // residents embrace near a collapsed building (AFP/Getty)
|
||||
'/hero/ve-quake-2.jpg', // community + rescue workers search the rubble (AP)
|
||||
'/hero/ve-quake-3.jpg', // severe building damage in Caracas (AFP/Getty)
|
||||
];
|
||||
|
||||
/**
|
||||
* Full-bleed emergency relief banner pinned to the very top of the
|
||||
* home page during the Venezuela earthquake response.
|
||||
*
|
||||
* This is deliberately loud — a disaster appeal, not a subtle promo:
|
||||
*
|
||||
* - A full-bleed crossfading gallery of news photographs from the
|
||||
* quake (via the shared {@link HeroBanner}: slow pan + crossfade,
|
||||
* reduced-motion aware) sits behind the copy. A light dark gradient
|
||||
* keeps the headline and CTAs readable while letting the photos stay
|
||||
* the focus.
|
||||
* - A large display headline ("Venezuela needs you") with the final
|
||||
* word painted inside a solid brand-orange highlighter block — the
|
||||
* same idiom as the home hero's "unstoppable".
|
||||
* - Two unmistakable calls to action: **Donate to relief** deep-links
|
||||
* to the Venezuela-filtered campaign browse (`/campaigns?country=VE`)
|
||||
* so donors land straight on fundable relief campaigns; **Raise funds
|
||||
* for Venezuela** routes organizers through `StartCampaignLink`
|
||||
* (auth-gated) to publish a new fundraiser.
|
||||
*
|
||||
* Not dismissible by design — while the appeal is active it stays put
|
||||
* for every visitor (product decision). When the response winds down,
|
||||
* remove `<VenezuelaReliefBanner />` from {@link CampaignsPage}.
|
||||
*
|
||||
* All copy lives under `campaigns.home.venezuelaRelief.*` in the
|
||||
* locale files so every shipped language stays in sync.
|
||||
*/
|
||||
export function VenezuelaReliefBanner({ className }: { className?: string }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<section
|
||||
aria-labelledby="venezuela-relief-title"
|
||||
role="region"
|
||||
className={cn(
|
||||
'relative overflow-hidden border-b border-border bg-[hsl(220_25%_6%)] text-white',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{/* Layer 1 — full-bleed crossfading photo gallery. A long
|
||||
interval gives a slow, contemplative pacing; HeroBanner's
|
||||
built-in 1.5s crossfade + slow pan handles the dissolve. */}
|
||||
<HeroBanner images={VENEZUELA_RELIEF_IMAGES} intervalMs={9000} />
|
||||
|
||||
{/* Layer 2 — readability gradient. Lighter than a typical hero
|
||||
overlay so the photograph stays the focus: a gentle vertical
|
||||
darken plus a horizontal start-edge darken. The horizontal
|
||||
stops are pinned with explicit percentages (rather than the
|
||||
default even thirds) so the dark backing reliably reaches the
|
||||
end of the centred content column on ultrawide screens and
|
||||
fades to a clean transparent on the trailing half. */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 bg-gradient-to-t from-black/75 via-black/35 to-black/20"
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 bg-[linear-gradient(to_right,rgba(0,0,0,0.72)_0%,rgba(0,0,0,0.5)_35%,rgba(0,0,0,0)_70%)] rtl:bg-[linear-gradient(to_left,rgba(0,0,0,0.72)_0%,rgba(0,0,0,0.5)_35%,rgba(0,0,0,0)_70%)]"
|
||||
/>
|
||||
|
||||
{/* Layer 2a — side shadowbox / vignette. Darkens only the outermost
|
||||
edges so the banner frames cleanly on ultrawide displays instead
|
||||
of the photo bleeding flat to the screen edges. The dark stops
|
||||
sit at 0% and 100% and fall off fast (by ~12%), so on normal
|
||||
widths the readable centre is untouched while wide monitors get
|
||||
a soft letterbox-style frame on both sides. */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 bg-[linear-gradient(to_right,rgba(0,0,0,0.55)_0%,rgba(0,0,0,0)_12%,rgba(0,0,0,0)_88%,rgba(0,0,0,0.55)_100%)]"
|
||||
/>
|
||||
|
||||
{/* Layer 2b — film-grain noise. A tiny inline SVG fractal-noise
|
||||
texture tiled across the banner at low opacity, with
|
||||
`mix-blend-overlay` so it reads as grain over the photo rather
|
||||
than a flat grey wash. Adds depth and ties the warm photo tones
|
||||
to the dark UI. Pure CSS/SVG, negligible cost, `pointer-events-
|
||||
none` so it never intercepts clicks. */}
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="absolute inset-0 opacity-[0.12] mix-blend-overlay pointer-events-none"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")",
|
||||
backgroundSize: '160px 160px',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Layer 3 — content. Fills ~85% of the initial viewport so it
|
||||
reads as the headline of the day rather than a sibling band,
|
||||
with a sensible minimum on very short / very tall screens.
|
||||
`dvh` so mobile browser chrome (collapsing address bar) doesn't
|
||||
jump the height. */}
|
||||
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 py-20 sm:py-28 h-[85dvh] min-h-[520px] max-h-[1200px] flex flex-col justify-center">
|
||||
<div className="max-w-3xl">
|
||||
<h2
|
||||
id="venezuela-relief-title"
|
||||
className="font-display italic font-normal uppercase tracking-wide leading-[0.92] text-5xl sm:text-7xl lg:text-8xl drop-shadow-[0_2px_12px_rgba(0,0,0,0.45)]"
|
||||
style={{ WebkitTextStroke: '0.018em currentColor' }}
|
||||
>
|
||||
<Trans
|
||||
i18nKey="campaigns.home.venezuelaRelief.title"
|
||||
components={[
|
||||
// Index 0: the emphasised word, painted inside a solid
|
||||
// brand-orange highlighter block that hugs the text — the
|
||||
// same idiom as the home hero's "unstoppable". `text-indent`
|
||||
// compensates for Bebas Neue's italic skew so the orange
|
||||
// sits flush against the first letter.
|
||||
<span
|
||||
key="hl"
|
||||
className="inline-block w-fit ps-0 pe-3 bg-primary text-white align-baseline"
|
||||
style={{ textIndent: '-0.06em' }}
|
||||
/>,
|
||||
]}
|
||||
/>
|
||||
</h2>
|
||||
|
||||
{/* Body sits lower, with generous breathing room above it. A
|
||||
soft shadow keeps it legible now that the overlay is light. */}
|
||||
<p className="mt-7 text-base sm:text-lg lg:text-xl text-white max-w-xl leading-relaxed drop-shadow-[0_1px_8px_rgba(0,0,0,0.6)]">
|
||||
{t('campaigns.home.venezuelaRelief.body')}
|
||||
</p>
|
||||
|
||||
<div className="mt-7 flex flex-col sm:flex-row flex-wrap gap-3">
|
||||
{/* Primary CTA — donate to Venezuela-filtered relief campaigns */}
|
||||
<Button
|
||||
size="lg"
|
||||
asChild
|
||||
className="rounded-full text-white font-semibold text-base h-12 px-7 [&_svg]:size-[18px] motion-safe:transition-colors"
|
||||
>
|
||||
<Link to="/campaigns?country=VE">
|
||||
<HeartHandshake className="mr-2" />
|
||||
{t('campaigns.home.venezuelaRelief.donate')}
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
{/* Secondary CTA — start a relief fundraiser (auth-gated) */}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="lg"
|
||||
asChild
|
||||
className="rounded-full h-12 px-6 text-base border-white/40 bg-white/10 text-white hover:bg-white/20 hover:text-white hover:border-white/60 [&_svg]:size-[18px]"
|
||||
>
|
||||
<StartCampaignLink>
|
||||
<PlusCircle className="mr-2" />
|
||||
{t('campaigns.home.venezuelaRelief.startCampaign')}
|
||||
</StartCampaignLink>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Photo credit — accuracy + attribution */}
|
||||
<p className="text-xs text-white/50 pt-1">
|
||||
{t('campaigns.home.venezuelaRelief.credit')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export default VenezuelaReliefBanner;
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "حملاتك منشورة على Nostr وتعمل التبرعات عبر رابط الحملة. تصفّح كل الحملات على /campaigns؛ ويختار فريق {{appName}} مجموعة منتقاة لعرضها على الصفحة الرئيسية.",
|
||||
"empty": "لا توجد حملات بعد",
|
||||
"emptyHint": "كن أول من يبدأ حملة تمويل على {{appName}}. اروِ قصتك، اختر المستفيدين، وشارك الرابط.",
|
||||
"venezuelaRelief": {
|
||||
"title": "فنزويلا بحاجة <0>إليك</0>",
|
||||
"body": "ضرب زلزال قويّ شمال فنزويلا، وكانت كاراكاس ولا غوايرا الأشدّ تضرّرًا. لا تستطيع العائلات هناك تجاوز هذه المحنة وحدها. تبرّعك يذهب مباشرة إلى حملات الإغاثة على الأرض، فيحوّل رحمتك اليوم إلى مأوى وطعام وأمل.",
|
||||
"donate": "تبرّع للإغاثة",
|
||||
"startCampaign": "اجمع التبرّعات من أجل فنزويلا",
|
||||
"credit": "صور من كاراكاس، فنزويلا. (AP؛ AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "لماذا {{appName}}",
|
||||
"title": "مبني بشكل مختلف.",
|
||||
|
||||
+8
-1
@@ -1442,7 +1442,7 @@
|
||||
"home": {
|
||||
"seoTitle": "Fundraisers",
|
||||
"seoDescription": "Connecting the world to unstoppable funding.",
|
||||
"heroTagline": "Connecting the\u00a0world to<1></1><0>unstoppable</0> funding.",
|
||||
"heroTagline": "Connecting the world to<1></1><0>unstoppable</0> funding.",
|
||||
"heroBody": "Raise Bitcoin directly from supporters around the world. Every donation settles straight to your wallet, with no middlemen, no chargebacks, and no platform holding your funds.",
|
||||
"startCampaign": "Start a campaign",
|
||||
"verifyCampaigns": "Verify campaigns",
|
||||
@@ -1463,6 +1463,13 @@
|
||||
"yourCampaignsDesc": "Your campaigns are live on Nostr and donations work via the campaign link. Browse all campaigns at /campaigns; the {{appName}} team features a curated selection on the homepage.",
|
||||
"empty": "No campaigns yet",
|
||||
"emptyHint": "Be the first to start a fundraiser on {{appName}}. Tell your story, choose your beneficiaries, and share the link.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela needs <0>you</0>",
|
||||
"body": "A powerful earthquake has struck northern Venezuela, hitting Caracas and La Guaira hardest. Families there can't get through this alone. Your donation goes straight to relief campaigns on the ground, turning your compassion into shelter, food, and hope today.",
|
||||
"donate": "Donate to relief",
|
||||
"startCampaign": "Raise funds for Venezuela",
|
||||
"credit": "Photos from Caracas, Venezuela. (AP; AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Why {{appName}}",
|
||||
"title": "Built different.",
|
||||
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "Tus campañas están activas en Nostr y las donaciones funcionan mediante el enlace de la campaña. Explora todas las campañas en /campaigns; el equipo de {{appName}} destaca una selección curada en la página de inicio.",
|
||||
"empty": "Aún no hay campañas",
|
||||
"emptyHint": "Sé el primero en iniciar una recaudación en {{appName}}. Cuenta tu historia, elige a los beneficiarios y comparte el enlace.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela <0>te</0> necesita",
|
||||
"body": "Un fuerte terremoto ha sacudido el norte de Venezuela, golpeando con mayor dureza a Caracas y La Guaira. Las familias de allí no pueden salir adelante solas. Tu donación va directa a las campañas de ayuda sobre el terreno, transformando hoy mismo tu compasión en refugio, alimento y esperanza.",
|
||||
"donate": "Donar a la ayuda",
|
||||
"startCampaign": "Recauda fondos para Venezuela",
|
||||
"credit": "Fotos de Caracas, Venezuela. (AP; AFP vía Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Por qué {{appName}}",
|
||||
"title": "Construido diferente.",
|
||||
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "کمپینهای شما در Nostr فعال هستند و کمکهای مالی از طریق لینک کمپین کار میکنند. همه کمپینها را در /campaigns مرور کنید؛ تیم {{appName}} مجموعهای منتخب را در صفحه اصلی معرفی میکند.",
|
||||
"empty": "هنوز کمپینی وجود ندارد",
|
||||
"emptyHint": "اولین نفری باشید که در {{appName}} کمپین راهاندازی میکند. داستان خود را بگویید، ذینفعان را انتخاب کنید، و لینک را به اشتراک بگذارید.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela به <0>شما</0> نیاز دارد",
|
||||
"body": "زمینلرزهای ویرانگر شمال Venezuela را لرزانده و بیش از همه Caracas و La Guaira را در هم کوبیده است. خانوادههای آنجا نمیتوانند بهتنهایی از این مصیبت عبور کنند. کمک شما مستقیماً به کمپینهای امدادرسانی در محل میرسد و دلسوزیتان را همین امروز به سرپناه، غذا و امید بدل میکند.",
|
||||
"donate": "کمک به امدادرسانی",
|
||||
"startCampaign": "جمعآوری کمک برای Venezuela",
|
||||
"credit": "تصاویری از Caracas، ونزوئلا. (AP؛ AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "چرا {{appName}}",
|
||||
"title": "متفاوت ساخته شده است.",
|
||||
|
||||
@@ -1369,6 +1369,13 @@
|
||||
"yourCampaignsDesc": "Vos campagnes sont en ligne sur Nostr et les dons fonctionnent via le lien de la campagne. Parcourez toutes les campagnes sur /campaigns ; l'équipe de {{appName}} met en avant une sélection sur la page d'accueil.",
|
||||
"empty": "Aucune campagne pour l'instant",
|
||||
"emptyHint": "Soyez le premier à démarrer une collecte de fonds sur {{appName}}. Racontez votre histoire, choisissez vos bénéficiaires et partagez le lien.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Le Venezuela a besoin de <0>vous</0>",
|
||||
"body": "Un puissant séisme a frappé le nord du Venezuela, touchant le plus durement Caracas et La Guaira. Là-bas, les familles ne peuvent pas surmonter cette épreuve seules. Votre don va directement aux campagnes de secours sur le terrain et transforme votre compassion en abri, en nourriture et en espoir, dès aujourd'hui.",
|
||||
"donate": "Faire un don aux secours",
|
||||
"startCampaign": "Récolter des fonds pour le Venezuela",
|
||||
"credit": "Photos de Caracas, au Venezuela. (AP ; AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Pourquoi {{appName}}",
|
||||
"title": "Conçu différemment.",
|
||||
|
||||
@@ -1373,6 +1373,13 @@
|
||||
"searchAriaLabel": "कैंपेन खोजें",
|
||||
"noMatch": "“{{query}}” से मेल खाने वाला कोई कैंपेन नहीं",
|
||||
"noMatchHint": "अलग खोज शब्द आज़माएँ, या खोज साफ़ करें।",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela को <0>आपकी</0> ज़रूरत है",
|
||||
"body": "उत्तरी Venezuela में एक भीषण भूकंप आया है, जिसने Caracas और La Guaira को सबसे ज़्यादा तबाह किया है। वहाँ के परिवार इस मुश्किल वक़्त से अकेले नहीं उबर सकते। आपका दान सीधे ज़मीन पर चल रहे राहत अभियानों तक पहुँचता है, और आज ही आपकी करुणा को आसरा, भोजन और उम्मीद में बदल देता है।",
|
||||
"donate": "राहत के लिए दान करें",
|
||||
"startCampaign": "Venezuela के लिए धन जुटाएँ",
|
||||
"credit": "Caracas, Venezuela की तस्वीरें। (AP; AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "क्यों {{appName}}",
|
||||
"title": "अलग ढंग से बना।",
|
||||
|
||||
@@ -1373,6 +1373,13 @@
|
||||
"searchAriaLabel": "Cari kampanye",
|
||||
"noMatch": "Tidak ada kampanye yang cocok dengan “{{query}}”",
|
||||
"noMatchHint": "Coba kata pencarian lain, atau bersihkan pencarian.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela membutuhkan <0>Anda</0>",
|
||||
"body": "Gempa bumi dahsyat telah mengguncang Venezuela bagian utara, dengan dampak terparah di Caracas dan La Guaira. Keluarga-keluarga di sana tidak bisa melewati cobaan ini sendirian. Donasi Anda langsung mengalir ke kampanye bantuan di lapangan, mengubah belas kasih Anda menjadi tempat berlindung, makanan, dan harapan hari ini.",
|
||||
"donate": "Donasi untuk bantuan",
|
||||
"startCampaign": "Galang dana untuk Venezuela",
|
||||
"credit": "Foto dari Caracas, Venezuela. (AP; AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Mengapa {{appName}}",
|
||||
"title": "Dibangun berbeda.",
|
||||
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "យុទ្ធនាការរបស់អ្នកនៅរស់នៅលើ Nostr ហើយការបរិច្ចាគដំណើរការតាមរយៈតំណយុទ្ធនាការ។ រកមើលយុទ្ធនាការទាំងអស់នៅ /campaigns; ក្រុម {{appName}} បង្ហាញការជ្រើសរើសដែលបានសម្រិតសម្រាំងនៅទំព័រដើម។",
|
||||
"empty": "មិនទាន់មានយុទ្ធនាការនៅឡើយ",
|
||||
"emptyHint": "ធ្វើជាមនុស្សដំបូងដែលចាប់ផ្ដើមការប្រមូលមូលនិធិនៅ {{appName}}។ ប្រាប់រឿងរបស់អ្នក ជ្រើសរើសអ្នកទទួលផល និងចែករំលែកតំណ។",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela ត្រូវការ<0>អ្នក</0>",
|
||||
"body": "រញ្ជួយដីដ៏ខ្លាំងមួយបានវាយប្រហារភាគខាងជើងនៃ Venezuela ដោយធ្វើឱ្យ Caracas និង La Guaira រងគ្រោះធ្ងន់ធ្ងរបំផុត។ គ្រួសារនៅទីនោះមិនអាចឆ្លងផុតវិបត្តិនេះតែម្នាក់ឯងបានឡើយ។ ការបរិច្ចាគរបស់អ្នកនឹងទៅដល់ដោយផ្ទាល់ទៅកាន់យុទ្ធនាការសង្គ្រោះនៅនឹងកន្លែង ប្រែក្លាយក្ដីមេត្តាករុណារបស់អ្នកទៅជាជម្រក អាហារ និងក្ដីសង្ឃឹមនៅថ្ងៃនេះ។",
|
||||
"donate": "បរិច្ចាគដើម្បីសង្គ្រោះ",
|
||||
"startCampaign": "ប្រមូលមូលនិធិសម្រាប់ Venezuela",
|
||||
"credit": "រូបថតពី Caracas ប្រទេសវេណេស៊ុយអេឡា។ (AP; AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "ហេតុអ្វី {{appName}}",
|
||||
"title": "សាងសង់ខុសប្លែក។",
|
||||
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "ستاسو کمپاینونه په Nostr کې ژوندي دي او مرستې د کمپاین له لینک څخه کار کوي. ټول کمپاینونه په /campaigns کې وګورئ؛ د {{appName}} ټیم په کور پاڼه کې یوه ټاکل شوې ټولګه ښیي.",
|
||||
"empty": "تر اوسه کوم کمپاین نشته",
|
||||
"emptyHint": "په {{appName}} کې د مرستو راټولولو کمپاین پیل کوونکی لومړی شئ. خپله کیسه ووایاست، ګټه اخیستونکي وټاکئ، او لینک شریک کړئ.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela <0>تاسو</0> ته اړتیا لري",
|
||||
"body": "یوې زورورې زلزلې د Venezuela شمال ولړزاوه، چې تر ټولو سخت زیان يې Caracas او La Guaira ته ورساوه. هلته کورنۍ يوازې له دې کړاو څخه نشي خلاصېدلی. ستاسو ډالۍ مستقیماً پر ځمکه فعالو مرستندویه کمپاینونو ته رسیږي، او ستاسو زړهسوی نن په سرپناه، خوراک او هیله بدلوي.",
|
||||
"donate": "مرستې ته ډالۍ ورکړئ",
|
||||
"startCampaign": "د Venezuela لپاره مرسته راټوله کړئ",
|
||||
"credit": "انځور: اوسېدونکي د Caracas په یوه نړېدلې ودانۍ ترڅنګ یو بل غېږ کې نیسي. (AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "ولې {{appName}}",
|
||||
"title": "په بل ډول جوړ شوی.",
|
||||
|
||||
@@ -1369,6 +1369,13 @@
|
||||
"yourCampaignsDesc": "Suas campanhas estão no ar no Nostr e as doações funcionam através do link da campanha. Navegue por todas as campanhas em /campaigns; a equipe do {{appName}} apresenta uma seleção curada na página inicial.",
|
||||
"empty": "Nenhuma campanha ainda",
|
||||
"emptyHint": "Seja o primeiro a iniciar uma arrecadação no {{appName}}. Conte sua história, escolha seus beneficiários e compartilhe o link.",
|
||||
"venezuelaRelief": {
|
||||
"title": "A Venezuela precisa de <0>você</0>",
|
||||
"body": "Um forte terremoto atingiu o norte da Venezuela, castigando com mais força Caracas e La Guaira. As famílias de lá não conseguem superar isso sozinhas. Sua doação vai diretamente para as campanhas de ajuda no local, transformando hoje a sua compaixão em abrigo, comida e esperança.",
|
||||
"donate": "Doar para a ajuda",
|
||||
"startCampaign": "Arrecadar fundos para a Venezuela",
|
||||
"credit": "Foto: moradores se abraçam perto de um prédio desabado em Caracas. (AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Por que o {{appName}}",
|
||||
"title": "Construído diferente.",
|
||||
|
||||
@@ -1369,6 +1369,13 @@
|
||||
"yourCampaignsDesc": "Ваши кампании уже в эфире в Nostr, и пожертвования работают через ссылку кампании. Просмотрите все кампании на /campaigns; команда {{appName}} выделяет отобранную подборку на главной странице.",
|
||||
"empty": "Пока нет кампаний",
|
||||
"emptyHint": "Будьте первым, кто запустит сбор средств на {{appName}}. Расскажите свою историю, выберите бенефициаров и поделитесь ссылкой.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Венесуэле нужна <0>ваша</0> помощь",
|
||||
"body": "Мощное землетрясение обрушилось на север Венесуэлы, сильнее всего пострадали Caracas и La Guaira. Семьям там не справиться в одиночку. Ваше пожертвование идёт напрямую в кампании помощи на месте, превращая ваше сострадание в кров, еду и надежду уже сегодня.",
|
||||
"donate": "Пожертвовать на помощь",
|
||||
"startCampaign": "Собрать средства для Венесуэлы",
|
||||
"credit": "Фото: жители обнимаются рядом с обрушившимся зданием в Caracas. (AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Почему {{appName}}",
|
||||
"title": "Сделано по-другому.",
|
||||
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "Mishandirapamwe yako iri panetwork yeNostr uye mipiro inoshanda kuburikidza nemurawu wemushandirapamwe. Tarisa mishandirapamwe yose pa/campaigns; boka re{{appName}} rinosarudza yakananga papeji rekutanga.",
|
||||
"empty": "Hapana mishandirapamwe parizvino",
|
||||
"emptyHint": "Iva wekutanga kutanga kuunganidza mari pa{{appName}}. Taura nyaya yako, sarudza vanobatsirwa, uchipa rwumwe rwekugovera.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela <0>inokuda</0>",
|
||||
"body": "Kudengenyeka kwenyika kune simba kwakarova kuchamhembe kweVenezuela, kuchikuvadza Caracas neLa Guaira zvakanyanya. Mhuri dziri ikoko hadzigoni kupfuura mudambudziko iri dzega. Chipo chako chinonanga kumishandirapamwe yekubatsira iri panzvimbo, ichishandura tsitsi dzako kuva pekugara, chikafu, netariro nhasi.",
|
||||
"donate": "Ipa kubatsira",
|
||||
"startCampaign": "Unganidza mari yeVenezuela",
|
||||
"credit": "Mufananidzo: vagari vachimbundirana pedyo nechivako chakawira muCaracas. (AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Sei {{appName}}",
|
||||
"title": "Yakavakwa zvakasiyana.",
|
||||
|
||||
@@ -1373,6 +1373,13 @@
|
||||
"searchAriaLabel": "Tafuta kampeni",
|
||||
"noMatch": "Hakuna kampeni zinazolingana na “{{query}}”",
|
||||
"noMatchHint": "Jaribu neno tofauti la utafutaji, au futa utafutaji.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela <0>inakuhitaji</0>",
|
||||
"body": "Tetemeko kubwa la ardhi limeikumba kaskazini mwa Venezuela, likiathiri vibaya zaidi maeneo ya Caracas na La Guaira. Familia zilizoko huko haziwezi kupita katika dhiki hii peke yao. Mchango wako unawafikia moja kwa moja wahanga kupitia kampeni za misaada zilizoko eneo la tukio, ukigeuza huruma yako kuwa makao, chakula, na matumaini leo.",
|
||||
"donate": "Changia misaada",
|
||||
"startCampaign": "Changisha fedha kwa ajili ya Venezuela",
|
||||
"credit": "Picha: wakazi wakikumbatiana karibu na jengo lililoporomoka mjini Caracas. (AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Kwa nini {{appName}}",
|
||||
"title": "Imejengwa tofauti.",
|
||||
|
||||
@@ -1373,6 +1373,13 @@
|
||||
"searchAriaLabel": "Kampanyaları ara",
|
||||
"noMatch": "“{{query}}” ile eşleşen kampanya yok",
|
||||
"noMatchHint": "Farklı bir arama terimi deneyin ya da aramayı temizleyin.",
|
||||
"venezuelaRelief": {
|
||||
"title": "Venezuela <0>size</0> ihtiyaç duyuyor",
|
||||
"body": "Kuzey Venezuela'yı şiddetli bir deprem vurdu; en ağır darbeyi Caracas ve La Guaira aldı. Oradaki aileler bu acıyı tek başlarına atlatamaz. Bağışınız doğrudan sahadaki yardım kampanyalarına ulaşır ve şefkatinizi bugün barınağa, gıdaya ve umuda dönüştürür.",
|
||||
"donate": "Yardıma bağış yap",
|
||||
"startCampaign": "Venezuela için fon toplayın",
|
||||
"credit": "Fotoğraf: Caracas'ta çöken bir binanın yakınında kucaklaşan halk. (AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "Neden {{appName}}",
|
||||
"title": "Farklı inşa edildi.",
|
||||
|
||||
@@ -931,6 +931,13 @@
|
||||
"searchAriaLabel": "搜尋活動",
|
||||
"noMatch": "沒有活動符合「{{query}}」",
|
||||
"noMatchHint": "請嘗試不同的搜尋字詞,或清除搜尋。",
|
||||
"venezuelaRelief": {
|
||||
"title": "委內瑞拉需要<0>你</0>",
|
||||
"body": "一場強烈地震襲擊了 Venezuela 北部,其中 Caracas 與 La Guaira 受創最重。當地的家庭無法獨自撐過這場災難。你的捐款將直接送達當地的救援活動,讓你的關懷在今天就化為遮風避雨的住所、溫飽的食物,以及繼續走下去的希望。",
|
||||
"donate": "捐助救援",
|
||||
"startCampaign": "為委內瑞拉募款",
|
||||
"credit": "照片:居民在 Caracas 一棟倒塌建築附近相擁。(AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "為什麼選擇 {{appName}}",
|
||||
"title": "生來不同。",
|
||||
|
||||
@@ -927,6 +927,13 @@
|
||||
"yourCampaignsDesc": "你的活动已在 Nostr 上线,通过活动链接即可接收捐款。在 /campaigns 浏览所有活动;{{appName}} 团队会在首页展示精选活动。",
|
||||
"empty": "暂无活动",
|
||||
"emptyHint": "成为在 {{appName}} 发起众筹的第一人。讲述你的故事、选择受益人、并分享链接。",
|
||||
"venezuelaRelief": {
|
||||
"title": "委内瑞拉需要<0>你</0>",
|
||||
"body": "一场强烈地震袭击了委内瑞拉北部,Caracas 与 La Guaira 受灾最为严重。那里的家庭无法独自挺过这一切。你的捐款将直接送达灾区一线的救援活动,把你的善意化作今天的栖身之所、食物与希望。",
|
||||
"donate": "为救援捐款",
|
||||
"startCampaign": "为委内瑞拉筹款",
|
||||
"credit": "图片:居民在 Caracas 一栋倒塌建筑附近相拥。(AFP via Getty Images)"
|
||||
},
|
||||
"whyDifferent": {
|
||||
"eyebrow": "为什么选 {{appName}}",
|
||||
"title": "我们与众不同。",
|
||||
|
||||
@@ -19,6 +19,7 @@ import { CampaignListsStrip } from '@/components/campaign-lists/CampaignListsStr
|
||||
import { HeroLightningMap } from '@/components/HeroLightningMap';
|
||||
import { StartCampaignLink } from '@/components/StartCampaignLink';
|
||||
import { AppDownloadNudge } from '@/components/AppDownloadNudge';
|
||||
import { VenezuelaReliefBanner } from '@/components/VenezuelaReliefBanner';
|
||||
import { useCampaigns } from '@/hooks/useCampaigns';
|
||||
import { useCampaignList } from '@/hooks/useCampaignLists';
|
||||
import { useAppContext } from '@/hooks/useAppContext';
|
||||
@@ -129,6 +130,7 @@ export function CampaignsPage() {
|
||||
|
||||
return (
|
||||
<main className="min-h-screen">
|
||||
<VenezuelaReliefBanner />
|
||||
<Hero />
|
||||
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 py-10 lg:py-14 space-y-12" id="campaigns">
|
||||
|
||||
Reference in New Issue
Block a user