Compare commits

...

2 Commits

5 changed files with 83 additions and 26 deletions
@@ -74,7 +74,7 @@ export default function DisplacementCard({
rotate: rotate, rotate: rotate,
}} }}
className={ className={
`w-[15.486vw] aspect-[223/240] rounded-[16px] bg-[radial-gradient(circle,rgba(0,0,0,1)_-70%,rgba(34,36,37,1)_100%);] flex flex-col items-center justify-between p-[1.111vw] lg:absolute max-lg:relative max-lg:w-full max-lg:h-full overflow-hidden md:max-lg:p-[2.083vw] max-md:p-[4.444vw] max-md:aspect-[165/240] ` + `w-[15.486vw] aspect-[223/240] rounded-[16px] bg-[radial-gradient(circle,rgba(0,0,0,1)_-70%,rgba(34,36,37,1)_100%);] flex flex-col items-center justify-between p-[1.111vw] lg:absolute max-lg:relative max-lg:w-full max-lg:h-full overflow-hidden md:max-lg:p-[2.083vw] max-md:p-[4.444vw] max-md:aspect-[165/240] max-md:h-auto ` +
className className
} }
onClick={onClick} onClick={onClick}
@@ -25,6 +25,7 @@ function Iphone({ active }: { active: boolean }) {
muted muted
autoPlay autoPlay
loop loop
playsInline
className={`mx-auto w-[98%] h-[99%] translate-y-[0.5%] z-[7] lg:rounded-[3vw] rounded-2xl md:max-lg:rounded-[4vw] max-md:rounded-[8vw]`} className={`mx-auto w-[98%] h-[99%] translate-y-[0.5%] z-[7] lg:rounded-[3vw] rounded-2xl md:max-lg:rounded-[4vw] max-md:rounded-[8vw]`}
/> />
) : ( ) : (
+60 -9
View File
@@ -31,6 +31,7 @@ export default function WebDemo() {
const [showPopup, setShowPopup] = useState(false); const [showPopup, setShowPopup] = useState(false);
const [iframeSrc, setIframeSrc] = useState<string>(""); const [iframeSrc, setIframeSrc] = useState<string>("");
const isMobile = useMediaQuery("(max-width: 768px)"); const isMobile = useMediaQuery("(max-width: 768px)");
const [isPseudoFullscreen, setIsPseudoFullscreen] = useState(false);
useEffect(() => { useEffect(() => {
if (isMobile) { if (isMobile) {
@@ -53,17 +54,47 @@ export default function WebDemo() {
!isMobile && setShowPopup(false); !isMobile && setShowPopup(false);
}, [isMobile]); }, [isMobile]);
const enablePseudoFullScreen = () => {
setIsPseudoFullscreen(true);
onFullScreenEnter();
};
const disablePseudoFullScreen = () => {
setIsPseudoFullscreen(false);
onFullScreenExit();
};
const enableDemoFullscreenMode = useCallback( const enableDemoFullscreenMode = useCallback(
(enableFullscreen: boolean) => { async (enableFullscreen: boolean) => {
const cur = demoRef.current; const cur = demoRef.current;
if (!cur) return; if (!cur) return;
if (enableFullscreen) { if (enableFullscreen) {
cur.requestFullscreen(); // Проверяем поддержку Fullscreen API
onFullScreenEnter(); if (cur.requestFullscreen) {
try {
await cur.requestFullscreen();
setIsPseudoFullscreen(false);
onFullScreenEnter();
} catch (error) {
console.log(
"Fullscreen API not supported, using pseudo-fullscreen instead"
);
enablePseudoFullScreen();
}
} else {
enablePseudoFullScreen();
}
} else if (document.fullscreenElement) { } else if (document.fullscreenElement) {
document.exitFullscreen(); try {
onFullScreenExit(); await document.exitFullscreen();
disablePseudoFullScreen();
} catch (error) {
console.log("Error exiting fullscreen:", error);
disablePseudoFullScreen();
}
} else {
disablePseudoFullScreen();
} }
}, },
[onFullScreenEnter, onFullScreenExit] [onFullScreenEnter, onFullScreenExit]
@@ -114,7 +145,7 @@ export default function WebDemo() {
index={1} index={1}
className="lg:top-[8.333vw] lg:left-0 md:max-lg:!translate-y-[3.125vw]" className="lg:top-[8.333vw] lg:left-0 md:max-lg:!translate-y-[3.125vw]"
> >
<div className="flex lg:w-[11.361vw] lg:h-[11.361vw] max-lg:my-auto md:w-[23.26vw] md:h-[23.26vw] w-[33.26vw] h-[33.26vw] overflow-hidden rounded-full aspect-square"> <div className="flex lg:w-[11.361vw] lg:h-[11.361vw] max-lg:my-auto md:w-[23.26vw] md:h-[23.26vw] w-[33.26vw] h-[33.26vw] overflow-hidden z-[1] rounded-full aspect-square">
<video <video
src="/videos/pages/web/demo/cars.mp4" src="/videos/pages/web/demo/cars.mp4"
muted muted
@@ -208,7 +239,7 @@ export default function WebDemo() {
index={5} index={5}
className="lg:bottom-0 lg:right-[16.389vw] " className="lg:bottom-0 lg:right-[16.389vw] "
> >
<div className="flex lg:w-[11.361vw] lg:h-[11.361vw] max-lg:my-auto md:w-[23.26vw] md:h-[23.26vw] w-[33.26vw] h-[33.26vw] overflow-hidden rounded-full aspect-square"> <div className="flex lg:w-[11.361vw] lg:h-[11.361vw] max-lg:my-auto md:w-[23.26vw] md:h-[23.26vw] w-[33.26vw] h-[33.26vw] overflow-hidden z-[1] rounded-full aspect-square">
<video <video
src="/videos/pages/web/demo/appartaments.mp4" src="/videos/pages/web/demo/appartaments.mp4"
loop loop
@@ -235,11 +266,30 @@ export default function WebDemo() {
animate={{ animate={{
width: demoActive ? "100vw" : isMobile ? "100%" : "80vw", width: demoActive ? "100vw" : isMobile ? "100%" : "80vw",
}} }}
style={
isPseudoFullscreen
? {
position: "fixed",
top: 0,
left: 0,
width: "100vw",
height: "100vh",
zIndex: 9999,
margin: 0,
borderRadius: 0,
backgroundColor: "#000",
aspectRatio: "unset",
}
: undefined
}
className="relative max-w-full aspect-[1400/784] mx-auto rounded-[1.111vw] overflow-clip className="relative max-w-full aspect-[1400/784] mx-auto rounded-[1.111vw] overflow-clip
md:max-lg:h-screen md:max-lg:rounded-[2.083vw] md:max-lg:h-screen md:max-lg:rounded-[2.083vw]
max-md:w-[94.444vw] max-md:aspect-[340/600] max-md:rounded-[4.444vw]" max-md:w-[94.444vw] max-md:aspect-[340/600] max-md:rounded-[4.444vw]"
> >
<div className="relative w-full h-full overflow-clip rounded-[1.111vw] md:max-lg:rounded-[2.083vw] max-md:rounded-[4.444vw]"> <div
style={isPseudoFullscreen ? { borderRadius: 0 } : undefined}
className="relative w-full h-full overflow-clip rounded-[1.111vw] md:max-lg:rounded-[2.083vw] max-md:rounded-[4.444vw]"
>
{!demoActive ? ( {!demoActive ? (
<div className="absolute top-0 left-0 z-[8] w-full h-full bg-[#00000066] flex flex-col items-center justify-center max-md:p-[4.444vw]"> <div className="absolute top-0 left-0 z-[8] w-full h-full bg-[#00000066] flex flex-col items-center justify-center max-md:p-[4.444vw]">
<span className="line2 font-medium text-center whitespace-pre-line"> <span className="line2 font-medium text-center whitespace-pre-line">
@@ -275,7 +325,8 @@ export default function WebDemo() {
<iframe <iframe
ref={iframeRef} ref={iframeRef}
src={iframeSrc} src={iframeSrc}
className=" relative w-full h-full rounded-[1.111vw] text-center" className=" relative w-full h-full rounded-[1.111vw] text-center mix-blend-screen"
style={isPseudoFullscreen ? { borderRadius: 0 } : undefined}
onLoad={() => console.log("Iframe loaded successfully")} onLoad={() => console.log("Iframe loaded successfully")}
onError={(e) => console.error("Iframe error:", e)} onError={(e) => console.error("Iframe error:", e)}
title="Virtual Tour" title="Virtual Tour"
@@ -28,8 +28,8 @@ export default function WebDevelopmentTimeline() {
return ( return (
<div <div
className="self-center w-max mx-auto btn-m text-black bg-[#B5F54E] rounded-[1.111vw] px-[1.389vw] py-[0.764vw] text-[0.972vw] z-10 className="self-center w-max mx-auto btn-m text-black bg-[#B5F54E] rounded-[1.111vw] px-[1.389vw] py-[0.764vw] text-[0.972vw] z-10
md:max-lg:text-[1.563vw] md:max-lg:px-[1.563vw] md:max-lg:py-[0.911vw] md:max-lg:rounded-[2.083vw] md:max-lg:text-[1.563vw] md:max-lg:px-[1.563vw] md:max-lg:py-[0.911vw] md:max-lg:rounded-[2.083vw]
max-md:text-[3.333vw] max-md:px-[3.333vw] max-md:py-[1.944vw] max-md:rounded-[4.444vw]" max-md:text-[3.333vw] max-md:px-[3.333vw] max-md:py-[1.944vw] max-md:rounded-[4.444vw]"
> >
{title} {title}
</div> </div>
@@ -90,7 +90,7 @@ export default function WebDevelopmentTimeline() {
<div <div
className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] border-l px-[0.833vw] last:border-x gap-[4.167vw] relative className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] border-l px-[0.833vw] last:border-x gap-[4.167vw] relative
md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw] md:max-lg:min-h-[66.469vw] md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw] md:max-lg:min-h-[66.469vw]
max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:overflow-clip max-md:min-h-[125vw] max-lg:snap-center" max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center max-md:overflow-hidden"
> >
<AccordeonGroup <AccordeonGroup
isNewClient={isNewClient} isNewClient={isNewClient}
@@ -122,7 +122,7 @@ export default function WebDevelopmentTimeline() {
<div <div
className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] border-l px-[0.833vw] last:border-x gap-[4.167vw] relative className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] border-l px-[0.833vw] last:border-x gap-[4.167vw] relative
md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw] md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw]
max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center" max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center max-md:overflow-hidden"
> >
<AccordeonGroup <AccordeonGroup
isNewClient={isNewClient} isNewClient={isNewClient}
@@ -150,7 +150,7 @@ export default function WebDevelopmentTimeline() {
<div <div
className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] border-l px-[0.833vw] last:border-x gap-[4.167vw] relative className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] border-l px-[0.833vw] last:border-x gap-[4.167vw] relative
md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw] md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw]
max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center" max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center max-md:overflow-hidden"
> >
<AccordeonGroup <AccordeonGroup
isNewClient={isNewClient} isNewClient={isNewClient}
@@ -178,7 +178,7 @@ export default function WebDevelopmentTimeline() {
<div <div
className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] px-[0.833vw] border-x gap-[4.167vw] relative className="w-full min-h-[35vw] flex flex-col justify-between border-[#37393B] px-[0.833vw] border-x gap-[4.167vw] relative
md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw] md:max-lg:flex-shrink-0 md:max-lg:w-[39.063vw] md:max-lg:border md:max-lg:p-[2.083vw] md:max-lg:rounded-[2.083vw] md:max-lg:flex-col-reverse md:max-lg:justify-end md:max-lg:gap-[2.083vw]
max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center" max-md:flex-shrink-0 max-md:w-[83.333vw] max-md:border max-md:p-[4.444vw] max-md:rounded-[4.444vw] max-md:flex-col-reverse max-md:justify-end max-md:gap-[4.444vw] max-md:min-h-[125vw] max-lg:snap-center max-md:overflow-hidden"
> >
<AccordeonGroup <AccordeonGroup
isNewClient={isNewClient} isNewClient={isNewClient}
+15 -10
View File
@@ -11,7 +11,7 @@ export default function WebExperience() {
}); });
return ( return (
<div> <div className="max-md:overflow-x-hidden">
<h2 <h2
className="font-medium text-[4.444vw] leading-[95%] tracking-[-0.02em] text-start mb-[4.444vw] bg-gradient-to-r from-[#7A55FF] via-[#C932E8] to-[#FF79D2] bg-clip-text className="font-medium text-[4.444vw] leading-[95%] tracking-[-0.02em] text-start mb-[4.444vw] bg-gradient-to-r from-[#7A55FF] via-[#C932E8] to-[#FF79D2] bg-clip-text
md:max-lg:text-[5.208vw] md:max-lg:mb-[8.333vw] md:max-lg:text-[5.208vw] md:max-lg:mb-[8.333vw]
@@ -26,7 +26,7 @@ export default function WebExperience() {
ref={gridRef} ref={gridRef}
className="grid grid-cols-[39.861vw_23.819vw_31.736vw] grid-rows-[35vw_24.167vw] gap-[0.833vw] className="grid grid-cols-[39.861vw_23.819vw_31.736vw] grid-rows-[35vw_24.167vw] gap-[0.833vw]
md:max-lg:grid-cols-[46.875vw_46.875vw] md:max-lg:grid-rows-[46.875vw_46.875vw_46.875vw] md:max-lg:gap-[1.823vw] md:max-lg:grid-cols-[46.875vw_46.875vw] md:max-lg:grid-rows-[46.875vw_46.875vw_46.875vw] md:max-lg:gap-[1.823vw]
max-md:grid-cols-1 max-md:grid-rows-[77.778vw_100vw_100vw_77.778vw_72.222vw_100vw] max-md:gap-[3.889vw]" max-md:grid-cols-1 max-md:grid-rows-[77.778vw_100vw_100vw_77.778vw_72.222vw_100vw] max-md:gap-[3.889vw] max-md:overflow-hidden"
> >
<motion.div <motion.div
animate={{ animate={{
@@ -48,13 +48,14 @@ export default function WebExperience() {
/> />
<div className="absolute inset-0 bg-gradient-to-b from-[#00000099]" /> <div className="absolute inset-0 bg-gradient-to-b from-[#00000099]" />
</motion.div> </motion.div>
<motion.div <motion.div
animate={{ animate={{
opacity: +inView, opacity: +inView,
y: inView ? 0 : 100, y: inView ? 0 : 100,
}} }}
transition={{ delay: 0.2, bounce: "none" }} transition={{ delay: 0.2, bounce: "none" }}
className="rounded-[1.111vw] overflow-hidden p-[2.222vw] flex flex-col justify-between backdrop-blur-[20px] bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF05] className="rounded-[1.111vw] overflow-hidden p-[2.222vw] flex flex-col justify-between backdrop-blur-[20px] bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF05] relative
md:max-lg:p-[4.167vw] md:max-lg:text-[3.125vw] md:max-lg:p-[4.167vw] md:max-lg:text-[3.125vw]
max-md:rounded-[4.444vw] max-md:p-[8.889vw]" max-md:rounded-[4.444vw] max-md:p-[8.889vw]"
> >
@@ -62,9 +63,10 @@ export default function WebExperience() {
<img <img
src="/img/pages/web/experience/crm.png" src="/img/pages/web/experience/crm.png"
alt="" alt=""
className="flex-1 object-contain absolute lg:bottom-[2.222vw] md:max-lg:bottom-[3.125vw] bottom-[8.889vw] left-1/2 -translate-x-1/2" className="flex-1 object-contain absolute lg:bottom-[2.222vw] md:max-lg:bottom-[3.125vw] bottom-[5.889vw] left-1/2 -translate-x-1/2"
/> />
</motion.div> </motion.div>
<motion.div <motion.div
animate={{ animate={{
opacity: +inView, opacity: +inView,
@@ -72,7 +74,7 @@ export default function WebExperience() {
}} }}
transition={{ delay: 0.4, bounce: "none" }} transition={{ delay: 0.4, bounce: "none" }}
className="rounded-[1.111vw] overflow-hidden p-[2.222vw] flex flex-col justify-between backdrop-blur-[20px] bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF05] className="rounded-[1.111vw] overflow-hidden p-[2.222vw] flex flex-col justify-between backdrop-blur-[20px] bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF05]
md:max-lg:p-[4.167vw] md:max-lg:text-[3.125vw] md:max-lg:p-[4.167vw] md:max-lg:text-[3.125vw]
max-md:rounded-[4.444vw] max-md:p-[8.889vw]" max-md:rounded-[4.444vw] max-md:p-[8.889vw]"
> >
<span className="headline1"> <span className="headline1">
@@ -81,28 +83,30 @@ export default function WebExperience() {
<img <img
src="/img/pages/web/experience/import.png" src="/img/pages/web/experience/import.png"
alt="" alt=""
className="translate-y-[2.222vw] max-lg:scale-[120%] md:max-lg:translate-x-[2.222vw] md:max-lg:translate-y-[4.222vw] max-md:translate-x-[8.222vw] max-md:translate-y-[12.222vw]" className="translate-y-[2.222vw] max-lg:scale-[1.2] md:max-lg:translate-x-[2.222vw] md:max-lg:translate-y-[4.222vw] max-md:translate-x-[0vw] max-md:translate-y-[12.222vw]"
/> />
</motion.div> </motion.div>
<motion.div <motion.div
animate={{ animate={{
opacity: +inView, opacity: +inView,
y: inView ? 0 : 100, y: inView ? 0 : 100,
}} }}
transition={{ delay: 0.4, bounce: "none" }} transition={{ delay: 0.4, bounce: "none" }}
className="rounded-[1.111vw] overflow-hidden p-[2.222vw] flex flex-col justify-between backdrop-blur-[20px] bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF05] className="rounded-[1.111vw] overflow-hidden p-[2.222vw] flex flex-col justify-between backdrop-blur-[20px] bg-gradient-to-r from-[#FFFFFF14] to-[#FFFFFF05] relative
md:max-lg:p-[4.167vw] md:max-lg:text-[3.125vw] md:max-lg:p-[4.167vw] md:max-lg:text-[3.125vw]
max-md:rounded-[4.444vw] max-md:p-[8.889vw]" max-md:rounded-[4.444vw] max-md:p-[8.889vw]"
> >
<span className="headline1">Ипотечный калькулятор</span> <span className="headline1 relative z-10">Ипотечный калькулятор</span>
<img <img
src="/img/pages/web/experience/calculator.png" src="/img/pages/web/experience/calculator.png"
alt="" alt=""
className="absolute w-[37.639vw] right-0 bottom-[2.222vw] className="absolute w-[37.639vw] right-0 bottom-[2.222vw]
md:max-lg:left-[15.167vw] md:max-lg:right-0 md:max-lg:bottom-[8.771vw] md:max-lg:w-auto md:max-lg:scale-[150%] md:max-lg:left-[15.167vw] md:max-lg:bottom-[8.771vw] md:max-lg:w-auto md:max-lg:scale-[1.5]
max-md:left-[32vw] max-md:right-0 max-md:bottom-[5vw] max-md:w-auto max-md:scale-[150%]" max-md:left-[32vw] max-md:bottom-[5vw] max-md:w-auto max-md:scale-[1.5]"
/> />
</motion.div> </motion.div>
<motion.div <motion.div
animate={{ animate={{
opacity: +inView, opacity: +inView,
@@ -121,6 +125,7 @@ export default function WebExperience() {
/> />
<div className="absolute inset-0 bg-gradient-to-b from-[#00000099]" /> <div className="absolute inset-0 bg-gradient-to-b from-[#00000099]" />
</motion.div> </motion.div>
<motion.div <motion.div
animate={{ animate={{
opacity: +inView, opacity: +inView,