diff --git a/AGENTS.md b/AGENTS.md
deleted file mode 100644
index e587469..0000000
--- a/AGENTS.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# AGENTS.md
-
-Common Ground — editorial impact/NKO шаблон: сохраняй newsroom-структуру, публичный ledger, кампании с бюджетом, истории людей, волонтерские смены и проверяемые документы.
-
-## Project Specifics
-
-- Кампании, метрики, ledger, истории, смены, документы, партнеры и бюджет описаны в `src/entities/site-content.ts`.
-- `src/app` — только route wrappers; композиция страниц находится в `src/widgets/template-ui.tsx`.
-- Mock-пожертвования держи в `src/features/*/ui`; не добавляй реальные платежи, CRM, donor accounts или API без запроса.
-- Не делай generic charity landing: каждая страница должна усиливать доверие через цель, прогресс, документы, ответственного, место или конкретную смену.
-- Избегай мягкой декоративной благотворительности; стиль должен ощущаться как редакция, полевой desk и публичная отчетность.
-- Проверка после правок: `pnpm lint` и `pnpm build`.
diff --git a/SITEMAP.md b/SITEMAP.md
deleted file mode 100644
index 459bc00..0000000
--- a/SITEMAP.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Common Ground Sitemap
-
-Editorial impact шаблон для НКО и campaign platform. Сайт продает доверие через кампании с бюджетом, истории людей, волонтерские смены, живой реестр средств и проверяемые документы.
-
-## Pages
-
-| Route | Page | Blocks and copy intent |
-| --- | --- | --- |
-| `/` | Главная | Newspaper hero, issue label, доверительный редакционный блок, featured campaign, impact strip, свежий ledger средств. |
-| `/campaigns` | Кампании | Campaign index: регион, срок, сумма, прогресс, проблема, распределение средств и переход в детальную кампанию. |
-| `/campaigns/clean-water` | Кампания | Dossier-style detail: проблема, цель, checkpoints, progress, donation mock-panel и бюджет кампании. |
-| `/impact` | Отчет о влиянии | Метрики, методика подтверждения, ledger, связь цифр с документами и полевыми данными. |
-| `/stories` | Истории | Editorial story cards with images, place, result and field context. |
-| `/volunteer` | Волонтерские смены | Операционная доска: дата, время, роль, место, свободные места и тип задачи. |
-| `/transparency` | Прозрачность | Структура расходов, mock-отчет, документы, партнеры и блоки проверки. |
-
-## Visual Direction
-
-- Newspaper/editorial layout on clay paper with strong black rules, blue primary, green secondary and warm accent.
-- Avoid generic charity softness: the visual language is newsroom, field desk and public ledger.
-- Real human/field imagery from Unsplash is used for campaign and story context.
-- Feature mock: `DonationPanel` in `src/features/donation-panel/ui/donation-panel.tsx`.
-- Domain content lives in `src/entities/site-content.ts`.
diff --git a/next.config.mjs b/next.config.mjs
index b1e31a1..f713a74 100644
--- a/next.config.mjs
+++ b/next.config.mjs
@@ -1,5 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
+ /* config options here */
+ // Оптимизация бандла
experimental: {
optimizePackageImports: [
"lucide-react",
@@ -19,12 +21,11 @@ const nextConfig = {
"@radix-ui/react-tooltip",
],
},
+ // Компрессия и оптимизация
compress: true,
+ // Оптимизация изображений
images: {
formats: ["image/avif", "image/webp"],
- remotePatterns: [
- { protocol: "https", hostname: "images.unsplash.com" },
- ],
},
};
diff --git a/package.json b/package.json
index 7db64ba..9354352 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "template-commonground-impact-shadcn",
+ "name": "tungulov-space",
"version": "0.1.0",
"private": true,
"scripts": {
diff --git a/src/app/campaigns/clean-water/page.tsx b/src/app/campaigns/clean-water/page.tsx
deleted file mode 100644
index fc93de0..0000000
--- a/src/app/campaigns/clean-water/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { CampaignDetailPage } from "@/widgets/template-ui";
-
-export default function Page() {
- return ;
-}
diff --git a/src/app/campaigns/page.tsx b/src/app/campaigns/page.tsx
deleted file mode 100644
index fffb1b3..0000000
--- a/src/app/campaigns/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { CampaignsPage } from "@/widgets/template-ui";
-
-export default function Page() {
- return ;
-}
diff --git a/src/app/globals.css b/src/app/globals.css
index 0f9c55b..dc98be7 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -6,8 +6,8 @@
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
- --font-sans: var(--font-commonground);
- --font-mono: var(--font-commonground);
+ --font-sans: var(--font-geist-sans);
+ --font-mono: var(--font-geist-mono);
--color-sidebar-ring: var(--sidebar-ring);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
@@ -44,100 +44,79 @@
}
:root {
- --radius: 0.18rem;
- --background: oklch(0.96 0.018 83);
- --foreground: oklch(0.17 0.025 65);
- --card: oklch(0.99 0.012 84);
- --card-foreground: oklch(0.17 0.025 65);
- --popover: oklch(0.99 0.012 84);
- --popover-foreground: oklch(0.17 0.025 65);
- --primary: oklch(0.43 0.095 218);
- --primary-foreground: oklch(0.98 0.014 84);
- --secondary: oklch(0.83 0.09 145);
- --secondary-foreground: oklch(0.17 0.025 65);
- --muted: oklch(0.89 0.028 80);
- --muted-foreground: oklch(0.42 0.032 63);
- --accent: oklch(0.73 0.105 50);
- --accent-foreground: oklch(0.17 0.025 65);
- --destructive: oklch(0.58 0.22 29);
- --border: oklch(0.28 0.026 65);
- --input: oklch(0.28 0.026 65);
- --ring: oklch(0.43 0.095 218);
- --chart-1: oklch(0.43 0.095 218);
- --chart-2: oklch(0.73 0.105 50);
- --chart-3: oklch(0.83 0.09 145);
- --chart-4: oklch(0.56 0.13 20);
- --chart-5: oklch(0.68 0.1 285);
- --sidebar: oklch(0.99 0.012 84);
- --sidebar-foreground: oklch(0.17 0.025 65);
- --sidebar-primary: oklch(0.43 0.095 218);
- --sidebar-primary-foreground: oklch(0.98 0.014 84);
- --sidebar-accent: oklch(0.89 0.028 80);
- --sidebar-accent-foreground: oklch(0.17 0.025 65);
- --sidebar-border: oklch(0.28 0.026 65);
- --sidebar-ring: oklch(0.43 0.095 218);
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
}
.dark {
- --background: oklch(0.17 0.025 65);
- --foreground: oklch(0.96 0.018 83);
- --card: oklch(0.22 0.026 65);
- --card-foreground: oklch(0.96 0.018 83);
- --popover: oklch(0.22 0.026 65);
- --popover-foreground: oklch(0.96 0.018 83);
- --primary: oklch(0.73 0.105 50);
- --primary-foreground: oklch(0.17 0.025 65);
- --secondary: oklch(0.32 0.055 145);
- --secondary-foreground: oklch(0.96 0.018 83);
- --muted: oklch(0.26 0.026 65);
- --muted-foreground: oklch(0.78 0.022 83);
- --accent: oklch(0.61 0.09 218);
- --accent-foreground: oklch(0.96 0.018 83);
- --border: oklch(0.82 0.018 83);
- --input: oklch(0.82 0.018 83);
- --ring: oklch(0.73 0.105 50);
- --sidebar: oklch(0.2 0.026 65);
- --sidebar-foreground: oklch(0.96 0.018 83);
- --sidebar-primary: oklch(0.73 0.105 50);
- --sidebar-primary-foreground: oklch(0.17 0.025 65);
- --sidebar-accent: oklch(0.26 0.026 65);
- --sidebar-accent-foreground: oklch(0.96 0.018 83);
- --sidebar-border: oklch(0.82 0.018 83);
- --sidebar-ring: oklch(0.73 0.105 50);
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.205 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.922 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.556 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.556 0 0);
}
@layer base {
* {
@apply border-border outline-ring/50;
}
-
- html {
- scroll-behavior: smooth;
- }
-
body {
@apply bg-background text-foreground;
- background-image:
- radial-gradient(circle at 12% 10%, oklch(0.83 0.09 145 / 0.18), transparent 24rem),
- linear-gradient(90deg, oklch(0.17 0.025 65 / 0.045) 1px, transparent 1px);
- background-size: auto, 22px 22px;
- font-feature-settings: "ss01" 1, "cv01" 1, "tnum" 1;
- }
-
- a {
- text-decoration-thickness: 1px;
- text-underline-offset: 0.18em;
}
}
-
-.newsprint {
- background-image:
- linear-gradient(90deg, oklch(0.17 0.025 65 / 0.06) 1px, transparent 1px),
- linear-gradient(180deg, oklch(0.17 0.025 65 / 0.035) 1px, transparent 1px);
- background-size: 18px 18px;
-}
-
-.impact-rule {
- border-top: 3px double var(--foreground);
- border-bottom: 3px double var(--foreground);
-}
diff --git a/src/app/impact/page.tsx b/src/app/impact/page.tsx
deleted file mode 100644
index ff2ca98..0000000
--- a/src/app/impact/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { ImpactPage } from "@/widgets/template-ui";
-
-export default function Page() {
- return ;
-}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 010e9c3..fa5d047 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,18 +1,18 @@
import type { Metadata } from "next";
-import { Noto_Serif } from "next/font/google";
+import { Roboto_Flex } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/shared/hooks/theme-provider";
import { ThemeMessageListener } from "@/shared/hooks/theme-message-listener";
-const notoSerif = Noto_Serif({
- variable: "--font-commonground",
- weight: ["300", "400", "500", "600", "700", "800", "900"],
+const robotoFlex = Roboto_Flex({
+ variable: "--font-roboto-flex",
+ weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
subsets: ["latin", "cyrillic"],
});
export const metadata: Metadata = {
- title: "Common Ground - кампании и открытая отчетность",
- description: "Editorial impact шаблон для НКО: кампании, пожертвования, истории людей, волонтерские смены и прозрачный бюджет.",
+ title: "Create Next App",
+ description: "Generated by create next app",
};
export default function RootLayout({
@@ -22,10 +22,10 @@ export default function RootLayout({
}>) {
return (
-
+
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 2794f3c..5d915f1 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,5 +1,99 @@
-import { HomePage } from "@/widgets/template-ui";
+"use client";
-export default function Page() {
- return ;
+import { motion } from "framer-motion";
+import { ArrowRightIcon } from "lucide-react";
+
+const technologyBadges = [
+ "Next.js",
+ "React",
+ "Tailwind",
+ "shadcn",
+ "Gitea",
+ "Live runtime",
+ "AI context",
+] as const;
+
+function FluwSquareIcon({ className = "size-11" }: { className?: string }) {
+ return (
+
+
+
+ );
+}
+
+function StatusPill() {
+ return (
+
+
+ Проект готов к работе
+
+ );
+}
+
+export default function Home() {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ Fluw template
+
+
+ Пустой шаблон приложения для быстрого старта
+
+
+
+
+
+
+
+ Начните с чистой основы. Доведите идею до живого продукта.
+
+
+
+ Это пустой шаблон Fluw для нового веб-приложения: чистая
+ структура, live runtime, визуальные правки, AI-контекст и кодовая
+ база, которую можно развивать.
+
+
+
+ {technologyBadges.map((badge) => (
+
+ {badge}
+
+ ))}
+
+
+
+
+
+
+
+ );
}
diff --git a/src/app/stories/page.tsx b/src/app/stories/page.tsx
deleted file mode 100644
index 3a8e767..0000000
--- a/src/app/stories/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { StoriesPage } from "@/widgets/template-ui";
-
-export default function Page() {
- return ;
-}
diff --git a/src/app/transparency/page.tsx b/src/app/transparency/page.tsx
deleted file mode 100644
index e61c20b..0000000
--- a/src/app/transparency/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { TransparencyPage } from "@/widgets/template-ui";
-
-export default function Page() {
- return ;
-}
diff --git a/src/app/volunteer/page.tsx b/src/app/volunteer/page.tsx
deleted file mode 100644
index 6716f5d..0000000
--- a/src/app/volunteer/page.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-import { VolunteerPage } from "@/widgets/template-ui";
-
-export default function Page() {
- return ;
-}
diff --git a/src/entities/site-content.ts b/src/entities/site-content.ts
deleted file mode 100644
index 3766c84..0000000
--- a/src/entities/site-content.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-export const site = {
- name: "Common Ground",
- tagline: "кампании, истории и отчетность без тумана",
- email: "fielddesk@commonground.org",
- issue: "Выпуск 04 / май",
- phone: "+7 495 221-70-18",
-};
-
-export const navItems = [
- { href: "/campaigns", label: "Кампании" },
- { href: "/impact", label: "Отчет" },
- { href: "/stories", label: "Истории" },
- { href: "/volunteer", label: "Смены" },
- { href: "/transparency", label: "Прозрачность" },
-] as const;
-
-export const campaigns = [
- {
- slug: "clean-water",
- title: "Чистая вода для северных поселков",
- goal: 4200000,
- raised: 2870000,
- region: "Карелия",
- deadline: "24 дня до закупки",
- image: "https://images.unsplash.com/photo-1506744038136-46273834b3fb?auto=format&fit=crop&w=1400&q=82",
- lead: "Три поселка зависят от привозной воды и старых скважин с высоким железом.",
- text: "Собираем на модульные станции фильтрации, обучение операторов, сервисный запас и лабораторный контроль на первый год.",
- allocation: [
- { label: "станции и монтаж", value: 61 },
- { label: "логистика", value: 18 },
- { label: "обучение", value: 9 },
- { label: "расходники", value: 12 },
- ],
- checkpoints: ["анализ воды", "закупка фильтров", "монтаж", "обучение оператора"],
- },
- {
- slug: "warm-classrooms",
- title: "Теплые классы на зимний семестр",
- goal: 1800000,
- raised: 990000,
- region: "Псковская область",
- deadline: "до 15 августа",
- image: "https://images.unsplash.com/photo-1509062522246-3755977927d7?auto=format&fit=crop&w=1400&q=82",
- lead: "В двух школах температура в младших классах падает ниже нормы в ветреные дни.",
- text: "Меняем окна, усиливаем радиаторы, закрываем тепловые мосты и делаем безопасные зоны для младших классов.",
- allocation: [
- { label: "окна", value: 46 },
- { label: "отопление", value: 31 },
- { label: "работы", value: 17 },
- { label: "контроль", value: 6 },
- ],
- checkpoints: ["замеры", "смета", "закупка", "приемка"],
- },
- {
- slug: "legal-aid",
- title: "Юридическая помощь семьям",
- goal: 960000,
- raised: 740000,
- region: "онлайн и регионы",
- deadline: "набор открыт",
- image: "https://images.unsplash.com/photo-1521791136064-7986c2920216?auto=format&fit=crop&w=1400&q=82",
- lead: "Семьи теряют месяцы на документы, потому что помощь разбросана по разным службам.",
- text: "Финансируем консультации, шаблоны заявлений, сопровождение документов и горячую линию с понятным расписанием.",
- allocation: [
- { label: "юристы", value: 58 },
- { label: "горячая линия", value: 19 },
- { label: "шаблоны", value: 11 },
- { label: "координация", value: 12 },
- ],
- checkpoints: ["прием заявки", "разбор документов", "письмо", "сопровождение"],
- },
-] as const;
-
-export const impactMetrics = [
- { value: "18 420", label: "людей получили доступ к программам", detail: "подтверждено партнерами на местах" },
- { value: "91%", label: "расходов имеют открытое подтверждение", detail: "акты, фото, платежные реестры" },
- { value: "312", label: "волонтерских смен закрыто за год", detail: "логистика, звонки, выезды, склад" },
- { value: "37", label: "локальных координаторов обучено", detail: "после завершения кампаний" },
-] as const;
-
-export const ledger = [
- { date: "02 мая", source: "частные доноры", amount: "+418 000 ₽", note: "132 перевода до 12 000 ₽" },
- { date: "06 мая", source: "закупка фильтров", amount: "-690 000 ₽", note: "счет CG-WTR-041" },
- { date: "10 мая", source: "корпоративный матчинг", amount: "+1 200 000 ₽", note: "партнер удвоил сбор недели" },
- { date: "14 мая", source: "логистика Карелия", amount: "-182 000 ₽", note: "доставка модулей и расходников" },
-] as const;
-
-export const stories = [
- {
- title: "Станция, которую обслуживает местная команда",
- place: "поселок Ладожский",
- image: "https://images.unsplash.com/photo-1494526585095-c41746248156?auto=format&fit=crop&w=1200&q=82",
- text: "После запуска школа перестала закупать воду в канистрах. Оператор из поселка прошел обучение и ведет журнал расходников.",
- result: "420 учеников и сотрудников",
- },
- {
- title: "Волонтерская смена без хаоса",
- place: "Псков",
- image: "https://images.unsplash.com/photo-1559027615-cd4628902d4a?auto=format&fit=crop&w=1200&q=82",
- text: "Координаторы заранее разделили задачи: замеры, доставка, прием материалов и фотофиксация. Смена закончилась актом, а не перепиской.",
- result: "18 окон принято за день",
- },
- {
- title: "Документы стали понятнее",
- place: "онлайн",
- image: "https://images.unsplash.com/photo-1554224155-6726b3ff858f?auto=format&fit=crop&w=1200&q=82",
- text: "Семьи получили шаблоны заявлений и короткие консультации без очереди в городских центрах.",
- result: "64 дела закрыто за месяц",
- },
-] as const;
-
-export const volunteerShifts = [
- { date: "15 июня", time: "11:00-15:00", title: "Сортировка семейных наборов", spots: "8 мест", location: "склад Север", role: "логистика" },
- { date: "22 июня", time: "07:30-19:00", title: "Выездная фотофиксация", spots: "3 места", location: "Карелия", role: "field team" },
- { date: "29 июня", time: "10:00-14:00", title: "Горячая линия документов", spots: "6 мест", location: "онлайн", role: "операторы" },
- { date: "04 июля", time: "13:00-17:00", title: "Проверка актов и чеков", spots: "4 места", location: "офис", role: "отчетность" },
-] as const;
-
-export const transparency = [
- { label: "Программы", value: 68, detail: "закупка, монтаж, консультации, расходники" },
- { label: "Логистика", value: 14, detail: "доставка, склад, выездные смены" },
- { label: "Команда", value: 12, detail: "координация, полевые менеджеры, горячая линия" },
- { label: "Администрирование", value: 6, detail: "банк, бухгалтерия, связь, документы" },
-] as const;
-
-export const documents = [
- { title: "Реестр платежей", status: "обновлен 14 мая", owner: "финансовый координатор" },
- { title: "Акты приемки", status: "17 документов", owner: "полевые партнеры" },
- { title: "Фотофиксация", status: "84 файла", owner: "волонтерская команда" },
- { title: "Письма партнеров", status: "9 подтверждений", owner: "программный отдел" },
-] as const;
-
-export const partners = ["Северная вода", "Школа 18", "Legal Desk", "Field Notes", "Local Lab"] as const;
diff --git a/src/features/donation-panel/ui/donation-panel.tsx b/src/features/donation-panel/ui/donation-panel.tsx
deleted file mode 100644
index d56f467..0000000
--- a/src/features/donation-panel/ui/donation-panel.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-"use client";
-
-import { useMemo, useState } from "react";
-import { HeartHandshakeIcon, ReceiptTextIcon } from "lucide-react";
-
-import { Button } from "@/shared/ui/button";
-
-const amounts = [1000, 2500, 5000, 12000] as const;
-const modes = ["разово", "ежемесячно"] as const;
-
-const impactByAmount: Record = {
- 1000: "закрывает расходники для одного семейного набора",
- 2500: "оплачивает доставку фильтров до пункта выдачи",
- 5000: "помогает провести обучение локального оператора",
- 12000: "покрывает часть сервисного запаса станции на месяц",
-};
-
-function formatRub(value: number) {
- return new Intl.NumberFormat("ru-RU", { maximumFractionDigits: 0 }).format(value);
-}
-
-export function DonationPanel() {
- const [amount, setAmount] = useState(amounts[1]);
- const [mode, setMode] = useState<(typeof modes)[number]>(modes[0]);
-
- const receiptRows = useMemo(
- () => [
- { label: "помощь кампании", value: `${formatRub(amount)} ₽` },
- { label: "платежный провайдер", value: "не подключен" },
- { label: "тип поддержки", value: mode },
- ],
- [amount, mode],
- );
-
- return (
-
-
-
-
-
-
-
Поддержать сбор
-
- Mock-панель без реальных платежей. Показывает будущую механику выбора суммы и назначения.
-
-
-
-
-
- {modes.map((item) => (
- setMode(item)}
- className={`border-2 border-foreground px-3 py-2 text-sm font-black uppercase ${
- mode === item ? "bg-foreground text-background" : "bg-background"
- }`}
- >
- {item}
-
- ))}
-
-
-
- {amounts.map((item) => (
- setAmount(item)}
- className={`border-2 border-foreground px-3 py-3 text-lg font-black ${
- amount === item ? "bg-primary text-primary-foreground" : "bg-background"
- }`}
- >
- {formatRub(item)} ₽
-
- ))}
-
-
-
-
Что изменит сумма
-
{impactByAmount[amount]}.
-
-
-
- {receiptRows.map((row) => (
-
- {row.label}
- {row.value}
-
- ))}
-
-
-
-
- Продолжить без оплаты
-
-
- );
-}
diff --git a/src/widgets/template-ui.tsx b/src/widgets/template-ui.tsx
deleted file mode 100644
index dcf317c..0000000
--- a/src/widgets/template-ui.tsx
+++ /dev/null
@@ -1,496 +0,0 @@
-import type { ReactNode } from "react";
-import Image from "next/image";
-import Link from "next/link";
-import {
- ArrowRightIcon,
- ClipboardCheckIcon,
- FileTextIcon,
- LandmarkIcon,
- MapPinIcon,
- NewspaperIcon,
- ReceiptTextIcon,
- ShieldCheckIcon,
- UsersIcon,
-} from "lucide-react";
-
-import { DonationPanel } from "@/features/donation-panel/ui/donation-panel";
-import {
- campaigns,
- documents,
- impactMetrics,
- ledger,
- navItems,
- partners,
- site,
- stories,
- transparency,
- volunteerShifts,
-} from "@/entities/site-content";
-import { Badge } from "@/shared/ui/badge";
-import { Button } from "@/shared/ui/button";
-import { Progress } from "@/shared/ui/progress";
-
-type Campaign = (typeof campaigns)[number];
-
-function formatRub(value: number) {
- return new Intl.NumberFormat("ru-RU", { maximumFractionDigits: 0 }).format(value);
-}
-
-function campaignProgress(campaign: Campaign) {
- return Math.round((campaign.raised / campaign.goal) * 100);
-}
-
-function Shell({ children }: { children: ReactNode }) {
- return (
-
-
- {children}
-
-
- );
-}
-
-function EditorialTitle({ label, title, text }: { label: string; title: string; text: string }) {
- return (
-
-
-
{label}
-
{title}
-
{text}
-
-
- );
-}
-
-function CampaignCard({ campaign, featured = false }: { campaign: Campaign; featured?: boolean }) {
- const href = campaign.slug === "clean-water" ? "/campaigns/clean-water" : "/campaigns";
-
- return (
-
-
-
-
-
- {campaign.deadline}
-
-
-
-
-
- {campaign.region}
-
- {campaignProgress(campaign)}% цели
-
-
{campaign.title}
-
{campaign.lead}
-
{campaign.text}
-
-
- {formatRub(campaign.raised)} ₽ собрано
- {formatRub(campaign.goal)} ₽ цель
-
-
-
-
- );
-}
-
-function MetricCard({ metric }: { metric: (typeof impactMetrics)[number] }) {
- return (
-
- {metric.value}
- {metric.label}
- {metric.detail}
-
- );
-}
-
-function LedgerTable() {
- return (
-
- {ledger.map((row) => (
-
-
{row.date}
-
{row.source}
-
{row.amount}
-
{row.note}
-
- ))}
-
- );
-}
-
-function StoryCard({ story }: { story: (typeof stories)[number] }) {
- return (
-
-
-
-
-
-
-
- {story.place}
-
-
{story.title}
-
{story.text}
-
{story.result}
-
-
- );
-}
-
-function DocumentCard({ item }: { item: (typeof documents)[number] }) {
- return (
-
-
- {item.title}
- {item.status}
- {item.owner}
-
- );
-}
-
-export function HomePage() {
- const featured = campaigns[0];
-
- return (
-
-
-
-
-
{site.issue} / {site.tagline}
-
- Помощь, которую видно по документам и людям
-
-
- Common Ground - шаблон для НКО и impact-платформы, где каждая кампания показывает
- цель, бюджет, полевой прогресс, истории и открытый реестр расходов.
-
-
-
- Смотреть кампании
-
-
- Открыть отчетность
-
-
-
-
-
- полевой выпуск
-
- НКО продает доверие. Поэтому первый экран сразу дает цель, факт, ответственного и путь к документам.
-
-
-
- открытых кампаний
- 3
-
-
- обновление реестра
- еженедельно
-
-
- полевой desk
- {site.email}
-
-
-
-
-
-
-
-
-
-
- {impactMetrics.map((item) => (
-
-
{item.value}
-
{item.label}
-
- ))}
-
-
-
-
-
-
-
живой реестр
-
Последние движения средств
-
- Не прячьте доверие в PDF. Покажите свежие поступления, закупки и основание расходов прямо на сайте.
-
-
-
-
-
-
- );
-}
-
-export function CampaignsPage() {
- return (
-
-
-
-
- {campaigns.map((campaign) => (
-
- ))}
-
-
-
- );
-}
-
-export function CampaignDetailPage() {
- const campaign = campaigns[0];
-
- return (
-
-
-
-
- {campaign.region}
- {campaign.deadline}
-
-
{campaign.title}
-
{campaign.lead}
-
{campaign.text}
-
-
-
- {formatRub(campaign.raised)} ₽ собрано
- {formatRub(campaign.goal)} ₽ цель
-
-
-
- {campaign.checkpoints.map((point, index) => (
-
-
0{index + 1}
-
{point}
-
- ))}
-
-
-
-
-
-
-
-
-
-
бюджет кампании
-
Куда уйдет каждый рубль
-
-
- {campaign.allocation.map((item) => (
-
-
- {item.label}
- {item.value}%
-
-
-
- ))}
-
-
-
-
- );
-}
-
-export function ImpactPage() {
- return (
-
-
-
-
- {impactMetrics.map((item) => (
-
- ))}
-
-
-
-
-
-
-
Методика подтверждения
-
- Каждая цифра связывается с документом: актом, фото, письмом партнера, платежом или сменой координатора.
-
-
-
-
-
-
- );
-}
-
-export function StoriesPage() {
- return (
-
-
-
-
- {stories.map((story) => (
-
- ))}
-
-
-
- );
-}
-
-export function VolunteerPage() {
- return (
-
-
-
-
- {volunteerShifts.map((shift) => (
-
-
-
{shift.date}
-
{shift.time}
-
- {shift.title}
-
-
- {shift.spots}
-
-
-
- {shift.location}
-
-
- {shift.role}
-
-
- ))}
-
-
-
- );
-}
-
-export function TransparencyPage() {
- return (
-
-
-
-
-
-
-
Структура расходов
-
- {transparency.map((item) => (
-
-
- {item.label}
- {item.value}%
-
-
-
{item.detail}
-
- ))}
-
-
-
-
- Партнерская проверка
-
- Отчеты, акты, фотофиксация и письма партнеров должны иметь отдельные блоки, а не прятаться в футере.
-
-
-
- Скачать mock-отчет
-
-
-
-
-
-
-
-
документы
-
Что можно проверить
-
- {partners.map((partner) => (
-
- {partner}
-
- ))}
-
-
-
- {documents.map((item) => (
-
- ))}
-
-
-
-
- );
-}