feat(sprint-1): инициализация monorepo, Next.js, NestJS, страница логотипа
Инфраструктура: - pnpm workspaces monorepo (apps/web, apps/api, packages/) - docker-compose.yml: PostgreSQL 16 - .env.example: DATABASE_URL, API_PORT, NEXT_PUBLIC_API_URL Backend (apps/api — NestJS 11): - Инициализирован NestJS с pnpm - Prisma 7 + prisma.config.ts подключен к PostgreSQL - Схема: User (role: viewer/editor), ExperimentalComponent (status: draft/review/approved) Frontend (apps/web — Next.js 16): - App Router, TypeScript, Tailwind CSS 4, Fira Sans (Google Fonts) - globals.css: CSS-токены бренда (цвета 053M–080M, шрифты) - layout.tsx: корневой layout с боковой навигацией - Sidebar.tsx: навигация по всем разделам (Фундамент, Компоненты, Блоки, Страницы, Оффлайн, Эксперименты) - page.tsx: редирект → /foundation/logo - /foundation/logo: полная страница «Логотип» - Иерархия и версии (Основной / Общий) - Цветовые варианты (основной, инвертированный, на форме) - Охранная зона с визуализацией - Таблица минимальных размеров (форма сотрудников) - Недопустимые варианты (6 правил) - Блок скачивания (placeholder до получения вектора) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,466 @@
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Логотип | Брендбук О!Клиника",
|
||||
};
|
||||
|
||||
/* ─── Компонент: плашка правила ─────────────────────────────── */
|
||||
function RuleTag({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<span
|
||||
className="inline-block px-2 py-0.5 rounded text-xs font-medium"
|
||||
style={{ background: "#e0f5f4", color: "var(--brand-073m)" }}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Компонент: секция брендбука ────────────────────────────── */
|
||||
function Section({
|
||||
id,
|
||||
title,
|
||||
subtitle,
|
||||
children,
|
||||
}: {
|
||||
id?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<section id={id} className="mb-12">
|
||||
<div className="mb-6">
|
||||
<h2
|
||||
className="text-xl font-semibold"
|
||||
style={{ color: "var(--bb-text)" }}
|
||||
>
|
||||
{title}
|
||||
</h2>
|
||||
{subtitle && (
|
||||
<p className="mt-1 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||
{subtitle}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── SVG-заглушка логотипа (до получения вектора) ─────────── */
|
||||
function LogoPlaceholder({
|
||||
variant = "main",
|
||||
size = "md",
|
||||
}: {
|
||||
variant?: "main" | "general" | "inverted" | "brown" | "white";
|
||||
size?: "sm" | "md" | "lg";
|
||||
}) {
|
||||
const sizes = { sm: 160, md: 280, lg: 380 };
|
||||
const w = sizes[size];
|
||||
|
||||
const bg =
|
||||
variant === "inverted"
|
||||
? "var(--brand-073m)"
|
||||
: variant === "white"
|
||||
? "var(--brand-053m)"
|
||||
: "#f8f9fa";
|
||||
|
||||
const tealColor =
|
||||
variant === "inverted" || variant === "white"
|
||||
? "#ffffff"
|
||||
: "var(--brand-053m)";
|
||||
|
||||
const darkColor =
|
||||
variant === "inverted" || variant === "white"
|
||||
? "#ffffff"
|
||||
: "var(--brand-073m)";
|
||||
|
||||
const brownColor =
|
||||
variant === "brown" ? "var(--brand-080m)" : tealColor;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="flex items-center justify-center rounded-lg border p-6"
|
||||
style={{
|
||||
background: bg,
|
||||
borderColor:
|
||||
variant === "inverted" || variant === "white"
|
||||
? "transparent"
|
||||
: "var(--bb-border)",
|
||||
width: w,
|
||||
minHeight: Math.round(w * 0.55),
|
||||
}}
|
||||
>
|
||||
{/* SVG-приближение логотипа */}
|
||||
<svg
|
||||
viewBox="0 0 240 120"
|
||||
width={w - 48}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-label="Логотип Клиника УХО ГОРЛО НОС"
|
||||
>
|
||||
{/* Графический элемент — три капли */}
|
||||
<ellipse cx="18" cy="22" rx="8" ry="12" fill={brownColor} />
|
||||
<ellipse cx="30" cy="10" rx="6" ry="9" fill={brownColor} />
|
||||
<ellipse cx="10" cy="38" rx="10" ry="7" fill={brownColor} opacity="0.85" />
|
||||
|
||||
{/* Текст КЛИНИКА */}
|
||||
<text
|
||||
x="46"
|
||||
y="26"
|
||||
fontFamily="Arial, sans-serif"
|
||||
fontWeight="700"
|
||||
fontSize="20"
|
||||
fill={darkColor}
|
||||
letterSpacing="1"
|
||||
>
|
||||
КЛИНИКА
|
||||
</text>
|
||||
|
||||
{/* Текст УХО ГОРЛО НОС */}
|
||||
<text
|
||||
x="46"
|
||||
y="54"
|
||||
fontFamily="Arial, sans-serif"
|
||||
fontWeight="700"
|
||||
fontSize="20"
|
||||
fill={tealColor}
|
||||
letterSpacing="1"
|
||||
>
|
||||
УХО•ГОРЛО•НОС
|
||||
</text>
|
||||
|
||||
{/* Текст ИМ. ПРОФ. */}
|
||||
<text
|
||||
x="46"
|
||||
y="78"
|
||||
fontFamily="Arial, sans-serif"
|
||||
fontWeight="400"
|
||||
fontSize="14"
|
||||
fill={darkColor}
|
||||
letterSpacing="0.5"
|
||||
>
|
||||
ИМ. ПРОФ. Е.Н. ОЛЕНЕВОЙ
|
||||
</text>
|
||||
|
||||
{/* Метка версии */}
|
||||
{variant === "general" && (
|
||||
<text
|
||||
x="46"
|
||||
y="100"
|
||||
fontFamily="Arial, sans-serif"
|
||||
fontWeight="400"
|
||||
fontSize="10"
|
||||
fill={darkColor}
|
||||
opacity="0.5"
|
||||
>
|
||||
Общий (сеть клиник)
|
||||
</text>
|
||||
)}
|
||||
{variant === "main" && (
|
||||
<text
|
||||
x="46"
|
||||
y="100"
|
||||
fontFamily="Arial, sans-serif"
|
||||
fontWeight="400"
|
||||
fontSize="10"
|
||||
fill={darkColor}
|
||||
opacity="0.5"
|
||||
>
|
||||
Основной (направление)
|
||||
</text>
|
||||
)}
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Компонент: таблица охранной зоны ─────────────────────── */
|
||||
function ClearspaceDemo() {
|
||||
return (
|
||||
<div className="inline-flex items-center justify-center rounded-lg border p-10 relative"
|
||||
style={{ borderColor: "var(--bb-border)", background: "#f8f9fa" }}
|
||||
>
|
||||
{/* Охранная зона — пунктирная рамка */}
|
||||
<div
|
||||
className="absolute inset-6 border-2 border-dashed rounded"
|
||||
style={{ borderColor: "var(--brand-053m)", opacity: 0.4 }}
|
||||
/>
|
||||
{/* Стрелки-обозначения */}
|
||||
<div className="absolute top-1.5 left-1/2 -translate-x-1/2 text-[10px]"
|
||||
style={{ color: "var(--brand-053m)" }}>
|
||||
x
|
||||
</div>
|
||||
<div className="absolute bottom-1.5 left-1/2 -translate-x-1/2 text-[10px]"
|
||||
style={{ color: "var(--brand-053m)" }}>
|
||||
x
|
||||
</div>
|
||||
<div className="absolute left-1.5 top-1/2 -translate-y-1/2 text-[10px]"
|
||||
style={{ color: "var(--brand-053m)" }}>
|
||||
x
|
||||
</div>
|
||||
<div className="absolute right-1.5 top-1/2 -translate-y-1/2 text-[10px]"
|
||||
style={{ color: "var(--brand-053m)" }}>
|
||||
x
|
||||
</div>
|
||||
<LogoPlaceholder variant="main" size="sm" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Компонент: недопустимое использование ─────────────────── */
|
||||
function ProhibitedItem({ label }: { label: string }) {
|
||||
return (
|
||||
<div
|
||||
className="flex items-start gap-3 p-4 rounded-lg border"
|
||||
style={{ borderColor: "#fecaca", background: "#fff5f5" }}
|
||||
>
|
||||
<span className="text-red-400 text-lg leading-none mt-0.5">✕</span>
|
||||
<p className="text-sm" style={{ color: "#7f1d1d" }}>
|
||||
{label}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Главная страница «Логотип» ────────────────────────────── */
|
||||
export default function LogoPage() {
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto px-8 py-10">
|
||||
{/* Заголовок страницы */}
|
||||
<div className="mb-10 pb-6 border-b" style={{ borderColor: "var(--bb-border)" }}>
|
||||
<p
|
||||
className="text-xs font-semibold uppercase tracking-widest mb-2"
|
||||
style={{ color: "var(--brand-053m)" }}
|
||||
>
|
||||
Фундамент → 1.2
|
||||
</p>
|
||||
<h1 className="text-3xl font-semibold mb-3" style={{ color: "var(--bb-text)" }}>
|
||||
Логотип
|
||||
</h1>
|
||||
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Логотип может быть использован во всех визуальных коммуникациях бренда.
|
||||
Он не подлежит никаким изменениям и не допускается его сочетание ни с каким
|
||||
дополнительным текстом.
|
||||
</p>
|
||||
|
||||
<div
|
||||
className="mt-4 px-4 py-3 rounded-lg border text-sm flex items-center gap-2"
|
||||
style={{ borderColor: "#fde68a", background: "#fffbeb", color: "#92400e" }}
|
||||
>
|
||||
<span>⚠️</span>
|
||||
<span>
|
||||
Векторный файл логотипа будет добавлен после передачи SVG-файлов.
|
||||
Ниже — SVG-приближение для справки.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 1. Иерархия и версии */}
|
||||
<Section
|
||||
id="hierarchy"
|
||||
title="Иерархия и версии"
|
||||
subtitle="Клиника использует два варианта логотипа в зависимости от контекста применения."
|
||||
>
|
||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
|
||||
<div>
|
||||
<LogoPlaceholder variant="main" size="md" />
|
||||
<div className="mt-4">
|
||||
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||
Основной логотип
|
||||
</p>
|
||||
<p className="text-sm mb-2" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Локальные версии по направлениям (ЛОР, аллергология и др.).
|
||||
Применяется в точках контакта с клиентами, на лендингах и сайтах направлений.
|
||||
</p>
|
||||
<RuleTag>Точки контакта с клиентом</RuleTag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<LogoPlaceholder variant="general" size="md" />
|
||||
<div className="mt-4">
|
||||
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||
Общий логотип
|
||||
</p>
|
||||
<p className="text-sm mb-2" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Версия сети клиник. Применяется для онлайн и оффлайн коммуникаций
|
||||
с клиентами, во внутренней документации. Допустимо на общем сайте.
|
||||
</p>
|
||||
<RuleTag>Сеть клиник · Документация · Сайт</RuleTag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 2. Цветовые варианты */}
|
||||
<Section
|
||||
id="variants"
|
||||
title="Цветовые варианты"
|
||||
subtitle="Логотип существует в нескольких вариантах в зависимости от фона носителя."
|
||||
>
|
||||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
<div>
|
||||
<LogoPlaceholder variant="main" size="sm" />
|
||||
<p className="mt-2 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Основной — на светлом фоне
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<LogoPlaceholder variant="inverted" size="sm" />
|
||||
<p className="mt-2 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Инвертированный — на тёмном фоне
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<LogoPlaceholder variant="brown" size="sm" />
|
||||
<p className="mt-2 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Коричневый — на форме (бежевый костюм)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 3. Охранная зона */}
|
||||
<Section
|
||||
id="clearspace"
|
||||
title="Охранная зона"
|
||||
subtitle="Вокруг логотипа всегда должно быть свободное пространство, равное высоте буквы «x» в названии."
|
||||
>
|
||||
<div className="flex flex-wrap gap-8 items-start">
|
||||
<ClearspaceDemo />
|
||||
<div className="flex-1 min-w-48 space-y-3 pt-2">
|
||||
<p className="text-sm" style={{ color: "var(--bb-text)" }}>
|
||||
Охранная зона — минимальное расстояние от логотипа до любого другого
|
||||
графического элемента или края носителя.
|
||||
</p>
|
||||
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Пунктирная рамка обозначает охранную зону. Никакие другие элементы
|
||||
не должны пересекать её границы.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 4. Минимальные размеры */}
|
||||
<Section
|
||||
id="sizes"
|
||||
title="Минимальные размеры"
|
||||
subtitle="Размеры логотипа для размещения на форме сотрудников."
|
||||
>
|
||||
<div
|
||||
className="overflow-hidden rounded-lg border"
|
||||
style={{ borderColor: "var(--bb-border)" }}
|
||||
>
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr style={{ background: "var(--bb-sidebar-bg)" }}>
|
||||
<th
|
||||
className="text-left px-5 py-3 font-medium"
|
||||
style={{ color: "var(--bb-text-muted)" }}
|
||||
>
|
||||
Размер одежды
|
||||
</th>
|
||||
<th
|
||||
className="text-left px-5 py-3 font-medium"
|
||||
style={{ color: "var(--bb-text-muted)" }}
|
||||
>
|
||||
Длина логотипа
|
||||
</th>
|
||||
<th
|
||||
className="text-left px-5 py-3 font-medium"
|
||||
style={{ color: "var(--bb-text-muted)" }}
|
||||
>
|
||||
Высота логотипа
|
||||
</th>
|
||||
<th
|
||||
className="text-left px-5 py-3 font-medium"
|
||||
style={{ color: "var(--bb-text-muted)" }}
|
||||
>
|
||||
Расположение
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr className="border-t" style={{ borderColor: "var(--bb-border)" }}>
|
||||
<td className="px-5 py-3" style={{ color: "var(--bb-text)" }}>
|
||||
До 46 (включительно)
|
||||
</td>
|
||||
<td className="px-5 py-3 font-mono text-xs" style={{ color: "var(--bb-text)" }}>
|
||||
70 мм
|
||||
</td>
|
||||
<td className="px-5 py-3 font-mono text-xs" style={{ color: "var(--bb-text)" }}>
|
||||
25,5 мм
|
||||
</td>
|
||||
<td className="px-5 py-3" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Левая сторона груди
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="border-t" style={{ borderColor: "var(--bb-border)" }}>
|
||||
<td className="px-5 py-3" style={{ color: "var(--bb-text)" }}>
|
||||
От 48
|
||||
</td>
|
||||
<td className="px-5 py-3 font-mono text-xs" style={{ color: "var(--bb-text)" }}>
|
||||
90 мм
|
||||
</td>
|
||||
<td className="px-5 py-3 font-mono text-xs" style={{ color: "var(--bb-text)" }}>
|
||||
32,8 мм
|
||||
</td>
|
||||
<td className="px-5 py-3" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Левая сторона груди
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 5. Недопустимые варианты */}
|
||||
<Section
|
||||
id="prohibited"
|
||||
title="Недопустимые варианты использования"
|
||||
subtitle="Следующие варианты применения логотипа запрещены."
|
||||
>
|
||||
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
|
||||
<ProhibitedItem label="Изменять пропорции или искажать логотип" />
|
||||
<ProhibitedItem label="Изменять цвета элементов логотипа" />
|
||||
<ProhibitedItem label="Добавлять рядом произвольный текст" />
|
||||
<ProhibitedItem label="Размещать на фоне, с которым логотип не контрастирует" />
|
||||
<ProhibitedItem label="Использовать отдельные элементы логотипа без остальных" />
|
||||
<ProhibitedItem label="Применять тени, обводки, градиенты" />
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 6. Скачать файлы */}
|
||||
<Section
|
||||
id="download"
|
||||
title="Скачать файлы"
|
||||
subtitle="Официальные файлы логотипа для использования в коммуникациях."
|
||||
>
|
||||
<div
|
||||
className="rounded-lg border p-6 flex flex-col sm:flex-row items-start sm:items-center gap-4"
|
||||
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
||||
>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||
Векторные файлы логотипа (SVG, PNG)
|
||||
</p>
|
||||
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Будут доступны после передачи исходных файлов от дизайнера.
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
disabled
|
||||
className="px-4 py-2 rounded-lg text-sm font-medium cursor-not-allowed"
|
||||
style={{
|
||||
background: "#e5e7eb",
|
||||
color: "#9ca3af",
|
||||
}}
|
||||
>
|
||||
Скачать (скоро)
|
||||
</button>
|
||||
</div>
|
||||
</Section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user