diff --git a/frontend/app/[locale]/about/page.module.css b/frontend/app/[locale]/about/page.module.css index b0a070d..0a50b1c 100644 --- a/frontend/app/[locale]/about/page.module.css +++ b/frontend/app/[locale]/about/page.module.css @@ -115,4 +115,4 @@ .sidebar { max-width: 100%; } -} \ No newline at end of file +} diff --git a/frontend/app/[locale]/about/page.tsx b/frontend/app/[locale]/about/page.tsx index 34db02e..19c7c1b 100644 --- a/frontend/app/[locale]/about/page.tsx +++ b/frontend/app/[locale]/about/page.tsx @@ -62,28 +62,12 @@ export default function ResumePage() { - -
- 📫 Connect with me:
-
- - Telegram link - - - LinkedIn link - - - email link - -
-
); } \ No newline at end of file diff --git a/frontend/app/[locale]/contact/page.tsx b/frontend/app/[locale]/contact/page.tsx index cbe76d3..f9837da 100644 --- a/frontend/app/[locale]/contact/page.tsx +++ b/frontend/app/[locale]/contact/page.tsx @@ -6,36 +6,42 @@ import styles from './page.module.css'; const contacts = [ { - name: 'Telegram', + name: 'telegram', handle: '@diametrfq', url: 'https://t.me/diametrfq', iconUrl: '/logo/telegram.svg', }, { - name: 'LinkedIn', + name: 'linkedin', handle: 'Dmitry Khokhlov', url: 'https://www.linkedin.com/in/diametrfq', iconUrl: '/logo/linkedin.svg', }, { - name: 'GitHub', + name: 'github', handle: 'DiametrFQ', url: 'https://github.com/DiametrFQ', - iconUrl: 'https://cdn.worldvectorlogo.com/logos/github-icon-1.svg', + iconUrl: '/logo/github.png', themeBehavior: 'invertOnDark', }, { - name: 'Email', + name: 'email', handle: 'hohlov.03@inbox.ru', url: 'mailto:hohlov.03@inbox.ru', iconUrl: '/logo/email.png', }, { - name: 'Steam', + name: 'steam', handle: 'diametrfq', url: 'https://steamcommunity.com/id/diametrfq/', iconUrl: '/logo/steam.png', }, + { + name: 'workEmail', + handle: 'diameterfq@gmail.com', + url: 'mailto:diameterfq@gmail.com', + iconUrl: '/logo/gmail.svg', + }, ]; export default function Contact() { @@ -64,7 +70,7 @@ export default function Contact() { />
-

{contact.name}

+

{t('logoNames.'+contact.name)}

{contact.handle}

diff --git a/frontend/app/[locale]/telegram/components/PostList.tsx b/frontend/app/[locale]/telegram/components/PostList.tsx index 7c4f01f..0473e52 100644 --- a/frontend/app/[locale]/telegram/components/PostList.tsx +++ b/frontend/app/[locale]/telegram/components/PostList.tsx @@ -37,7 +37,8 @@ const PostList: React.FC<{ posts: Post[] }> = ({ posts }) => {
{posts.map((post, index) => ( - ))}\n
+ ))} + ); }; diff --git a/frontend/app/_components/Header/Header.tsx b/frontend/app/_components/Header/Header.tsx index 0357ac6..46cf9e3 100644 --- a/frontend/app/_components/Header/Header.tsx +++ b/frontend/app/_components/Header/Header.tsx @@ -1,14 +1,23 @@ -import Link from 'next/link.js'; +import Link from 'next/link'; import styles from './header.module.css'; import { ThemeSwitcher } from './_comonents/ThemeSwitcher/ThemeSwitcher'; import { LanguageSwitcher } from './_comonents/LanguageSwitcher/LanguageSwitcher'; +import { BurgerSidebarTrigger } from '../Sidebar/components/ToggleSidebarButton'; const Header = () => { return (
- + {/* Блок №1: для мобильного триггера */} +
+ +
+ + {/* Блок №2: для логотипа */} + DiametrFQ + + {/* Блок №3: для опций */}
diff --git a/frontend/app/_components/Header/header.module.css b/frontend/app/_components/Header/header.module.css index b6e632c..7953c1e 100644 --- a/frontend/app/_components/Header/header.module.css +++ b/frontend/app/_components/Header/header.module.css @@ -1,42 +1,64 @@ +/* --- Мобильная версия (по умолчанию) --- */ .header { - background-color: var(--background); + display: grid; + /* Создаем 3 колонки: левая и правая занимают равное место, центральная - по контенту */ + grid-template-columns: 1fr auto 1fr; + align-items: center; padding: 10px 20px; - display: flex; + background-color: var(--background); color: var(--foreground); - display: flex; - justify-content: space-between; } -.logo { - font-size: 2rem; - font-weight: bold; - letter-spacing: 2px; - height: 100%; - display: flex; - align-items: center; +/* Контейнер для бургера слева */ +.mobileTriggerContainer { + justify-self: start; /* Прижимаем к левому краю своей колонки */ } -@media (max-width: 420px) { - .logo { - font-size: 18px; - } +/* Ссылка с логотипом по центру */ +.logoLink { + justify-self: center; /* Центрируем в своей колонке */ + text-decoration: none; + color: inherit; } -.menuButton { - border-radius: 16px; - border: none; - font-size: 2rem; - color: white; - background-color: none; - cursor: pointer; - background-color: var(--background); - transition: margin 700ms; +.logo { + font-size: 1.5rem; + font-weight: bold; + letter-spacing: 2px; } +/* Контейнер с опциями справа */ .options { + justify-self: end; /* Прижимаем к правому краю своей колонки */ display: flex; - flex-direction: row; gap: 5px; - justify-content: center; - align-items: center; +} + + +/* --- Десктопная версия (для экранов шире 768px) --- */ +@media (min-width: 769px) { + .header { + /* Меняем структуру сетки! Теперь у нас 2 колонки */ + grid-template-columns: auto 1fr; + gap: 1.5rem; /* Добавим отступ между лого и опциями */ + } + + /* Скрываем мобильный бургер, он не нужен на десктопе */ + .mobileTriggerContainer { + display: none; + } + + /* Теперь логотип становится первым элементом в новой сетке */ + .logoLink { + justify-self: start; /* Прижимаем его к левому краю */ + } + + .logo { + font-size: 2rem; /* Возвращаем полный размер логотипа */ + } + + /* Опции остаются прижатыми вправо */ + .options { + justify-self: end; + } } \ No newline at end of file diff --git a/frontend/app/_components/NowPlaying/NowPlaying.module.css b/frontend/app/_components/NowPlaying/NowPlaying.module.css index 4c6a695..c02cef7 100644 --- a/frontend/app/_components/NowPlaying/NowPlaying.module.css +++ b/frontend/app/_components/NowPlaying/NowPlaying.module.css @@ -1,4 +1,3 @@ -/* Внешний контейнер. Просто держит все в углу. */ .widgetContainer { position: fixed; bottom: 2rem; @@ -8,7 +7,6 @@ align-items: center; } -/* Этот блок будет анимироваться */ .widgetAnimator { display: flex; border-radius: 16px; @@ -20,37 +18,29 @@ } .widgetAnimator.hidden { - /* Мы не просто скрываем его, а сдвигаем, чтобы кнопка осталась на месте */ - transform: translateX(calc(100% - 48px)); /* 48px - ширина кнопки */ + transform: translateX(calc(100% - 48px)); } -/* Контент внутри. Добавляем отступ справа, чтобы освободить место для кнопки */ .widgetContent { display: flex; align-items: center; padding: 8px; - /* Важно: добавляем отступ справа, равный ширине кнопки, чтобы текст не заезжал под нее */ - padding-right: 56px; /* 48px (ширина кнопки) + 8px (зазор) */ + padding-right: 56px; min-height: 72px; } -/* --- КЛЮЧЕВЫЕ ИЗМЕНЕНИЯ ЗДЕСЬ --- */ .toggleButton { - /* Возвращаем позиционирование, чтобы z-index работал */ position: relative; - /* Поднимаем кнопку над контентом */ z-index: 2; - /* Сдвигаем кнопку влево на ее собственную ширину, чтобы она наложилась на .widgetAnimator */ margin-left: -48px; - /* Остальные стили для внешнего вида */ display: flex; align-items: center; justify-content: center; width: 48px; height: 72px; - background-color: rgba(0,0,0,0.2); /* Делаем чуть темнее для контраста */ + background-color: rgba(0,0,0,0.2); border: none; color: white; cursor: pointer; @@ -75,14 +65,11 @@ transform: rotate(180deg); } - -/* --- Остальные стили без изменений --- */ .notPlaying { display: flex; align-items: center; gap: 12px; font-weight: 500; - /* Убедимся, что и этот блок имеет отступ */ padding-right: 56px; } @@ -133,4 +120,25 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} + +@media (max-width: 768px) { + .widgetContainer { + bottom: 1rem; + right: 1rem; + } + + .widgetContent { + min-height: 64px; + padding-right: 48px; + } + + .albumArt { + width: 48px; + height: 48px; + } + + .toggleButton { + height: 64px; + } } \ No newline at end of file diff --git a/frontend/app/_components/Sidebar/Sidebar.tsx b/frontend/app/_components/Sidebar/Sidebar.tsx index e820a99..f995e33 100644 --- a/frontend/app/_components/Sidebar/Sidebar.tsx +++ b/frontend/app/_components/Sidebar/Sidebar.tsx @@ -1,11 +1,22 @@ -'use client' +'use client'; -import { Sidebar, SidebarContent, SidebarGroup, SidebarGroupContent, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from '@/components/ui/sidebar7'; +import { + Sidebar, + SidebarContent, + SidebarHeader, + SidebarGroup, + SidebarGroupContent, + SidebarMenu, + SidebarMenuButton, + SidebarMenuItem, + useSidebar, // 1. ИМПОРТИРУЕМ ХУК useSidebar +} from '@/components/ui/sidebar7'; import { DropdownMenu, DropdownMenuTrigger } from '@radix-ui/react-dropdown-menu'; import { useLocale, useTranslations } from 'next-intl'; import Link from 'next/link'; import { usePathname } from 'next/navigation'; -import ToggleSidebarButton from './components/ToggleSidebarButton'; +import { BurgerSidebarTrigger } from './components/ToggleSidebarButton'; +import styles from './styles/sidebar.module.css'; import './styles/global.css'; const items = [ @@ -14,37 +25,60 @@ const items = [ { title: 'portfolio', url: '/portfolio', iconName: 'groups' }, { title: 'contact', url: '/contact', iconName: 'groups' }, { title: 'telegram', url: '/telegram', iconName: 'groups' }, -] +]; -const onlyEng = items.filter(item => item.title !== 'telegram').map(item => item.title); +const onlyEng = items.filter((item) => item.title !== 'telegram').map((item) => item.title); export default function AppSidebar() { const pathname = usePathname(); const locale = useLocale(); - const t = useTranslations('SidebarNavigation'); + // 2. ПОЛУЧАЕМ КОНТЕКСТ САЙДБАРА + const { isMobile, setOpenMobile } = useSidebar(); + + // 3. СОЗДАЕМ ОБРАБОТЧИК КЛИКА + const handleLinkClick = () => { + // Закрываем сайдбар только если мы на мобильном устройстве + if (isMobile) { + setOpenMobile(false); + } + }; + return ( - - - - - + +
+ + + +
+ {items.map((item) => ( - (locale === 'en' && onlyEng.includes(item.title) || locale === 'ru') && - + (locale === 'en' && onlyEng.includes(item.title)) || + (locale === 'ru') + ) && ( + - {item.iconName} + + {item.iconName} + {t(`${item.title}.title`)} @@ -58,4 +92,4 @@ export default function AppSidebar() {
); -}; +} \ No newline at end of file diff --git a/frontend/app/_components/Sidebar/components/ToggleSidebarButton.module.css b/frontend/app/_components/Sidebar/components/ToggleSidebarButton.module.css new file mode 100644 index 0000000..815edf8 --- /dev/null +++ b/frontend/app/_components/Sidebar/components/ToggleSidebarButton.module.css @@ -0,0 +1,13 @@ +.toggleButton { + display: flex; + align-items: center; + justify-content: center; + padding: 6px; + border-radius: 8px; + cursor: pointer; + transition: background-color 0.2s ease-in-out; +} + +.toggleButton:hover { + background-color: var(--accent); +} \ No newline at end of file diff --git a/frontend/app/_components/Sidebar/components/ToggleSidebarButton.tsx b/frontend/app/_components/Sidebar/components/ToggleSidebarButton.tsx index dd7cc01..bf821b4 100644 --- a/frontend/app/_components/Sidebar/components/ToggleSidebarButton.tsx +++ b/frontend/app/_components/Sidebar/components/ToggleSidebarButton.tsx @@ -1,21 +1,32 @@ -import SVGImageElement from 'next/image'; +'use client'; + +import Image from 'next/image'; import { useSidebar } from '@/components/ui/sidebar7'; -import style from './styles/toggleSidebarButton.module.css'; +import { Button } from '@/components/ui/button'; +import { cn } from '@/lib/utils'; + +type Props = { + className?: string; +}; -const ToggleSidebarButton = () => { - const { toggleSidebar } = useSidebar() +export function BurgerSidebarTrigger({ className }: Props) { + const { toggleSidebar } = useSidebar(); return ( -
- + Menu -
+ ); -}; - -export default ToggleSidebarButton; \ No newline at end of file +} \ No newline at end of file diff --git a/frontend/app/_components/Sidebar/components/styles/toggleSidebarButton.module.css b/frontend/app/_components/Sidebar/components/styles/toggleSidebarButton.module.css deleted file mode 100644 index 4288d4e..0000000 --- a/frontend/app/_components/Sidebar/components/styles/toggleSidebarButton.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.toggleButton { - /* pointer-events: auto; */ - font-family: "Material Symbols Outlined"; - font-size: 48px; - background-color: white; - transition: background-color 0.2s ease-in-out; - border-radius: 16px; -} - -.toggleButton:hover { - background-color: rgb(208, 208, 208) -} - diff --git a/frontend/app/_components/Sidebar/styles/sidebar.module.css b/frontend/app/_components/Sidebar/styles/sidebar.module.css index 8f7bfa8..60ae7ed 100644 --- a/frontend/app/_components/Sidebar/styles/sidebar.module.css +++ b/frontend/app/_components/Sidebar/styles/sidebar.module.css @@ -1,14 +1,18 @@ -/* .sidebar { - position: relative; - left: -250px; - width: 250px; - background: #222; - color: white; - padding: 20px; - transition: left 0.3s ease-in-out; +/* По умолчанию (mobile-first) скрываем десктопный хедер в сайдбаре */ +.desktopHeaderContainer { + display: none; } -.sidebar.open { - left: 0; -} */ +/* Показываем его только на экранах шире 768px */ +@media (min-width: 769px) { + .desktopHeaderContainer { + display: block; /* Показываем контейнер */ + } + /* Стилизуем сам SidebarHeader для правильного расположения */ + .desktopHeaderContainer > header { + display: flex; + justify-content: flex-end; /* Двигаем кнопку вправо */ + padding: 0.5rem; + } +} \ No newline at end of file diff --git a/frontend/app/_styles/globals.css b/frontend/app/_styles/globals.css index e22e497..ba699cd 100644 --- a/frontend/app/_styles/globals.css +++ b/frontend/app/_styles/globals.css @@ -79,6 +79,17 @@ body { } @layer base { + :root { + --background: 0 0% 100%; + --foreground: 240 10% 3.9%; + --invert-filter: invert(0); + } + .dark { + --background: 240 10% 3.9%; + --foreground: 0 0% 98%; + --invert-filter: invert(1); + } + * { @apply border-border; } diff --git a/frontend/app/_styles/page.module.css b/frontend/app/_styles/page.module.css index 5d67265..b93fb79 100644 --- a/frontend/app/_styles/page.module.css +++ b/frontend/app/_styles/page.module.css @@ -110,7 +110,31 @@ a.secondary { flex-shrink: 0; } -/* Enable hover only on non-touch devices */ +@media (max-width: 768px) { + .page { + padding: 40px 20px; + min-height: auto; + } + + .main { + align-items: center; + } + + .ctas { + flex-direction: column; + } + + .ctas a { + font-size: 14px; + height: 40px; + padding: 0 16px; + } + + a.secondary { + min-width: auto; + } +} + @media (hover: hover) and (pointer: fine) { a.primary:hover { background: var(--button-primary-hover); diff --git a/frontend/app/i18n.ts b/frontend/app/i18n.ts index 566c656..382bbe5 100644 --- a/frontend/app/i18n.ts +++ b/frontend/app/i18n.ts @@ -1,12 +1,9 @@ import {notFound} from 'next/navigation'; import {getRequestConfig} from 'next-intl/server'; - -import {locales as appLocales, type locale as LocaleType} from '@/types/i18n'; +import {locales as appLocales, type locale as tyeLocale} from '@/types/i18n'; export default getRequestConfig(async ({locale}) => { - if (!appLocales.includes(locale as LocaleType)) { - notFound(); - } + if (!appLocales.includes(locale as tyeLocale)) notFound(); return { locale, diff --git a/frontend/components/ui/sidebar7.tsx b/frontend/components/ui/sidebar7.tsx index dd52c20..3b309f3 100644 --- a/frontend/components/ui/sidebar7.tsx +++ b/frontend/components/ui/sidebar7.tsx @@ -10,7 +10,13 @@ import { cn } from "@/lib/utils" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Separator } from "@/components/ui/separator" -import { Sheet, SheetContent } from "@/components/ui/sheet" +import { + Sheet, + SheetContent, + SheetHeader, + SheetTitle, + SheetDescription +} from "@/components/ui/sheet" import { Skeleton } from "@/components/ui/skeleton" import { Tooltip, @@ -19,6 +25,7 @@ import { TooltipTrigger, } from "@/components/ui/tooltip" + const SIDEBAR_COOKIE_NAME = "sidebar:state" const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7 const SIDEBAR_WIDTH = "16rem" @@ -169,11 +176,11 @@ const Sidebar = React.forwardRef< }, ref ) => { - const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); + const sidebarContext = useSidebar(); - if (isMobile) { + if (sidebarContext.isMobile) { return ( - + + + Основная навигация + + Выберите страницу для перехода. + + +
{children}
@@ -195,11 +209,12 @@ const Sidebar = React.forwardRef<