i18n: translate CampaignsPage landing
Add campaigns.home.* namespace covering the hero (tagline, body,
three CTAs), the Featured and Community Campaigns section headings and
descriptions, the Browse-all link, the moderator-only Pending and
Hidden section labels (title/description/emptyText), the non-mod
"Your campaigns" section, and the empty-state card.
The hero tagline uses <Trans i18nKey="campaigns.home.heroTagline"
components={{0: <span/>}}> so each locale controls where the orange
highlighter falls. The English-only inner-span optical alignment
(negative margin to counter Bebas Neue italic skew on a leading 'u')
is dropped — it was overfit to one word and would have produced ugly
results in any non-English layout.
The ArrowRight icon in the "How it works" CTA picks up rtl:rotate-180
so it points the right way in RTL languages.
This commit is contained in:
@@ -57,6 +57,30 @@
|
||||
"goHome": "العودة للصفحة الرئيسية"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "حملات تمويل",
|
||||
"seoDescription": "نربط الناشطين بتمويل لا يمكن إيقافه.",
|
||||
"heroTagline": "تمويل <0>لا يمكن إيقافه</0> للناشطين.",
|
||||
"heroBody": "اجمع البتكوين مباشرةً من داعمين حول العالم. كل تبرّع يصل إلى محفظتك دون وسطاء، دون استرداد، ودون أن تحتفظ أي منصة بأموالك.",
|
||||
"startCampaign": "ابدأ حملة",
|
||||
"howItWorks": "كيف يعمل",
|
||||
"exploreCampaigns": "تصفّح الحملات",
|
||||
"featured": "مميّزة",
|
||||
"featuredDesc": "حملات منتقاة بعناية من فريق {{appName}}.",
|
||||
"community": "حملات المجتمع",
|
||||
"communityDesc": "ساعد في تمويل التغييرات التي تستحق العناء.",
|
||||
"browseAll": "تصفّح كل الحملات ←",
|
||||
"pending": "بانتظار الموافقة",
|
||||
"pendingDesc": "حملات موجودة على الشبكة لم يوافق عليها ولم يُخفها أي مشرف من فريق Soapbox بعد.",
|
||||
"pendingEmpty": "لا يوجد شيء بانتظار المراجعة.",
|
||||
"hidden": "مخفية",
|
||||
"hiddenDesc": "حملات أُزيلت من الصفحة الرئيسية العامة. استخدم قائمة البطاقة لإلغاء الإخفاء.",
|
||||
"hiddenEmpty": "لا توجد حملات مخفية حالياً.",
|
||||
"yourCampaigns": "حملاتك",
|
||||
"yourCampaignsDesc": "حملاتك منشورة على Nostr وتعمل التبرعات عبر الرابط. ستظهر على الصفحة الرئيسية بمجرد أن يوافق عليها مشرف من فريق Soapbox.",
|
||||
"empty": "لا توجد حملات بعد",
|
||||
"emptyHint": "كن أول من يبدأ حملة تمويل على {{appName}}. اروِ قصتك، اختر المستفيدين، وشارك الرابط."
|
||||
},
|
||||
"all": {
|
||||
"title": "كل الحملات",
|
||||
"seoTitle": "كل الحملات",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "Go home"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "Fundraisers",
|
||||
"seoDescription": "Connecting activists to unstoppable funding.",
|
||||
"heroTagline": "Connecting activists to <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",
|
||||
"howItWorks": "How it works",
|
||||
"exploreCampaigns": "Explore campaigns",
|
||||
"featured": "Featured",
|
||||
"featuredDesc": "Hand-picked campaigns from the {{appName}} team.",
|
||||
"community": "Community Campaigns",
|
||||
"communityDesc": "Help fund the changes worth making.",
|
||||
"browseAll": "Browse all campaigns →",
|
||||
"pending": "Pending approval",
|
||||
"pendingDesc": "Campaigns on the network that no Team Soapbox moderator has approved or hidden yet.",
|
||||
"pendingEmpty": "Nothing awaiting review.",
|
||||
"hidden": "Hidden",
|
||||
"hiddenDesc": "Campaigns suppressed from the public homepage. Use the kebab menu on a card to unhide.",
|
||||
"hiddenEmpty": "No campaigns are currently hidden.",
|
||||
"yourCampaigns": "Your campaigns",
|
||||
"yourCampaignsDesc": "Your campaigns are live on Nostr and donations work via the campaign link. They appear on the homepage once a Team Soapbox moderator approves them.",
|
||||
"empty": "No campaigns yet",
|
||||
"emptyHint": "Be the first to start a fundraiser on {{appName}}. Tell your story, choose your beneficiaries, and share the link."
|
||||
},
|
||||
"all": {
|
||||
"title": "All Campaigns",
|
||||
"seoTitle": "All campaigns",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "Ir al inicio"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "Recaudaciones",
|
||||
"seoDescription": "Conectamos a activistas con financiación imparable.",
|
||||
"heroTagline": "Activistas con financiación <0>imparable</0>.",
|
||||
"heroBody": "Recauda Bitcoin directamente de simpatizantes de todo el mundo. Cada donación va a tu cartera sin intermediarios, sin contracargos y sin que ninguna plataforma retenga tus fondos.",
|
||||
"startCampaign": "Iniciar una campaña",
|
||||
"howItWorks": "Cómo funciona",
|
||||
"exploreCampaigns": "Explorar campañas",
|
||||
"featured": "Destacadas",
|
||||
"featuredDesc": "Campañas seleccionadas por el equipo de {{appName}}.",
|
||||
"community": "Campañas de la comunidad",
|
||||
"communityDesc": "Ayuda a financiar los cambios que valen la pena.",
|
||||
"browseAll": "Ver todas las campañas →",
|
||||
"pending": "Pendientes de aprobación",
|
||||
"pendingDesc": "Campañas presentes en la red que ningún moderador del equipo Soapbox ha aprobado u ocultado todavía.",
|
||||
"pendingEmpty": "Nada pendiente de revisión.",
|
||||
"hidden": "Ocultas",
|
||||
"hiddenDesc": "Campañas suprimidas de la página de inicio pública. Usa el menú de la tarjeta para mostrarlas de nuevo.",
|
||||
"hiddenEmpty": "No hay campañas ocultas actualmente.",
|
||||
"yourCampaigns": "Tus campañas",
|
||||
"yourCampaignsDesc": "Tus campañas están activas en Nostr y las donaciones funcionan mediante el enlace. Aparecerán en la página de inicio cuando un moderador del equipo Soapbox las apruebe.",
|
||||
"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."
|
||||
},
|
||||
"all": {
|
||||
"title": "Todas las campañas",
|
||||
"seoTitle": "Todas las campañas",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "رفتن به خانه"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "کمپینهای جذب کمک مالی",
|
||||
"seoDescription": "اتصال فعالان به تأمین مالی غیرقابل توقف.",
|
||||
"heroTagline": "تأمین مالی <0>غیرقابل توقف</0> برای فعالان.",
|
||||
"heroBody": "بیتکوین را مستقیماً از حامیان سراسر جهان دریافت کنید. هر کمک مالی بدون واسطه، بدون استرداد، و بدون اینکه هیچ پلتفرمی پول شما را نگه دارد، مستقیماً به کیف پول شما میرسد.",
|
||||
"startCampaign": "شروع یک کمپین",
|
||||
"howItWorks": "چگونه کار میکند",
|
||||
"exploreCampaigns": "مرور کمپینها",
|
||||
"featured": "ویژه",
|
||||
"featuredDesc": "کمپینهای منتخب تیم {{appName}}.",
|
||||
"community": "کمپینهای جامعه",
|
||||
"communityDesc": "به تأمین مالی تغییراتی که ارزش انجام دادن دارند کمک کنید.",
|
||||
"browseAll": "← مرور همه کمپینها",
|
||||
"pending": "در انتظار تأیید",
|
||||
"pendingDesc": "کمپینهایی که در شبکه هستند و هیچ ناظر تیم Soapbox هنوز آنها را تأیید یا پنهان نکرده است.",
|
||||
"pendingEmpty": "چیزی برای بررسی نیست.",
|
||||
"hidden": "پنهانشده",
|
||||
"hiddenDesc": "کمپینهایی که از صفحه اصلی عمومی حذف شدهاند. برای آشکار کردن دوباره از منوی کارت استفاده کنید.",
|
||||
"hiddenEmpty": "در حال حاضر هیچ کمپینی پنهان نشده است.",
|
||||
"yourCampaigns": "کمپینهای شما",
|
||||
"yourCampaignsDesc": "کمپینهای شما در Nostr فعال هستند و کمکهای مالی از طریق لینک کار میکنند. به محض تأیید توسط یک ناظر تیم Soapbox، در صفحه اصلی ظاهر میشوند.",
|
||||
"empty": "هنوز کمپینی وجود ندارد",
|
||||
"emptyHint": "اولین نفری باشید که در {{appName}} کمپین راهاندازی میکند. داستان خود را بگویید، ذینفعان را انتخاب کنید، و لینک را به اشتراک بگذارید."
|
||||
},
|
||||
"all": {
|
||||
"title": "همه کمپینها",
|
||||
"seoTitle": "همه کمپینها",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "ត្រឡប់ទៅទំព័រដើម"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "យុទ្ធនាការប្រមូលមូលនិធិ",
|
||||
"seoDescription": "ភ្ជាប់សកម្មជនទៅនឹងមូលនិធិដែលមិនអាចបញ្ឈប់បាន។",
|
||||
"heroTagline": "ផ្ដល់សកម្មជននូវមូលនិធិ <0>មិនអាចបញ្ឈប់</0>។",
|
||||
"heroBody": "ប្រមូល Bitcoin ដោយផ្ទាល់ពីអ្នកគាំទ្រនៅជុំវិញពិភពលោក។ ការបរិច្ចាគនីមួយៗបានចូលទៅកាន់កាបូបរបស់អ្នកដោយផ្ទាល់ ដោយគ្មានអ្នកកណ្ដាល គ្មានការប្រគល់សងវិញ និងគ្មានវេទិកាណាមួយរក្សាទុកប្រាក់របស់អ្នក។",
|
||||
"startCampaign": "ចាប់ផ្ដើមយុទ្ធនាការ",
|
||||
"howItWorks": "របៀបដំណើរការ",
|
||||
"exploreCampaigns": "រកមើលយុទ្ធនាការ",
|
||||
"featured": "បានជ្រើសរើស",
|
||||
"featuredDesc": "យុទ្ធនាការដែលជ្រើសរើសដោយក្រុម {{appName}}។",
|
||||
"community": "យុទ្ធនាការសហគមន៍",
|
||||
"communityDesc": "ជួយផ្ដល់មូលនិធិដល់ការផ្លាស់ប្ដូរដែលសក្តិសម។",
|
||||
"browseAll": "មើលយុទ្ធនាការទាំងអស់ →",
|
||||
"pending": "កំពុងរង់ចាំការអនុម័ត",
|
||||
"pendingDesc": "យុទ្ធនាការនៅលើបណ្ដាញដែលគ្មានអ្នកសម្របសម្រួលក្រុម Soapbox អនុម័ត ឬលាក់នៅឡើយ។",
|
||||
"pendingEmpty": "គ្មានអ្វីរង់ចាំការពិនិត្យ។",
|
||||
"hidden": "បានលាក់",
|
||||
"hiddenDesc": "យុទ្ធនាការដែលត្រូវបានដកចេញពីទំព័រដើមសាធារណៈ។ ប្រើម៉ឺនុយលើកាតដើម្បីឈប់លាក់។",
|
||||
"hiddenEmpty": "បច្ចុប្បន្នគ្មានយុទ្ធនាការត្រូវបានលាក់។",
|
||||
"yourCampaigns": "យុទ្ធនាការរបស់អ្នក",
|
||||
"yourCampaignsDesc": "យុទ្ធនាការរបស់អ្នកនៅរស់នៅលើ Nostr ហើយការបរិច្ចាគដំណើរការតាមរយៈតំណយុទ្ធនាការ។ វានឹងបង្ហាញនៅទំព័រដើម នៅពេលដែលអ្នកសម្របសម្រួលក្រុម Soapbox អនុម័ត។",
|
||||
"empty": "មិនទាន់មានយុទ្ធនាការនៅឡើយ",
|
||||
"emptyHint": "ធ្វើជាមនុស្សដំបូងដែលចាប់ផ្ដើមការប្រមូលមូលនិធិនៅ {{appName}}។ ប្រាប់រឿងរបស់អ្នក ជ្រើសរើសអ្នកទទួលផល និងចែករំលែកតំណ។"
|
||||
},
|
||||
"all": {
|
||||
"title": "យុទ្ធនាការទាំងអស់",
|
||||
"seoTitle": "យុទ្ធនាការទាំងអស់",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "کور ته لاړ شه"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "د مرستو راټولولو کمپاینونه",
|
||||
"seoDescription": "د فعالانو سره <0>نه درېدونکې</0> تمویل نښلوي.",
|
||||
"heroTagline": "د فعالانو لپاره <0>نه درېدونکی</0> تمویل.",
|
||||
"heroBody": "د نړۍ په ګوټ ګوټ کې د ملاتړ کوونکو څخه په مستقیم ډول بټکوین راټول کړئ. هره مرسته بې له منځګړو، بې له ستنېدنې، او پرته له دې چې کوم پلیټفارم ستاسو پیسې وساتي، مستقیماً ستاسو بټوې ته داخلېږي.",
|
||||
"startCampaign": "کمپاین پیل کړئ",
|
||||
"howItWorks": "څنګه کار کوي",
|
||||
"exploreCampaigns": "د کمپاینونو لټون",
|
||||
"featured": "ځانګړي",
|
||||
"featuredDesc": "د {{appName}} ټیم له خوا ټاکل شوي کمپاینونه.",
|
||||
"community": "د ټولنې کمپاینونه",
|
||||
"communityDesc": "د هغو بدلونونو په تمویل کې مرسته وکړئ چې وړ دي.",
|
||||
"browseAll": "← ټول کمپاینونه وګورئ",
|
||||
"pending": "د منلو په تمه",
|
||||
"pendingDesc": "هغه کمپاینونه چې په شبکه کې شته، خو د Soapbox ټیم هیڅ مدیر یې لا تر اوسه نه دی منلی او نه پټ کړی.",
|
||||
"pendingEmpty": "د بیاکتنې لپاره څه نشته.",
|
||||
"hidden": "پټ شوي",
|
||||
"hiddenDesc": "هغه کمپاینونه چې د عمومي کور پاڼې څخه پټ شوي. د بېرته ښودلو لپاره د کارت مینو وکاروئ.",
|
||||
"hiddenEmpty": "اوس مهال هیڅ کمپاین پټ نه دی.",
|
||||
"yourCampaigns": "ستاسو کمپاینونه",
|
||||
"yourCampaignsDesc": "ستاسو کمپاینونه په Nostr کې ژوندي دي او مرستې د کمپاین له لینک څخه کار کوي. کله چې د Soapbox ټیم یو مدیر یې ومني، په کور پاڼه کې به څرګند شي.",
|
||||
"empty": "تر اوسه کوم کمپاین نشته",
|
||||
"emptyHint": "په {{appName}} کې د مرستو راټولولو کمپاین پیل کوونکی لومړی شئ. خپله کیسه ووایاست، ګټه اخیستونکي وټاکئ، او لینک شریک کړئ."
|
||||
},
|
||||
"all": {
|
||||
"title": "ټول کمپاینونه",
|
||||
"seoTitle": "ټول کمپاینونه",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "Enda kumba"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "Mishandirapamwe yekuunganidza mari",
|
||||
"seoDescription": "Tinobatanidza vatsigiri vetsika nemari isingadziviswi.",
|
||||
"heroTagline": "Mari <0>isingadziviswi</0> kuvatsigiri vetsika.",
|
||||
"heroBody": "Unganidza Bitcoin yakananga kubva kuvatsigiri vepasi rose. Mupiro mumwe nemumwe unobva wapinda muchikwama chako, pasina vamiririri, pasina kudzoreredza, uye pasina platform inobata mari yako.",
|
||||
"startCampaign": "Tanga mushandirapamwe",
|
||||
"howItWorks": "Mashandire awo",
|
||||
"exploreCampaigns": "Tarisa mishandirapamwe",
|
||||
"featured": "Yakasarudzwa",
|
||||
"featuredDesc": "Mishandirapamwe yakasarudzwa neboka re{{appName}}.",
|
||||
"community": "Mishandirapamwe yeNharaunda",
|
||||
"communityDesc": "Batsira kupa mari kushanduko dzakakodzera.",
|
||||
"browseAll": "Tarisa mishandirapamwe yose →",
|
||||
"pending": "Yakamirira kutenderwa",
|
||||
"pendingDesc": "Mishandirapamwe iri panetwork isati yatenderwa kana kuvanzwa naani zvake muTeam Soapbox.",
|
||||
"pendingEmpty": "Hapana chinomirira kutariswa.",
|
||||
"hidden": "Yakavanzwa",
|
||||
"hiddenDesc": "Mishandirapamwe yakabviswa papeji rekutanga reveruzhinji. Shandisa menu pakadhi kuti uibvise pakuvanzwa.",
|
||||
"hiddenEmpty": "Parizvino hapana mushandirapamwe wakavanzwa.",
|
||||
"yourCampaigns": "Mishandirapamwe yako",
|
||||
"yourCampaignsDesc": "Mishandirapamwe yako iri panetwork yeNostr uye mipiro inoshanda kuburikidza nemurawu wemushandirapamwe. Inoonekwa papeji rekutanga kana muoni weTeam Soapbox aitenderera.",
|
||||
"empty": "Hapana mishandirapamwe parizvino",
|
||||
"emptyHint": "Iva wekutanga kutanga kuunganidza mari pa{{appName}}. Taura nyaya yako, sarudza vanobatsirwa, uchipa rwumwe rwekugovera."
|
||||
},
|
||||
"all": {
|
||||
"title": "Mishandirapamwe Yose",
|
||||
"seoTitle": "Mishandirapamwe yose",
|
||||
|
||||
@@ -57,6 +57,30 @@
|
||||
"goHome": "返回首页"
|
||||
},
|
||||
"campaigns": {
|
||||
"home": {
|
||||
"seoTitle": "众筹活动",
|
||||
"seoDescription": "为活动人士连接<0>不可阻挡</0>的资金。",
|
||||
"heroTagline": "为活动人士连接<0>不可阻挡</0>的资金。",
|
||||
"heroBody": "直接从世界各地的支持者那里筹集比特币。每一笔捐款都直达你的钱包,没有中间人、没有撤单、没有平台扣押你的资金。",
|
||||
"startCampaign": "发起活动",
|
||||
"howItWorks": "运作方式",
|
||||
"exploreCampaigns": "浏览活动",
|
||||
"featured": "精选",
|
||||
"featuredDesc": "由 {{appName}} 团队精心挑选的活动。",
|
||||
"community": "社区活动",
|
||||
"communityDesc": "为值得做的改变提供资金。",
|
||||
"browseAll": "浏览所有活动 →",
|
||||
"pending": "等待审批",
|
||||
"pendingDesc": "网络上尚未被任何 Soapbox 团队版主批准或隐藏的活动。",
|
||||
"pendingEmpty": "没有等待审查的内容。",
|
||||
"hidden": "已隐藏",
|
||||
"hiddenDesc": "已从公共首页隐藏的活动。使用卡片上的菜单可以取消隐藏。",
|
||||
"hiddenEmpty": "当前没有被隐藏的活动。",
|
||||
"yourCampaigns": "你的活动",
|
||||
"yourCampaignsDesc": "你的活动已在 Nostr 上线,通过活动链接可以接收捐款。一旦 Soapbox 团队版主批准,它们将出现在首页。",
|
||||
"empty": "暂无活动",
|
||||
"emptyHint": "成为在 {{appName}} 发起众筹的第一人。讲述你的故事、选择受益人、并分享链接。"
|
||||
},
|
||||
"all": {
|
||||
"title": "所有活动",
|
||||
"seoTitle": "所有活动",
|
||||
|
||||
+44
-52
@@ -1,6 +1,7 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useSeoMeta } from '@unhead/react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { ArrowRight, ChevronDown, EyeOff, HandHeart, Hourglass, PlusCircle, ShieldCheck } from 'lucide-react';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
@@ -24,7 +25,7 @@ import { type ParsedCampaign } from '@/lib/campaign';
|
||||
const MAX_FEATURED = 4;
|
||||
|
||||
export function CampaignsPage() {
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { config } = useAppContext();
|
||||
const { user } = useCurrentUser();
|
||||
|
||||
@@ -100,8 +101,8 @@ export function CampaignsPage() {
|
||||
});
|
||||
|
||||
useSeoMeta({
|
||||
title: `Fundraisers | ${config.appName}`,
|
||||
description: 'Connecting activists to unstoppable funding.',
|
||||
title: `${t('campaigns.home.seoTitle')} | ${config.appName}`,
|
||||
description: t('campaigns.home.seoDescription'),
|
||||
});
|
||||
|
||||
// Main grid excludes featured (they're shown above) and excludes any
|
||||
@@ -171,33 +172,25 @@ export function CampaignsPage() {
|
||||
WebkitTextStroke: '0.022em currentColor',
|
||||
}}
|
||||
>
|
||||
Connecting activists to
|
||||
{/* "unstoppable" gets a solid brand-orange highlighter
|
||||
block on its own line. The negative left margin
|
||||
(`-ml-1.5`) pulls the box's left edge back by exactly
|
||||
the box's own horizontal padding so the U sits flush
|
||||
with the column's left edge instead of being inset by
|
||||
the highlighter's padding. */}
|
||||
<br />
|
||||
{/* Asymmetric padding: zero on the left so "unstoppable"'s
|
||||
U sits flush with the column edge (matching the row
|
||||
above), but extra padding on the right so the orange
|
||||
box extends past the word's trailing edge as a
|
||||
deliberate visual flourish. The inner text is then
|
||||
nudged slightly leftward (negative left margin on the
|
||||
inner element) so the U optically aligns with the
|
||||
"C" in "Connecting" — Bebas Neue's italic skew shifts
|
||||
the visual left edge of the U rightward of its
|
||||
geometric box. */}
|
||||
<span className="inline-block w-fit pl-0 pr-3 pt-1 pb-0 -mt-1 -mb-3 bg-primary text-white leading-[0.8] align-baseline">
|
||||
<span className="-ml-1 inline-block">unstoppable</span>
|
||||
</span>{' '}
|
||||
funding.
|
||||
<Trans
|
||||
i18nKey="campaigns.home.heroTagline"
|
||||
components={{
|
||||
// Index 0: orange highlighter block. Wraps the
|
||||
// emphasized word(s) from the translation; the word
|
||||
// itself is supplied as the component's children by
|
||||
// i18next at render time. The English-only optical
|
||||
// tweak (negative inner-span margin to compensate
|
||||
// for Bebas Neue italic skew) is dropped because it
|
||||
// assumed the word started with a wide italic "u" —
|
||||
// not portable across translations.
|
||||
0: (
|
||||
<span className="inline-block w-fit pl-1 pr-3 pt-1 pb-0 -mt-1 -mb-3 bg-primary text-white leading-[0.8] align-baseline" />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</h1>
|
||||
<p className="text-base sm:text-lg text-white/80 max-w-xl">
|
||||
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.
|
||||
{t('campaigns.home.heroBody')}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3 pt-1">
|
||||
{/* Primary CTA — solid brand-orange pill. The dark hero gives
|
||||
@@ -209,7 +202,7 @@ export function CampaignsPage() {
|
||||
>
|
||||
<Link to="/campaigns/new">
|
||||
<PlusCircle className="mr-2" />
|
||||
Start a campaign
|
||||
{t('campaigns.home.startCampaign')}
|
||||
</Link>
|
||||
</Button>
|
||||
<Button
|
||||
@@ -219,8 +212,8 @@ export function CampaignsPage() {
|
||||
className="rounded-full h-12 px-6 text-base border-white/30 bg-white/5 text-white hover:bg-white/10 hover:text-white hover:border-white/50 [&_svg]:size-[18px]"
|
||||
>
|
||||
<Link to="/about">
|
||||
How it works
|
||||
<ArrowRight className="ml-2" />
|
||||
{t('campaigns.home.howItWorks')}
|
||||
<ArrowRight className="ml-2 rtl:rotate-180" />
|
||||
</Link>
|
||||
</Button>
|
||||
{!user && (
|
||||
@@ -230,7 +223,7 @@ export function CampaignsPage() {
|
||||
asChild
|
||||
className="rounded-full h-12 px-6 text-base border-white/30 bg-white/5 text-white hover:bg-white/10 hover:text-white hover:border-white/50"
|
||||
>
|
||||
<a href="#campaigns">Explore campaigns</a>
|
||||
<a href="#campaigns">{t('campaigns.home.exploreCampaigns')}</a>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -245,9 +238,9 @@ export function CampaignsPage() {
|
||||
<section className="space-y-5">
|
||||
<div className="flex items-end justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl sm:text-3xl font-bold tracking-tight">Featured</h2>
|
||||
<h2 className="text-2xl sm:text-3xl font-bold tracking-tight">{t('campaigns.home.featured')}</h2>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
Hand-picked campaigns from the Agora team.
|
||||
{t('campaigns.home.featuredDesc', { appName: config.appName })}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -266,15 +259,15 @@ export function CampaignsPage() {
|
||||
<section className="space-y-5">
|
||||
<div className="flex items-end justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl sm:text-3xl font-bold tracking-tight">Community Campaigns</h2>
|
||||
<h2 className="text-2xl sm:text-3xl font-bold tracking-tight">{t('campaigns.home.community')}</h2>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
Help fund the changes worth making.
|
||||
{t('campaigns.home.communityDesc')}
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild variant="outline" className="hidden sm:inline-flex">
|
||||
<Link to="/campaigns/new">
|
||||
<PlusCircle className="size-4 mr-2" />
|
||||
Start a campaign
|
||||
{t('campaigns.home.startCampaign')}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
@@ -295,7 +288,7 @@ export function CampaignsPage() {
|
||||
campaigns not yet moderated (and, optionally, hidden ones). */}
|
||||
<div className="pt-2 text-center sm:text-left">
|
||||
<Button asChild variant="ghost" size="sm">
|
||||
<Link to="/campaigns/all">Browse all campaigns →</Link>
|
||||
<Link to="/campaigns/all">{t('campaigns.home.browseAll')}</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
@@ -304,12 +297,12 @@ export function CampaignsPage() {
|
||||
{isMod && (
|
||||
<ModeratorSection
|
||||
icon={<Hourglass className="size-4" />}
|
||||
title="Pending approval"
|
||||
description="Campaigns on the network that no Team Soapbox moderator has approved or hidden yet."
|
||||
title={t('campaigns.home.pending')}
|
||||
description={t('campaigns.home.pendingDesc')}
|
||||
count={pendingCampaigns.length}
|
||||
campaigns={pendingCampaigns}
|
||||
isLoading={allLoading}
|
||||
emptyText="Nothing awaiting review."
|
||||
emptyText={t('campaigns.home.pendingEmpty')}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -317,12 +310,12 @@ export function CampaignsPage() {
|
||||
{isMod && (
|
||||
<ModeratorSection
|
||||
icon={<EyeOff className="size-4" />}
|
||||
title="Hidden"
|
||||
description="Campaigns suppressed from the public homepage. Use the kebab menu on a card to unhide."
|
||||
title={t('campaigns.home.hidden')}
|
||||
description={t('campaigns.home.hiddenDesc')}
|
||||
count={hiddenCampaigns.length}
|
||||
campaigns={hiddenCampaigns}
|
||||
isLoading={allLoading}
|
||||
emptyText="No campaigns are currently hidden."
|
||||
emptyText={t('campaigns.home.hiddenEmpty')}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -334,12 +327,10 @@ export function CampaignsPage() {
|
||||
<div>
|
||||
<h2 className="text-2xl sm:text-3xl font-bold tracking-tight inline-flex items-center gap-2">
|
||||
<ShieldCheck className="size-6 text-primary/70" />
|
||||
Your campaigns
|
||||
{t('campaigns.home.yourCampaigns')}
|
||||
</h2>
|
||||
<p className="text-sm text-muted-foreground mt-1 max-w-2xl">
|
||||
Your campaigns are live on Nostr and donations work via the
|
||||
campaign link. They appear on the homepage once a Team
|
||||
Soapbox moderator approves them.
|
||||
{t('campaigns.home.yourCampaignsDesc')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-5">
|
||||
@@ -495,21 +486,22 @@ function CampaignGridSkeleton() {
|
||||
}
|
||||
|
||||
function EmptyState() {
|
||||
const { t } = useTranslation();
|
||||
const { config } = useAppContext();
|
||||
return (
|
||||
<Card className="border-dashed">
|
||||
<CardContent className="py-12 px-8 text-center space-y-4">
|
||||
<HandHeart className="size-10 text-muted-foreground/60 mx-auto" />
|
||||
<div className="space-y-1.5">
|
||||
<h3 className="text-lg font-semibold">No campaigns yet</h3>
|
||||
<h3 className="text-lg font-semibold">{t('campaigns.home.empty')}</h3>
|
||||
<p className="text-muted-foreground max-w-sm mx-auto">
|
||||
Be the first to start a fundraiser on Agora. Tell your story, choose your
|
||||
beneficiaries, and share the link.
|
||||
{t('campaigns.home.emptyHint', { appName: config.appName })}
|
||||
</p>
|
||||
</div>
|
||||
<Button asChild>
|
||||
<Link to="/campaigns/new">
|
||||
<PlusCircle className="size-4 mr-2" />
|
||||
Start a campaign
|
||||
{t('campaigns.home.startCampaign')}
|
||||
</Link>
|
||||
</Button>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user