feat(frontend): адаптация под мобильные устройства

- Мобильная навигация: hamburger-меню и drawer вместо фиксированного sidebar
- Модальные окна на весь экран при ширине < 480px
- Адаптивные заголовки страниц и фильтры (touch-friendly)
- Card view для таблицы операций при ширине < 600px
- Горизонтальный скролл вкладок настроек
- Увеличенные touch-targets (44px) для пагинации и кнопок
- Уменьшенная высота графиков на мобильных
- Поддержка safe-area-inset для устройств с вырезами
- theme-color в index.html

Made-with: Cursor
This commit is contained in:
Anton
2026-03-10 11:50:36 +03:00
parent a895bb4b2f
commit 56b5c81ec5
7 changed files with 477 additions and 87 deletions

View File

@@ -1,13 +1,37 @@
import type { ReactNode } from 'react';
import { useState, type ReactNode } from 'react';
import { NavLink } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
export function Layout({ children }: { children: ReactNode }) {
const { user, logout } = useAuth();
const [drawerOpen, setDrawerOpen] = useState(false);
const closeDrawer = () => setDrawerOpen(false);
return (
<div className="layout">
<aside className="sidebar">
<button
type="button"
className="burger-btn"
aria-label="Открыть меню"
onClick={() => setDrawerOpen(true)}
>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="3" y1="6" x2="21" y2="6" />
<line x1="3" y1="12" x2="21" y2="12" />
<line x1="3" y1="18" x2="21" y2="18" />
</svg>
</button>
{drawerOpen && (
<div
className="sidebar-overlay"
aria-hidden="true"
onClick={closeDrawer}
/>
)}
<aside className={`sidebar ${drawerOpen ? 'sidebar-open' : ''}`}>
<div className="sidebar-brand">
<span className="sidebar-brand-icon"></span>
<span className="sidebar-brand-text">Семейный бюджет</span>
@@ -19,6 +43,7 @@ export function Layout({ children }: { children: ReactNode }) {
className={({ isActive }) =>
`nav-link${isActive ? ' active' : ''}`
}
onClick={closeDrawer}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
@@ -35,6 +60,7 @@ export function Layout({ children }: { children: ReactNode }) {
className={({ isActive }) =>
`nav-link${isActive ? ' active' : ''}`
}
onClick={closeDrawer}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<line x1="18" y1="20" x2="18" y2="10" />
@@ -49,6 +75,7 @@ export function Layout({ children }: { children: ReactNode }) {
className={({ isActive }) =>
`nav-link${isActive ? ' active' : ''}`
}
onClick={closeDrawer}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<circle cx="12" cy="12" r="3" />