From 863260149056c4ed0a977e1875b87eed1f839364 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 14 May 2026 21:25:11 +0500 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20UI=20style=20refresh=20=E2=80=94=20?= =?UTF-8?q?Lucide=20icons,=20theme,=20slider,=20filters,=20buttons,=20VK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/package.json | 1 - client/src/app/layout/AppHeader.tsx | 7 +- client/src/app/layout/MainLayout.tsx | 18 +- client/src/app/providers/AppProviders.tsx | 25 ++ .../features/cart/cart-badge/ui/CartBadge.tsx | 4 +- .../toggle-cart-icon/ui/ToggleCartIcon.tsx | 6 +- .../features/user/user-menu/ui/UserMenu.tsx | 4 +- .../pages/admin-layout/ui/AdminLayoutPage.tsx | 24 +- client/src/pages/cart/ui/CartPage.tsx | 10 +- client/src/pages/home/ui/ProductFilters.tsx | 228 ++++++++---------- client/src/pages/me/ui/MeLayoutPage.tsx | 16 +- client/src/pages/product/ui/ProductPage.tsx | 13 +- client/src/shared/config/index.ts | 2 +- .../shared/ui/ModeSwitcher/ModeSwitcher.tsx | 7 +- .../src/shared/ui/RichTextMessageEditor.tsx | 10 +- .../ui/SchemeSwitcher/SchemeSwitcher.tsx | 30 +-- .../catalog-slider/ui/CatalogSlider.tsx | 16 +- .../specs/2026-05-14-ui-style-refresh.md | 55 +++++ 18 files changed, 256 insertions(+), 220 deletions(-) create mode 100644 docs/superpowers/specs/2026-05-14-ui-style-refresh.md diff --git a/client/package.json b/client/package.json index 54fb1cc..2cd1406 100644 --- a/client/package.json +++ b/client/package.json @@ -17,7 +17,6 @@ "dependencies": { "@emotion/react": "^11.14.0", "@emotion/styled": "^11.14.1", - "@mui/icons-material": "^9.0.0", "@mui/material": "^9.0.0", "@tanstack/react-query": "^5.100.5", "@tiptap/extension-placeholder": "^3.22.5", diff --git a/client/src/app/layout/AppHeader.tsx b/client/src/app/layout/AppHeader.tsx index c1218c3..726ac39 100644 --- a/client/src/app/layout/AppHeader.tsx +++ b/client/src/app/layout/AppHeader.tsx @@ -1,6 +1,5 @@ import { useEffect, useState } from 'react' -import Inventory2OutlinedIcon from '@mui/icons-material/Inventory2Outlined' -import MenuRoundedIcon from '@mui/icons-material/MenuRounded' +import { Menu, Package } from 'lucide-react' import AppBar from '@mui/material/AppBar' import Badge from '@mui/material/Badge' import Box from '@mui/material/Box' @@ -101,7 +100,7 @@ export function AppHeader() { edge="start" sx={{ mr: 1 }} > - + )} @@ -137,7 +136,7 @@ export function AppHeader() { navigate('/me/orders')} aria-label="Заказы"> - + diff --git a/client/src/app/layout/MainLayout.tsx b/client/src/app/layout/MainLayout.tsx index 95e2bdd..1ed91c4 100644 --- a/client/src/app/layout/MainLayout.tsx +++ b/client/src/app/layout/MainLayout.tsx @@ -4,11 +4,12 @@ import Container from '@mui/material/Container' import Divider from '@mui/material/Divider' import Grid from '@mui/material/Grid' import Link from '@mui/material/Link' +import SvgIcon from '@mui/material/SvgIcon' import Stack from '@mui/material/Stack' import Typography from '@mui/material/Typography' import { Link as RouterLink } from 'react-router-dom' import { AppHeader } from '@/app/layout/AppHeader' -import { STORE_EMAIL, STORE_NAME, STORE_PHONE, STORE_SOCIAL_NOTE } from '@/shared/config' +import { STORE_EMAIL, STORE_NAME, STORE_PHONE, VK_URL } from '@/shared/config' export function MainLayout({ children }: PropsWithChildren) { const year = new Date().getFullYear() @@ -82,9 +83,18 @@ export function MainLayout({ children }: PropsWithChildren) { {STORE_PHONE} - - {STORE_SOCIAL_NOTE} - + + + + + VK + diff --git a/client/src/app/providers/AppProviders.tsx b/client/src/app/providers/AppProviders.tsx index e827022..ad90173 100644 --- a/client/src/app/providers/AppProviders.tsx +++ b/client/src/app/providers/AppProviders.tsx @@ -94,6 +94,31 @@ function AppThemeInner({ children }: PropsWithChildren) { h4: { fontWeight: 700 }, h5: { fontWeight: 600 }, }, + components: { + MuiButton: { + styleOverrides: { + root: { textTransform: 'none', borderRadius: 12, fontWeight: 600 }, + contained: { + boxShadow: '0 4px 14px 0 rgba(0,0,0,0.15)', + '&:hover': { + boxShadow: '0 6px 20px 0 rgba(0,0,0,0.25)', + transform: 'translateY(-1px)', + }, + }, + outlined: { + '&:hover': { boxShadow: '0 2px 8px 0 rgba(0,0,0,0.1)' }, + }, + }, + }, + MuiIconButton: { + styleOverrides: { + root: { + transition: 'all 0.2s ease', + '&:hover': { transform: 'scale(1.1)' }, + }, + }, + }, + }, }), [controller.resolvedMode, controller.scheme], ) diff --git a/client/src/features/cart/cart-badge/ui/CartBadge.tsx b/client/src/features/cart/cart-badge/ui/CartBadge.tsx index 40c2a83..f6c6fd1 100644 --- a/client/src/features/cart/cart-badge/ui/CartBadge.tsx +++ b/client/src/features/cart/cart-badge/ui/CartBadge.tsx @@ -1,4 +1,4 @@ -import ShoppingCartRoundedIcon from '@mui/icons-material/ShoppingCartRounded' +import { ShoppingCart } from 'lucide-react' import Badge from '@mui/material/Badge' import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' @@ -23,7 +23,7 @@ export function CartBadge({ user, cartCount, onNavigate }: Props) { aria-label="Корзина" > - + diff --git a/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx b/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx index 98c10e7..56d948b 100644 --- a/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx +++ b/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx @@ -1,6 +1,4 @@ -import AddShoppingCartOutlinedIcon from '@mui/icons-material/AddShoppingCartOutlined' -import ShoppingCartOutlinedIcon from '@mui/icons-material/ShoppingCartOutlined' -import ShoppingCartRoundedIcon from '@mui/icons-material/ShoppingCartRounded' +import { ShoppingCart, ShoppingCartOff } from 'lucide-react' import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' @@ -65,7 +63,7 @@ export function ToggleCartIcon(props: { - {user ? inCart ? : : } + {user ? inCart ? : : diff --git a/client/src/features/user/user-menu/ui/UserMenu.tsx b/client/src/features/user/user-menu/ui/UserMenu.tsx index fca6d69..1b971a2 100644 --- a/client/src/features/user/user-menu/ui/UserMenu.tsx +++ b/client/src/features/user/user-menu/ui/UserMenu.tsx @@ -1,5 +1,5 @@ import { useState } from 'react' -import PersonOutlineRoundedIcon from '@mui/icons-material/PersonOutlineRounded' +import { User } from 'lucide-react' import Badge from '@mui/material/Badge' import IconButton from '@mui/material/IconButton' import ListItemText from '@mui/material/ListItemText' @@ -40,7 +40,7 @@ export function UserMenu({ user, onNavigate, onLogout }: Props) { invisible={!user} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }} > - + diff --git a/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx b/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx index a375aa2..0242a09 100644 --- a/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx +++ b/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx @@ -1,12 +1,6 @@ import type { ReactNode } from 'react' import { useMemo, useState } from 'react' -import AdminPanelSettingsOutlinedIcon from '@mui/icons-material/AdminPanelSettingsOutlined' -import AssignmentOutlinedIcon from '@mui/icons-material/AssignmentOutlined' -import DescriptionOutlinedIcon from '@mui/icons-material/DescriptionOutlined' -import PeopleOutlinedIcon from '@mui/icons-material/PeopleOutlined' -import PhotoLibraryOutlinedIcon from '@mui/icons-material/PhotoLibraryOutlined' -import RateReviewOutlinedIcon from '@mui/icons-material/RateReviewOutlined' -import StorefrontOutlinedIcon from '@mui/icons-material/StorefrontOutlined' +import { FileText, Image, LayoutGrid, ListOrdered, MessageSquare, People, Store } from 'lucide-react' import Badge from '@mui/material/Badge' import Box from '@mui/material/Box' import Divider from '@mui/material/Divider' @@ -60,13 +54,13 @@ export function AdminLayoutPage() { const navItems: NavItem[] = useMemo( () => [ - { to: '/admin', label: 'Товары', icon: }, - { to: '/admin/categories', label: 'Категории', icon: }, - { to: '/admin/gallery', label: 'Галерея', icon: }, - { to: '/admin/orders', label: 'Заказы', icon: }, - { to: '/admin/reviews', label: 'Отзывы', icon: }, - { to: '/admin/users', label: 'Пользователи', icon: }, - { to: '/admin/info', label: 'Инфо-страница', icon: }, + { to: '/admin', label: 'Товары', icon: }, + { to: '/admin/categories', label: 'Категории', icon: }, + { to: '/admin/gallery', label: 'Галерея', icon: }, + { to: '/admin/orders', label: 'Заказы', icon: }, + { to: '/admin/reviews', label: 'Отзывы', icon: }, + { to: '/admin/users', label: 'Пользователи', icon: }, + { to: '/admin/info', label: 'Инфо-страница', icon: }, ], [], ) @@ -143,7 +137,7 @@ export function AdminLayoutPage() { bgcolor: 'warning.50', }} > - + Админка diff --git a/client/src/pages/cart/ui/CartPage.tsx b/client/src/pages/cart/ui/CartPage.tsx index 7488cd8..26079ef 100644 --- a/client/src/pages/cart/ui/CartPage.tsx +++ b/client/src/pages/cart/ui/CartPage.tsx @@ -1,6 +1,4 @@ -import AddIcon from '@mui/icons-material/Add' -import DeleteOutlineOutlinedIcon from '@mui/icons-material/DeleteOutlineOutlined' -import RemoveIcon from '@mui/icons-material/Remove' +import { Minus, Plus, Trash2 } from 'lucide-react' import Alert from '@mui/material/Alert' import Box from '@mui/material/Box' import Button from '@mui/material/Button' @@ -115,7 +113,7 @@ export function CartPage() { size="small" sx={{ width: 32, height: 32 }} > - + - + @@ -149,7 +147,7 @@ export function CartPage() { size="small" sx={{ width: 32, height: 32 }} > - + diff --git a/client/src/pages/home/ui/ProductFilters.tsx b/client/src/pages/home/ui/ProductFilters.tsx index a27a8f9..925e90e 100644 --- a/client/src/pages/home/ui/ProductFilters.tsx +++ b/client/src/pages/home/ui/ProductFilters.tsx @@ -1,9 +1,11 @@ import { useMemo } from 'react' import Box from '@mui/material/Box' import Button from '@mui/material/Button' +import Chip from '@mui/material/Chip' import Collapse from '@mui/material/Collapse' import Divider from '@mui/material/Divider' import FormControl from '@mui/material/FormControl' +import InputAdornment from '@mui/material/InputAdornment' import InputLabel from '@mui/material/InputLabel' import MenuItem from '@mui/material/MenuItem' import Paper from '@mui/material/Paper' @@ -13,6 +15,7 @@ import TextField from '@mui/material/TextField' import ToggleButton from '@mui/material/ToggleButton' import ToggleButtonGroup from '@mui/material/ToggleButtonGroup' import Typography from '@mui/material/Typography' +import { Search, SlidersHorizontal } from 'lucide-react' import type { Category } from '@/entities/product/model/types' import type { UseProductFiltersResult } from '../lib/use-product-filters' @@ -60,53 +63,49 @@ export function ProductFilters({ spacing={2} sx={{ alignItems: { md: 'center' }, flexWrap: { md: 'wrap' } }} > - - Категория - - labelId="category-filter-label" - label="Категория" - value={categorySlug} - onChange={handleCategoryChange} - disabled={categoriesLoading} - > - - Все - - {categoriesForFilter.map((c) => ( - - {c.name} - - ))} - - - setQInput(e.target.value)} + slotProps={{ + input: { + startAdornment: ( + + + + ), + }, + }} sx={{ flexGrow: 1, minWidth: { xs: '100%', md: 360 } }} /> - - Наличие - - Быстрый фильтр по наличию - + + + handleCategoryChange('')} + /> + {categoriesForFilter.map((c) => ( + handleCategoryChange(c.slug)} + disabled={categoriesLoading} + /> + ))} + handleAvailabilityChange(v)} sx={{ alignSelf: { xs: 'flex-start', sm: 'auto' }, - '& .MuiToggleButton-root': { px: 2, fontWeight: 700, letterSpacing: 0.2, textTransform: 'none' }, + '& .MuiToggleButton-root': { px: 1.5, fontWeight: 600, textTransform: 'none' }, '& .MuiToggleButton-root.Mui-selected': { bgcolor: 'primary.main', color: 'primary.contrastText', @@ -135,114 +134,81 @@ export function ProductFilters({ spacing={1.5} sx={{ alignItems: { sm: 'center' }, justifyContent: 'space-between', flexWrap: 'wrap' }} > - + - - - Сортировка - labelId="sort-label" label="Сортировка" value={sort} onChange={handleSortChange}> - - Сначала новые - - Цена: по возрастанию - Цена: по убыванию - - + + + + Сортировка + labelId="sort-label" label="Сортировка" value={sort} onChange={handleSortChange}> + Сначала новые + Цена: по возрастанию + Цена: по убыванию + + - handlePriceMinChange(e.target.value)} - sx={{ width: { xs: '100%', md: 180 } }} - /> - handlePriceMaxChange(e.target.value)} - sx={{ width: { xs: '100%', md: 180 } }} - /> + handlePriceMinChange(e.target.value)} + sx={{ width: { xs: '100%', md: 160 } }} + /> + handlePriceMaxChange(e.target.value)} + sx={{ width: { xs: '100%', md: 160 } }} + /> - - На странице - - labelId="page-size-label" - label="На странице" - value={String(pageSize)} - onChange={handlePageSizeChange} - > - {[6, 12, 18, 24].map((n) => ( - - {n} - - ))} - - - + + На странице + labelId="page-size-label" label="На странице" value={String(pageSize)} onChange={handlePageSizeChange}> + {[6, 12, 18, 24].map((n) => ( + {n} + ))} + + + - + - - + Масштаб карточек - - Выберите размер карточек в каталоге - + handleCardScaleChange(v)} + sx={{ + alignSelf: { xs: 'flex-start', sm: 'auto' }, + '& .MuiToggleButton-root': { px: 1.5, fontWeight: 600, textTransform: 'none' }, + '& .MuiToggleButton-root.Mui-selected': { + bgcolor: 'primary.main', + color: 'primary.contrastText', + '&:hover': { bgcolor: 'primary.dark' }, + }, + }} + > + S + M + L + XL + - - handleCardScaleChange(v)} - sx={{ - alignSelf: { xs: 'flex-start', sm: 'auto' }, - '& .MuiToggleButton-root': { - px: 2, - fontWeight: 700, - letterSpacing: 0.2, - textTransform: 'none', - }, - '& .MuiToggleButton-root.Mui-selected': { - bgcolor: 'primary.main', - color: 'primary.contrastText', - '&:hover': { bgcolor: 'primary.dark' }, - }, - }} - > - S - M - L - XL - diff --git a/client/src/pages/me/ui/MeLayoutPage.tsx b/client/src/pages/me/ui/MeLayoutPage.tsx index 953c76a..25fdaf1 100644 --- a/client/src/pages/me/ui/MeLayoutPage.tsx +++ b/client/src/pages/me/ui/MeLayoutPage.tsx @@ -1,10 +1,6 @@ import type { ReactNode } from 'react' import { useMemo, useState } from 'react' -import ChatOutlinedIcon from '@mui/icons-material/ChatOutlined' -import LocalShippingOutlinedIcon from '@mui/icons-material/LocalShippingOutlined' -import PlaceOutlinedIcon from '@mui/icons-material/PlaceOutlined' -import SettingsOutlinedIcon from '@mui/icons-material/SettingsOutlined' -import TuneOutlinedIcon from '@mui/icons-material/TuneOutlined' +import { MapPin, MessageCircle, Settings, SlidersHorizontal, Truck } from 'lucide-react' import Alert from '@mui/material/Alert' import Badge from '@mui/material/Badge' import Box from '@mui/material/Box' @@ -56,10 +52,10 @@ export function MeLayoutPage() { const navItems: NavItem[] = useMemo( () => [ - { to: '/me/orders', label: 'Заказы', icon: }, - { to: '/me/messages', label: 'Сообщения', icon: }, - { to: '/me/settings', label: 'Настройки', icon: }, - { to: '/me/addresses', label: 'Адреса доставки', icon: }, + { to: '/me/orders', label: 'Заказы', icon: }, + { to: '/me/messages', label: 'Сообщения', icon: }, + { to: '/me/settings', label: 'Настройки', icon: }, + { to: '/me/addresses', label: 'Адреса доставки', icon: }, ], [], ) @@ -143,7 +139,7 @@ export function MeLayoutPage() { bgcolor: 'background.paper', }} > - + Профиль diff --git a/client/src/pages/product/ui/ProductPage.tsx b/client/src/pages/product/ui/ProductPage.tsx index c181eed..2cda61e 100644 --- a/client/src/pages/product/ui/ProductPage.tsx +++ b/client/src/pages/product/ui/ProductPage.tsx @@ -1,6 +1,5 @@ import { useMemo, useState } from 'react' -import CloseIcon from '@mui/icons-material/Close' -import StarRoundedIcon from '@mui/icons-material/StarRounded' +import { Star, X } from 'lucide-react' import Alert from '@mui/material/Alert' import Box from '@mui/material/Box' import Chip from '@mui/material/Chip' @@ -180,8 +179,8 @@ export function ProductPage() { value={p.reviewsSummary.avgRating ?? 0} readOnly precision={0.25} - icon={} - emptyIcon={} + icon={} + emptyIcon={} /> {reviewsCountRu(p.reviewsSummary.approvedReviewCount)} @@ -211,8 +210,8 @@ export function ProductPage() { value={rv.rating} readOnly size="small" - icon={} - emptyIcon={} + icon={} + emptyIcon={} /> {body ? ( @@ -259,7 +258,7 @@ export function ProductPage() { sx={{ position: 'absolute', top: 12, right: 12, zIndex: 2, color: 'white' }} aria-label="Закрыть" > - + { /** Демо-контакты для футера; при необходимости задайте через VITE_* в `.env`. */ export const STORE_EMAIL = import.meta.env.VITE_STORE_EMAIL ?? 'hello@example.com' export const STORE_PHONE = import.meta.env.VITE_STORE_PHONE ?? '+7 (900) 000-00-00' -export const STORE_SOCIAL_NOTE = import.meta.env.VITE_STORE_SOCIAL_NOTE ?? 'Соцсети: укажите ссылки при публикации' +export const VK_URL = import.meta.env.VITE_VK_URL ?? '#' diff --git a/client/src/shared/ui/ModeSwitcher/ModeSwitcher.tsx b/client/src/shared/ui/ModeSwitcher/ModeSwitcher.tsx index 2f70c70..0c811ea 100644 --- a/client/src/shared/ui/ModeSwitcher/ModeSwitcher.tsx +++ b/client/src/shared/ui/ModeSwitcher/ModeSwitcher.tsx @@ -1,5 +1,4 @@ -import DarkModeOutlinedIcon from '@mui/icons-material/DarkModeOutlined' -import LightModeOutlinedIcon from '@mui/icons-material/LightModeOutlined' +import { Monitor, Moon, Sun } from 'lucide-react' import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' import type { ThemeModePreference } from '@/shared/model/theme' @@ -22,10 +21,12 @@ function getModeLabel(mode: ThemeModePreference, resolvedMode: 'light' | 'dark') } export function ModeSwitcher({ mode, resolvedMode, onCycleMode }: Props) { + const icon = mode === 'system' ? : resolvedMode === 'dark' ? : + return ( - {resolvedMode === 'dark' ? : } + {icon} ) diff --git a/client/src/shared/ui/RichTextMessageEditor.tsx b/client/src/shared/ui/RichTextMessageEditor.tsx index f9ee69c..b65147a 100644 --- a/client/src/shared/ui/RichTextMessageEditor.tsx +++ b/client/src/shared/ui/RichTextMessageEditor.tsx @@ -1,7 +1,5 @@ import { useEffect } from 'react' -import FormatBoldOutlinedIcon from '@mui/icons-material/FormatBoldOutlined' -import FormatItalicOutlinedIcon from '@mui/icons-material/FormatItalicOutlined' -import FormatListBulletedOutlinedIcon from '@mui/icons-material/FormatListBulletedOutlined' +import { Bold, Italic, List } from 'lucide-react' import Box from '@mui/material/Box' import IconButton from '@mui/material/IconButton' import Stack from '@mui/material/Stack' @@ -59,7 +57,7 @@ export function RichTextMessageEditor({ disabled={disabled} aria-label="Жирный" > - + - + - + diff --git a/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx b/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx index a2abc5f..537f994 100644 --- a/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx +++ b/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx @@ -1,4 +1,3 @@ -import CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded' import Box from '@mui/material/Box' import IconButton from '@mui/material/IconButton' import { Cherry, Hammer, Trees, WavesHorizontal } from 'lucide-react' @@ -11,10 +10,10 @@ type Props = { } const SCHEMES: { key: ColorScheme; color: string; label: string; icon: React.ReactNode }[] = [ - { key: 'craft', color: '#6D4C41', label: 'Крафт', icon: }, - { key: 'forest', color: '#2E7D32', label: 'Лес', icon: }, - { key: 'ocean', color: '#1565C0', label: 'Океан', icon: }, - { key: 'berry', color: '#7B1FA2', label: 'Ягоды', icon: }, + { key: 'craft', color: '#6D4C41', label: 'Крафт', icon: }, + { key: 'forest', color: '#2E7D32', label: 'Лес', icon: }, + { key: 'ocean', color: '#1565C0', label: 'Океан', icon: }, + { key: 'berry', color: '#7B1FA2', label: 'Ягоды', icon: }, ] export function SchemeSwitcher({ value, onChange, orientation = 'horizontal' }: Props) { @@ -36,23 +35,24 @@ export function SchemeSwitcher({ value, onChange, orientation = 'horizontal' }: size="small" title={s.label} sx={{ - width: 30, - height: 30, - minWidth: 30, - bgcolor: s.color, + width: 36, + height: 36, + minWidth: 36, + bgcolor: 'transparent', border: 2, - borderColor: active ? 'common.white' : 'rgba(255,255,255,0.4)', - boxShadow: active ? `0 0 0 1.5px ${s.color}, 0 0 8px ${s.color}99` : 'none', - transform: active ? 'scale(1.1)' : 'scale(1)', - color: 'common.white', + borderColor: active ? s.color : 'transparent', + boxShadow: active ? `0 0 8px ${s.color}66` : 'none', + transform: active ? 'scale(1.15)' : 'scale(1)', + color: active ? s.color : 'text.secondary', transition: 'all 0.2s ease', '&:hover': { transform: 'scale(1.2)', - bgcolor: s.color, + borderColor: s.color, + color: s.color, }, }} > - {active ? : s.icon} + {s.icon} ) })} diff --git a/client/src/widgets/catalog-slider/ui/CatalogSlider.tsx b/client/src/widgets/catalog-slider/ui/CatalogSlider.tsx index 7ebf236..23e2658 100644 --- a/client/src/widgets/catalog-slider/ui/CatalogSlider.tsx +++ b/client/src/widgets/catalog-slider/ui/CatalogSlider.tsx @@ -80,24 +80,22 @@ function CatalogSliderInner({ slides }: { slides: CatalogSliderSlide[] }) { 1 ? 20 : 0, zIndex: 4, - pt: 4, - pb: slides.length > 1 ? 2 : 2, - WebkitTextStroke: '0.5px white', - // background: 'linear-gradient(to top, rgba(0,0,0,0.82) 0%, rgba(0,0,0,0.4) 50%, transparent 100%)', + background: 'linear-gradient(transparent, rgba(0,0,0,0.75))', + px: 3, + py: 2.5, }} > {captionText} diff --git a/docs/superpowers/specs/2026-05-14-ui-style-refresh.md b/docs/superpowers/specs/2026-05-14-ui-style-refresh.md new file mode 100644 index 0000000..3306eaf --- /dev/null +++ b/docs/superpowers/specs/2026-05-14-ui-style-refresh.md @@ -0,0 +1,55 @@ +# UI Style Refresh + +**Дата:** 2026-05-14 +**Статус:** Утверждён + +## Мотивация + +Освежить визуальный стиль сайта: заменить иконки на Lucide, переработать тему/переключатели схем, добавить VK в футер, обновить стиль каталога, слайдера и кнопок. + +## 1. Иконки: MUI → Lucide React (везде) + +Удалить зависимость `@mui/icons-material` из `client/package.json`. Все иконки MUI заменить на Lucide React. + +## 2. Theme/SchemeSwitcher + +Горизонтальное расположение. ModeSwitcher: `Sun`/`Moon`/`Monitor`. SchemeSwitcher: без bgcolor, цветная обводка у активной. + +## 3. VK в футер + +Кастомный SVG-логотип VK (`SvgIcon`), ссылка `href={VITE_VK_URL}`, удалить `STORE_SOCIAL_NOTE`. + +## 4. ProductFilters (каталог) + +Визуальный редизайн: Search с иконкой, Chips категорий, компактные фильтры, Material 3 стиль. + +## 5. CatalogSlider (слайдер) + +Подложка `rgba(0,0,0,0.7)` под текст, новый размер/вес шрифта, убрать WebkitTextStroke. + +## 6. Кнопки (MUI-тема) + +MuiButton: тени, градиент, hover-эффект. MuiIconButton: scale на hover. + +## Файлы для изменения + +| Файл | Изменение | +|---|---| +| `client/package.json` | Удалить `@mui/icons-material` | +| `client/src/app/providers/AppProviders.tsx` | MuiButton/MuiIconButton styleOverrides | +| `client/src/shared/config/index.ts` | Добавить VK_URL, удалить SOCIAL_NOTE | +| `client/src/app/layout/AppHeader.tsx` | MUI→Lucide иконки | +| `client/src/app/layout/MainLayout.tsx` | VK иконка, удалить SOCIAL_NOTE | +| `client/src/shared/ui/ModeSwitcher/ModeSwitcher.tsx` | Lucide + 3 режима | +| `client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx` | Убрать bgcolor, обводка | +| `client/src/features/cart/cart-badge/ui/CartBadge.tsx` | Lucide `ShoppingCart` | +| `client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx` | Lucide иконки | +| `client/src/features/user/user-menu/ui/UserMenu.tsx` | Lucide `User` | +| `client/src/widgets/navigation-drawer/ui/NavigationDrawer.tsx` | Lucide иконки | +| `client/src/widgets/catalog-slider/ui/CatalogSlider.tsx` | Подложка текста | +| `client/src/pages/home/ui/ProductFilters.tsx` | Визуальный редизайн | +| `client/src/pages/admin-layout/ui/AdminLayoutPage.tsx` | Lucide иконки | +| `client/src/pages/me/ui/MeLayoutPage.tsx` | Lucide иконки | +| `client/src/pages/products/ui/ProductPage.tsx` | Lucide `Star`, `X` | +| `client/src/pages/cart/ui/CartPage.tsx` | Lucide `Trash2`, `Plus`, `Minus` | +| `client/src/shared/ui/RichTextMessageEditor.tsx` | Lucide `Bold`, `Italic`, `List` | From d5075813a26bd6a3a8e4c8bbb35c8ec13b76ae78 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 14 May 2026 21:36:00 +0500 Subject: [PATCH 2/6] fix: lint and type errors in ToggleCartIcon, AdminLayout, ProductFilters, use-product-filters --- client/src/app/layout/AppHeader.tsx | 2 +- client/src/app/layout/MainLayout.tsx | 2 +- client/src/entities/info/api/info-page-api.ts | 2 - .../features/cart/cart-badge/ui/CartBadge.tsx | 2 +- .../toggle-cart-icon/ui/ToggleCartIcon.tsx | 4 +- .../features/user/user-menu/ui/UserMenu.tsx | 2 +- .../pages/admin-layout/ui/AdminLayoutPage.tsx | 4 +- client/src/pages/cart/ui/CartPage.tsx | 2 +- .../src/pages/home/lib/use-product-filters.ts | 4 +- client/src/pages/home/ui/ProductFilters.tsx | 52 ++++++++++++++++--- client/src/pages/me/ui/MeLayoutPage.tsx | 2 +- client/src/pages/product/ui/ProductPage.tsx | 2 +- .../shared/ui/ModeSwitcher/ModeSwitcher.tsx | 2 +- .../src/shared/ui/RichTextMessageEditor.tsx | 2 +- .../plans/2026-05-14-ui-style-refresh.md | 45 ++++++++++++++++ 15 files changed, 105 insertions(+), 24 deletions(-) create mode 100644 docs/superpowers/plans/2026-05-14-ui-style-refresh.md diff --git a/client/src/app/layout/AppHeader.tsx b/client/src/app/layout/AppHeader.tsx index 726ac39..83c7825 100644 --- a/client/src/app/layout/AppHeader.tsx +++ b/client/src/app/layout/AppHeader.tsx @@ -1,5 +1,4 @@ import { useEffect, useState } from 'react' -import { Menu, Package } from 'lucide-react' import AppBar from '@mui/material/AppBar' import Badge from '@mui/material/Badge' import Box from '@mui/material/Box' @@ -12,6 +11,7 @@ import Typography from '@mui/material/Typography' import useMediaQuery from '@mui/material/useMediaQuery' import { useQuery } from '@tanstack/react-query' import { useUnit } from 'effector-react' +import { Menu, Package } from 'lucide-react' import { Link as RouterLink, useNavigate } from 'react-router-dom' import { useThemeController } from '@/app/providers/theme-controller' import { fetchMyCart } from '@/entities/cart/api/cart-api' diff --git a/client/src/app/layout/MainLayout.tsx b/client/src/app/layout/MainLayout.tsx index 1ed91c4..ddc01f2 100644 --- a/client/src/app/layout/MainLayout.tsx +++ b/client/src/app/layout/MainLayout.tsx @@ -4,8 +4,8 @@ import Container from '@mui/material/Container' import Divider from '@mui/material/Divider' import Grid from '@mui/material/Grid' import Link from '@mui/material/Link' -import SvgIcon from '@mui/material/SvgIcon' import Stack from '@mui/material/Stack' +import SvgIcon from '@mui/material/SvgIcon' import Typography from '@mui/material/Typography' import { Link as RouterLink } from 'react-router-dom' import { AppHeader } from '@/app/layout/AppHeader' diff --git a/client/src/entities/info/api/info-page-api.ts b/client/src/entities/info/api/info-page-api.ts index 0a37103..70873ac 100644 --- a/client/src/entities/info/api/info-page-api.ts +++ b/client/src/entities/info/api/info-page-api.ts @@ -1,8 +1,6 @@ import { apiClient } from '@/shared/api/client' import type { InfoPageBlock } from '../model/types' - - export async function fetchPublicInfoBlocks(): Promise<{ items: InfoPageBlock[] }> { const { data } = await apiClient.get<{ items: InfoPageBlock[] }>('info-page/blocks') return data diff --git a/client/src/features/cart/cart-badge/ui/CartBadge.tsx b/client/src/features/cart/cart-badge/ui/CartBadge.tsx index f6c6fd1..a35b677 100644 --- a/client/src/features/cart/cart-badge/ui/CartBadge.tsx +++ b/client/src/features/cart/cart-badge/ui/CartBadge.tsx @@ -1,7 +1,7 @@ -import { ShoppingCart } from 'lucide-react' import Badge from '@mui/material/Badge' import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' +import { ShoppingCart } from 'lucide-react' import type { AuthUser } from '@/shared/model/auth' type Props = { diff --git a/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx b/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx index 56d948b..ba618e3 100644 --- a/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx +++ b/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx @@ -1,8 +1,8 @@ -import { ShoppingCart, ShoppingCartOff } from 'lucide-react' import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useUnit } from 'effector-react' +import { ShoppingCart } from 'lucide-react' import { useNavigate } from 'react-router-dom' import { addToCart, fetchMyCart, removeCartItem } from '@/entities/cart/api/cart-api' import { $user } from '@/shared/model/auth' @@ -63,7 +63,7 @@ export function ToggleCartIcon(props: { - {user ? inCart ? : : + {user ? inCart ? : : } diff --git a/client/src/features/user/user-menu/ui/UserMenu.tsx b/client/src/features/user/user-menu/ui/UserMenu.tsx index 1b971a2..65607dd 100644 --- a/client/src/features/user/user-menu/ui/UserMenu.tsx +++ b/client/src/features/user/user-menu/ui/UserMenu.tsx @@ -1,10 +1,10 @@ import { useState } from 'react' -import { User } from 'lucide-react' import Badge from '@mui/material/Badge' import IconButton from '@mui/material/IconButton' import ListItemText from '@mui/material/ListItemText' import Menu from '@mui/material/Menu' import MenuItem from '@mui/material/MenuItem' +import { User } from 'lucide-react' import type { AuthUser } from '@/shared/model/auth' type Props = { diff --git a/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx b/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx index 0242a09..72a6674 100644 --- a/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx +++ b/client/src/pages/admin-layout/ui/AdminLayoutPage.tsx @@ -1,6 +1,5 @@ import type { ReactNode } from 'react' import { useMemo, useState } from 'react' -import { FileText, Image, LayoutGrid, ListOrdered, MessageSquare, People, Store } from 'lucide-react' import Badge from '@mui/material/Badge' import Box from '@mui/material/Box' import Divider from '@mui/material/Divider' @@ -16,6 +15,7 @@ import Typography from '@mui/material/Typography' import useMediaQuery from '@mui/material/useMediaQuery' import { useQuery } from '@tanstack/react-query' import { useUnit } from 'effector-react' +import { FileText, Image, LayoutGrid, ListOrdered, MessageSquare, Store, Users } from 'lucide-react' import { Navigate, Route, Routes, useLocation, useNavigate } from 'react-router-dom' import { fetchAdminOrdersSummary } from '@/entities/order/api/admin-order-api' import { AdminCategoriesPage } from '@/pages/admin-categories' @@ -59,7 +59,7 @@ export function AdminLayoutPage() { { to: '/admin/gallery', label: 'Галерея', icon: }, { to: '/admin/orders', label: 'Заказы', icon: }, { to: '/admin/reviews', label: 'Отзывы', icon: }, - { to: '/admin/users', label: 'Пользователи', icon: }, + { to: '/admin/users', label: 'Пользователи', icon: }, { to: '/admin/info', label: 'Инфо-страница', icon: }, ], [], diff --git a/client/src/pages/cart/ui/CartPage.tsx b/client/src/pages/cart/ui/CartPage.tsx index 26079ef..a952105 100644 --- a/client/src/pages/cart/ui/CartPage.tsx +++ b/client/src/pages/cart/ui/CartPage.tsx @@ -1,4 +1,3 @@ -import { Minus, Plus, Trash2 } from 'lucide-react' import Alert from '@mui/material/Alert' import Box from '@mui/material/Box' import Button from '@mui/material/Button' @@ -9,6 +8,7 @@ import Tooltip from '@mui/material/Tooltip' import Typography from '@mui/material/Typography' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useUnit } from 'effector-react' +import { Minus, Plus, Trash2 } from 'lucide-react' import { Link as RouterLink } from 'react-router-dom' import { fetchMyCart, removeCartItem, setCartQty } from '@/entities/cart/api/cart-api' import { formatPriceRub } from '@/shared/lib/format-price' diff --git a/client/src/pages/home/lib/use-product-filters.ts b/client/src/pages/home/lib/use-product-filters.ts index 388ac94..d5c5ee3 100644 --- a/client/src/pages/home/lib/use-product-filters.ts +++ b/client/src/pages/home/lib/use-product-filters.ts @@ -24,8 +24,8 @@ export function useProductFilters() { return () => window.clearTimeout(t) }, [qInput]) - const handleCategoryChange = (e: SelectChangeEvent) => { - setCategorySlug(e.target.value) + const handleCategoryChange = (slug: string) => { + setCategorySlug(slug) setPage(1) } diff --git a/client/src/pages/home/ui/ProductFilters.tsx b/client/src/pages/home/ui/ProductFilters.tsx index 925e90e..71ffe30 100644 --- a/client/src/pages/home/ui/ProductFilters.tsx +++ b/client/src/pages/home/ui/ProductFilters.tsx @@ -83,9 +83,26 @@ export function ProductFilters({ - + - + Сортировка labelId="sort-label" label="Сортировка" value={sort} onChange={handleSortChange}> - Сначала новые + + Сначала новые + Цена: по возрастанию Цена: по убыванию @@ -176,9 +199,16 @@ export function ProductFilters({ На странице - labelId="page-size-label" label="На странице" value={String(pageSize)} onChange={handlePageSizeChange}> + + labelId="page-size-label" + label="На странице" + value={String(pageSize)} + onChange={handlePageSizeChange} + > {[6, 12, 18, 24].map((n) => ( - {n} + + {n} + ))} @@ -186,7 +216,15 @@ export function ProductFilters({ - + Масштаб карточек Date: Thu, 14 May 2026 21:46:41 +0500 Subject: [PATCH 3/6] fix: icon spacing, scheme bg, drawer layout, filter margin, cart icon states --- client/src/app/layout/AppHeader.tsx | 14 +++++++++++++- .../cart/toggle-cart-icon/ui/ToggleCartIcon.tsx | 4 ++-- client/src/pages/home/ui/HomePage.tsx | 12 +++++++----- .../navigation-drawer/ui/NavigationDrawer.tsx | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/client/src/app/layout/AppHeader.tsx b/client/src/app/layout/AppHeader.tsx index 83c7825..6f606f8 100644 --- a/client/src/app/layout/AppHeader.tsx +++ b/client/src/app/layout/AppHeader.tsx @@ -156,7 +156,19 @@ export function AppHeader() { {!isMobile && ( - setScheme(s)} /> + + setScheme(s)} /> + )} diff --git a/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx b/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx index ba618e3..db5d786 100644 --- a/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx +++ b/client/src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx @@ -2,7 +2,7 @@ import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { useUnit } from 'effector-react' -import { ShoppingCart } from 'lucide-react' +import { CirclePlus, ShoppingCart } from 'lucide-react' import { useNavigate } from 'react-router-dom' import { addToCart, fetchMyCart, removeCartItem } from '@/entities/cart/api/cart-api' import { $user } from '@/shared/model/auth' @@ -63,7 +63,7 @@ export function ToggleCartIcon(props: { - {user ? inCart ? : : } + {user ? (inCart ? : ) : } diff --git a/client/src/pages/home/ui/HomePage.tsx b/client/src/pages/home/ui/HomePage.tsx index 42acf25..70498bd 100644 --- a/client/src/pages/home/ui/HomePage.tsx +++ b/client/src/pages/home/ui/HomePage.tsx @@ -79,11 +79,13 @@ export function HomePage() { Игрушки, сувениры и другие изделия ручной работы. - + + + {productsQuery.isLoading && ( diff --git a/client/src/widgets/navigation-drawer/ui/NavigationDrawer.tsx b/client/src/widgets/navigation-drawer/ui/NavigationDrawer.tsx index 42968b7..2d61e6a 100644 --- a/client/src/widgets/navigation-drawer/ui/NavigationDrawer.tsx +++ b/client/src/widgets/navigation-drawer/ui/NavigationDrawer.tsx @@ -92,8 +92,8 @@ export function NavigationDrawer({ - - + + From 001742a8568d14bd3ec581a15f9d52bf2c1481ef Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 14 May 2026 21:55:54 +0500 Subject: [PATCH 4/6] fix: icon gap, lighter scheme bg, filled cart icon for inCart --- client/src/app/layout/AppHeader.tsx | 4 ++-- .../src/features/cart/toggle-cart-icon/ui/ToggleCartIcon.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/app/layout/AppHeader.tsx b/client/src/app/layout/AppHeader.tsx index 6f606f8..a9e91a1 100644 --- a/client/src/app/layout/AppHeader.tsx +++ b/client/src/app/layout/AppHeader.tsx @@ -155,13 +155,13 @@ export function AppHeader() { )} {!isMobile && ( - + - {user ? (inCart ? : ) : } + {user ? (inCart ? : ) : } From 4b027c643a02c8d7bfea6b2b0ab1ae456daabbc3 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 14 May 2026 22:01:21 +0500 Subject: [PATCH 5/6] fix: scheme icon gap 1, lighter/larger bg --- client/src/app/layout/AppHeader.tsx | 9 ++++----- client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/client/src/app/layout/AppHeader.tsx b/client/src/app/layout/AppHeader.tsx index a9e91a1..96a27ef 100644 --- a/client/src/app/layout/AppHeader.tsx +++ b/client/src/app/layout/AppHeader.tsx @@ -155,16 +155,15 @@ export function AppHeader() { )} {!isMobile && ( - + setScheme(s)} /> diff --git a/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx b/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx index 537f994..62e1f0e 100644 --- a/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx +++ b/client/src/shared/ui/SchemeSwitcher/SchemeSwitcher.tsx @@ -22,7 +22,7 @@ export function SchemeSwitcher({ value, onChange, orientation = 'horizontal' }: sx={{ display: 'flex', flexDirection: orientation === 'vertical' ? 'column' : 'row', - gap: 0.5, + gap: 1, alignItems: 'center', }} > From 298c4f63d58815ca8aa72d3fd4ac5b6dfc8c4642 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 14 May 2026 22:02:56 +0500 Subject: [PATCH 6/6] test refactor --- client/src/app/layout/AppHeader.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/app/layout/AppHeader.tsx b/client/src/app/layout/AppHeader.tsx index 96a27ef..7a0b734 100644 --- a/client/src/app/layout/AppHeader.tsx +++ b/client/src/app/layout/AppHeader.tsx @@ -160,9 +160,9 @@ export function AppHeader() { sx={{ display: 'flex', alignItems: 'center', - bgcolor: 'rgba(255,255,255,0.15)', + bgcolor: 'rgba(255, 255, 255, 0.25)', borderRadius: 3, - px: 1, + px: 0.5, py: 0.5, }} >