diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e587469 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ +# 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 new file mode 100644 index 0000000..459bc00 --- /dev/null +++ b/SITEMAP.md @@ -0,0 +1,23 @@ +# 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 f713a74..b1e31a1 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,7 +1,5 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - /* config options here */ - // Оптимизация бандла experimental: { optimizePackageImports: [ "lucide-react", @@ -21,11 +19,12 @@ 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 9354352..7db64ba 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "tungulov-space", + "name": "template-commonground-impact-shadcn", "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 new file mode 100644 index 0000000..fc93de0 --- /dev/null +++ b/src/app/campaigns/clean-water/page.tsx @@ -0,0 +1,5 @@ +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 new file mode 100644 index 0000000..fffb1b3 --- /dev/null +++ b/src/app/campaigns/page.tsx @@ -0,0 +1,5 @@ +import { CampaignsPage } from "@/widgets/template-ui"; + +export default function Page() { + return ; +} diff --git a/src/app/globals.css b/src/app/globals.css index dc98be7..0f9c55b 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-geist-sans); - --font-mono: var(--font-geist-mono); + --font-sans: var(--font-commonground); + --font-mono: var(--font-commonground); --color-sidebar-ring: var(--sidebar-ring); --color-sidebar-border: var(--sidebar-border); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); @@ -44,79 +44,100 @@ } :root { - --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); + --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); } .dark { - --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); + --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); } @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 new file mode 100644 index 0000000..ff2ca98 --- /dev/null +++ b/src/app/impact/page.tsx @@ -0,0 +1,5 @@ +import { ImpactPage } from "@/widgets/template-ui"; + +export default function Page() { + return ; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index fa5d047..010e9c3 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,18 +1,18 @@ import type { Metadata } from "next"; -import { Roboto_Flex } from "next/font/google"; +import { Noto_Serif } from "next/font/google"; import "./globals.css"; import { ThemeProvider } from "@/shared/hooks/theme-provider"; import { ThemeMessageListener } from "@/shared/hooks/theme-message-listener"; -const robotoFlex = Roboto_Flex({ - variable: "--font-roboto-flex", - weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"], +const notoSerif = Noto_Serif({ + variable: "--font-commonground", + weight: ["300", "400", "500", "600", "700", "800", "900"], subsets: ["latin", "cyrillic"], }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Common Ground - кампании и открытая отчетность", + description: "Editorial impact шаблон для НКО: кампании, пожертвования, истории людей, волонтерские смены и прозрачный бюджет.", }; 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 5d915f1..2794f3c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,99 +1,5 @@ -"use client"; +import { HomePage } from "@/widgets/template-ui"; -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 ( -