diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx
index a1d479b..d3ed726 100644
--- a/src/app/blog/page.tsx
+++ b/src/app/blog/page.tsx
@@ -33,7 +33,7 @@ export default function BlogPage() {
- element.classList.contains(cls) || element.classList.contains(\`btn-\${cls}\`)
+ element.classList.contains(cls) || element.classList.contains(`btn-${cls}`)
);
if (hasButtonClass && element.textContent && element.textContent.trim().length > 0) {
@@ -237,7 +237,8 @@ export default function RootLayout({
try {
const urlObj = new URL(url);
return urlObj.pathname;
- } catch (e) {
+ }
+ catch (e) {
return url;
}
}
@@ -631,17 +632,17 @@ export default function RootLayout({
const rect = element.getBoundingClientRect();
const overlay = document.createElement('div');
overlay.className = 'webild-hover-overlay';
- overlay.style.cssText = \`
+ overlay.style.cssText = `
position: fixed !important;
- top: \${rect.top - 2}px !important;
- left: \${rect.left - 2}px !important;
- width: \${rect.width + 4}px !important;
- height: \${rect.height + 4}px !important;
+ top: ${rect.top - 2}px !important;
+ left: ${rect.left - 2}px !important;
+ width: ${rect.width + 4}px !important;
+ height: ${rect.height + 4}px !important;
background-color: rgba(90, 113, 230, 0.15) !important;
pointer-events: none !important;
z-index: 999998 !important;
transition: all 0.15s ease !important;
- \`;
+ `;
document.body.appendChild(overlay);
return overlay;
};
@@ -704,11 +705,11 @@ export default function RootLayout({
elementTypeLabel.classList.add('label-bottom');
}
- elementTypeLabel.style.cssText = \`
- left: \${labelLeft}px !important;
- top: \${labelTop}px !important;
+ elementTypeLabel.style.cssText = `
+ left: ${labelLeft}px !important;
+ top: ${labelTop}px !important;
transform: none !important;
- \`;
+ `;
};
const removeElementTypeLabel = () => {
@@ -962,7 +963,7 @@ export default function RootLayout({
const getStorageKey = () => {
const url = new URL(window.location.href);
const pathParts = url.pathname.split('/').filter(Boolean);
- return \`webild-changes-\${pathParts.join('-')}\`;
+ return `webild-changes-${pathParts.join('-')}`;
};
const saveChangeToStorage = (change) => {
@@ -1187,7 +1188,7 @@ export default function RootLayout({
if (isBackground) {
oldValue = window.getComputedStyle(element).backgroundImage;
- element.style.backgroundImage = \`url('\${newSrc}')\`;
+ element.style.backgroundImage = `url('${newSrc}')`;
replaced = true;
} else if (element.tagName.toLowerCase() === 'img') {
oldValue = element.src;
@@ -1197,7 +1198,7 @@ export default function RootLayout({
const hasBackgroundImage = window.getComputedStyle(element).backgroundImage !== 'none';
if (hasBackgroundImage) {
oldValue = window.getComputedStyle(element).backgroundImage;
- element.style.backgroundImage = \`url('\${newSrc}')\`;
+ element.style.backgroundImage = `url('${newSrc}')`;
replaced = true;
}
}
@@ -1372,7 +1373,9 @@ export default function RootLayout({
' background-color: #4d96ff05 !important;' +
'}' +
'img.webild-hover,' +
- 'img.webild-selected {' +
+ 'img.webild-selected,' +
+ 'video.webild-hover,' +
+ 'video.webild-selected {' +
' outline-offset: 2px !important;' +
'}' +
'.webild-element-type-label {' +
@@ -1444,6 +1447,10 @@ export default function RootLayout({
return 'Image';
}
+ if (tagName === 'video') {
+ return 'Video';
+ }
+
const backgroundImage = computedStyle.backgroundImage;
if (backgroundImage && backgroundImage !== 'none') {
const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/);
@@ -1526,6 +1533,38 @@ export default function RootLayout({
return url;
};
+ const getMediaTypeFromUrl = (url) => {
+ const videoExts = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.mkv', '.m4v', '.wmv'];
+ const imageExts = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.svg', '.bmp', '.ico', '.tiff', '.avif'];
+ try {
+ const pathname = new URL(url).pathname.toLowerCase();
+ if (videoExts.some(function(ext) { return pathname.endsWith(ext); })) return 'video';
+ if (imageExts.some(function(ext) { return pathname.endsWith(ext); })) return 'image';
+ } catch(e) {}
+ return 'unknown';
+ };
+
+ const swapMediaElement = (oldEl, newTag, newSrc) => {
+ const newEl = document.createElement(newTag);
+ Array.from(oldEl.attributes).forEach(function(attr) {
+ if (attr.name !== 'src' && attr.name !== 'alt' && attr.name !== 'srcset' && attr.name !== 'autoplay' && attr.name !== 'loop' && attr.name !== 'muted' && attr.name !== 'playsinline') {
+ try { newEl.setAttribute(attr.name, attr.value); } catch(e) {}
+ }
+ });
+ newEl.style.cssText = oldEl.style.cssText;
+ if (newTag === 'video') {
+ newEl.setAttribute('autoplay', '');
+ newEl.setAttribute('loop', '');
+ newEl.setAttribute('muted', '');
+ newEl.setAttribute('playsinline', '');
+ }
+ newEl.src = newSrc;
+ if (oldEl.parentNode) {
+ oldEl.parentNode.replaceChild(newEl, oldEl);
+ }
+ return newEl;
+ };
+
const getElementInfo = (element, assignId = false) => {
const rect = element.getBoundingClientRect();
const tagName = element.tagName.toLowerCase();
@@ -1568,7 +1607,18 @@ export default function RootLayout({
isBackground: false
};
}
-
+
+ if (tagName === 'video') {
+ const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || '';
+ const resolvedSrc = extractOriginalUrl(rawSrc);
+ info.imageData = {
+ src: resolvedSrc,
+ alt: element.getAttribute('aria-label') || undefined,
+ isBackground: false,
+ isVideo: true
+ };
+ }
+
const computedStyle = window.getComputedStyle(element);
const backgroundImage = computedStyle.backgroundImage;
if (backgroundImage && backgroundImage !== 'none') {
@@ -1616,7 +1666,8 @@ export default function RootLayout({
const tagName = element.tagName?.toLowerCase();
if (invalidElements.includes(tagName)) return false;
const isImage = tagName === 'img';
- if (isImage) return true;
+ const isVideo = tagName === 'video';
+ if (isImage || isVideo) return true;
const hasInnerHTML = element.innerHTML && element.innerHTML.trim().length > 0;
const hasTextContent = element.textContent && element.textContent.trim().length > 0;
const hasChildren = element.children && element.children.length > 0;
@@ -1656,7 +1707,7 @@ export default function RootLayout({
node.nodeType === Node.TEXT_NODE && node.textContent && node.textContent.trim().length > 0
);
- const hasImages = element.tagName === 'IMG' || computedStyle.backgroundImage !== 'none' || element.querySelector('img');
+ const hasImages = element.tagName === 'IMG' || element.tagName === 'VIDEO' || computedStyle.backgroundImage !== 'none' || element.querySelector('img') || element.querySelector('video');
const isInteractive = ['BUTTON', 'A', 'INPUT', 'SELECT', 'TEXTAREA'].includes(element.tagName);
const hasFewChildren = element.children.length <= 3;
const area = rect.width * rect.height;
@@ -2337,11 +2388,22 @@ export default function RootLayout({
updateButtonText(element, change.oldValue);
}
} else if (change.type === 'replaceImage') {
- const isBackground = element.tagName.toLowerCase() !== 'img';
+ const revertTag = element.tagName.toLowerCase();
+ const isBackground = revertTag !== 'img' && revertTag !== 'video';
if (isBackground) {
element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : '';
} else {
- element.src = change.oldValue;
+ const oldMediaType = getMediaTypeFromUrl(change.oldValue);
+ if (revertTag === 'video' && oldMediaType === 'image') {
+ swapMediaElement(element, 'img', change.oldValue);
+ } else if (revertTag === 'img' && oldMediaType === 'video') {
+ swapMediaElement(element, 'video', change.oldValue);
+ } else if (revertTag === 'video') {
+ element.src = change.oldValue;
+ element.load();
+ } else {
+ element.src = change.oldValue;
+ }
}
}
} catch (err) {
@@ -2441,7 +2503,7 @@ export default function RootLayout({
if (!isActive) return;
if (e.data.type === 'webild-replace-image') {
- const { selector, newSrc, isBackground } = e.data.data;
+ const { selector, newSrc, isBackground, allowMediaTypeSwap } = e.data.data;
let element = null;
try {
@@ -2472,7 +2534,32 @@ export default function RootLayout({
replaced = true;
} else if (element.tagName.toLowerCase() === 'img') {
oldValue = element.src;
- element.src = newSrc;
+ const newMediaType = getMediaTypeFromUrl(newSrc);
+ if (newMediaType === 'video' && allowMediaTypeSwap) {
+ const swapped = swapMediaElement(element, 'video', newSrc);
+ if (selectedElement === element) selectedElement = swapped;
+ element = swapped;
+ } else {
+ element.src = newSrc;
+ }
+ replaced = true;
+ } else if (element.tagName.toLowerCase() === 'video') {
+ oldValue = element.src || element.currentSrc || '';
+ const newMediaType = getMediaTypeFromUrl(newSrc);
+ const sources = element.querySelectorAll('source');
+ if (newMediaType === 'image' && allowMediaTypeSwap) {
+ const swapped = swapMediaElement(element, 'img', newSrc);
+ if (selectedElement === element) selectedElement = swapped;
+ element = swapped;
+ } else {
+ if (sources.length > 0) {
+ sources.forEach(function(source) { source.src = newSrc; });
+ element.load();
+ } else {
+ element.src = newSrc;
+ element.load();
+ }
+ }
replaced = true;
} else {
const hasBackgroundImage = window.getComputedStyle(element).backgroundImage !== 'none';
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 960672a..6630851 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -5,7 +5,7 @@ import ContactSplit from '@/components/sections/contact/ContactSplit';
import FaqDouble from '@/components/sections/faq/FaqDouble';
import FeatureCardSeven from '@/components/sections/feature/FeatureCardSeven';
import FooterBaseCard from '@/components/sections/footer/FooterBaseCard';
-import HeroSplitKpi from '@/components/sections/hero/HeroSplitKpi';
+import HeroOverlay from '@/components/sections/hero/HeroOverlay';
import ProductCardThree from '@/components/sections/product/ProductCardThree';
import TestimonialCardFive from '@/components/sections/testimonial/TestimonialCardFive';
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
@@ -36,12 +36,9 @@ export default function LandingPage() {
-
{
+ const navigationItems = [
+ { name: "Features", id: "/#features" },
+ { name: "Products", id: "/#products" },
+ { name: "Testimonials", id: "/#testimonials" },
+ { name: "FAQ", id: "/#faq" },
+ { name: "Contact", id: "/#contact" }
+ ];
-interface ProductPageProps {
- params: Promise<{ id: string }>;
-}
-
-export default function ProductPage({ params }: ProductPageProps) {
- const { id } = use(params);
- const router = useRouter();
-
- const {
- product,
- isLoading,
- images,
- meta,
- variants,
- quantityVariant,
- selectedQuantity,
- createCartItem,
- } = useProductDetail(id);
-
- const {
- items: cartItems,
- isOpen: cartOpen,
- setIsOpen: setCartOpen,
- addItem,
- updateQuantity,
- removeItem,
- total: cartTotal,
- getCheckoutItems,
- } = useCart();
-
- const { buyNow, checkout, isLoading: isCheckoutLoading } = useCheckout();
-
- const handleAddToCart = useCallback(() => {
- const item = createCartItem();
- if (item) {
- addItem(item);
- }
- }, [createCartItem, addItem]);
-
- const handleBuyNow = useCallback(() => {
- if (product) {
- buyNow(product, selectedQuantity);
- }
- }, [product, selectedQuantity, buyNow]);
-
- const handleCheckout = useCallback(async () => {
- if (cartItems.length === 0) return;
-
- const currentUrl = new URL(window.location.href);
- currentUrl.searchParams.set("success", "true");
-
- await checkout(getCheckoutItems(), { successUrl: currentUrl.toString() });
- }, [cartItems, checkout, getCheckoutItems]);
-
- if (isLoading) {
- return (
-
-
-
- setCartOpen(true) }}
- className="py-4 px-6 md:px-8 lg:px-12"
- navItemClassName="text-foreground hover:text-primary-cta"
- buttonClassName=""
- buttonTextClassName=""
- />
-
-
-
- Loading product...
-
-
-
-
-
- );
- }
-
- if (!product) {
- return (
-
-
-
- setCartOpen(true) }}
- className="py-4 px-6 md:px-8 lg:px-12"
- navItemClassName="text-foreground hover:text-primary-cta"
- buttonClassName=""
- buttonTextClassName=""
- />
-
-
-
-
-
Product not found
-
-
-
-
-
-
-
- );
- }
-
- return (
-
-
-
- setCartOpen(true) }}
- className="py-4 px-6 md:px-8 lg:px-12"
- navItemClassName="text-foreground hover:text-primary-cta"
- buttonClassName=""
- buttonTextClassName=""
- />
-
-
-
0 ? variants : undefined}
- quantity={quantityVariant}
- ribbon={meta.ribbon}
- inventoryStatus={meta.inventoryStatus}
- inventoryQuantity={meta.inventoryQuantity}
- sku={meta.sku}
- buttons={[
- { text: "Add To Cart", onClick: handleAddToCart },
- { text: "Buy Now", onClick: handleBuyNow },
- ]}
- />
-
-
-
setCartOpen(false)}
- items={cartItems}
- onQuantityChange={updateQuantity}
- onRemove={removeItem}
- total={`$${cartTotal}`}
- buttons={[
- {
- text: isCheckoutLoading ? "Processing..." : "Check Out", onClick: handleCheckout,
- },
- ]}
- />
-
-
-
-
- );
+ return (
+
+
+
+ setCartOpen(true) }}
+ className="py-4 px-6 md:px-8 lg:px-12"
+ navItemClassName="text-foreground hover:text-primary-cta"
+ buttonClassName=""
+ buttonTextClassName=""
+ />
+
+
+
0 ? variants : undefined}
+ quantity={quantityVariant}
+ ribbon={meta.ribbon}
+ inventoryStatus={meta.inventoryStatus}
+ inventoryQuantity={meta.inventoryQuantity}
+ sku={meta.sku}
+ buttons={[
+ { text: "Add To Cart", onClick: handleAddToCart },
+ { text: "Buy Now", onClick: handleBuyNow },
+ ]}
+ />
+
+
+
setCartOpen(false)}
+ items={cartItems}
+ onQuantityChange={updateQuantity}
+ onRemove={removeItem}
+ total={`$${cartTotal}`}
+ buttons={[
+ {
+ text: isCheckoutLoading ? "Processing..." : "Check Out", onClick: handleCheckout,
+ },
+ ]}
+ />
+
+
+
+
+ );
}
diff --git a/src/app/shop/page.tsx b/src/app/shop/page.tsx
index a6649d8..1307413 100644
--- a/src/app/shop/page.tsx
+++ b/src/app/shop/page.tsx
@@ -34,7 +34,7 @@ export default function ShopPage() {
{} }}
@@ -91,7 +91,7 @@ export default function ShopPage() {
{} }}