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:
+1
-6
@@ -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 />
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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 = "",
|
||||
|
||||
@@ -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">
|
||||
Расскажем и покажем как это работает на созвоне
|
||||
{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}
|
||||
|
||||
Reference in New Issue
Block a user