v4
This commit is contained in:
39
src/components/ErrorBoundary.jsx
Normal file
39
src/components/ErrorBoundary.jsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Component } from 'react'
|
||||
|
||||
export default class ErrorBoundary extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = { hasError: false, error: null }
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
return { hasError: true, error }
|
||||
}
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
console.error('ErrorBoundary caught:', error, info)
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return (
|
||||
<div style={{ padding: '80px 24px', textAlign: 'center' }}>
|
||||
<h1>Something went wrong</h1>
|
||||
<p style={{ color: '#666', marginBottom: 24 }}>
|
||||
{this.state.error?.message || 'An unexpected error occurred'}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => { this.setState({ hasError: false, error: null }) }}
|
||||
style={{
|
||||
padding: '12px 24px', background: '#FA2D39', color: '#fff',
|
||||
border: 'none', borderRadius: 6, cursor: 'pointer', fontSize: 16
|
||||
}}
|
||||
>
|
||||
Try again
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return this.props.children
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { useRef } from 'react'
|
||||
import footerHtml from '../data/layout-footer.html?raw'
|
||||
import { useNavFix } from '../hooks/useNavFix'
|
||||
|
||||
export default function Footer() {
|
||||
const ref = useRef(null)
|
||||
useNavFix(ref)
|
||||
return <div ref={ref} dangerouslySetInnerHTML={{ __html: footerHtml }} />
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { useRef } from 'react'
|
||||
import headerHtml from '../data/layout-header.html?raw'
|
||||
import { useNavFix } from '../hooks/useNavFix'
|
||||
|
||||
export default function Header() {
|
||||
const ref = useRef(null)
|
||||
useNavFix(ref)
|
||||
return <div ref={ref} dangerouslySetInnerHTML={{ __html: headerHtml }} />
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useEffect } from 'react'
|
||||
import { Outlet, useLocation } from 'react-router-dom'
|
||||
import Header from './Header'
|
||||
import Footer from './Footer'
|
||||
import PageShell from './PageShell'
|
||||
import headerHtml from '../data/layout-header.html?raw'
|
||||
import footerHtml from '../data/layout-footer.html?raw'
|
||||
import WhatsAppButton from './WhatsAppButton'
|
||||
import useThemeAssets from '../hooks/useThemeAssets'
|
||||
import useLayoutInit from '../hooks/useLayoutInit'
|
||||
import { PAGE_IDS } from '../config'
|
||||
|
||||
export default function Layout() {
|
||||
const { pathname } = useLocation()
|
||||
@@ -18,11 +20,11 @@ export default function Layout() {
|
||||
if (removed) return
|
||||
removed = true
|
||||
if (window.__removePreloader) {
|
||||
setTimeout(window.__removePreloader, 800)
|
||||
window.__removePreloader()
|
||||
}
|
||||
}
|
||||
const tryRemove = () => {
|
||||
if (window.__removePreloader && window.__cssReady && window.__layoutReady && document.readyState === 'complete') {
|
||||
if (window.__removePreloader && window.__cssReady && window.__layoutReady) {
|
||||
removePreloader()
|
||||
return true
|
||||
}
|
||||
@@ -33,7 +35,7 @@ export default function Layout() {
|
||||
document.addEventListener('css-ready', onReady)
|
||||
window.addEventListener('layout-ready', onReady)
|
||||
window.addEventListener('load', onReady)
|
||||
const fallback = setTimeout(removePreloader, 15000)
|
||||
const fallback = setTimeout(removePreloader, 5000)
|
||||
return () => {
|
||||
document.removeEventListener('css-ready', onReady)
|
||||
window.removeEventListener('layout-ready', onReady)
|
||||
@@ -45,11 +47,8 @@ export default function Layout() {
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0)
|
||||
|
||||
const pageIds = {
|
||||
'/': 23, '/about': 31, '/service': 32, '/project': 36, '/contact': 48,
|
||||
}
|
||||
const path = pathname.replace(/\/$/, '') || '/'
|
||||
const pageId = pageIds[path] || 23
|
||||
const pageId = PAGE_IDS[path] || 23
|
||||
const isHome = path === '/'
|
||||
|
||||
if (window.elementorFrontendConfig) {
|
||||
@@ -66,36 +65,12 @@ export default function Layout() {
|
||||
].filter(Boolean).join(' ')
|
||||
}, [pathname])
|
||||
|
||||
useEffect(() => {
|
||||
const style = document.createElement('style')
|
||||
style.id = 'rakar_opt-dynamic-css'
|
||||
style.textContent = `
|
||||
:root{--icon-font:"Font Awesome 6 Free";--fa-style-family:"Font Awesome 6 Free";}
|
||||
.header-logo .logo img{width:260px;}
|
||||
.th-menu-wrapper .mobile-logo img{width:180px;}
|
||||
.th-menu-wrapper .mobile-logo{background-color:#0a004c;}
|
||||
.breadcumb-wrapper{background-repeat:no-repeat;background-position:center center;background-image:url('/wp-content/uploads/2024/07/breadcumb-bg.jpg');background-size:cover;}
|
||||
.hero-inner{position:relative;}
|
||||
.hero-inner::before{content:'';position:absolute;inset:0;background:linear-gradient(90deg,rgba(0,0,0,0.7) 0%,rgba(0,0,0,0.3) 100%);z-index:1;pointer-events:none;}
|
||||
.hero-inner .container{position:relative;z-index:2;}
|
||||
.hero-style5 .sub-title2.sub{color:#fff !important;}
|
||||
.hero-style5 .hero-title,.hero-style5 .hero-text{color:#fff !important;}
|
||||
.slider-area .slider-arrow{display:inline-flex;align-items:center;justify-content:center;width:50px;height:50px;border-radius:50%;background:rgba(255,255,255,0.2);color:#fff;border:none;cursor:pointer;transition:0.3s;font-size:18px;}
|
||||
.slider-area .slider-arrow:hover{background:#FA2D39;}
|
||||
.slider-area .slider-controller{display:flex;align-items:center;justify-content:center;gap:10px;margin-top:40px;}
|
||||
.slider-area .slider-pagination{display:flex;align-items:center;gap:6px;}
|
||||
.slider-area .slider-pagination button{width:12px;height:12px;border-radius:50%;border:none;background:#999;opacity:0.4;cursor:pointer;padding:0;transition:0.3s;}
|
||||
.slider-area .slider-pagination button.active{opacity:1;background:#FA2D39;}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
return () => style.remove()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header />
|
||||
<PageShell html={headerHtml} />
|
||||
<Outlet />
|
||||
<Footer />
|
||||
<PageShell html={footerHtml} />
|
||||
<WhatsAppButton />
|
||||
</>
|
||||
)
|
||||
|
||||
10
src/components/Loading.jsx
Normal file
10
src/components/Loading.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
export default function Loading() {
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
height: '80vh', color: '#fff', fontSize: '18px',
|
||||
}}>
|
||||
Loading...
|
||||
</div>
|
||||
)
|
||||
}
|
||||
8
src/components/PageShell.jsx
Normal file
8
src/components/PageShell.jsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { useRef } from 'react'
|
||||
import { useNavFix } from '../hooks/useNavFix'
|
||||
|
||||
export default function PageShell({ html }) {
|
||||
const ref = useRef(null)
|
||||
useNavFix(ref)
|
||||
return <div ref={ref} dangerouslySetInnerHTML={{ __html: html }} />
|
||||
}
|
||||
@@ -1,17 +1,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
const PHONE = '971564148980'
|
||||
const WHATSAPP_URL = `https://wa.me/${PHONE}`
|
||||
import { WHATSAPP_PHONE } from '../config'
|
||||
const WHATSAPP_URL = `https://wa.me/${WHATSAPP_PHONE}`
|
||||
|
||||
export default function WhatsAppButton() {
|
||||
const [visible, setVisible] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setVisible(true)
|
||||
}, [])
|
||||
|
||||
if (!visible) return null
|
||||
|
||||
return (
|
||||
<>
|
||||
<a
|
||||
|
||||
Reference in New Issue
Block a user