asset path and iframe setting
This commit is contained in:
Vendored
+8
-7
@@ -1,4 +1,4 @@
|
||||
# Deployed under /citpl_website/ — Apache must proxy API to the Node server.
|
||||
# Deployed under /citpl_website/ - Apache must proxy API to the Node server.
|
||||
# Requires: mod_rewrite, mod_proxy, mod_proxy_http, mod_headers
|
||||
# Start Node on the host: npm run server (or pm2 start server/index.js)
|
||||
|
||||
@@ -11,17 +11,18 @@
|
||||
RewriteRule ^uploads/(.*)$ http://127.0.0.1:3001/uploads/$1 [P,L]
|
||||
</IfModule>
|
||||
|
||||
# Allow admin login preview iframe (same origin)
|
||||
# Allow embedding from this site and https://demo.cavinkare.in/
|
||||
# X-Frame-Options cannot allow a third origin - unset it and use CSP only.
|
||||
<IfModule mod_headers.c>
|
||||
Header always edit Content-Security-Policy "frame-ancestors 'none'" "frame-ancestors 'self'"
|
||||
Header always edit X-Frame-Options "DENY" "SAMEORIGIN"
|
||||
Header always unset X-Frame-Options
|
||||
Header unset X-Frame-Options
|
||||
Header always edit Content-Security-Policy "frame-ancestors 'none'" "frame-ancestors 'self' https://demo.cavinkare.in/"
|
||||
|
||||
<FilesMatch "^(preview\.html|index\.html)$">
|
||||
<FilesMatch "^(preview\.html|index\.html|admin\.html)$">
|
||||
Header unset X-Frame-Options
|
||||
Header always unset X-Frame-Options
|
||||
Header unset Content-Security-Policy
|
||||
Header always unset Content-Security-Policy
|
||||
Header always set X-Frame-Options "SAMEORIGIN"
|
||||
Header always set Content-Security-Policy "frame-ancestors 'self'"
|
||||
Header always set Content-Security-Policy "frame-ancestors 'self' https://demo.cavinkare.in/"
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
|
||||
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
import{c as e,l as t,m as n,u as r}from"./x-DnG5sti3.js";import{r as i,t as a}from"./App-CuujNhcz.js";var o=n(r(),1),s=t(),c=e();(0,s.createRoot)(document.getElementById(`root`)).render((0,c.jsx)(o.StrictMode,{children:(0,c.jsx)(i,{children:(0,c.jsx)(a,{})})}));
|
||||
import{c as e,l as t,m as n,u as r}from"./x-DnG5sti3.js";import{r as i,t as a}from"./App-g0Gkzm_v.js";var o=n(r(),1),s=t(),c=e();(0,s.createRoot)(document.getElementById(`root`)).render((0,c.jsx)(o.StrictMode,{children:(0,c.jsx)(i,{children:(0,c.jsx)(a,{})})}));
|
||||
@@ -1 +1 @@
|
||||
import{c as e,l as t,m as n,u as r}from"./x-DnG5sti3.js";import{n as i,r as a,t as o}from"./App-CuujNhcz.js";var s=n(r(),1),c=t(),l=e();function u(){return(0,s.useEffect)(()=>(document.body.classList.add(`admin-preview-embed`),()=>document.body.classList.remove(`admin-preview-embed`)),[]),(0,l.jsx)(o,{previewMode:!0})}(0,c.createRoot)(document.getElementById(`root`)).render((0,l.jsx)(s.StrictMode,{children:(0,l.jsx)(i.Provider,{value:!0,children:(0,l.jsx)(a,{previewMode:!0,children:(0,l.jsx)(u,{})})})}));
|
||||
import{c as e,l as t,m as n,u as r}from"./x-DnG5sti3.js";import{n as i,r as a,t as o}from"./App-g0Gkzm_v.js";var s=n(r(),1),c=t(),l=e();function u(){return(0,s.useEffect)(()=>(document.body.classList.add(`admin-preview-embed`),()=>document.body.classList.remove(`admin-preview-embed`)),[]),(0,l.jsx)(o,{previewMode:!0})}(0,c.createRoot)(document.getElementById(`root`)).render((0,l.jsx)(s.StrictMode,{children:(0,l.jsx)(i.Provider,{value:!0,children:(0,l.jsx)(a,{previewMode:!0,children:(0,l.jsx)(u,{})})})}));
|
||||
Vendored
+2
-2
@@ -5,9 +5,9 @@
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Cavin Infotech | One Trusted Technology Partner</title>
|
||||
<script type="module" crossorigin src="/citpl_website/assets/main-oTwpSzcd.js"></script>
|
||||
<script type="module" crossorigin src="/citpl_website/assets/main-BxILBfZ3.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/citpl_website/assets/x-DnG5sti3.js">
|
||||
<link rel="modulepreload" crossorigin href="/citpl_website/assets/App-CuujNhcz.js">
|
||||
<link rel="modulepreload" crossorigin href="/citpl_website/assets/App-g0Gkzm_v.js">
|
||||
<link rel="stylesheet" crossorigin href="/citpl_website/assets/App-DpUt8oMg.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Vendored
+2
-2
@@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>CITPL Preview</title>
|
||||
<script type="module" crossorigin src="/citpl_website/assets/preview-C0prGlYe.js"></script>
|
||||
<script type="module" crossorigin src="/citpl_website/assets/preview-wEp9RUMD.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/citpl_website/assets/x-DnG5sti3.js">
|
||||
<link rel="modulepreload" crossorigin href="/citpl_website/assets/App-CuujNhcz.js">
|
||||
<link rel="modulepreload" crossorigin href="/citpl_website/assets/App-g0Gkzm_v.js">
|
||||
<link rel="stylesheet" crossorigin href="/citpl_website/assets/App-DpUt8oMg.css">
|
||||
<link rel="stylesheet" crossorigin href="/citpl_website/assets/preview-DknkzKsF.css">
|
||||
</head>
|
||||
|
||||
+8
-7
@@ -1,4 +1,4 @@
|
||||
# Deployed under /citpl_website/ — Apache must proxy API to the Node server.
|
||||
# Deployed under /citpl_website/ - Apache must proxy API to the Node server.
|
||||
# Requires: mod_rewrite, mod_proxy, mod_proxy_http, mod_headers
|
||||
# Start Node on the host: npm run server (or pm2 start server/index.js)
|
||||
|
||||
@@ -11,17 +11,18 @@
|
||||
RewriteRule ^uploads/(.*)$ http://127.0.0.1:3001/uploads/$1 [P,L]
|
||||
</IfModule>
|
||||
|
||||
# Allow admin login preview iframe (same origin)
|
||||
# Allow embedding from this site and https://demo.cavinkare.in/
|
||||
# X-Frame-Options cannot allow a third origin - unset it and use CSP only.
|
||||
<IfModule mod_headers.c>
|
||||
Header always edit Content-Security-Policy "frame-ancestors 'none'" "frame-ancestors 'self'"
|
||||
Header always edit X-Frame-Options "DENY" "SAMEORIGIN"
|
||||
Header always unset X-Frame-Options
|
||||
Header unset X-Frame-Options
|
||||
Header always edit Content-Security-Policy "frame-ancestors 'none'" "frame-ancestors 'self' https://demo.cavinkare.in/"
|
||||
|
||||
<FilesMatch "^(preview\.html|index\.html)$">
|
||||
<FilesMatch "^(preview\.html|index\.html|admin\.html)$">
|
||||
Header unset X-Frame-Options
|
||||
Header always unset X-Frame-Options
|
||||
Header unset Content-Security-Policy
|
||||
Header always unset Content-Security-Policy
|
||||
Header always set X-Frame-Options "SAMEORIGIN"
|
||||
Header always set Content-Security-Policy "frame-ancestors 'self'"
|
||||
Header always set Content-Security-Policy "frame-ancestors 'self' https://demo.cavinkare.in/"
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
|
||||
+26
-26
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
|
||||
const BASE = import.meta.env.BASE_URL;
|
||||
import { assetUrl } from './lib/assetUrl';
|
||||
import { motion, useScroll, useTransform, useMotionValueEvent, useReducedMotion } from 'framer-motion';
|
||||
import { useContent } from './context/ContentContext';
|
||||
import { usePreviewMode } from './context/PreviewContext';
|
||||
@@ -566,7 +566,7 @@ export default function App({ previewMode = false }) {
|
||||
borderBottom: activeSection === 'products' ? '1px solid rgba(15, 23, 42, 0.08)' : '1px solid rgba(255, 255, 255, 0.05)'
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<img src={`${BASE}assets/cavin_logo.svg`} alt="Cavin Infotech Logo" style={{ height: isMobile ? '38px' : '50px', display: 'block' }} />
|
||||
<img src={assetUrl('/assets/cavin_logo.svg')} alt="Cavin Infotech Logo" style={{ height: isMobile ? '38px' : '50px', display: 'block' }} />
|
||||
</div>
|
||||
|
||||
{!isMobile && (
|
||||
@@ -608,7 +608,7 @@ export default function App({ previewMode = false }) {
|
||||
);
|
||||
})}
|
||||
<div className="btn-sparkle-wrapper">
|
||||
<img src={`${BASE}assets/button_hover_effect.png`} className="btn-sparkles" alt="" />
|
||||
<img src={assetUrl('/assets/button_hover_effect.png')} className="btn-sparkles" alt="" />
|
||||
<button className="btn-talk" onClick={() => setIsStrategyOpen(true)}>
|
||||
Book a Strategy Call
|
||||
</button>
|
||||
@@ -728,7 +728,7 @@ export default function App({ previewMode = false }) {
|
||||
pointerEvents: 'none'
|
||||
}}
|
||||
>
|
||||
<source src={`${hero.video}?v=2`} type="video/mp4" />
|
||||
<source src={`${assetUrl(hero.video)}?v=2`} type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
|
||||
@@ -937,7 +937,7 @@ export default function App({ previewMode = false }) {
|
||||
{/* Globe Visual */}
|
||||
<div style={{ position: 'relative', width: '280px', height: '280px', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<img
|
||||
src={`${BASE}assets/GlobeVector.svg`}
|
||||
src={assetUrl('/assets/GlobeVector.svg')}
|
||||
alt="Globe Map"
|
||||
style={{ width: '100%', height: '100%', objectFit: 'contain', opacity: 0.3 }}
|
||||
/>
|
||||
@@ -962,7 +962,7 @@ export default function App({ previewMode = false }) {
|
||||
padding: '0.2rem',
|
||||
}}>
|
||||
<img
|
||||
src={logo.image}
|
||||
src={assetUrl(logo.image)}
|
||||
alt={logo.name}
|
||||
style={{ maxHeight: '100%', maxWidth: '100%', objectFit: 'contain' }}
|
||||
/>
|
||||
@@ -982,7 +982,7 @@ export default function App({ previewMode = false }) {
|
||||
|
||||
{/* Globe in background - Increased Size & Brightness */}
|
||||
<img
|
||||
src={`${BASE}assets/GlobeVector.svg`}
|
||||
src={assetUrl('/assets/GlobeVector.svg')}
|
||||
alt="Globe Map"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
@@ -1045,18 +1045,18 @@ export default function App({ previewMode = false }) {
|
||||
|
||||
{/* orbital logos with smooth continuous motion in horizontally elongated oval paths - No Skewing */}
|
||||
{/* Outer Orbit - Increased size further to radiusX=520, radiusY=320 */}
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 33.svg`} alt="MRF Logo" radiusX={520} radiusY={320} startAngle={0} duration={60} clockwise={true} size={170} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 31.svg`} alt="ACA Global Logo" radiusX={520} radiusY={320} startAngle={78} duration={60} clockwise={true} size={175} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 30.svg`} alt="Polyhose Logo" radiusX={520} radiusY={320} startAngle={144} duration={60} clockwise={true} size={170} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 32.svg`} alt="Dawn Pictures Logo" radiusX={520} radiusY={320} startAngle={216} duration={60} clockwise={true} size={180} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 35.svg`} alt="Hero Logo" radiusX={520} radiusY={320} startAngle={282} duration={60} clockwise={true} size={170} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 33.svg')} alt="MRF Logo" radiusX={520} radiusY={320} startAngle={0} duration={60} clockwise={true} size={170} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 31.svg')} alt="ACA Global Logo" radiusX={520} radiusY={320} startAngle={78} duration={60} clockwise={true} size={175} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 30.svg')} alt="Polyhose Logo" radiusX={520} radiusY={320} startAngle={144} duration={60} clockwise={true} size={170} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 32.svg')} alt="Dawn Pictures Logo" radiusX={520} radiusY={320} startAngle={216} duration={60} clockwise={true} size={180} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 35.svg')} alt="Hero Logo" radiusX={520} radiusY={320} startAngle={282} duration={60} clockwise={true} size={170} />
|
||||
|
||||
{/* Inner Orbit - Adjusted size to radiusX=360, radiusY=225 */}
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 28.svg`} alt="Valeo Logo" radiusX={360} radiusY={225} startAngle={36} duration={40} clockwise={false} size={170} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 36.svg`} alt="BorgWarner Logo" radiusX={360} radiusY={225} startAngle={108} duration={40} clockwise={false} size={170} />
|
||||
<OrbitalLogo src={`${BASE}assets/kone.png`} alt="KONE Logo" radiusX={360} radiusY={225} startAngle={180} duration={40} clockwise={false} size={160} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 34.svg`} alt="Chola MS Logo" radiusX={360} radiusY={225} startAngle={252} duration={40} clockwise={false} size={170} />
|
||||
<OrbitalLogo src={`${BASE}assets/Frame 27.svg`} alt="CavinKare Logo" radiusX={360} radiusY={225} startAngle={324} duration={40} clockwise={false} size={180} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 28.svg')} alt="Valeo Logo" radiusX={360} radiusY={225} startAngle={36} duration={40} clockwise={false} size={170} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 36.svg')} alt="BorgWarner Logo" radiusX={360} radiusY={225} startAngle={108} duration={40} clockwise={false} size={170} />
|
||||
<OrbitalLogo src={assetUrl('/assets/kone.png')} alt="KONE Logo" radiusX={360} radiusY={225} startAngle={180} duration={40} clockwise={false} size={160} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 34.svg')} alt="Chola MS Logo" radiusX={360} radiusY={225} startAngle={252} duration={40} clockwise={false} size={170} />
|
||||
<OrbitalLogo src={assetUrl('/assets/Frame 27.svg')} alt="CavinKare Logo" radiusX={360} radiusY={225} startAngle={324} duration={40} clockwise={false} size={180} />
|
||||
|
||||
</div>
|
||||
)}
|
||||
@@ -1104,7 +1104,7 @@ export default function App({ previewMode = false }) {
|
||||
transition: 'all 0.3s ease'
|
||||
}}>
|
||||
<img
|
||||
src={cert.image}
|
||||
src={assetUrl(cert.image)}
|
||||
alt={cert.alt}
|
||||
style={{
|
||||
height: idx === 0 ? '85%' : idx === 3 ? '55%' : idx === 4 ? '100%' : '80%',
|
||||
@@ -1369,7 +1369,7 @@ export default function App({ previewMode = false }) {
|
||||
<div className="glass-card" style={{
|
||||
padding: '2rem 1.8rem',
|
||||
borderRadius: '20px',
|
||||
background: `linear-gradient(to bottom, rgba(2, 7, 16, 0.95) 0%, rgba(2, 7, 16, 0.6) 45%, rgba(2, 7, 16, 0) 85%), url(${BASE}assets/whyus_hologram.jpg)`,
|
||||
background: `linear-gradient(to bottom, rgba(2, 7, 16, 0.95) 0%, rgba(2, 7, 16, 0.6) 45%, rgba(2, 7, 16, 0) 85%), url(${assetUrl('/assets/whyus_hologram.jpg')})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
border: '1px solid rgba(255, 255, 255, 0.06)',
|
||||
@@ -1431,7 +1431,7 @@ export default function App({ previewMode = false }) {
|
||||
height: '100%'
|
||||
}}>
|
||||
<img
|
||||
src={`${BASE}assets/whyus_arab_meeting.jpg`}
|
||||
src={assetUrl('/assets/whyus_arab_meeting.jpg')}
|
||||
alt="Corporate collaboration"
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
/>
|
||||
@@ -1501,7 +1501,7 @@ export default function App({ previewMode = false }) {
|
||||
height: '100%'
|
||||
}}>
|
||||
<img
|
||||
src={`${BASE}assets/whyus_vr_man.jpg`}
|
||||
src={assetUrl('/assets/whyus_vr_man.jpg')}
|
||||
alt="Sunset boardroom"
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
/>
|
||||
@@ -1515,7 +1515,7 @@ export default function App({ previewMode = false }) {
|
||||
border: '1px solid rgba(255, 255, 255, 0.06)',
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
backgroundImage: `linear-gradient(to bottom, rgba(2, 7, 16, 0.95) 0%, rgba(2, 7, 16, 0.6) 45%, rgba(2, 7, 16, 0) 85%), url(${BASE}assets/whyus_hologram.jpg)`,
|
||||
backgroundImage: `linear-gradient(to bottom, rgba(2, 7, 16, 0.95) 0%, rgba(2, 7, 16, 0.6) 45%, rgba(2, 7, 16, 0) 85%), url(${assetUrl('/assets/whyus_hologram.jpg')})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
display: 'flex',
|
||||
@@ -1695,7 +1695,7 @@ export default function App({ previewMode = false }) {
|
||||
>
|
||||
{/* Full-bleed image */}
|
||||
<img
|
||||
src={insight.image}
|
||||
src={assetUrl(insight.image)}
|
||||
alt={insight.title}
|
||||
className="blog-card-img"
|
||||
style={{
|
||||
@@ -1775,7 +1775,7 @@ export default function App({ previewMode = false }) {
|
||||
padding: '4rem 0 0 0',
|
||||
}}>
|
||||
<img
|
||||
src={`${BASE}assets/citp_footer_design.png`}
|
||||
src={assetUrl('/assets/citp_footer_design.png')}
|
||||
alt="Cavin Infotech Logo Divider"
|
||||
style={{
|
||||
width: '100%',
|
||||
@@ -1851,7 +1851,7 @@ export default function App({ previewMode = false }) {
|
||||
{/* Phone mockup container on mobile */}
|
||||
<div style={{ width: '100%', height: '180px', position: 'relative', overflow: 'hidden', borderRadius: '12px' }}>
|
||||
<img
|
||||
src={footer.cta.image}
|
||||
src={assetUrl(footer.cta.image)}
|
||||
alt="Phone preview"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
@@ -1870,7 +1870,7 @@ export default function App({ previewMode = false }) {
|
||||
<Reveal>
|
||||
<div style={{ position: 'relative', width: '100%', marginBottom: '3rem' }}>
|
||||
<img
|
||||
src={footer.cta.image}
|
||||
src={assetUrl(footer.cta.image)}
|
||||
alt="CTA Banner"
|
||||
style={{
|
||||
width: '100%',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { motion, AnimatePresence, useReducedMotion } from 'framer-motion';
|
||||
import { ArrowRight, Clock } from 'lucide-react';
|
||||
import { assetUrl } from '../lib/assetUrl';
|
||||
|
||||
export default function FeaturedGallery({ gallery }) {
|
||||
const galleryData = gallery?.items || [];
|
||||
@@ -82,7 +83,7 @@ function ResponsiveGalleryWrapper({ galleryData, activeIdx, setActiveIdx }) {
|
||||
border: '1px solid rgba(255, 255, 255, 0.06)',
|
||||
position: 'relative',
|
||||
height: isFirst ? '320px' : '240px',
|
||||
backgroundImage: `linear-gradient(to bottom, rgba(2, 7, 16, 0.3) 0%, rgba(2, 7, 16, 0.95) 100%), url(${item.image})`,
|
||||
backgroundImage: `linear-gradient(to bottom, rgba(2, 7, 16, 0.3) 0%, rgba(2, 7, 16, 0.95) 100%), url(${assetUrl(item.image)})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
display: 'flex',
|
||||
@@ -171,7 +172,7 @@ function ResponsiveGalleryWrapper({ galleryData, activeIdx, setActiveIdx }) {
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundImage: `url(${item.image})`,
|
||||
backgroundImage: `url(${assetUrl(item.image)})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
zIndex: 1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { motion, useReducedMotion } from 'framer-motion';
|
||||
import { assetUrl } from '../lib/assetUrl';
|
||||
|
||||
const ACCENT_GRADIENTS = [
|
||||
'radial-gradient(circle at top right, rgba(139, 92, 246, 0.08) 0%, transparent 50%), linear-gradient(to bottom, #FAF9FA 0%, #F6F2F5 100%)',
|
||||
@@ -114,7 +115,7 @@ export default function ProductCard({ product, isMobile, delay = 0, index = 0 })
|
||||
background: 'transparent',
|
||||
}}>
|
||||
<img
|
||||
src={product.image}
|
||||
src={assetUrl(product.image)}
|
||||
alt={`${product.name} dashboard`}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
import { createContext, useContext, useEffect, useState } from 'react';
|
||||
import defaultContent from '../../server/seed/default-content.json';
|
||||
import { API_BASE } from '../lib/apiBase';
|
||||
import { prefixAssets } from '../lib/assetUrl';
|
||||
|
||||
const ContentContext = createContext(null);
|
||||
|
||||
const BASE = import.meta.env.BASE_URL;
|
||||
|
||||
// Recursively prefix /assets/ paths with the Vite base URL
|
||||
function prefixAssets(obj) {
|
||||
if (typeof obj === 'string') {
|
||||
return obj.startsWith('/assets/') ? `${BASE}${obj.slice(1)}` : obj;
|
||||
}
|
||||
if (Array.isArray(obj)) return obj.map(prefixAssets);
|
||||
if (obj && typeof obj === 'object') {
|
||||
const out = {};
|
||||
for (const k in obj) out[k] = prefixAssets(obj[k]);
|
||||
return out;
|
||||
}
|
||||
return obj;
|
||||
function allowedPreviewOrigins() {
|
||||
const origins = new Set(['https://demo.cavinkare.in/', 'https://demo.cavinkare.in']);
|
||||
if (typeof window !== 'undefined') origins.add(window.location.origin);
|
||||
return origins;
|
||||
}
|
||||
|
||||
export function ContentProvider({ children, previewMode = false }) {
|
||||
@@ -51,9 +42,10 @@ export function ContentProvider({ children, previewMode = false }) {
|
||||
if (!previewMode) return;
|
||||
|
||||
setLoading(false);
|
||||
const origins = allowedPreviewOrigins();
|
||||
|
||||
const onMessage = (event) => {
|
||||
if (event.origin !== window.location.origin) return;
|
||||
if (!origins.has(event.origin)) return;
|
||||
if (event.data?.type !== 'ADMIN_PREVIEW' || !event.data.fullContent) return;
|
||||
|
||||
setContent(prefixAssets(event.data.fullContent));
|
||||
@@ -68,7 +60,13 @@ export function ContentProvider({ children, previewMode = false }) {
|
||||
};
|
||||
|
||||
window.addEventListener('message', onMessage);
|
||||
window.parent?.postMessage({ type: 'PREVIEW_READY' }, window.location.origin);
|
||||
for (const origin of origins) {
|
||||
try {
|
||||
window.parent?.postMessage({ type: 'PREVIEW_READY' }, origin);
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
return () => window.removeEventListener('message', onMessage);
|
||||
}, [previewMode]);
|
||||
@@ -82,6 +80,6 @@ export function ContentProvider({ children, previewMode = false }) {
|
||||
|
||||
export function useContent() {
|
||||
const ctx = useContext(ContentContext);
|
||||
if (!ctx) throw new Error('useContent must be used within ContentProvider');
|
||||
if (!ctx) throw new Error('useContent must be used within a ContentProvider');
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Vite base, e.g. "/citpl_website/" in production and "/" in local dev.
|
||||
*/
|
||||
export const ASSET_BASE = (import.meta.env.BASE_URL || '/').endsWith('/')
|
||||
? (import.meta.env.BASE_URL || '/')
|
||||
: `${import.meta.env.BASE_URL || ''}/`;
|
||||
|
||||
/**
|
||||
* Resolve content/seed asset paths for subdirectory deploys.
|
||||
* "/assets/foo.svg" → "/citpl_website/assets/foo.svg" in prod
|
||||
*/
|
||||
export function assetUrl(path) {
|
||||
if (!path || typeof path !== 'string') return path;
|
||||
|
||||
if (/^(data:|blob:)/i.test(path)) return path;
|
||||
|
||||
// Absolute URL wrongly pointing at domain-root /assets or /uploads
|
||||
if (/^https?:\/\//i.test(path)) {
|
||||
try {
|
||||
const u = new URL(path);
|
||||
if (u.pathname.startsWith('/assets/') || u.pathname.startsWith('/uploads/')) {
|
||||
const prefix = ASSET_BASE.replace(/\/$/, '');
|
||||
if (!u.pathname.startsWith(`${prefix}/`)) {
|
||||
u.pathname = `${prefix}${u.pathname}`;
|
||||
return u.href;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
} catch {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
const prefix = ASSET_BASE.replace(/\/$/, '');
|
||||
|
||||
// Already under the site base
|
||||
if (prefix && (path === prefix || path.startsWith(`${prefix}/`))) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (path.startsWith('/assets/') || path.startsWith('/uploads/')) {
|
||||
return `${prefix}${path}`;
|
||||
}
|
||||
|
||||
if (path.startsWith('assets/') || path.startsWith('uploads/')) {
|
||||
return `${ASSET_BASE}${path}`;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/** Recursively rewrite asset strings inside content JSON. */
|
||||
export function prefixAssets(obj) {
|
||||
if (typeof obj === 'string') return assetUrl(obj);
|
||||
if (Array.isArray(obj)) return obj.map(prefixAssets);
|
||||
if (obj && typeof obj === 'object') {
|
||||
const out = {};
|
||||
for (const k in obj) out[k] = prefixAssets(obj[k]);
|
||||
return out;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
Reference in New Issue
Block a user