From 16fb6c3104b26431f1cdf8f932a52709960275a2 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:21 +0000 Subject: [PATCH 01/39] Update docs/CARDSTACK_SECTIONS.md --- docs/CARDSTACK_SECTIONS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CARDSTACK_SECTIONS.md b/docs/CARDSTACK_SECTIONS.md index 8538146..5902e40 100644 --- a/docs/CARDSTACK_SECTIONS.md +++ b/docs/CARDSTACK_SECTIONS.md @@ -269,7 +269,7 @@ Buttons are rendered with automatic primary/secondary styling: ```tsx const buttons: ButtonConfig[] = [ - { text: "Get Started", href: "/signup" }, // Primary + { text: "Download Now", href: "/signup" }, // Primary { text: "Learn More", onClick: () => {} } // Secondary ]; ``` -- 2.49.1 From 4478c6c86583447003fb74098a662361e72178ec Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:22 +0000 Subject: [PATCH 02/39] Update docs/COMPONENT_IMPLEMENTATION.md --- docs/COMPONENT_IMPLEMENTATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/COMPONENT_IMPLEMENTATION.md b/docs/COMPONENT_IMPLEMENTATION.md index f0461a5..0339728 100644 --- a/docs/COMPONENT_IMPLEMENTATION.md +++ b/docs/COMPONENT_IMPLEMENTATION.md @@ -351,7 +351,7 @@ For button text and short labels: { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 15 } -- 2.49.1 From 531c3f0508f95ed75d3e5fbf5f0c663fb861be7a Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:23 +0000 Subject: [PATCH 03/39] Update docs/PREVIEW_PAGE_STANDARDS.md --- docs/PREVIEW_PAGE_STANDARDS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/PREVIEW_PAGE_STANDARDS.md b/docs/PREVIEW_PAGE_STANDARDS.md index 7ed66ef..a9b9336 100644 --- a/docs/PREVIEW_PAGE_STANDARDS.md +++ b/docs/PREVIEW_PAGE_STANDARDS.md @@ -107,7 +107,7 @@ export default function SectionPreviewPage() { title="Preview Section Title" description="This is a preview of the section component with example content." buttons={[ - { text: "Get Started", href: "#" }, + { text: "Download Now", href: "#" }, { text: "Learn More", onClick: () => console.log("Learn more") } ]} // Add section-specific props @@ -308,7 +308,7 @@ Customize theme settings when: title="Build Amazing Websites Faster" description="Create stunning, responsive websites with our modern component library. Ship faster, iterate quicker." buttons={[ - { text: "Get Started", href: "/signup" }, + { text: "Download Now", href: "/signup" }, { text: "View Demo", onClick: () => window.open("/demo") } ]} /> -- 2.49.1 From 52f96951691849df62611567fb8771619ac31f24 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:23 +0000 Subject: [PATCH 04/39] Update docs/REGISTRY_STANDARDS.md --- docs/REGISTRY_STANDARDS.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/REGISTRY_STANDARDS.md b/docs/REGISTRY_STANDARDS.md index 865d7a7..77cd185 100644 --- a/docs/REGISTRY_STANDARDS.md +++ b/docs/REGISTRY_STANDARDS.md @@ -163,7 +163,7 @@ Defines text length constraints for string props. "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 15 } @@ -267,12 +267,12 @@ Single-line example showing typical implementation. **Button:** ```json -"usage": " console.log('clicked')} />" +"usage": " console.log('clicked')} />" ``` **Section with minimal props:** ```json -"usage": "" +"usage": "" ``` **CardStack section:** @@ -308,7 +308,7 @@ Single-line example showing typical implementation. "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 15 } @@ -380,7 +380,7 @@ Single-line example showing typical implementation. "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 15 } @@ -396,7 +396,7 @@ Single-line example showing typical implementation. "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usage": " console.log('clicked')} />" + "usage": " console.log('clicked')} />" } ``` -- 2.49.1 From 1667e6d2fd8a65e2eec88f02da271d2fda1d1be5 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:24 +0000 Subject: [PATCH 05/39] Update registry/components/ButtonBounceEffect.json --- registry/components/ButtonBounceEffect.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonBounceEffect.json b/registry/components/ButtonBounceEffect.json index 48ffbfa..c541b02 100644 --- a/registry/components/ButtonBounceEffect.json +++ b/registry/components/ButtonBounceEffect.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From 47ada2015903f4fc3ceb530f0b72520d9a74750f Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:24 +0000 Subject: [PATCH 06/39] Update registry/components/ButtonDirectionalHover.json --- registry/components/ButtonDirectionalHover.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonDirectionalHover.json b/registry/components/ButtonDirectionalHover.json index 44830e1..1c565d2 100644 --- a/registry/components/ButtonDirectionalHover.json +++ b/registry/components/ButtonDirectionalHover.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From 6acf1e4aa4f01ae9b02f0074526d3aedcf8b89f1 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:25 +0000 Subject: [PATCH 07/39] Update registry/components/ButtonElasticEffect.json --- registry/components/ButtonElasticEffect.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonElasticEffect.json b/registry/components/ButtonElasticEffect.json index 13ad861..08989fe 100644 --- a/registry/components/ButtonElasticEffect.json +++ b/registry/components/ButtonElasticEffect.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From 4c33dc9f01d1350595f997511740189352b0fafb Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:26 +0000 Subject: [PATCH 08/39] Update registry/components/ButtonExpandHover.json --- registry/components/ButtonExpandHover.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonExpandHover.json b/registry/components/ButtonExpandHover.json index c0d0be4..df48cd0 100644 --- a/registry/components/ButtonExpandHover.json +++ b/registry/components/ButtonExpandHover.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From b3bbb800da9c408d7930dd22e31bd3fbd3cd9761 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:26 +0000 Subject: [PATCH 09/39] Update registry/components/ButtonShiftHover.json --- registry/components/ButtonShiftHover.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonShiftHover.json b/registry/components/ButtonShiftHover.json index fb50a44..3933b20 100644 --- a/registry/components/ButtonShiftHover.json +++ b/registry/components/ButtonShiftHover.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From 9ab96324734e5802055e654d01ac8aa898761345 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:27 +0000 Subject: [PATCH 10/39] Update registry/components/ButtonTextShift.json --- registry/components/ButtonTextShift.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonTextShift.json b/registry/components/ButtonTextShift.json index 9b9e2e0..b47269a 100644 --- a/registry/components/ButtonTextShift.json +++ b/registry/components/ButtonTextShift.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From c3fe3f97578dffa6172323d00b9eb76c8c96869b Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:27 +0000 Subject: [PATCH 11/39] Update registry/components/ButtonTextStagger.json --- registry/components/ButtonTextStagger.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/ButtonTextStagger.json b/registry/components/ButtonTextStagger.json index e7eb24c..ec244f0 100644 --- a/registry/components/ButtonTextStagger.json +++ b/registry/components/ButtonTextStagger.json @@ -5,7 +5,7 @@ "textRules": { "text": { "required": true, - "example": "Get Started", + "example": "Download Now", "minChars": 2, "maxChars": 25 } @@ -21,7 +21,7 @@ "ariaLabel?": "string", "type?": "'button' | 'submit' | 'reset' (default: 'button')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for general use" ], -- 2.49.1 From 96c65c14fee0320eb23b370d09baaa11f82aa7d6 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:28 +0000 Subject: [PATCH 12/39] Update theme fonts --- src/app/layout.tsx | 183 ++++++++++++++------------------------------- 1 file changed, 58 insertions(+), 125 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4883afe..162d9ab 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,18 +6,8 @@ import "./globals.css"; import { ServiceWrapper } from "@/components/ServiceWrapper"; import Tag from "@/tag/Tag"; -const halant = Halant({ - variable: "--font-halant", subsets: ["latin"], - weight: ["300", "400", "500", "600", "700"], -}); -const inter = Inter({ - variable: "--font-inter", subsets: ["latin"], -}); -const openSans = Open_Sans({ - variable: "--font-open-sans", subsets: ["latin"], -}); export const metadata: Metadata = { title: "Torah Lock - iOS Torah Lock for Jewish Morning Prayers", description: "Start your day with Hashem. Torah Lock is a beautiful iOS app designed to help Jewish users pray every morning with guided prayers, reminders, and community connection.", keywords: "prayer app, iOS, Jewish, morning prayers, spiritual growth, Torah Lock", metadataBase: new URL("https://shachar-prayer.com"), @@ -33,6 +23,11 @@ export const metadata: Metadata = { }, }; +const inter = Inter({ + variable: "--font-inter", + subsets: ["latin"], +}); + export default function RootLayout({ children, }: Readonly<{ @@ -41,9 +36,7 @@ export default function RootLayout({ return ( - + {children} @@ -288,9 +281,7 @@ export default function RootLayout({ const getElementInfo = (element, assignId = false) => { const rect = element.getBoundingClientRect(); const tagName = element.tagName.toLowerCase(); - const selector = getUniqueSelector(element, assignId); - const sectionId = getSectionId(element); - + let className = undefined; try { if (element.className) { @@ -318,8 +309,7 @@ export default function RootLayout({ }; if (tagName === 'img') { - const originalSrc = extractOriginalUrl(element.src); - info.imageData = { + info.imageData = { src: originalSrc, alt: element.alt || undefined, naturalWidth: element.naturalWidth, @@ -330,8 +320,7 @@ export default function RootLayout({ if (tagName === 'video') { const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || ''; - const resolvedSrc = extractOriginalUrl(rawSrc); - info.imageData = { + info.imageData = { src: resolvedSrc, alt: element.getAttribute('aria-label') || undefined, isBackground: false, @@ -344,8 +333,7 @@ export default function RootLayout({ if (backgroundImage && backgroundImage !== 'none') { const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/); if (urlMatch) { - const originalBgSrc = extractOriginalUrl(urlMatch[1]); - if (tagName !== 'img') { + if (tagName !== 'img') { info.imageData = { src: originalBgSrc, isBackground: true @@ -357,8 +345,7 @@ export default function RootLayout({ } } - const elementType = getElementType(element); - info.elementType = elementType; + info.elementType = elementType; if (elementType === 'Button') { const buttonText = element.textContent?.trim() || element.value || element.getAttribute('aria-label') || ''; @@ -451,13 +438,11 @@ export default function RootLayout({ }; const isTextElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Text'; + return elementType === 'Text'; }; const isButtonElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Button'; + return elementType === 'Button'; }; const updateButtonText = (element, newText) => { @@ -532,8 +517,7 @@ export default function RootLayout({ }; const handleInput = () => { - const elementInfo = getElementInfo(element); - let currentText = element.textContent; + let currentText = element.textContent; // Ensure there's always at least a space to keep the element editable if (currentText === '' || currentText === null || currentText.length === 0) { @@ -646,8 +630,7 @@ export default function RootLayout({ }, '*'); if (save && originalContent !== element.textContent) { - const elementInfo = getElementInfo(element); - let finalText = element.textContent; + let finalText = element.textContent; // Trim the final text and convert space-only to empty string for saving if (finalText === ' ' || finalText.trim() === '') { @@ -776,7 +759,7 @@ export default function RootLayout({ lastMouseX = e.clientX; lastMouseY = e.clientY; - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target) || target === hoveredElement || target === selectedElement) { return; @@ -808,8 +791,7 @@ export default function RootLayout({ hoverOverlay = createHoverOverlay(target); } - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -851,7 +833,7 @@ export default function RootLayout({ e.preventDefault(); e.stopPropagation(); - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target)) return; if (selectedElement && selectedElement !== target) { @@ -896,8 +878,7 @@ export default function RootLayout({ hoveredElement = null; } - const elementInfo = getElementInfo(target, true); - selectedElement.dataset.webildSelector = elementInfo.selector; + selectedElement.dataset.webildSelector = elementInfo.selector; showElementTypeLabel(target, elementInfo.elementType); window.parent.postMessage({ @@ -980,8 +961,7 @@ export default function RootLayout({ isScrolling = false; if (lastMouseX > 0 && lastMouseY > 0) { - const target = getMostSpecificElement(lastMouseX, lastMouseY); - if (target && isValidElement(target) && target !== selectedElement) { + if (target && isValidElement(target) && target !== selectedElement) { hoveredElement = target; const computedStyle = window.getComputedStyle(target); @@ -995,8 +975,7 @@ export default function RootLayout({ hoveredElement.classList.add(hoverClass); hoverOverlay = createHoverOverlay(target); - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -1019,8 +998,7 @@ export default function RootLayout({ const saveChangeToStorage = (change) => { try { - const storageKey = getStorageKey(); - const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); + const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); const filteredChanges = existingChanges.filter(c => { return !(c.oldValue === change.oldValue && c.sectionId === change.sectionId); @@ -1040,8 +1018,7 @@ export default function RootLayout({ const clearLocalChanges = () => { try { - const storageKey = getStorageKey(); - localStorage.removeItem(storageKey); + localStorage.removeItem(storageKey); window.parent.postMessage({ type: 'webild-local-changes-cleared', data: {} @@ -1090,8 +1067,7 @@ export default function RootLayout({ if (e.data.type === 'webild-cancel-changes') { try { - const storageKey = getStorageKey(); - const savedChanges = localStorage.getItem(storageKey); + const savedChanges = localStorage.getItem(storageKey); if (savedChanges) { const changes = JSON.parse(savedChanges); changes.forEach(change => { @@ -1113,8 +1089,7 @@ export default function RootLayout({ if (isBackground) { element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : ''; } else { - const oldMediaType = getMediaTypeFromUrl(change.oldValue); - if (revertTag === 'video' && oldMediaType === 'image') { + if (revertTag === 'video' && oldMediaType === 'image') { swapMediaElement(element, 'img', change.oldValue); } else if (revertTag === 'img' && oldMediaType === 'video') { swapMediaElement(element, 'video', change.oldValue); @@ -1162,8 +1137,7 @@ export default function RootLayout({ const el = textElements[i]; if (isTextElement(el) && el.textContent.trim() === (oldValue || '').trim()) { element = el; - const newSelector = getUniqueSelector(element, true); - if (newSelector) { + if (newSelector) { element.dataset.webildSelector = newSelector; } break; @@ -1254,10 +1228,8 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'img') { oldValue = element.src; - const newMediaType = getMediaTypeFromUrl(newSrc); - if (newMediaType === 'video' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'video', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (newMediaType === 'video' && allowMediaTypeSwap) { + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { element.src = newSrc; @@ -1265,11 +1237,9 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'video') { oldValue = element.src || element.currentSrc || ''; - const newMediaType = getMediaTypeFromUrl(newSrc); - const sources = element.querySelectorAll('source'); + const sources = element.querySelectorAll('source'); if (newMediaType === 'image' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'img', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { if (sources.length > 0) { @@ -1291,8 +1261,7 @@ export default function RootLayout({ } if (replaced) { - const elementInfo = getElementInfo(element); - + let cleanOldValue = oldValue; if (oldValue.includes('url(')) { const urlMatch = oldValue.match(/url(['"]?([^'")]+)['"]?)/); @@ -1363,13 +1332,7 @@ export default function RootLayout({ } }, true); - const urlCheckInterval = setInterval(() => { - if (lastPathname !== window.location.pathname) { - lastPathname = window.location.pathname; - notifyPageChange(); - } - }, 500); - + notifyPageChange(); window.webildCleanup = () => { @@ -1655,9 +1618,7 @@ export default function RootLayout({ const getElementInfo = (element, assignId = false) => { const rect = element.getBoundingClientRect(); const tagName = element.tagName.toLowerCase(); - const selector = getUniqueSelector(element, assignId); - const sectionId = getSectionId(element); - + let className = undefined; try { if (element.className) { @@ -1685,8 +1646,7 @@ export default function RootLayout({ }; if (tagName === 'img') { - const originalSrc = extractOriginalUrl(element.src); - info.imageData = { + info.imageData = { src: originalSrc, alt: element.alt || undefined, naturalWidth: element.naturalWidth, @@ -1697,8 +1657,7 @@ export default function RootLayout({ if (tagName === 'video') { const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || ''; - const resolvedSrc = extractOriginalUrl(rawSrc); - info.imageData = { + info.imageData = { src: resolvedSrc, alt: element.getAttribute('aria-label') || undefined, isBackground: false, @@ -1711,8 +1670,7 @@ export default function RootLayout({ if (backgroundImage && backgroundImage !== 'none') { const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/); if (urlMatch) { - const originalBgSrc = extractOriginalUrl(urlMatch[1]); - if (tagName !== 'img') { + if (tagName !== 'img') { info.imageData = { src: originalBgSrc, isBackground: true @@ -1724,8 +1682,7 @@ export default function RootLayout({ } } - const elementType = getElementType(element); - info.elementType = elementType; + info.elementType = elementType; if (elementType === 'Button') { const buttonText = element.textContent?.trim() || element.value || element.getAttribute('aria-label') || ''; @@ -1818,13 +1775,11 @@ export default function RootLayout({ }; const isTextElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Text'; + return elementType === 'Text'; }; const isButtonElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Button'; + return elementType === 'Button'; }; const updateButtonText = (element, newText) => { @@ -1899,8 +1854,7 @@ export default function RootLayout({ }; const handleInput = () => { - const elementInfo = getElementInfo(element); - let currentText = element.textContent; + let currentText = element.textContent; // Ensure there's always at least a space to keep the element editable if (currentText === '' || currentText === null || currentText.length === 0) { @@ -2013,8 +1967,7 @@ export default function RootLayout({ }, '*'); if (save && originalContent !== element.textContent) { - const elementInfo = getElementInfo(element); - let finalText = element.textContent; + let finalText = element.textContent; // Trim the final text and convert space-only to empty string for saving if (finalText === ' ' || finalText.trim() === '') { @@ -2143,7 +2096,7 @@ export default function RootLayout({ lastMouseX = e.clientX; lastMouseY = e.clientY; - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target) || target === hoveredElement || target === selectedElement) { return; @@ -2175,8 +2128,7 @@ export default function RootLayout({ hoverOverlay = createHoverOverlay(target); } - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -2218,7 +2170,7 @@ export default function RootLayout({ e.preventDefault(); e.stopPropagation(); - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target)) return; if (selectedElement && selectedElement !== target) { @@ -2263,8 +2215,7 @@ export default function RootLayout({ hoveredElement = null; } - const elementInfo = getElementInfo(target, true); - selectedElement.dataset.webildSelector = elementInfo.selector; + selectedElement.dataset.webildSelector = elementInfo.selector; showElementTypeLabel(target, elementInfo.elementType); window.parent.postMessage({ @@ -2347,8 +2298,7 @@ export default function RootLayout({ isScrolling = false; if (lastMouseX > 0 && lastMouseY > 0) { - const target = getMostSpecificElement(lastMouseX, lastMouseY); - if (target && isValidElement(target) && target !== selectedElement) { + if (target && isValidElement(target) && target !== selectedElement) { hoveredElement = target; const computedStyle = window.getComputedStyle(target); @@ -2362,8 +2312,7 @@ export default function RootLayout({ hoveredElement.classList.add(hoverClass); hoverOverlay = createHoverOverlay(target); - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -2386,8 +2335,7 @@ export default function RootLayout({ const saveChangeToStorage = (change) => { try { - const storageKey = getStorageKey(); - const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); + const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); const filteredChanges = existingChanges.filter(c => { return !(c.oldValue === change.oldValue && c.sectionId === change.sectionId); @@ -2407,8 +2355,7 @@ export default function RootLayout({ const clearLocalChanges = () => { try { - const storageKey = getStorageKey(); - localStorage.removeItem(storageKey); + localStorage.removeItem(storageKey); window.parent.postMessage({ type: 'webild-local-changes-cleared', data: {} @@ -2457,8 +2404,7 @@ export default function RootLayout({ if (e.data.type === 'webild-cancel-changes') { try { - const storageKey = getStorageKey(); - const savedChanges = localStorage.getItem(storageKey); + const savedChanges = localStorage.getItem(storageKey); if (savedChanges) { const changes = JSON.parse(savedChanges); changes.forEach(change => { @@ -2480,8 +2426,7 @@ export default function RootLayout({ if (isBackground) { element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : ''; } else { - const oldMediaType = getMediaTypeFromUrl(change.oldValue); - if (revertTag === 'video' && oldMediaType === 'image') { + if (revertTag === 'video' && oldMediaType === 'image') { swapMediaElement(element, 'img', change.oldValue); } else if (revertTag === 'img' && oldMediaType === 'video') { swapMediaElement(element, 'video', change.oldValue); @@ -2529,8 +2474,7 @@ export default function RootLayout({ const el = textElements[i]; if (isTextElement(el) && el.textContent.trim() === (oldValue || '').trim()) { element = el; - const newSelector = getUniqueSelector(element, true); - if (newSelector) { + if (newSelector) { element.dataset.webildSelector = newSelector; } break; @@ -2621,10 +2565,8 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'img') { oldValue = element.src; - const newMediaType = getMediaTypeFromUrl(newSrc); - if (newMediaType === 'video' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'video', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (newMediaType === 'video' && allowMediaTypeSwap) { + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { element.src = newSrc; @@ -2632,11 +2574,9 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'video') { oldValue = element.src || element.currentSrc || ''; - const newMediaType = getMediaTypeFromUrl(newSrc); - const sources = element.querySelectorAll('source'); + const sources = element.querySelectorAll('source'); if (newMediaType === 'image' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'img', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { if (sources.length > 0) { @@ -2658,8 +2598,7 @@ export default function RootLayout({ } if (replaced) { - const elementInfo = getElementInfo(element); - + let cleanOldValue = oldValue; if (oldValue.includes('url(')) { const urlMatch = oldValue.match(/url(['"]?([^'")]+)['"]?)/); @@ -2730,13 +2669,7 @@ export default function RootLayout({ } }, true); - const urlCheckInterval = setInterval(() => { - if (lastPathname !== window.location.pathname) { - lastPathname = window.location.pathname; - notifyPageChange(); - } - }, 500); - + notifyPageChange(); window.webildCleanup = () => { -- 2.49.1 From 566e0f3c182ae5a656b746192ce5693bfca1e474 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:28 +0000 Subject: [PATCH 13/39] Update registry/components/HeroBillboardDashboard.json --- registry/components/HeroBillboardDashboard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroBillboardDashboard.json b/registry/components/HeroBillboardDashboard.json index 3756727..c8ad28c 100644 --- a/registry/components/HeroBillboardDashboard.json +++ b/registry/components/HeroBillboardDashboard.json @@ -31,7 +31,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://example.com' }", + "{ text: 'Download Now', href: 'https://example.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." -- 2.49.1 From 9444747c7cc1d704fbbd724241bb3df291794d35 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:29 +0000 Subject: [PATCH 14/39] Update registry/components/HeroBillboardRotatedCarousel.json --- registry/components/HeroBillboardRotatedCarousel.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroBillboardRotatedCarousel.json b/registry/components/HeroBillboardRotatedCarousel.json index 30ec21f..60816a1 100644 --- a/registry/components/HeroBillboardRotatedCarousel.json +++ b/registry/components/HeroBillboardRotatedCarousel.json @@ -60,7 +60,7 @@ "ariaLabel?": "string (default: 'Hero section')", "className?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From cb09fe667c3189d80011c7c6b219ddc7ea4fac3d Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:29 +0000 Subject: [PATCH 15/39] Update registry/components/HeroBillboardScroll.json --- registry/components/HeroBillboardScroll.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroBillboardScroll.json b/registry/components/HeroBillboardScroll.json index 49f4d47..841bdcb 100644 --- a/registry/components/HeroBillboardScroll.json +++ b/registry/components/HeroBillboardScroll.json @@ -63,7 +63,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', onClick: () => console.log('Get Started clicked') }", + "{ text: 'Download Now', onClick: () => console.log('Download Now clicked') }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -85,7 +85,7 @@ "ariaLabel?": "string (default: 'Hero section')", "className?": "string" }, - "usageExample": "\n console.log('Get Started clicked') }, { text: 'Learn More', href: 'about' }]} \n />\n", + "usageExample": "\n console.log('Download Now clicked') }, { text: 'Learn More', href: 'about' }]} \n />\n", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From a4bb39654b3a4523b9814529fa9800d658bedc6c Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:30 +0000 Subject: [PATCH 16/39] Update registry/components/HeroBillboardTestimonial.json --- registry/components/HeroBillboardTestimonial.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroBillboardTestimonial.json b/registry/components/HeroBillboardTestimonial.json index da62065..0ccf8d5 100644 --- a/registry/components/HeroBillboardTestimonial.json +++ b/registry/components/HeroBillboardTestimonial.json @@ -68,7 +68,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://example.com' }", + "{ text: 'Download Now', href: 'https://example.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -124,7 +124,7 @@ "marqueeTextClassName?": "string", "marqueeIconClassName?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages with social proof", "Use for product showcases with testimonials", -- 2.49.1 From 16232f4ea0f4c1c827906917e01a29de71c0958a Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:31 +0000 Subject: [PATCH 17/39] Update registry/components/HeroCarouselLogo.json --- registry/components/HeroCarouselLogo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroCarouselLogo.json b/registry/components/HeroCarouselLogo.json index d9b8915..0004800 100644 --- a/registry/components/HeroCarouselLogo.json +++ b/registry/components/HeroCarouselLogo.json @@ -42,7 +42,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://github.com' }", + "{ text: 'Download Now', href: 'https://github.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Buttons are required (cannot be empty array). Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -59,7 +59,7 @@ "ariaLabel?": "string (default: 'Hero section')", "className?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From 895c6da0bb2123e5aae1bef9b85c8cb4698fc402 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:31 +0000 Subject: [PATCH 18/39] Update registry/components/HeroCentered.json --- registry/components/HeroCentered.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroCentered.json b/registry/components/HeroCentered.json index e43ea33..365722c 100644 --- a/registry/components/HeroCentered.json +++ b/registry/components/HeroCentered.json @@ -82,7 +82,7 @@ "marqueeTextClassName?": "string", "marqueeIconClassName?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for impactful landing pages with social proof emphasis", "Include avatars for social proof", -- 2.49.1 From 1c28afff811b71db06b7c4a2dd5f021c06b0b21a Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:32 +0000 Subject: [PATCH 19/39] Update registry/components/HeroLogo.json --- registry/components/HeroLogo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroLogo.json b/registry/components/HeroLogo.json index 8bb2601..1727c96 100644 --- a/registry/components/HeroLogo.json +++ b/registry/components/HeroLogo.json @@ -47,7 +47,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://github.com' }", + "{ text: 'Download Now', href: 'https://github.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Buttons are required (cannot be empty array). Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -67,7 +67,7 @@ "ariaLabel?": "string (default: 'Hero section')", "className?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From 0bfa9d9de750fe95548d37b09289494dfb1cb405 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:32 +0000 Subject: [PATCH 20/39] Update registry/components/HeroLogoBillboardSplit.json --- registry/components/HeroLogoBillboardSplit.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroLogoBillboardSplit.json b/registry/components/HeroLogoBillboardSplit.json index d9f24b3..2452f82 100644 --- a/registry/components/HeroLogoBillboardSplit.json +++ b/registry/components/HeroLogoBillboardSplit.json @@ -78,7 +78,7 @@ "ariaLabel?": "string (default: 'Hero section')", "className?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From fb2ee70e8464e4c0934ae51200f8f4289944d217 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:33 +0000 Subject: [PATCH 21/39] Update registry/components/HeroOverlay.json --- registry/components/HeroOverlay.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroOverlay.json b/registry/components/HeroOverlay.json index d82dd65..b04547d 100644 --- a/registry/components/HeroOverlay.json +++ b/registry/components/HeroOverlay.json @@ -67,7 +67,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://example.com' }", + "{ text: 'Download Now', href: 'https://example.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -91,7 +91,7 @@ "ariaLabel?": "string (default: 'Hero section')", "className?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From c5f23545d24c804f317b82d1ae2ef07e230e6453 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:34 +0000 Subject: [PATCH 22/39] Update registry/components/HeroSignup.json --- registry/components/HeroSignup.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroSignup.json b/registry/components/HeroSignup.json index 6e8713f..e2c3060 100644 --- a/registry/components/HeroSignup.json +++ b/registry/components/HeroSignup.json @@ -43,7 +43,7 @@ "tagIcon?": "LucideIcon", "tagAnimation?": "'none' | 'opacity' | 'slide-up' | 'blur-reveal'", "inputPlaceholder?": "string (default: 'Enter your email')", - "buttonText?": "string (default: 'Get Started')", + "buttonText?": "string (default: 'Download Now')", "onSubmit?": "(email: string) => void", "ariaLabel?": "string (default: 'Hero section')", "className?": "string", -- 2.49.1 From b7dcad8d9d2907fc7f755dd6ea584772435f2d8b Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:35 +0000 Subject: [PATCH 23/39] Update registry/components/HeroSplit.json --- registry/components/HeroSplit.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroSplit.json b/registry/components/HeroSplit.json index 0b6adf2..952d9eb 100644 --- a/registry/components/HeroSplit.json +++ b/registry/components/HeroSplit.json @@ -56,7 +56,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://example.com' }", + "{ text: 'Download Now', href: 'https://example.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." -- 2.49.1 From 95e02b1077151eebf1b82000b93a2ac5ed701803 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:35 +0000 Subject: [PATCH 24/39] Update registry/components/HeroSplitDoubleCarousel.json --- registry/components/HeroSplitDoubleCarousel.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroSplitDoubleCarousel.json b/registry/components/HeroSplitDoubleCarousel.json index 9f056f7..5bf5b10 100644 --- a/registry/components/HeroSplitDoubleCarousel.json +++ b/registry/components/HeroSplitDoubleCarousel.json @@ -60,7 +60,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://example.com' }", + "{ text: 'Download Now', href: 'https://example.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -86,7 +86,7 @@ "showMarqueeCard?": "boolean (default: true)", "className?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages with visual portfolios", "Use for image galleries and creative showcases", -- 2.49.1 From 6bd71f249ea74177cd124452de8431f78be686d2 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:36 +0000 Subject: [PATCH 25/39] Update registry/components/HeroSplitKpi.json --- registry/components/HeroSplitKpi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/HeroSplitKpi.json b/registry/components/HeroSplitKpi.json index 2e0daf6..d1503aa 100644 --- a/registry/components/HeroSplitKpi.json +++ b/registry/components/HeroSplitKpi.json @@ -89,7 +89,7 @@ "imagePosition?": "'left' | 'right' (default: 'right')", "className?": "string" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for landing pages", "Use for feature showcases", -- 2.49.1 From 93896e9a91fde21dabafe8d4617ec791b57e0c8e Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:37 +0000 Subject: [PATCH 26/39] Update registry/components/HeroSplitTestimonial.json --- registry/components/HeroSplitTestimonial.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/HeroSplitTestimonial.json b/registry/components/HeroSplitTestimonial.json index 8309508..97a6117 100644 --- a/registry/components/HeroSplitTestimonial.json +++ b/registry/components/HeroSplitTestimonial.json @@ -76,7 +76,7 @@ "props": "Partial - Additional button props like className, textClassName (optional)" }, "examples": [ - "{ text: 'Get Started', href: 'https://example.com' }", + "{ text: 'Download Now', href: 'https://example.com' }", "{ text: 'Learn More', href: 'about' }" ], "note": "Button variant is controlled by ThemeProvider's defaultButtonVariant. Border radius is controlled by ThemeProvider's borderRadius (options: 'sharp', 'rounded', 'soft', 'pill'). All sections should be wrapped in a single ThemeProvider at the app/page level to maintain consistent styling across the entire site." @@ -134,7 +134,7 @@ "marqueeTextClassName?": "string", "marqueeIconClassName?": "string" }, - "usageExample": "\n \n", + "usageExample": "\n \n", "do": [ "Use for landing pages with social proof", "Use for product showcases with testimonials", -- 2.49.1 From c83a44c33fc5906e47a51f602145bd95044db6d1 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:38 +0000 Subject: [PATCH 27/39] Update registry/components/InlineImageSplitTextAbout.json --- registry/components/InlineImageSplitTextAbout.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/InlineImageSplitTextAbout.json b/registry/components/InlineImageSplitTextAbout.json index daf1bcc..7e1d144 100644 --- a/registry/components/InlineImageSplitTextAbout.json +++ b/registry/components/InlineImageSplitTextAbout.json @@ -46,7 +46,7 @@ "ariaLabel?": "string (default: 'About section')", "className?": "string" }, - "usageExample": "// Wrap in ThemeProvider\n\n \n", + "usageExample": "// Wrap in ThemeProvider\n\n \n", "do": [ "Use for about pages", "Use for company information", -- 2.49.1 From 200af0249616ef39c42e30d10491f16b0b2563e0 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:38 +0000 Subject: [PATCH 28/39] Update registry/components/NavbarLayoutFloatingInline.json --- registry/components/NavbarLayoutFloatingInline.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/NavbarLayoutFloatingInline.json b/registry/components/NavbarLayoutFloatingInline.json index 88ac55d..87ea079 100644 --- a/registry/components/NavbarLayoutFloatingInline.json +++ b/registry/components/NavbarLayoutFloatingInline.json @@ -17,7 +17,7 @@ "required": true, "minChars": 2, "maxChars": 24, - "example": "Get Started" + "example": "Download Now" }, "href": { "required": false, -- 2.49.1 From f099812827d14ec8e70f1d1ef86b4dc48120f7c8 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:39 +0000 Subject: [PATCH 29/39] Update registry/components/NavbarLayoutFloatingOverlay.json --- registry/components/NavbarLayoutFloatingOverlay.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/NavbarLayoutFloatingOverlay.json b/registry/components/NavbarLayoutFloatingOverlay.json index 16b67d5..33aeed7 100644 --- a/registry/components/NavbarLayoutFloatingOverlay.json +++ b/registry/components/NavbarLayoutFloatingOverlay.json @@ -17,7 +17,7 @@ "required": true, "minChars": 2, "maxChars": 24, - "example": "Get Started" + "example": "Download Now" }, "href": { "required": false, -- 2.49.1 From 0717fe06e5fc232c981ab1b78d595e82a9057cd7 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:40 +0000 Subject: [PATCH 30/39] Update registry/components/NavbarStyleCentered.json --- registry/components/NavbarStyleCentered.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/components/NavbarStyleCentered.json b/registry/components/NavbarStyleCentered.json index 9785b4b..1c06f33 100644 --- a/registry/components/NavbarStyleCentered.json +++ b/registry/components/NavbarStyleCentered.json @@ -17,7 +17,7 @@ "required": true, "minChars": 2, "maxChars": 15, - "example": "Get Started" + "example": "Download Now" }, "href": { "required": false, @@ -55,7 +55,7 @@ "brandName?": "string (default: 'Webild')", "className?": "string (default: '')" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for feature showcases", "Use for capability displays", -- 2.49.1 From 4d5f0f128e3d577250284c52acf89a55d1aa7a0d Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:40 +0000 Subject: [PATCH 31/39] Update registry/components/PricingCardEight.json --- registry/components/PricingCardEight.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/PricingCardEight.json b/registry/components/PricingCardEight.json index bab897b..3b50bba 100644 --- a/registry/components/PricingCardEight.json +++ b/registry/components/PricingCardEight.json @@ -65,7 +65,7 @@ "ariaLabel?": "string (default: 'Pricing section')", "className?": "string" }, - "usageExample": "", + "usageExample": "", "do": [ "Use for feature showcases", "Use for capability displays", -- 2.49.1 From 4bd3c6a0dbac9140f5de42a451e0ccf9129896a7 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:41 +0000 Subject: [PATCH 32/39] Update registry/components/PricingCardTwo.json --- registry/components/PricingCardTwo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/PricingCardTwo.json b/registry/components/PricingCardTwo.json index bd62bfb..ad2300c 100644 --- a/registry/components/PricingCardTwo.json +++ b/registry/components/PricingCardTwo.json @@ -94,7 +94,7 @@ "ariaLabel?": "string (default: 'Pricing section')", "className?": "string" }, - "usageExample": " console.log('clicked') }, { text: 'Chat to Sales', onClick: () => console.log('chat') }], features: ['Up to 10 team members', '100GB storage', 'Priority support'] }]} title=\"Choose Your Plan\" description=\"Find the perfect plan for your needs\" textboxLayout=\"default\" animationType=\"slide-up\" useInvertedBackground={false} />", + "usageExample": " console.log('clicked') }, { text: 'Chat to Sales', onClick: () => console.log('chat') }], features: ['Up to 10 team members', '100GB storage', 'Priority support'] }]} title=\"Choose Your Plan\" description=\"Find the perfect plan for your needs\" textboxLayout=\"default\" animationType=\"slide-up\" useInvertedBackground={false} />", "do": [ "Use for feature showcases", "Use for capability displays", -- 2.49.1 From eb962a3200b748f1212a471451da451d756326d6 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:41 +0000 Subject: [PATCH 33/39] Update registry/components/TextAbout.json --- registry/components/TextAbout.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/components/TextAbout.json b/registry/components/TextAbout.json index 0fcdbaa..73f1b5c 100644 --- a/registry/components/TextAbout.json +++ b/registry/components/TextAbout.json @@ -32,7 +32,7 @@ "ariaLabel?": "string (default: 'About section')", "className?": "string" }, - "usageExample": "// Wrap in ThemeProvider\n\n \n", + "usageExample": "// Wrap in ThemeProvider\n\n \n", "do": [ "Use for feature showcases", "Use for capability displays", -- 2.49.1 From b703be17d443f0e9fcd56cd57274701ea4303080 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:42 +0000 Subject: [PATCH 34/39] Update registry/schemas/HeroSignup.schema.json --- registry/schemas/HeroSignup.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/schemas/HeroSignup.schema.json b/registry/schemas/HeroSignup.schema.json index 385d339..d60b8f7 100644 --- a/registry/schemas/HeroSignup.schema.json +++ b/registry/schemas/HeroSignup.schema.json @@ -8,7 +8,7 @@ "tagIcon?": "LucideIcon", "tagAnimation?": "'none' | 'opacity' | 'slide-up' | 'blur-reveal'", "inputPlaceholder?": "string (default: 'Enter your email')", - "buttonText?": "string (default: 'Get Started')", + "buttonText?": "string (default: 'Download Now')", "onSubmit?": "(email: string) => void", "ariaLabel?": "string (default: 'Hero section')", "className?": "string", -- 2.49.1 From 6d07833c068b663996edfa0a8e4276d1fa6b0ba8 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:42 +0000 Subject: [PATCH 35/39] Update src/app/layout.tsx --- src/app/layout.tsx | 183 +++++++++++++++++++++++++++++++-------------- 1 file changed, 125 insertions(+), 58 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 162d9ab..4883afe 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,8 +6,18 @@ import "./globals.css"; import { ServiceWrapper } from "@/components/ServiceWrapper"; import Tag from "@/tag/Tag"; +const halant = Halant({ + variable: "--font-halant", subsets: ["latin"], + weight: ["300", "400", "500", "600", "700"], +}); +const inter = Inter({ + variable: "--font-inter", subsets: ["latin"], +}); +const openSans = Open_Sans({ + variable: "--font-open-sans", subsets: ["latin"], +}); export const metadata: Metadata = { title: "Torah Lock - iOS Torah Lock for Jewish Morning Prayers", description: "Start your day with Hashem. Torah Lock is a beautiful iOS app designed to help Jewish users pray every morning with guided prayers, reminders, and community connection.", keywords: "prayer app, iOS, Jewish, morning prayers, spiritual growth, Torah Lock", metadataBase: new URL("https://shachar-prayer.com"), @@ -23,11 +33,6 @@ export const metadata: Metadata = { }, }; -const inter = Inter({ - variable: "--font-inter", - subsets: ["latin"], -}); - export default function RootLayout({ children, }: Readonly<{ @@ -36,7 +41,9 @@ export default function RootLayout({ return ( - + {children} @@ -281,7 +288,9 @@ export default function RootLayout({ const getElementInfo = (element, assignId = false) => { const rect = element.getBoundingClientRect(); const tagName = element.tagName.toLowerCase(); - + const selector = getUniqueSelector(element, assignId); + const sectionId = getSectionId(element); + let className = undefined; try { if (element.className) { @@ -309,7 +318,8 @@ export default function RootLayout({ }; if (tagName === 'img') { - info.imageData = { + const originalSrc = extractOriginalUrl(element.src); + info.imageData = { src: originalSrc, alt: element.alt || undefined, naturalWidth: element.naturalWidth, @@ -320,7 +330,8 @@ export default function RootLayout({ if (tagName === 'video') { const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || ''; - info.imageData = { + const resolvedSrc = extractOriginalUrl(rawSrc); + info.imageData = { src: resolvedSrc, alt: element.getAttribute('aria-label') || undefined, isBackground: false, @@ -333,7 +344,8 @@ export default function RootLayout({ if (backgroundImage && backgroundImage !== 'none') { const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/); if (urlMatch) { - if (tagName !== 'img') { + const originalBgSrc = extractOriginalUrl(urlMatch[1]); + if (tagName !== 'img') { info.imageData = { src: originalBgSrc, isBackground: true @@ -345,7 +357,8 @@ export default function RootLayout({ } } - info.elementType = elementType; + const elementType = getElementType(element); + info.elementType = elementType; if (elementType === 'Button') { const buttonText = element.textContent?.trim() || element.value || element.getAttribute('aria-label') || ''; @@ -438,11 +451,13 @@ export default function RootLayout({ }; const isTextElement = (element) => { - return elementType === 'Text'; + const elementType = getElementType(element); + return elementType === 'Text'; }; const isButtonElement = (element) => { - return elementType === 'Button'; + const elementType = getElementType(element); + return elementType === 'Button'; }; const updateButtonText = (element, newText) => { @@ -517,7 +532,8 @@ export default function RootLayout({ }; const handleInput = () => { - let currentText = element.textContent; + const elementInfo = getElementInfo(element); + let currentText = element.textContent; // Ensure there's always at least a space to keep the element editable if (currentText === '' || currentText === null || currentText.length === 0) { @@ -630,7 +646,8 @@ export default function RootLayout({ }, '*'); if (save && originalContent !== element.textContent) { - let finalText = element.textContent; + const elementInfo = getElementInfo(element); + let finalText = element.textContent; // Trim the final text and convert space-only to empty string for saving if (finalText === ' ' || finalText.trim() === '') { @@ -759,7 +776,7 @@ export default function RootLayout({ lastMouseX = e.clientX; lastMouseY = e.clientY; - || e.target; + const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; if (!isValidElement(target) || target === hoveredElement || target === selectedElement) { return; @@ -791,7 +808,8 @@ export default function RootLayout({ hoverOverlay = createHoverOverlay(target); } - showElementTypeLabel(target, elementType); + const elementType = getElementType(target); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -833,7 +851,7 @@ export default function RootLayout({ e.preventDefault(); e.stopPropagation(); - || e.target; + const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; if (!isValidElement(target)) return; if (selectedElement && selectedElement !== target) { @@ -878,7 +896,8 @@ export default function RootLayout({ hoveredElement = null; } - selectedElement.dataset.webildSelector = elementInfo.selector; + const elementInfo = getElementInfo(target, true); + selectedElement.dataset.webildSelector = elementInfo.selector; showElementTypeLabel(target, elementInfo.elementType); window.parent.postMessage({ @@ -961,7 +980,8 @@ export default function RootLayout({ isScrolling = false; if (lastMouseX > 0 && lastMouseY > 0) { - if (target && isValidElement(target) && target !== selectedElement) { + const target = getMostSpecificElement(lastMouseX, lastMouseY); + if (target && isValidElement(target) && target !== selectedElement) { hoveredElement = target; const computedStyle = window.getComputedStyle(target); @@ -975,7 +995,8 @@ export default function RootLayout({ hoveredElement.classList.add(hoverClass); hoverOverlay = createHoverOverlay(target); - showElementTypeLabel(target, elementType); + const elementType = getElementType(target); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -998,7 +1019,8 @@ export default function RootLayout({ const saveChangeToStorage = (change) => { try { - const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); + const storageKey = getStorageKey(); + const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); const filteredChanges = existingChanges.filter(c => { return !(c.oldValue === change.oldValue && c.sectionId === change.sectionId); @@ -1018,7 +1040,8 @@ export default function RootLayout({ const clearLocalChanges = () => { try { - localStorage.removeItem(storageKey); + const storageKey = getStorageKey(); + localStorage.removeItem(storageKey); window.parent.postMessage({ type: 'webild-local-changes-cleared', data: {} @@ -1067,7 +1090,8 @@ export default function RootLayout({ if (e.data.type === 'webild-cancel-changes') { try { - const savedChanges = localStorage.getItem(storageKey); + const storageKey = getStorageKey(); + const savedChanges = localStorage.getItem(storageKey); if (savedChanges) { const changes = JSON.parse(savedChanges); changes.forEach(change => { @@ -1089,7 +1113,8 @@ export default function RootLayout({ if (isBackground) { element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : ''; } else { - if (revertTag === 'video' && oldMediaType === 'image') { + 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); @@ -1137,7 +1162,8 @@ export default function RootLayout({ const el = textElements[i]; if (isTextElement(el) && el.textContent.trim() === (oldValue || '').trim()) { element = el; - if (newSelector) { + const newSelector = getUniqueSelector(element, true); + if (newSelector) { element.dataset.webildSelector = newSelector; } break; @@ -1228,8 +1254,10 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'img') { oldValue = element.src; - if (newMediaType === 'video' && allowMediaTypeSwap) { - if (selectedElement === element) selectedElement = swapped; + 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; @@ -1237,9 +1265,11 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'video') { oldValue = element.src || element.currentSrc || ''; - const sources = element.querySelectorAll('source'); + const newMediaType = getMediaTypeFromUrl(newSrc); + const sources = element.querySelectorAll('source'); if (newMediaType === 'image' && allowMediaTypeSwap) { - if (selectedElement === element) selectedElement = swapped; + const swapped = swapMediaElement(element, 'img', newSrc); + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { if (sources.length > 0) { @@ -1261,7 +1291,8 @@ export default function RootLayout({ } if (replaced) { - + const elementInfo = getElementInfo(element); + let cleanOldValue = oldValue; if (oldValue.includes('url(')) { const urlMatch = oldValue.match(/url(['"]?([^'")]+)['"]?)/); @@ -1332,7 +1363,13 @@ export default function RootLayout({ } }, true); - + const urlCheckInterval = setInterval(() => { + if (lastPathname !== window.location.pathname) { + lastPathname = window.location.pathname; + notifyPageChange(); + } + }, 500); + notifyPageChange(); window.webildCleanup = () => { @@ -1618,7 +1655,9 @@ export default function RootLayout({ const getElementInfo = (element, assignId = false) => { const rect = element.getBoundingClientRect(); const tagName = element.tagName.toLowerCase(); - + const selector = getUniqueSelector(element, assignId); + const sectionId = getSectionId(element); + let className = undefined; try { if (element.className) { @@ -1646,7 +1685,8 @@ export default function RootLayout({ }; if (tagName === 'img') { - info.imageData = { + const originalSrc = extractOriginalUrl(element.src); + info.imageData = { src: originalSrc, alt: element.alt || undefined, naturalWidth: element.naturalWidth, @@ -1657,7 +1697,8 @@ export default function RootLayout({ if (tagName === 'video') { const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || ''; - info.imageData = { + const resolvedSrc = extractOriginalUrl(rawSrc); + info.imageData = { src: resolvedSrc, alt: element.getAttribute('aria-label') || undefined, isBackground: false, @@ -1670,7 +1711,8 @@ export default function RootLayout({ if (backgroundImage && backgroundImage !== 'none') { const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/); if (urlMatch) { - if (tagName !== 'img') { + const originalBgSrc = extractOriginalUrl(urlMatch[1]); + if (tagName !== 'img') { info.imageData = { src: originalBgSrc, isBackground: true @@ -1682,7 +1724,8 @@ export default function RootLayout({ } } - info.elementType = elementType; + const elementType = getElementType(element); + info.elementType = elementType; if (elementType === 'Button') { const buttonText = element.textContent?.trim() || element.value || element.getAttribute('aria-label') || ''; @@ -1775,11 +1818,13 @@ export default function RootLayout({ }; const isTextElement = (element) => { - return elementType === 'Text'; + const elementType = getElementType(element); + return elementType === 'Text'; }; const isButtonElement = (element) => { - return elementType === 'Button'; + const elementType = getElementType(element); + return elementType === 'Button'; }; const updateButtonText = (element, newText) => { @@ -1854,7 +1899,8 @@ export default function RootLayout({ }; const handleInput = () => { - let currentText = element.textContent; + const elementInfo = getElementInfo(element); + let currentText = element.textContent; // Ensure there's always at least a space to keep the element editable if (currentText === '' || currentText === null || currentText.length === 0) { @@ -1967,7 +2013,8 @@ export default function RootLayout({ }, '*'); if (save && originalContent !== element.textContent) { - let finalText = element.textContent; + const elementInfo = getElementInfo(element); + let finalText = element.textContent; // Trim the final text and convert space-only to empty string for saving if (finalText === ' ' || finalText.trim() === '') { @@ -2096,7 +2143,7 @@ export default function RootLayout({ lastMouseX = e.clientX; lastMouseY = e.clientY; - || e.target; + const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; if (!isValidElement(target) || target === hoveredElement || target === selectedElement) { return; @@ -2128,7 +2175,8 @@ export default function RootLayout({ hoverOverlay = createHoverOverlay(target); } - showElementTypeLabel(target, elementType); + const elementType = getElementType(target); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -2170,7 +2218,7 @@ export default function RootLayout({ e.preventDefault(); e.stopPropagation(); - || e.target; + const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; if (!isValidElement(target)) return; if (selectedElement && selectedElement !== target) { @@ -2215,7 +2263,8 @@ export default function RootLayout({ hoveredElement = null; } - selectedElement.dataset.webildSelector = elementInfo.selector; + const elementInfo = getElementInfo(target, true); + selectedElement.dataset.webildSelector = elementInfo.selector; showElementTypeLabel(target, elementInfo.elementType); window.parent.postMessage({ @@ -2298,7 +2347,8 @@ export default function RootLayout({ isScrolling = false; if (lastMouseX > 0 && lastMouseY > 0) { - if (target && isValidElement(target) && target !== selectedElement) { + const target = getMostSpecificElement(lastMouseX, lastMouseY); + if (target && isValidElement(target) && target !== selectedElement) { hoveredElement = target; const computedStyle = window.getComputedStyle(target); @@ -2312,7 +2362,8 @@ export default function RootLayout({ hoveredElement.classList.add(hoverClass); hoverOverlay = createHoverOverlay(target); - showElementTypeLabel(target, elementType); + const elementType = getElementType(target); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -2335,7 +2386,8 @@ export default function RootLayout({ const saveChangeToStorage = (change) => { try { - const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); + const storageKey = getStorageKey(); + const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); const filteredChanges = existingChanges.filter(c => { return !(c.oldValue === change.oldValue && c.sectionId === change.sectionId); @@ -2355,7 +2407,8 @@ export default function RootLayout({ const clearLocalChanges = () => { try { - localStorage.removeItem(storageKey); + const storageKey = getStorageKey(); + localStorage.removeItem(storageKey); window.parent.postMessage({ type: 'webild-local-changes-cleared', data: {} @@ -2404,7 +2457,8 @@ export default function RootLayout({ if (e.data.type === 'webild-cancel-changes') { try { - const savedChanges = localStorage.getItem(storageKey); + const storageKey = getStorageKey(); + const savedChanges = localStorage.getItem(storageKey); if (savedChanges) { const changes = JSON.parse(savedChanges); changes.forEach(change => { @@ -2426,7 +2480,8 @@ export default function RootLayout({ if (isBackground) { element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : ''; } else { - if (revertTag === 'video' && oldMediaType === 'image') { + 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); @@ -2474,7 +2529,8 @@ export default function RootLayout({ const el = textElements[i]; if (isTextElement(el) && el.textContent.trim() === (oldValue || '').trim()) { element = el; - if (newSelector) { + const newSelector = getUniqueSelector(element, true); + if (newSelector) { element.dataset.webildSelector = newSelector; } break; @@ -2565,8 +2621,10 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'img') { oldValue = element.src; - if (newMediaType === 'video' && allowMediaTypeSwap) { - if (selectedElement === element) selectedElement = swapped; + 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; @@ -2574,9 +2632,11 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'video') { oldValue = element.src || element.currentSrc || ''; - const sources = element.querySelectorAll('source'); + const newMediaType = getMediaTypeFromUrl(newSrc); + const sources = element.querySelectorAll('source'); if (newMediaType === 'image' && allowMediaTypeSwap) { - if (selectedElement === element) selectedElement = swapped; + const swapped = swapMediaElement(element, 'img', newSrc); + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { if (sources.length > 0) { @@ -2598,7 +2658,8 @@ export default function RootLayout({ } if (replaced) { - + const elementInfo = getElementInfo(element); + let cleanOldValue = oldValue; if (oldValue.includes('url(')) { const urlMatch = oldValue.match(/url(['"]?([^'")]+)['"]?)/); @@ -2669,7 +2730,13 @@ export default function RootLayout({ } }, true); - + const urlCheckInterval = setInterval(() => { + if (lastPathname !== window.location.pathname) { + lastPathname = window.location.pathname; + notifyPageChange(); + } + }, 500); + notifyPageChange(); window.webildCleanup = () => { -- 2.49.1 From d3b6f0cefe7ded5dcd1b35486cda90e411ec9779 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:43 +0000 Subject: [PATCH 36/39] Update src/app/page.tsx --- src/app/page.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index d7c0847..72998d3 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -41,11 +41,11 @@ export default function LandingPage() {
-- 2.49.1 From 90620ba24e77e50346f524892df27ad97a0fdc44 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:43 +0000 Subject: [PATCH 37/39] Update src/components/sections/hero/HeroSignup.tsx --- src/components/sections/hero/HeroSignup.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sections/hero/HeroSignup.tsx b/src/components/sections/hero/HeroSignup.tsx index d6867a1..1b109dd 100644 --- a/src/components/sections/hero/HeroSignup.tsx +++ b/src/components/sections/hero/HeroSignup.tsx @@ -60,7 +60,7 @@ const HeroSignup = ({ tagIcon, tagAnimation, inputPlaceholder = "Enter your email", - buttonText = "Get Started", + buttonText = "Download Now", onSubmit, ariaLabel = "Hero section", className = "", -- 2.49.1 From 8aefc03fda7761d39bcdad6a3646a4466e6b0bbb Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:45 +0000 Subject: [PATCH 38/39] Update theme fonts --- src/app/layout.tsx | 187 +++++++++++++++------------------------------ 1 file changed, 62 insertions(+), 125 deletions(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4883afe..cf46598 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,18 +6,8 @@ import "./globals.css"; import { ServiceWrapper } from "@/components/ServiceWrapper"; import Tag from "@/tag/Tag"; -const halant = Halant({ - variable: "--font-halant", subsets: ["latin"], - weight: ["300", "400", "500", "600", "700"], -}); -const inter = Inter({ - variable: "--font-inter", subsets: ["latin"], -}); -const openSans = Open_Sans({ - variable: "--font-open-sans", subsets: ["latin"], -}); export const metadata: Metadata = { title: "Torah Lock - iOS Torah Lock for Jewish Morning Prayers", description: "Start your day with Hashem. Torah Lock is a beautiful iOS app designed to help Jewish users pray every morning with guided prayers, reminders, and community connection.", keywords: "prayer app, iOS, Jewish, morning prayers, spiritual growth, Torah Lock", metadataBase: new URL("https://shachar-prayer.com"), @@ -33,6 +23,15 @@ export const metadata: Metadata = { }, }; +const inter = Inter({ + variable: "--font-inter", + subsets: ["latin"], +}); +const openSans = Open_Sans({ + variable: "--font-open-sans", + subsets: ["latin"], +}); + export default function RootLayout({ children, }: Readonly<{ @@ -41,9 +40,7 @@ export default function RootLayout({ return ( - + {children} @@ -288,9 +285,7 @@ export default function RootLayout({ const getElementInfo = (element, assignId = false) => { const rect = element.getBoundingClientRect(); const tagName = element.tagName.toLowerCase(); - const selector = getUniqueSelector(element, assignId); - const sectionId = getSectionId(element); - + let className = undefined; try { if (element.className) { @@ -318,8 +313,7 @@ export default function RootLayout({ }; if (tagName === 'img') { - const originalSrc = extractOriginalUrl(element.src); - info.imageData = { + info.imageData = { src: originalSrc, alt: element.alt || undefined, naturalWidth: element.naturalWidth, @@ -330,8 +324,7 @@ export default function RootLayout({ if (tagName === 'video') { const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || ''; - const resolvedSrc = extractOriginalUrl(rawSrc); - info.imageData = { + info.imageData = { src: resolvedSrc, alt: element.getAttribute('aria-label') || undefined, isBackground: false, @@ -344,8 +337,7 @@ export default function RootLayout({ if (backgroundImage && backgroundImage !== 'none') { const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/); if (urlMatch) { - const originalBgSrc = extractOriginalUrl(urlMatch[1]); - if (tagName !== 'img') { + if (tagName !== 'img') { info.imageData = { src: originalBgSrc, isBackground: true @@ -357,8 +349,7 @@ export default function RootLayout({ } } - const elementType = getElementType(element); - info.elementType = elementType; + info.elementType = elementType; if (elementType === 'Button') { const buttonText = element.textContent?.trim() || element.value || element.getAttribute('aria-label') || ''; @@ -451,13 +442,11 @@ export default function RootLayout({ }; const isTextElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Text'; + return elementType === 'Text'; }; const isButtonElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Button'; + return elementType === 'Button'; }; const updateButtonText = (element, newText) => { @@ -532,8 +521,7 @@ export default function RootLayout({ }; const handleInput = () => { - const elementInfo = getElementInfo(element); - let currentText = element.textContent; + let currentText = element.textContent; // Ensure there's always at least a space to keep the element editable if (currentText === '' || currentText === null || currentText.length === 0) { @@ -646,8 +634,7 @@ export default function RootLayout({ }, '*'); if (save && originalContent !== element.textContent) { - const elementInfo = getElementInfo(element); - let finalText = element.textContent; + let finalText = element.textContent; // Trim the final text and convert space-only to empty string for saving if (finalText === ' ' || finalText.trim() === '') { @@ -776,7 +763,7 @@ export default function RootLayout({ lastMouseX = e.clientX; lastMouseY = e.clientY; - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target) || target === hoveredElement || target === selectedElement) { return; @@ -808,8 +795,7 @@ export default function RootLayout({ hoverOverlay = createHoverOverlay(target); } - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -851,7 +837,7 @@ export default function RootLayout({ e.preventDefault(); e.stopPropagation(); - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target)) return; if (selectedElement && selectedElement !== target) { @@ -896,8 +882,7 @@ export default function RootLayout({ hoveredElement = null; } - const elementInfo = getElementInfo(target, true); - selectedElement.dataset.webildSelector = elementInfo.selector; + selectedElement.dataset.webildSelector = elementInfo.selector; showElementTypeLabel(target, elementInfo.elementType); window.parent.postMessage({ @@ -980,8 +965,7 @@ export default function RootLayout({ isScrolling = false; if (lastMouseX > 0 && lastMouseY > 0) { - const target = getMostSpecificElement(lastMouseX, lastMouseY); - if (target && isValidElement(target) && target !== selectedElement) { + if (target && isValidElement(target) && target !== selectedElement) { hoveredElement = target; const computedStyle = window.getComputedStyle(target); @@ -995,8 +979,7 @@ export default function RootLayout({ hoveredElement.classList.add(hoverClass); hoverOverlay = createHoverOverlay(target); - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -1019,8 +1002,7 @@ export default function RootLayout({ const saveChangeToStorage = (change) => { try { - const storageKey = getStorageKey(); - const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); + const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); const filteredChanges = existingChanges.filter(c => { return !(c.oldValue === change.oldValue && c.sectionId === change.sectionId); @@ -1040,8 +1022,7 @@ export default function RootLayout({ const clearLocalChanges = () => { try { - const storageKey = getStorageKey(); - localStorage.removeItem(storageKey); + localStorage.removeItem(storageKey); window.parent.postMessage({ type: 'webild-local-changes-cleared', data: {} @@ -1090,8 +1071,7 @@ export default function RootLayout({ if (e.data.type === 'webild-cancel-changes') { try { - const storageKey = getStorageKey(); - const savedChanges = localStorage.getItem(storageKey); + const savedChanges = localStorage.getItem(storageKey); if (savedChanges) { const changes = JSON.parse(savedChanges); changes.forEach(change => { @@ -1113,8 +1093,7 @@ export default function RootLayout({ if (isBackground) { element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : ''; } else { - const oldMediaType = getMediaTypeFromUrl(change.oldValue); - if (revertTag === 'video' && oldMediaType === 'image') { + if (revertTag === 'video' && oldMediaType === 'image') { swapMediaElement(element, 'img', change.oldValue); } else if (revertTag === 'img' && oldMediaType === 'video') { swapMediaElement(element, 'video', change.oldValue); @@ -1162,8 +1141,7 @@ export default function RootLayout({ const el = textElements[i]; if (isTextElement(el) && el.textContent.trim() === (oldValue || '').trim()) { element = el; - const newSelector = getUniqueSelector(element, true); - if (newSelector) { + if (newSelector) { element.dataset.webildSelector = newSelector; } break; @@ -1254,10 +1232,8 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'img') { oldValue = element.src; - const newMediaType = getMediaTypeFromUrl(newSrc); - if (newMediaType === 'video' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'video', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (newMediaType === 'video' && allowMediaTypeSwap) { + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { element.src = newSrc; @@ -1265,11 +1241,9 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'video') { oldValue = element.src || element.currentSrc || ''; - const newMediaType = getMediaTypeFromUrl(newSrc); - const sources = element.querySelectorAll('source'); + const sources = element.querySelectorAll('source'); if (newMediaType === 'image' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'img', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { if (sources.length > 0) { @@ -1291,8 +1265,7 @@ export default function RootLayout({ } if (replaced) { - const elementInfo = getElementInfo(element); - + let cleanOldValue = oldValue; if (oldValue.includes('url(')) { const urlMatch = oldValue.match(/url(['"]?([^'")]+)['"]?)/); @@ -1363,13 +1336,7 @@ export default function RootLayout({ } }, true); - const urlCheckInterval = setInterval(() => { - if (lastPathname !== window.location.pathname) { - lastPathname = window.location.pathname; - notifyPageChange(); - } - }, 500); - + notifyPageChange(); window.webildCleanup = () => { @@ -1655,9 +1622,7 @@ export default function RootLayout({ const getElementInfo = (element, assignId = false) => { const rect = element.getBoundingClientRect(); const tagName = element.tagName.toLowerCase(); - const selector = getUniqueSelector(element, assignId); - const sectionId = getSectionId(element); - + let className = undefined; try { if (element.className) { @@ -1685,8 +1650,7 @@ export default function RootLayout({ }; if (tagName === 'img') { - const originalSrc = extractOriginalUrl(element.src); - info.imageData = { + info.imageData = { src: originalSrc, alt: element.alt || undefined, naturalWidth: element.naturalWidth, @@ -1697,8 +1661,7 @@ export default function RootLayout({ if (tagName === 'video') { const rawSrc = element.src || element.currentSrc || (element.querySelector('source') && element.querySelector('source').src) || ''; - const resolvedSrc = extractOriginalUrl(rawSrc); - info.imageData = { + info.imageData = { src: resolvedSrc, alt: element.getAttribute('aria-label') || undefined, isBackground: false, @@ -1711,8 +1674,7 @@ export default function RootLayout({ if (backgroundImage && backgroundImage !== 'none') { const urlMatch = backgroundImage.match(/url(['"]?([^'")]+)['"]?)/); if (urlMatch) { - const originalBgSrc = extractOriginalUrl(urlMatch[1]); - if (tagName !== 'img') { + if (tagName !== 'img') { info.imageData = { src: originalBgSrc, isBackground: true @@ -1724,8 +1686,7 @@ export default function RootLayout({ } } - const elementType = getElementType(element); - info.elementType = elementType; + info.elementType = elementType; if (elementType === 'Button') { const buttonText = element.textContent?.trim() || element.value || element.getAttribute('aria-label') || ''; @@ -1818,13 +1779,11 @@ export default function RootLayout({ }; const isTextElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Text'; + return elementType === 'Text'; }; const isButtonElement = (element) => { - const elementType = getElementType(element); - return elementType === 'Button'; + return elementType === 'Button'; }; const updateButtonText = (element, newText) => { @@ -1899,8 +1858,7 @@ export default function RootLayout({ }; const handleInput = () => { - const elementInfo = getElementInfo(element); - let currentText = element.textContent; + let currentText = element.textContent; // Ensure there's always at least a space to keep the element editable if (currentText === '' || currentText === null || currentText.length === 0) { @@ -2013,8 +1971,7 @@ export default function RootLayout({ }, '*'); if (save && originalContent !== element.textContent) { - const elementInfo = getElementInfo(element); - let finalText = element.textContent; + let finalText = element.textContent; // Trim the final text and convert space-only to empty string for saving if (finalText === ' ' || finalText.trim() === '') { @@ -2143,7 +2100,7 @@ export default function RootLayout({ lastMouseX = e.clientX; lastMouseY = e.clientY; - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target) || target === hoveredElement || target === selectedElement) { return; @@ -2175,8 +2132,7 @@ export default function RootLayout({ hoverOverlay = createHoverOverlay(target); } - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -2218,7 +2174,7 @@ export default function RootLayout({ e.preventDefault(); e.stopPropagation(); - const target = getMostSpecificElement(e.clientX, e.clientY) || e.target; + || e.target; if (!isValidElement(target)) return; if (selectedElement && selectedElement !== target) { @@ -2263,8 +2219,7 @@ export default function RootLayout({ hoveredElement = null; } - const elementInfo = getElementInfo(target, true); - selectedElement.dataset.webildSelector = elementInfo.selector; + selectedElement.dataset.webildSelector = elementInfo.selector; showElementTypeLabel(target, elementInfo.elementType); window.parent.postMessage({ @@ -2347,8 +2302,7 @@ export default function RootLayout({ isScrolling = false; if (lastMouseX > 0 && lastMouseY > 0) { - const target = getMostSpecificElement(lastMouseX, lastMouseY); - if (target && isValidElement(target) && target !== selectedElement) { + if (target && isValidElement(target) && target !== selectedElement) { hoveredElement = target; const computedStyle = window.getComputedStyle(target); @@ -2362,8 +2316,7 @@ export default function RootLayout({ hoveredElement.classList.add(hoverClass); hoverOverlay = createHoverOverlay(target); - const elementType = getElementType(target); - showElementTypeLabel(target, elementType); + showElementTypeLabel(target, elementType); window.parent.postMessage({ type: 'webild-element-hover', @@ -2386,8 +2339,7 @@ export default function RootLayout({ const saveChangeToStorage = (change) => { try { - const storageKey = getStorageKey(); - const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); + const existingChanges = JSON.parse(localStorage.getItem(storageKey) || '[]'); const filteredChanges = existingChanges.filter(c => { return !(c.oldValue === change.oldValue && c.sectionId === change.sectionId); @@ -2407,8 +2359,7 @@ export default function RootLayout({ const clearLocalChanges = () => { try { - const storageKey = getStorageKey(); - localStorage.removeItem(storageKey); + localStorage.removeItem(storageKey); window.parent.postMessage({ type: 'webild-local-changes-cleared', data: {} @@ -2457,8 +2408,7 @@ export default function RootLayout({ if (e.data.type === 'webild-cancel-changes') { try { - const storageKey = getStorageKey(); - const savedChanges = localStorage.getItem(storageKey); + const savedChanges = localStorage.getItem(storageKey); if (savedChanges) { const changes = JSON.parse(savedChanges); changes.forEach(change => { @@ -2480,8 +2430,7 @@ export default function RootLayout({ if (isBackground) { element.style.backgroundImage = change.oldValue ? 'url(' + change.oldValue + ')' : ''; } else { - const oldMediaType = getMediaTypeFromUrl(change.oldValue); - if (revertTag === 'video' && oldMediaType === 'image') { + if (revertTag === 'video' && oldMediaType === 'image') { swapMediaElement(element, 'img', change.oldValue); } else if (revertTag === 'img' && oldMediaType === 'video') { swapMediaElement(element, 'video', change.oldValue); @@ -2529,8 +2478,7 @@ export default function RootLayout({ const el = textElements[i]; if (isTextElement(el) && el.textContent.trim() === (oldValue || '').trim()) { element = el; - const newSelector = getUniqueSelector(element, true); - if (newSelector) { + if (newSelector) { element.dataset.webildSelector = newSelector; } break; @@ -2621,10 +2569,8 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'img') { oldValue = element.src; - const newMediaType = getMediaTypeFromUrl(newSrc); - if (newMediaType === 'video' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'video', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (newMediaType === 'video' && allowMediaTypeSwap) { + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { element.src = newSrc; @@ -2632,11 +2578,9 @@ export default function RootLayout({ replaced = true; } else if (element.tagName.toLowerCase() === 'video') { oldValue = element.src || element.currentSrc || ''; - const newMediaType = getMediaTypeFromUrl(newSrc); - const sources = element.querySelectorAll('source'); + const sources = element.querySelectorAll('source'); if (newMediaType === 'image' && allowMediaTypeSwap) { - const swapped = swapMediaElement(element, 'img', newSrc); - if (selectedElement === element) selectedElement = swapped; + if (selectedElement === element) selectedElement = swapped; element = swapped; } else { if (sources.length > 0) { @@ -2658,8 +2602,7 @@ export default function RootLayout({ } if (replaced) { - const elementInfo = getElementInfo(element); - + let cleanOldValue = oldValue; if (oldValue.includes('url(')) { const urlMatch = oldValue.match(/url(['"]?([^'")]+)['"]?)/); @@ -2730,13 +2673,7 @@ export default function RootLayout({ } }, true); - const urlCheckInterval = setInterval(() => { - if (lastPathname !== window.location.pathname) { - lastPathname = window.location.pathname; - notifyPageChange(); - } - }, 500); - + notifyPageChange(); window.webildCleanup = () => { -- 2.49.1 From f340ba7d4f5ca4dcb963caee5922e952f481de86 Mon Sep 17 00:00:00 2001 From: bender Date: Wed, 4 Mar 2026 07:45:46 +0000 Subject: [PATCH 39/39] Update theme fonts -- 2.49.1