Refactor App component structure by removing LanguageSwitcher and integrating Header. Update LanguageSwitchButton for improved localization handling. Clean up Feedback and LeadForm components by removing unused code. Enhance AvailableDemos with better translation support and adjust layout for mobile responsiveness.

This commit is contained in:
2026-04-16 13:15:17 +05:00
parent 3f8e11edf7
commit 99114120b9
7 changed files with 22 additions and 129 deletions
+1 -6
View File
@@ -1,18 +1,13 @@
import { Footer } from "@/components/Layout/Footer";
import { LanguageSwitcher } from "@/components/Layout/LanguageSwitcher";
import Header from "@/components/Layout/Header";
import { LocaleSync } from "@/components/Layout/LocaleSync";
import StreamDemo from "@/features/stream-demo/StreamDemo";
import Header from "@/components/Layout/Header";
export default function App() {
return (
<div className="flex min-h-dvh flex-col">
<<<<<<< HEAD
<LocaleSync />
<LanguageSwitcher />
=======
<Header />
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
{/* Без overflow-clip: иначе flex-1 + clip часто даёт пустой/обрезанный экран */}
<div className="min-h-0 flex-1 px-[10px] pb-8 pt-14 md:max-lg:pt-6 md:px-4 md:pt-4 lg:px-[1.389vw] lg:pt-8">
<StreamDemo />
-5
View File
@@ -6,11 +6,6 @@ import { useModalStore } from "@/stores/useModalStore";
import FeedbackModal from "@/components/modals/FeedbackFormModal";
import { LeadForm } from "@/features/lead-form/LeadForm";
<<<<<<< HEAD
=======
const DEFAULT_STREAM_DEMO_PRODUCTS = ["Удаленная демонстрация"] as Product[];
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
export function Feedback() {
useAddReferer();
const { t } = useTranslation();
+5 -9
View File
@@ -92,17 +92,13 @@ export function Footer() {
alt={t("footer.skolkovoAlt")}
className=" lg:hidden md:size-[6.25vw] size-[13.333vw] max-md:absolute max-md:right-0 max-md:bottom-6"
/>
<img
src="/img/components/header/Sk.svg"
alt={t("footer.skolkovoAlt")}
className="hidden lg:block lg:size-[3.333vw] lg:mt-[2.292vw] lg:self-start"
/>
</div>
<<<<<<< HEAD
) : null}
=======
<img
src="/img/components/header/Sk.svg"
alt="Сколково"
className=" lg:size-[3.333vw] lg:mt-[2.292vw] md:size-[6.25vw] size-[13.333vw] max-md:absolute max-md:right-0 max-md:bottom-6"
/>
</div>
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
<div className="lg:gap-x-[0.833vw] gap-y-2 flex max-lg:flex-col">
<a
+12 -5
View File
@@ -1,27 +1,34 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import type { AppLocale } from "@/i18n";
import { setLangInUrl } from "@/lib/urlLang";
export default function LanguageSwitchButton({
className,
}: {
className?: string;
}) {
const [locale, setLocale] = useState<"ru" | "en">("ru");
const { i18n, t } = useTranslation();
const current = (i18n.language.startsWith("ru") ? "ru" : "en") as AppLocale;
function handleClick() {
return setLocale(locale === "ru" ? "en" : "ru");
const next: AppLocale = current === "ru" ? "en" : "ru";
void i18n.changeLanguage(next);
setLangInUrl(next);
}
return (
<button
type="button"
className={`btnm bg-[#37393B99] active:bg-[#37393B80]
lg:px-[1.667vw] lg:py-[1.181vw] lg:rounded-[0.833vw]
md:px-[2.604vw] md:py-[1.302vw] md:rounded-[1.563vw]
px-[5.556vw] py-[2.778vw] rounded-[3.333vw]
${className}
${className ?? ""}
`}
onClick={handleClick}
aria-label={t("languageSwitcher.ariaLabel")}
>
{locale === "ru" ? "RU" : "EN"}
{current === "ru" ? "RU" : "EN"}
</button>
);
}
@@ -1,39 +0,0 @@
import { useTranslation } from "react-i18next";
import type { AppLocale } from "@/i18n";
import { setLangInUrl } from "@/lib/urlLang";
const LOCALES: AppLocale[] = ["ru", "en"];
export function LanguageSwitcher() {
const { i18n, t } = useTranslation();
const current = (i18n.language.startsWith("ru") ? "ru" : "en") as AppLocale;
function select(lang: AppLocale) {
if (lang === current) return;
void i18n.changeLanguage(lang);
setLangInUrl(lang);
}
return (
<div
className="fixed right-[10px] top-4 z-50 flex gap-1 md:right-4 md:top-6 lg:right-[1.389vw] lg:top-8"
role="navigation"
aria-label={t("languageSwitcher.ariaLabel")}
>
{LOCALES.map((lang) => (
<button
key={lang}
type="button"
onClick={() => select(lang)}
className={`btns rounded-xl px-3 py-2 font-medium transition-colors lg:rounded-[0.833vw] lg:px-[0.833vw] lg:py-[0.486vw] ${
current === lang
? "bg-white text-black"
: "bg-[#37393B99] text-white hover:bg-[#37393B]"
}`}
>
{t(`languageSwitcher.${lang}`)}
</button>
))}
</div>
);
}
-5
View File
@@ -17,11 +17,6 @@ import type { LeadFormValues } from "./types";
export type { LeadFormValues } from "./types";
<<<<<<< HEAD
=======
const GENERIC_SUBMIT_ERROR = "Не удалось отправить заявку. Попробуйте позже.";
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
export function LeadForm({
defaultProducts,
idPrefix = "",
+4 -60
View File
@@ -1,31 +1,21 @@
<<<<<<< HEAD
import { useState } from "react";
import { useRef, useState, type MouseEvent as ReactMouseEvent } from "react";
import { useTranslation } from "react-i18next";
import BR from "@/components/Layout/LineBreak";
import {
REMOTE_DEMO_TAG,
useGetProjectsQuery,
} from "@/queries/getProjects";
=======
import { useRef, useState, type MouseEvent as ReactMouseEvent } from "react";
import { REMOTE_DEMO_TAG, useGetProjectsQuery } from "@/queries/getProjects";
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
import { StreamingProject } from "./StreamingProject";
import { useSwipeable } from "react-swipeable";
import { useMediaQueries } from "@/hooks/useMediaQueries";
export default function AvailableDemos() {
<<<<<<< HEAD
const { t } = useTranslation();
const { isMd, isLg } = useMediaQueries();
=======
const { isMd } = useMediaQueries();
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
const { data: streamingProjects } = useGetProjectsQuery(REMOTE_DEMO_TAG);
const [current, setCurrent] = useState(0);
const projects = streamingProjects ?? [];
// Свайп на мобилке
const slideCount = Math.min(projects.length + 1, 4);
const handlers = useSwipeable({
onSwipedLeft: () =>
@@ -40,7 +30,6 @@ export default function AvailableDemos() {
touchEventOptions: { passive: false },
});
// Скролл на десктопе
const sliderRef = useRef<HTMLDivElement>(null);
function onSliderMouseDown(e: ReactMouseEvent<HTMLDivElement>) {
@@ -69,16 +58,11 @@ export default function AvailableDemos() {
<div>
<div className="flex lg:flex-row flex-col lg:mb-[4.444vw] md:mb-[8.333vw] md:gap-[3.125vw]">
<h2 className="line2 max-md:line1 w-full max-md:mb-[5.556vw]">
<<<<<<< HEAD
{t("demos.titleLine1")} <BR lg sm /> {t("demos.titleLine2")}
=======
Доступные <br className="lg:block md:hidden block" /> демонстрации
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
</h2>
{/* Тиндер на мобилке */}
<div
className="lg:hidden md:hidden grid-cols-4 gap-3 px-5 [scrollbar-width:none] relative max-md:aspect-[340/344] [transform-style:preserve-3d] items-stretch mb-[5.556vw]"
className="grid lg:hidden md:hidden grid-cols-4 gap-3 px-5 [scrollbar-width:none] relative max-md:aspect-[340/344] [transform-style:preserve-3d] items-stretch mb-[5.556vw]"
{...handlers}
>
{projects.slice(0, 3).map((project, index, { length }) => (
@@ -104,56 +88,17 @@ export default function AvailableDemos() {
: ""
}`}
>
<<<<<<< HEAD
{projects.slice(0, 3).map((project, index, { length }) => (
<StreamingProject
key={project.id}
{...project}
index={index}
current={current}
count={length + 1}
href="/"
/>
))}
<div
className={`bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF00] [background:linear-gradient(to_right,#FFFFFF14,#FFFFFF00)] p-0.5 lg:rounded-[1.111vw] rounded-2xl flex flex-1 justify-center !duration-500 items-center md:min-w-[300px] group max-md:absolute self-stretch max-md:h-full transition-[scale,transform] will-change-[transform,scale] select-none max-md:w-[calc(100%-40px)] max-md:bg-[#0F101199] max-md:[backdrop-filter:blur(40px)] ${
slideCount - 1 === current
? "max-md:[transform:translateZ(40px)]"
: "max-md:[scale:85%]"
} ${
slideCount - 1 === (current + 1) % slideCount
? "max-md:translate-x-[calc(7.5%+20px)]"
: slideCount - 1 ===
(current - 1 + slideCount) % slideCount
? "max-md:translate-x-[calc(-7.5%-20px)]"
: ""
}`}
>
<div className="md:bg-[#0F1011] h-full w-full lg:rounded-[1.111vw] rounded-2xl flex items-center p-6">
<div className="flex flex-col items-center space-y-6">
<p className="heading2 font-medium text-center">
{t("demos.ctaTitle")}
</p>
<a
href="/form"
className="btnm font-medium group-hover:scale-105 duration-500 lg:px-[1.667vw] lg:py-[1.181vw] px-6 py-[17px] transition-transform lg:rounded-[0.833vw] rounded-xl bg-gradient"
>
{t("demos.ctaButton")}
</a>
</div>
=======
<div className="md:bg-[#0F1011] h-full w-full lg:rounded-[1.111vw] rounded-2xl flex items-center p-6">
<div className="flex flex-col items-center space-y-6">
<p className="heading2 font-medium text-center">
Расскажем и покажем как это работает на&nbsp;созвоне
{t("demos.ctaTitle")}
</p>
<a
href="#contacts"
className="btnm font-medium group-hover:scale-105 duration-500 lg:px-[1.667vw] lg:py-[1.181vw] px-6 py-[17px] transition-transform lg:rounded-[0.833vw] rounded-xl bg-gradient"
>
Оставить заявку
{t("demos.ctaButton")}
</a>
>>>>>>> 258568050cbcb3e46cc31416fc9a0ba7a21ac066
</div>
</div>
</div>
@@ -164,7 +109,6 @@ export default function AvailableDemos() {
</p>
</div>
{/* Слайдер на десктопе */}
<div
ref={sliderRef}
onMouseDown={isMd ? onSliderMouseDown : undefined}