Merge version_2 into main #2

Merged
bender merged 5 commits from version_2 into main 2026-02-20 07:53:45 +00:00
5 changed files with 183 additions and 23 deletions

View File

@@ -73,4 +73,4 @@ export default function BlogPage() {
</ReactLenis>
</ThemeProvider>
);
}
}

View File

@@ -87,7 +87,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 {' +
@@ -159,6 +161,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(['"]?([^'")]+)['"]?)/);
@@ -241,6 +247,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();
@@ -283,7 +321,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') {
@@ -331,7 +380,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;
@@ -371,7 +421,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;
@@ -434,6 +484,20 @@ export default function RootLayout({
originalContent = element.textContent;
element.contentEditable = 'true';
if (!element.dataset.webildOriginalWhiteSpace) {
const computedStyle = window.getComputedStyle(element);
element.dataset.webildOriginalWhiteSpace = computedStyle.whiteSpace;
element.dataset.webildOriginalWordWrap = computedStyle.wordWrap;
element.dataset.webildOriginalOverflowWrap = computedStyle.overflowWrap;
element.dataset.webildOriginalOverflow = computedStyle.overflow;
}
element.style.whiteSpace = 'pre-wrap';
element.style.wordWrap = 'break-word';
element.style.overflowWrap = 'break-word';
element.style.overflow = 'visible';
element.focus();
isEditing = true;
@@ -543,6 +607,23 @@ export default function RootLayout({
element.contentEditable = 'false';
isEditing = false;
if (element.dataset.webildOriginalWhiteSpace) {
element.style.whiteSpace = element.dataset.webildOriginalWhiteSpace === 'normal' ? '' : element.dataset.webildOriginalWhiteSpace;
delete element.dataset.webildOriginalWhiteSpace;
}
if (element.dataset.webildOriginalWordWrap) {
element.style.wordWrap = element.dataset.webildOriginalWordWrap === 'normal' ? '' : element.dataset.webildOriginalWordWrap;
delete element.dataset.webildOriginalWordWrap;
}
if (element.dataset.webildOriginalOverflowWrap) {
element.style.overflowWrap = element.dataset.webildOriginalOverflowWrap === 'normal' ? '' : element.dataset.webildOriginalOverflowWrap;
delete element.dataset.webildOriginalOverflowWrap;
}
if (element.dataset.webildOriginalOverflow) {
element.style.overflow = element.dataset.webildOriginalOverflow === 'visible' ? '' : element.dataset.webildOriginalOverflow;
delete element.dataset.webildOriginalOverflow;
}
if (element.dataset.beforeInputHandler === 'true') {
element.removeEventListener('beforeinput', () => {});
delete element.dataset.beforeInputHandler;
@@ -848,6 +929,9 @@ export default function RootLayout({
const handleScroll = () => {
if (!isActive) return;
if (isEditing) return;
if (selectedElement) {
makeUneditable(selectedElement, false);
selectedElement.classList.remove(selectedClass);
@@ -1018,11 +1102,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) {
@@ -1122,7 +1217,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 {
@@ -1153,7 +1248,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';
@@ -1221,6 +1341,31 @@ export default function RootLayout({
window.addEventListener('scroll', handleScroll, true);
window.addEventListener('message', handleMessage, true);
let lastPathname = window.location.pathname;
const notifyPageChange = () => {
window.parent.postMessage({
type: 'webild-page-changed',
data: { pathname: window.location.pathname }
}, '*');
};
window.addEventListener('popstate', () => {
if (lastPathname !== window.location.pathname) {
lastPathname = window.location.pathname;
notifyPageChange();
}
}, true);
const urlCheckInterval = setInterval(() => {
if (lastPathname !== window.location.pathname) {
lastPathname = window.location.pathname;
notifyPageChange();
}
}, 500);
notifyPageChange();
window.webildCleanup = () => {
isActive = false;
@@ -1231,6 +1376,10 @@ export default function RootLayout({
removeHoverOverlay();
removeElementTypeLabel();
if (urlCheckInterval) {
clearInterval(urlCheckInterval);
}
document.removeEventListener('mouseover', handleMouseOver, true);
document.removeEventListener('mouseout', handleMouseOut, true);
document.removeEventListener('click', handleClick, true);
@@ -1262,4 +1411,4 @@ export default function RootLayout({
</ServiceWrapper>
</html>
);
}
}

View File

@@ -10,6 +10,7 @@ import FeatureBento from "@/components/sections/feature/FeatureBento";
import TestimonialCardFifteen from "@/components/sections/testimonial/TestimonialCardFifteen";
import ContactSplit from "@/components/sections/contact/ContactSplit";
import FooterCard from "@/components/sections/footer/FooterCard";
import SocialProofOne from "@/components/sections/socialProof/SocialProofOne";
import { Award, BarChart3, CheckCircle, Clock, Cloud, Code, Cpu, Database, Eye, GitBranch, Github, Linkedin, Mail, Monitor, Package, Server, Settings, Shield, Smartphone, Sparkles, TrendingUp, Twitter, Users, Zap } from "lucide-react";
export default function LandingPage() {
@@ -103,6 +104,21 @@ export default function LandingPage() {
/>
</div>
<div id="ribbon" data-section="ribbon">
<SocialProofOne
title="Trusted by Industry Leaders"
description="Partnering with innovative companies that trust my expertise"
tag="Clients"
textboxLayout="default"
useInvertedBackground={true}
names={[
"Acme Corporation", "TechFlow Solutions", "Innovate Inc", "CloudSync Systems", "DataVault Pro", "NeuralNet AI", "VelocityScale", "PrismLabs"
]}
speed={40}
showCard={true}
/>
</div>
<div id="features" data-section="features">
<FeatureCardSeven
title="Featured Work"
@@ -222,4 +238,4 @@ export default function LandingPage() {
</div>
</ThemeProvider>
);
}
}

View File

@@ -90,8 +90,7 @@ export default function ProductPage({ params }: ProductPageProps) {
{ name: "About", id: "about" },
{ name: "Work", id: "features" },
{ name: "Skills", id: "metrics" },
{ name: "Contact", id: "contact" },
{ name: "Shop", id: "/shop" }
{ name: "Contact", id: "contact" }
]}
bottomLeftText="Developer & Creator"
bottomRightText="hello@hofcoral.dev"
@@ -141,8 +140,7 @@ export default function ProductPage({ params }: ProductPageProps) {
{ name: "About", id: "about" },
{ name: "Work", id: "features" },
{ name: "Skills", id: "metrics" },
{ name: "Contact", id: "contact" },
{ name: "Shop", id: "/shop" }
{ name: "Contact", id: "contact" }
]}
bottomLeftText="Developer & Creator"
bottomRightText="hello@hofcoral.dev"
@@ -199,8 +197,7 @@ export default function ProductPage({ params }: ProductPageProps) {
{ name: "About", id: "about" },
{ name: "Work", id: "features" },
{ name: "Skills", id: "metrics" },
{ name: "Contact", id: "contact" },
{ name: "Shop", id: "/shop" }
{ name: "Contact", id: "contact" }
]}
bottomLeftText="Developer & Creator"
bottomRightText="hello@hofcoral.dev"
@@ -258,4 +255,4 @@ export default function ProductPage({ params }: ProductPageProps) {
</ReactLenis>
</ThemeProvider>
);
}
}

View File

@@ -42,8 +42,7 @@ export default function ShopPage() {
{ name: "About", id: "about" },
{ name: "Work", id: "features" },
{ name: "Skills", id: "metrics" },
{ name: "Contact", id: "contact" },
{ name: "Shop", id: "/shop" }
{ name: "Contact", id: "contact" }
]}
bottomLeftText="Developer & Creator"
bottomRightText="hello@hofcoral.dev"
@@ -92,8 +91,7 @@ export default function ShopPage() {
{ name: "About", id: "about" },
{ name: "Work", id: "features" },
{ name: "Skills", id: "metrics" },
{ name: "Contact", id: "contact" },
{ name: "Shop", id: "/shop" }
{ name: "Contact", id: "contact" }
]}
bottomLeftText="Developer & Creator"
bottomRightText="hello@hofcoral.dev"
@@ -126,4 +124,4 @@ export default function ShopPage() {
</ReactLenis>
</ThemeProvider>
);
}
}