diff --git a/apps/web/.env.example b/apps/web/.env.example new file mode 100644 index 0000000..b0e8fc8 --- /dev/null +++ b/apps/web/.env.example @@ -0,0 +1 @@ +VITE_API_URL=http://localhost:8000/api diff --git a/apps/web/.gitignore b/apps/web/.gitignore new file mode 100644 index 0000000..1a202a3 --- /dev/null +++ b/apps/web/.gitignore @@ -0,0 +1,9 @@ +node_modules +dist +coverage +.env +.DS_Store +*.local +*.log +*.tsbuildinfo +.backend_known_hosts diff --git a/apps/web/.npmrc b/apps/web/.npmrc new file mode 100644 index 0000000..f1dc991 --- /dev/null +++ b/apps/web/.npmrc @@ -0,0 +1,3 @@ +save-exact=true +strict-peer-dependencies=true +auto-install-peers=false diff --git a/apps/web/.prettierrc b/apps/web/.prettierrc new file mode 100644 index 0000000..6bb3bf2 --- /dev/null +++ b/apps/web/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "singleQuote": false, + "trailingComma": "all", + "printWidth": 88 +} diff --git a/apps/web/DESIGN.md b/apps/web/DESIGN.md new file mode 100644 index 0000000..2f19646 --- /dev/null +++ b/apps/web/DESIGN.md @@ -0,0 +1,156 @@ +--- +version: alpha +name: DSTU Editorial Signal +description: A calm editorial media system for a large technical university. +colors: + primary: "#123C36" + primary-strong: "#082B27" + accent: "#D65A3A" + accent-soft: "#F6DDD4" + paper: "#F5F2EA" + surface: "#FFFDF8" + ink: "#17201E" + muted: "#66706D" + line: "#D9D8D0" + success: "#247A5A" + warning: "#A96616" + danger: "#B43D3D" + on-primary: "#FFFFFF" +typography: + display: + fontFamily: "Georgia, Cambria, serif" + fontSize: 4rem + fontWeight: 500 + lineHeight: 1.02 + letterSpacing: "-0.035em" + h1: + fontFamily: "Georgia, Cambria, serif" + fontSize: 3rem + fontWeight: 500 + lineHeight: 1.08 + h2: + fontFamily: "Georgia, Cambria, serif" + fontSize: 2rem + fontWeight: 500 + lineHeight: 1.15 + body: + fontFamily: "Inter, Arial, sans-serif" + fontSize: 1rem + fontWeight: 400 + lineHeight: 1.65 + label: + fontFamily: "Inter, Arial, sans-serif" + fontSize: 0.75rem + fontWeight: 700 + lineHeight: 1.2 + letterSpacing: "0.08em" +rounded: + sm: 0.375rem + md: 0.75rem + lg: 1.25rem +spacing: + xs: 0.25rem + sm: 0.5rem + md: 1rem + lg: 1.5rem + xl: 2.5rem + 2xl: 4rem +components: + button-primary: + backgroundColor: "{colors.primary}" + textColor: "{colors.on-primary}" + rounded: "{rounded.sm}" + padding: "0.75rem 1.125rem" + height: "2.75rem" + button-accent: + backgroundColor: "{colors.accent}" + textColor: "{colors.on-primary}" + rounded: "{rounded.sm}" + padding: "0.75rem 1.125rem" + height: "2.75rem" + card: + backgroundColor: "{colors.surface}" + textColor: "{colors.ink}" + rounded: "{rounded.md}" + padding: "1.25rem" +motion: + feedback: 140ms + content: 240ms + easing: "cubic-bezier(0.2, 0, 0, 1)" +--- + +## Overview + +The portal should feel like the digital edition of a respected technical university +newspaper combined with the calm wayfinding of a contemporary campus. It is made for +students checking what happens today, researchers reading long-form work, and staff +moving material through an editorial workflow. + +The page is a publication first and a software dashboard second. Public pages should +feel authored and alive. Administrative pages inherit the same typography, color and +editorial hierarchy rather than becoming a generic enterprise product. + +## Colors + +The canvas is warm paper, never sterile white. Deep green is institutional and +architectural; it anchors navigation, important buttons and large information blocks. +Terracotta is scarce and energetic, reserved for the current moment: primary calls to +action, live status and selected states. Body copy uses softened ink rather than black. + +Status colors communicate meaning and never replace a written label. + +## Typography + +Headlines use a restrained editorial serif. Interface copy, metadata and controls use a +neutral sans serif. Large titles are allowed to breathe, while dashboards use smaller, +denser headings. Long articles have a comfortable measure of roughly 68 characters. + +Uppercase is reserved for short section labels and metadata, never paragraphs or +navigation menus. + +## Layout + +Public pages use a 12-column editorial grid with deliberate asymmetry: a leading story +may occupy seven columns while a compact news rail occupies five. The maximum content +width follows the available viewport with a readable editorial cap. On narrow screens, +content becomes a single readable column without decorative reordering. + +Dashboard layouts use a fixed desktop rail and a drawer on mobile. Tables may scroll, +but the page itself must not. + +Responsive behavior is fluid rather than tied to named device widths. Layouts use +`minmax()`, `clamp()`, fractional columns and content-based wrapping. Media tabs scroll +when space is limited and collections gain columns only when their content fits. + +## Elevation & Depth + +Depth is mostly created with borders, overlapping paper surfaces and spacing. Shadows +are soft and rare. Hover states may lift a card by two pixels but should never make the +interface feel springy. + +## Shapes + +Corners are modest. Buttons and inputs use 0.375rem corners; cards use 0.75rem; feature +media may use 1.25rem. Pills are reserved for compact filters, tags and status, not general +containers. + +## Components + +Cards expose a clear reading order: section, title, summary, then metadata. Images do +not carry text overlays except in the single leading story. Forms use persistent labels, +visible focus rings and errors placed next to fields. + +Motion is quick and mechanical. Menus, dialogs and panels may combine opacity with a +small transform. Content transitions use cross-fades. Nothing bounces or takes longer +than 300ms. Reduced-motion users receive immediate state changes. + +## Do's and Don'ts + +- **Do** make the first screen feel like today's university edition. +- **Do** let real Russian headlines create the visual rhythm. +- **Do** preserve generous reading space around long-form content. +- **Do** use terracotta sparingly so it keeps meaning. +- **Don't** use gradients, glassmorphism, neon glows or giant rounded containers. +- **Don't** make every card animate independently. +- **Don't** turn the public portal into a grid of identical dashboard widgets. +- **Don't** hide essential labels behind icons. diff --git a/apps/web/IMG_4963.png b/apps/web/IMG_4963.png new file mode 100644 index 0000000..0dd173b Binary files /dev/null and b/apps/web/IMG_4963.png differ diff --git a/apps/web/README.md b/apps/web/README.md new file mode 100644 index 0000000..a7eb7df --- /dev/null +++ b/apps/web/README.md @@ -0,0 +1,98 @@ +# ДГТУ МЕДИА + +Frontend MVP информационной системы управления медиаконтентом университета. Проект +выполнен на JavaScript/JSX, React, Vite и Tailwind CSS. + +## Запуск + +Требуются Node.js 22+ и Corepack. + +```bash +corepack prepare pnpm@11.0.0 --activate +corepack pnpm install +corepack pnpm dev +``` + +Откройте `http://localhost:5173`. + +## Проверки + +```bash +corepack pnpm lint +corepack pnpm test +corepack pnpm build +``` + +## Структура + +```text +src/ + app/ маршрутизация, layouts и состояние сессии + pages/ публичные страницы и ролевые кабинеты + shared/ + api/ Axios-клиент и общая обработка ошибок + data/ реалистичные mock-данные + lib/ небольшие общие helpers + ui/ переиспользуемые компоненты +``` + +В `DESIGN.md` описаны дизайн-токены, визуальный характер, правила компонентов и +анимаций. + +## Реализованные страницы + +- главная редакционная страница; +- каталог с поиском и фильтрами через URL; +- страница материала; +- афиша событий; +- медиаканалы: радио, журналы и социальные сети; +- страница о медиапортале; +- вход и тестовые роли; +- профиль пользователя; +- кабинет редактора и форма материала; +- очередь модератора; +- статистика и пользователи администратора; +- страницы 403 и 404 с SVG-анимацией. + +## Тестовые роли + +Пароль может быть любым от 6 символов. + +| Роль | Учётная запись | +| --- | --- | +| Пользователь | `user@dstu.ru` | +| Редактор | `editor@dstu.ru` | +| Модератор | `moderator@dstu.ru` | +| Администратор | `admin@dstu.ru` | + +Роль также можно переключить в шапке кабинета для демонстрации интерфейсов. + +## Ожидаемые backend endpoints + +- `POST /auth/login`, `POST /auth/refresh`, `POST /auth/logout`; +- `GET/PATCH /users/me`; +- CRUD `/materials`, `/categories`, `/tags`, `/events`; +- `/materials/:id/comments`, `/subscriptions`, `/notifications`; +- `/moderation/queue`, `/moderation/:id/approve`, `/moderation/:id/return`; +- `/admin/users`, `/admin/stats`, `/admin/audit-log`; +- `POST /uploads`. + +Адрес API задаётся через `VITE_API_URL`. Пока интерфейс использует локальные mock-данные. + +## Безопасность зависимостей + +Проект закреплён на pnpm 11. В `pnpm-workspace.yaml` включены: + +- `minimumReleaseAge: 1440`; +- `blockExoticSubdeps: true`; +- `trustPolicy: no-downgrade`; +- явный `allowBuilds` только для `esbuild` и `@tailwindcss/oxide`. + +Lockfile необходимо хранить в репозитории. + +## Ограничения MVP + +- данные не сохраняются после обновления страницы; +- загрузка файлов и комментарии представлены интерфейсом без backend; +- внешние изображения загружаются с Unsplash; +- график администратора демонстрационный. diff --git a/apps/web/eslint.config.js b/apps/web/eslint.config.js new file mode 100644 index 0000000..6ea65fe --- /dev/null +++ b/apps/web/eslint.config.js @@ -0,0 +1,31 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; + +export default [ + { ignores: ["dist", "coverage"] }, + { + ...js.configs.recommended, + files: ["**/*.{js,jsx}"], + languageOptions: { + ecmaVersion: 2022, + globals: { ...globals.browser, ...globals.node, ...globals.vitest }, + parserOptions: { + ecmaFeatures: { jsx: true }, + sourceType: "module", + }, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + }, + }, +]; diff --git a/apps/web/index.html b/apps/web/index.html index 0237a74..db0c2e2 100644 --- a/apps/web/index.html +++ b/apps/web/index.html @@ -5,12 +5,22 @@ -