Files
REXNT/src/Components/Sections/Home/Home.jsx
2026-01-09 20:12:38 +03:00

470 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState, useRef } from "react";
import styled from 'styled-components';
import { Element } from "react-scroll";
import Departments from "../Departments/Departments";
export default function EngineeringHeroFlowbite() {
const defaultConfig = {
main_title: "شريكك الهندسي لتنفيذ وإدارة المشاريع باحتراف",
subtitle:
"حلول متكاملة تشمل التصميم، التنفيذ، التشغيل، والصيانة\nللمشاريع الصناعية والمدنية، وفق أحدث المعايير والتقنيات",
primary_color: "#e67e22",
background_color: "#000000",
text_color: "#ffffff",
secondary_surface: "#95a5a6",
secondary_action: "#34495e",
font_family: "Cairo",
font_size: 16,
};
const [config, setConfig] = useState(defaultConfig);
const [isMounted, setIsMounted] = useState(false);
const mainTitleRef = useRef(null);
const subtitleRef = useRef(null);
const departmentsRef = useRef(null);
useEffect(() => {
const id = "cairo-font-link";
if (!document.getElementById(id)) {
const link = document.createElement("link");
link.id = id;
link.rel = "stylesheet";
link.href = "https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap";
document.head.appendChild(link);
}
}, []);
useEffect(() => {
// slight delay to ensure mount then trigger animations
const t = setTimeout(() => setIsMounted(true), 60);
return () => clearTimeout(t);
}, []);
useEffect(() => {
const main = mainTitleRef.current;
const sub = subtitleRef.current;
const baseFontStack = "Arial, sans-serif";
const font = (config.font_family || defaultConfig.font_family) + ", " + baseFontStack;
const baseSize = config.font_size || defaultConfig.font_size;
if (main) {
const headingText = (config.main_title || defaultConfig.main_title)
.split("\n")
.map((s) => s.trim())
.filter(Boolean);
if (headingText.length === 1) {
main.textContent = headingText[0];
} else {
main.innerHTML = `<span style="display:block;line-height:1.02">${headingText[0]}</span><span style="display:block;font-weight:700;opacity:0.95;margin-top:6px">${headingText
.slice(1)
.join("<br/>")}</span>`;
}
main.style.fontFamily = font;
main.style.fontSize = `${baseSize * 3.8}px`;
main.style.color = config.text_color || defaultConfig.text_color;
main.style.fontWeight = 800;
main.style.textAlign = "right";
}
if (sub) {
sub.innerHTML = (config.subtitle || defaultConfig.subtitle)
.split("\n")
.map((s) => `<div>${s.trim()}</div>`)
.join("");
sub.style.fontFamily = font;
sub.style.fontSize = `${baseSize * 1.1}px`;
sub.style.color = config.text_color || defaultConfig.text_color;
sub.style.textAlign = "right";
sub.style.maxWidth = "800px";
}
const root = document.documentElement;
root.style.setProperty("--ehb-primary", config.primary_color || defaultConfig.primary_color);
root.style.setProperty("--ehb-background", config.background_color || defaultConfig.background_color);
root.style.setProperty("--ehb-surface", config.secondary_surface || defaultConfig.secondary_surface);
root.style.setProperty("--ehb-action", config.secondary_action || defaultConfig.secondary_action);
}, [config]);
useEffect(() => {
const element = {
defaultConfig,
onConfigChange: async (newCfg) => {
setConfig((c) => ({ ...c, ...newCfg }));
},
mapToCapabilities: (cfg) => ({
recolorables: [
{
get: () => cfg.background_color || defaultConfig.background_color,
set: (value) => {
cfg.background_color = value;
window?.elementSdk?.setConfig?.({ background_color: value });
setConfig({ ...cfg });
},
},
{
get: () => cfg.secondary_surface || defaultConfig.secondary_surface,
set: (value) => {
cfg.secondary_surface = value;
window?.elementSdk?.setConfig?.({ secondary_surface: value });
setConfig({ ...cfg });
},
},
{
get: () => cfg.text_color || defaultConfig.text_color,
set: (value) => {
cfg.text_color = value;
window?.elementSdk?.setConfig?.({ text_color: value });
setConfig({ ...cfg });
},
},
{
get: () => cfg.primary_color || defaultConfig.primary_color,
set: (value) => {
cfg.primary_color = value;
window?.elementSdk?.setConfig?.({ primary_color: value });
setConfig({ ...cfg });
},
},
{
get: () => cfg.secondary_action || defaultConfig.secondary_action,
set: (value) => {
cfg.secondary_action = value;
window?.elementSdk?.setConfig?.({ secondary_action: value });
setConfig({ ...cfg });
},
},
],
borderables: [],
fontEditable: {
get: () => cfg.font_family || defaultConfig.font_family,
set: (value) => {
cfg.font_family = value;
window?.elementSdk?.setConfig?.({ font_family: value });
setConfig({ ...cfg });
},
},
fontSizeable: {
get: () => cfg.font_size || defaultConfig.font_size,
set: (value) => {
cfg.font_size = value;
window?.elementSdk?.setConfig?.({ font_size: value });
setConfig({ ...cfg });
},
},
}),
mapToEditPanelValues: (cfg) =>
new Map([
["main_title", cfg.main_title || defaultConfig.main_title],
["subtitle", cfg.subtitle || defaultConfig.subtitle],
]),
};
if (window?.elementSdk?.init) {
try {
window.elementSdk.init(element);
} catch (e) {}
}
}, []);
const goToDepartments = (e) => {
e && e.preventDefault && e.preventDefault();
const el = document.getElementById("departments");
if (el) {
el.scrollIntoView({ behavior: "smooth", block: "start" });
} else {
window.scrollTo({ top: 0, behavior: "smooth" });
}
};
const OrangeActionButton = ({ onClick, children }) => {
return (
<StyledWrapper>
<button className="button" onClick={onClick} aria-label="تعرف على أقسامنا">
{children}
<svg className="icon" viewBox="0 0 24 24" fill="currentColor" aria-hidden>
<path fillRule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm4.28 10.28a.75.75 0 000-1.06l-3-3a.75.75 0 10-1.06 1.06l1.72 1.72H8.25a.75.75 0 000 1.5h5.69l-1.72 1.72a.75.75 0 101.06 1.06l3-3z" clipRule="evenodd" />
</svg>
</button>
</StyledWrapper>
);
};
return (
<div dir="rtl" className="h-screen w-full overflow-hidden" style={{ background: "var(--ehb-background, #000000)" }}>
<style>{`
:root { --ehb-primary: #e67e22; --ehb-background: #000000; --ehb-surface: #95a5a6; --ehb-action: #34495e }
.hero-section{position:relative;width:100%;height:100%;overflow:hidden}
.hero-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:linear-gradient(to bottom, rgba(0,0,0,0.65), rgba(0,0,0,0.35));z-index:3}
.hero-layout{position:relative;z-index:10;height:100%;display:flex;align-items:center;justify-content:space-between;padding:40px;gap:2rem;direction:ltr;flex-direction:row}
.hero-left{flex:1;display:flex;align-items:center;justify-content:flex-start;padding:20px;position:relative;flex-direction:column}
/* BIG IMAGE: slide-in slower, with delay */
.hero-left img{ max-width:100%; height:auto; display:block; transform: translateX(-20px) scale(0.995); opacity:1; will-change: transform, opacity; }
.hero-section.is-mounted .hero-left img{
transform: translateX(-120px) scale(0.96);
opacity: 0;
animation: slideInLeft 1200ms cubic-bezier(.2,.9,.2,1) 200ms both;
}
@keyframes slideInLeft {
0% { transform: translateX(-140px) scale(0.96); opacity: 0; filter: blur(2px); }
65% { transform: translateX(18px) scale(1.02); opacity: 1; filter: blur(0); }
100% { transform: translateX(0) scale(1); opacity: 1; }
}
/* partner bubbles - pop slower and float slower */
.partner-logos{display:flex;gap:18px;margin-top:20px;align-items:flex-end;justify-content:flex-start}
.partner-bubble{
width:110px;height:110px;border-radius:9999px;background:linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.02));display:flex;align-items:center;justify-content:center;overflow:hidden;box-shadow:0 12px 36px rgba(0,0,0,0.45);backdrop-filter: blur(4px);transition:transform 420ms cubic-bezier(.2,.9,.2,1),box-shadow 420ms;
transform-origin:center;
transform: translateY(10px) scale(0.9);
opacity: 0;
will-change: transform, opacity;
}
.hero-section.is-mounted .partner-bubble{
animation:
popIn 900ms cubic-bezier(.2,.9,.2,1) both,
floatBubble 5s ease-in-out 1100ms infinite;
}
.partner-bubble img{max-width:72%;max-height:72%;object-fit:contain;filter:grayscale(0.06) saturate(0.95)}
.partner-bubble:hover{transform:translateY(-10px) scale(1.08);box-shadow:0 34px 72px rgba(0,0,0,0.55)}
@keyframes popIn {
0% { transform: translateY(30px) scale(0.6); opacity: 0; filter: blur(2px); }
65% { transform: translateY(-10px) scale(1.06); opacity: 1; filter: blur(0); }
100% { transform: translateY(0) scale(1); opacity: 1; }
}
@keyframes floatBubble{0%{transform:translateY(0) scale(1)}25%{transform:translateY(-10px) scale(1.03)}50%{transform:translateY(-24px) scale(1.07)}75%{transform:translateY(-10px) scale(1.03)}100%{transform:translateY(0) scale(1)}}
/* partner strip */
.partner-strip-wrap{position:fixed;left:0;bottom:14px;z-index:30;pointer-events:auto;width:100%;display:flex;justify-content:flex-start;padding-left:40px;padding-right:40px}
.partner-strip{backface-visibility:hidden;transform-style:preserve-3d;perspective:1000px;display:flex;align-items:center;gap:18px;padding:12px 20px;border-radius:14px;box-shadow:0 18px 40px rgba(0,0,0,0.55);
background:linear-gradient(90deg, rgba(6,23,58,0.98) 0%, rgba(30,50,90,0.9) 35%, rgba(230,126,34,0.98) 100%);
transform: translateX(-120%) translateZ(0) rotateX(6deg) skewY(-2deg);
animation: slideInStrip 1600ms cubic-bezier(.2,.9,.2,1) 600ms forwards;
will-change:transform,opacity;
}
@keyframes slideInStrip{
0%{opacity:0;transform:translateX(-120%) translateZ(0) rotateX(8deg) skewY(-4deg) scale(0.98)}
70%{transform:translateX(12px) translateZ(6px) rotateX(2deg) skewY(-1deg) scale(1.01);opacity:1}
100%{transform:translateX(0) translateZ(10px) rotateX(0deg) skewY(0deg) scale(1);opacity:1}
}
.partner-item{display:flex;align-items:center;justify-content:center;padding:6px;border-radius:10px;min-width:84px;min-height:48px;background:rgba(255,255,255,0.04);backdrop-filter:blur(4px);box-shadow:0 6px 18px rgba(0,0,0,0.45);transition:transform 400ms cubic-bezier(.2,.9,.2,1),box-shadow 400ms}
.partner-item img{max-height:36px;max-width:140px;object-fit:contain;display:block;filter:grayscale(0.06) saturate(0.95)}
.partner-item:hover{transform:translateY(-6px) translateZ(18px) rotateX(6deg);box-shadow:0 30px 50px rgba(0,0,0,0.55)}
@media (max-width: 1024px){
.partner-strip{padding:10px 14px;border-radius:12px}
.partner-item{min-width:72px;min-height:44px}
.partner-item img{max-height:30px}
.partner-strip-wrap{padding-left:20px;padding-right:20px;bottom:10px}
}
@media (max-width: 640px){
.partner-strip{gap:10px;padding:8px;border-radius:10px}
.partner-item img{max-height:24px}
.partner-logos{gap:12px}
.partner-bubble{width:84px;height:84px}
}
/* HERO TEXT: slide from right (slower) */
.hero-content{flex:1;z-index:15;display:flex;flex-direction:column;align-items:flex-end;justify-content:center;padding:40px}
.hero-title{ opacity:1; transform: translateX(0) translateY(0) scale(1); will-change: transform, opacity; }
.hero-subtitle{ opacity:1; transform: translateX(0) translateY(0) scale(1); will-change: transform, opacity; }
.hero-section.is-mounted .hero-title{
opacity:0;
transform: translateX(120px) translateY(10px) scale(0.995);
animation: slideFromRight 1000ms cubic-bezier(.2,.9,.2,1) 260ms both;
}
.hero-section.is-mounted .hero-subtitle{
opacity:0;
transform: translateX(96px) translateY(6px) scale(0.995);
animation: slideFromRight 1000ms cubic-bezier(.2,.9,.2,1) 520ms both;
}
@keyframes slideFromRight {
0% { opacity:0; transform: translateX(120px) translateY(18px) scale(0.98); filter: blur(2px); }
65% { transform: translateX(-8px) translateY(-8px) scale(1.02); opacity:1; filter: blur(0); }
100% { opacity:1; transform: translateX(0) translateY(0) scale(1); }
}
.navy-glow{position:absolute;pointer-events:none;filter:blur(120px);z-index:4;opacity:1}
.navy-glow.bottom-left{left:0;bottom:0;width:80vh;height:80vh;background:radial-gradient(circle at 10% 90%, rgba(6,23,58,0.98), rgba(6,23,58,0.7), rgba(6,23,58,0.35) 40%, rgba(6,23,58,0) 70%)}
.navy-glow.top-right{right:0;top:0;width:70vh;height:70vh;background:radial-gradient(circle at 90% 10%, rgba(6,23,58,0.95), rgba(6,23,58,0.6), rgba(6,23,58,0.3) 40%, rgba(6,23,58,0) 70%)}
@media (max-width: 768px){
.hero-layout{flex-direction:column;align-items:center;text-align:center}
.hero-content{align-items:center}
.hero-title{font-size:calc(var(--base,16px) * 2.2) !important}
}
/* BUTTON: slower pop-in */
.button {
position: relative;
transition: all 0.3s ease-in-out;
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.2);
padding-block: 0.5rem;
padding-inline: 1.25rem;
background-color: var(--ehb-primary, #e67e22);
border-radius: 9999px;
display: flex;
align-items: center;
justify-content: center;
color: #ffff;
gap: 10px;
font-weight: bold;
border: 3px solid #ffffff4d;
outline: none;
overflow: hidden;
font-size: 15px;
cursor: pointer;
transform: translateY(0) scale(1);
opacity: 1;
}
.hero-section.is-mounted .button{
transform: scale(0.6);
opacity: 0;
animation: popIn 900ms cubic-bezier(.2,.9,.2,1) 760ms both;
will-change: transform, opacity;
}
.icon { width: 24px; height: 24px; transition: all 0.3s ease-in-out; }
.button:hover { transform: scale(1.05); border-color: #fff9; }
.button:hover .icon { transform: translate(4px); }
.button:hover::before { animation: shine 1.5s ease-out infinite; }
.button::before {
content: "";
position: absolute;
width: 100px;
height: 100%;
background-image: linear-gradient(
120deg,
rgba(255, 255, 255, 0) 30%,
rgba(255, 255, 255, 0.8),
rgba(255, 255, 255, 0) 70%
);
top: 0;
left: -100px;
opacity: 0.6;
}
@keyframes popIn {
0% { transform: translateY(30px) scale(0.6); opacity: 0; filter: blur(2px); }
65% { transform: translateY(-10px) scale(1.06); opacity: 1; filter: blur(0); }
100% { transform: translateY(0) scale(1); opacity: 1; }
}
@keyframes shine {
0% { left: -100px; }
60% { left: 100%; }
to { left: 100%; }
}
`}</style>
<div className={`hero-section ${isMounted ? "is-mounted" : ""}`}>
<div className="navy-glow bottom-left" />
<div className="navy-glow top-right" />
<div className="hero-overlay" />
<div className="hero-layout">
<div className="hero-left">
<img src="src/assets/REXNT.png" alt="REXNT" />
<div className="partner-logos" aria-hidden>
<div className="partner-bubble" style={{ animationDelay: "0ms" }} aria-label="شريك TPS">
<img src="src/assets/TPS-logo.png" alt="TPS" />
</div>
<div className="partner-bubble" style={{ animationDelay: "180ms" }} aria-label="شريك NSC">
<img src="src/assets/NSC.png" alt="NSC" />
</div>
<div className="partner-bubble" style={{ animationDelay: "360ms" }} aria-label="شريك LOGO">
<img src="src/assets/LOGO.png" alt="LOGO" />
</div>
</div>
</div>
<div className="hero-content">
<h1 ref={mainTitleRef} className="hero-title text-white text-right" style={{ fontWeight: 800, marginBottom: 16, textShadow: "2px 2px 10px rgba(0,0,0,0.6)" }} />
<p ref={subtitleRef} className="hero-subtitle text-white text-right" style={{ maxWidth: 800, textShadow: "1px 1px 6px rgba(0,0,0,0.45)", lineHeight: 1.6 }} />
<div style={{ marginTop: 18 }}>
<OrangeActionButton onClick={goToDepartments}>تعرف على أقسامنا</OrangeActionButton>
</div>
</div>
</div>
</div>
<div className="partner-strip-wrap" aria-hidden>
<div className="partner-strip" role="presentation" aria-hidden>
<div className="partner-item" aria-label="شريك TPS">
<img src="src/assets/TPS-logo.png" alt="TPS" />
</div>
<div className="partner-item" aria-label="شريك NSC">
<img src="src/assets/NSC.png" alt="NSC" />
</div>
<div className="partner-item" aria-label="شريك LOGO">
<img src="src/assets/LOGO.png" alt="LOGO" />
</div>
</div>
</div>
<Element name="departments" id="departments">
<Departments />
</Element>
</div>
);
}
const StyledWrapper = styled.div`
.button {
position: relative;
transition: all 0.3s ease-in-out;
box-shadow: 0px 10px 20px rgba(0, 0, 0, 0.2);
padding-block: 0.5rem;
padding-inline: 1.25rem;
background-color: var(--ehb-primary, #e67e22);
border-radius: 9999px;
display: flex;
align-items: center;
justify-content: center;
color: #ffff;
gap: 10px;
font-weight: bold;
border: 3px solid #ffffff4d;
outline: none;
overflow: hidden;
font-size: 15px;
cursor: pointer;
}
.icon { width: 24px; height: 24px; transition: all 0.3s ease-in-out; }
.button:hover { transform: scale(1.05); border-color: #fff9; }
.button:hover .icon { transform: translate(4px); }
.button:hover::before { animation: shine 1.5s ease-out infinite; }
.button::before {
content: "";
position: absolute;
width: 100px;
height: 100%;
background-image: linear-gradient(
120deg,
rgba(255, 255, 255, 0) 30%,
rgba(255, 255, 255, 0.8),
rgba(255, 255, 255, 0) 70%
);
top: 0;
left: -100px;
opacity: 0.6;
}
@keyframes shine {
0% { left: -100px; }
60% { left: 100%; }
to { left: 100%; }
}
`;