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 (
-
-
+
-
+
);
-};
-
-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<
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index fa3ffe9..13a1f4e 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -18,6 +18,15 @@
},
"ContactPage": {
"title": "Get in Touch",
- "subtitle": "Here is where you can find me."
+ "subtitle": "Here is where you can find me.",
+ "logoNames": {
+ "github": "GitHub",
+ "linkedin": "LinkedIn",
+ "email": "Email",
+ "workEmail": "Work Email",
+ "telegram": "Telegram",
+ "steam": "Steam",
+ "discord": "Discord"
+ }
}
}
\ No newline at end of file
diff --git a/frontend/locales/ru.json b/frontend/locales/ru.json
index 756392c..58b85fa 100644
--- a/frontend/locales/ru.json
+++ b/frontend/locales/ru.json
@@ -18,6 +18,15 @@
},
"ContactPage": {
"title": "Свяжитесь со мной",
- "subtitle": "Вот лучшие способы для связи."
+ "subtitle": "Вот где вы можете меня найти.",
+ "logoNames": {
+ "github": "GitHub",
+ "linkedin": "LinkedIn",
+ "email": "Почта",
+ "workEmail": "Рабочая почта",
+ "telegram": "Телеграм",
+ "steam": "Steam",
+ "discord": "Discord"
+ }
}
}
\ No newline at end of file
diff --git a/frontend/next.config.ts b/frontend/next.config.ts
index d2e437d..c1a81e9 100644
--- a/frontend/next.config.ts
+++ b/frontend/next.config.ts
@@ -58,6 +58,10 @@ const nextConfig: NextConfig = {
protocol: 'https',
hostname: 'cdn.worldvectorlogo.com',
},
+ {
+ protocol: 'https',
+ hostname: 'cdn*.cdn-telegram.org',
+ },
],
},
diff --git a/frontend/public/logo/github.png b/frontend/public/logo/github.png
index df53e88..b44cf59 100644
Binary files a/frontend/public/logo/github.png and b/frontend/public/logo/github.png differ
diff --git a/frontend/public/logo/gmail.svg b/frontend/public/logo/gmail.svg
new file mode 100644
index 0000000..40b7175
--- /dev/null
+++ b/frontend/public/logo/gmail.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file