PageSourceSearch

https://suchitra.com/assets/js/live-site-engine.js

js suchitra.com collected 2026-09-27 22:09:52 UTC 10,538 bytes, 223 lines download raw bytes

1// ==============================================================
2// SUCHITRA KRISHNAMOORTHI LIVE SITE CONTENT ENGINE (V2 SAFE)
3// Connects frontend pages to live Admin CMS data with zero layout disruption
4// Strictly protects footers, masonry layouts, and Zyro grid architecture
5// ==============================================================
6
7(function () {
8  'use strict';
9
10  let siteData = null;
11
12  document.addEventListener('DOMContentLoaded', initLiveContentEngine);
13
14  async function initLiveContentEngine() {
15    siteData = await fetchSiteContent();
16    if (!siteData) return;
17
18    const path = window.location.pathname.replace(/\/$/, '') || '/';
19    const pages = siteData.pages || {};
20
21    // Route-specific hydrations & Page Settings
22    if (path.includes('my-books')) {
23      if (pages.books) applyPageHeaderSettings('books', pages.books);
24      hydrateBooksPage(siteData.books || []);
25    } else if (path.includes('blog')) {
26      if (pages.blogs) applyPageHeaderSettings('blogs', pages.blogs);
27      // NOTE: Blog articles & masonry are rendered statically by server.js / Zyro
28      // with native layout, #blog-post-sizer, and active blogs.
29      // We do NOT tamper with .posts-list-wrapper to preserve layout and navigation.
30    } else if (path.includes('my-music')) {
31      if (pages.music) applyPageHeaderSettings('music', pages.music);
32    } else if (path.includes('my-paintings') || path.includes('gallery')) {
33      if (pages.paintings) applyPageHeaderSettings('paintings', pages.paintings);
34    } else if (path.includes('my-poetry')) {
35      if (pages.poetry) applyPageHeaderSettings('poetry', pages.poetry);
36    } else if (path.includes('my-movies') || path.includes('my-plays')) {
37      if (pages.movies) applyPageHeaderSettings('movies', pages.movies);
38    } else if (path.includes('my-videos') || path.includes('double-occupancy-series')) {
39      if (pages.videos) applyPageHeaderSettings('videos', pages.videos);
40    } else if (path === '/' || path === '/index.html' || path === '') {
41      hydrateHomePage(siteData);
42    }
43
44    // Always ensure footer newsletter inputs have clear, full placeholders
45    fixFooterNewsletterInputs();
46  }
47
48  // Footer Newsletter Form Input Label & Placeholder Fix
49  function fixFooterNewsletterInputs() {
50    const nameInputs = document.querySelectorAll('form input[name="field0"], form input[placeholder="Name"]');
51    nameInputs.forEach(input => {
52      input.setAttribute('placeholder', 'Your Name');
53      input.setAttribute('aria-label', 'Your Name');
54    });
55
56    const emailInputs = document.querySelectorAll('form input[name="field1"], form input[placeholder="Email"], form input[type="email"]');
57    emailInputs.forEach(input => {
58      input.setAttribute('placeholder', 'Your Email Address');
59      input.setAttribute('aria-label', 'Your Email Address');
60    });
61  }
62
63  // Apply Page Header & Banner Settings dynamically
64  // Strictly scoped to header containers only - NEVER touches footer or content grids!
65  function applyPageHeaderSettings(pageKey, pageData) {
66    if (!pageData) return;
67
68    const bannerContainer = document.getElementById('container-widget-1767804542652');
69
70    // 1. Tagline / Category Badge button (inside banner container only)
71    if (pageData.badge && bannerContainer) {
72      const badge = bannerContainer.querySelector('#button-widget-1767804542651 span, .page-header-badge');
73      if (badge) {
74        badge.innerText = pageData.badge;
75        badge.style.color = '#ffffff';
76      }
77    }
78
79    // 2. Heading Title (pure white, DM Serif Display)
80    if (pageData.title) {
81      // Blog page header title
82      const blogHead = document.querySelector('#text-widget-1461519401626 h2');
83      if (blogHead) {
84        blogHead.innerHTML = `<span style="font-size: 60px; font-family: 'DM Serif Display', serif; color: #ffffff !important;">${pageData.title}</span>`;
85        blogHead.style.color = '#ffffff';
86      }
87
88      // Standard page banner heading
89      if (bannerContainer) {
90        const headH2 = bannerContainer.querySelector('#heading-widget-1767804542650 h2');
91        if (headH2) {
92          headH2.innerHTML = `<span style="font-family: 'DM Serif Display', serif; font-size: 60px; color: #ffffff !important;">${pageData.title}</span>`;
93          headH2.style.color = '#ffffff';
94        }
95      }
96
97      document.title = `${pageData.title} | Suchitra Krishnamoorthi`;
98    }
99
100    // 3. Subtitle (inside banner container only - pure white)
101    if (pageData.subtitle && bannerContainer) {
102      const subP = bannerContainer.querySelector('#text-widget-1767804542648 p');
103      if (subP) {
104        subP.innerHTML = `<span style="color: #ffffff !important; font-size: 24px; font-style: italic; font-family: 'Playfair Display', serif;">${pageData.subtitle}</span>`;
105        subP.style.color = '#ffffff';
106      }
107    }
108
109    // 4. Description / Intro text
110    if (pageData.description) {
111      const descEl = document.querySelector('.page-header-desc');
112      if (descEl) descEl.innerText = pageData.description;
113    }
114
115    // 5. Banner Image - ONLY within specific banner container!
116    // Absolute rule: Never touch footer, body, or generic .grid-column!
117    if (pageData.banner_image) {
118      const cleanImg = resolveAssetUrl(pageData.banner_image);
119      
120      // Standard pages (my-books, my-music, my-paintings, my-videos, my-movies, my-poetry)
121      if (bannerContainer) {
122        const bannerImg = bannerContainer.querySelector('#image-widget-1767804542646 img, .imageWidget img');
123        if (bannerImg) {
124          bannerImg.src = cleanImg;
125        }
126      }
127
128      // Blog page header row (only if valid banner image and not meta thumbnail)
129      if (pageKey === 'blogs' && pageData.banner_image && !pageData.banner_image.includes('1-7727269')) {
130        const blogBanner = document.getElementById('container-widget-40');
131        if (blogBanner) {
132          blogBanner.style.backgroundImage = `url("${cleanImg}")`;
133          blogBanner.style.backgroundSize = 'cover';
134          blogBanner.style.backgroundPosition = 'center';
135        }
136      }
137    }
138  }
139
140  // Fetch Live Content from Backend (with fallback)
141  async function fetchSiteContent() {
142    try {
143      const res = await fetch('/api/content');
144      if (res.ok) {
145        return await res.json();
146      }
147    } catch (e) {}
148
149    // Fallback to static JSON
150    try {
151      const fb = await fetch('/data/site-content.json');
152      if (fb.ok) {
153        return await fb.json();
154      }
155    } catch (e) {}
156
157    return null;
158  }
159
160  // Asset URL Helper
161  function resolveAssetUrl(url) {
162    if (!url) return '/assets/images/wp-uploads/108-quotes-gita.webp';
163    if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('data:')) return url;
164    let clean = url.replace(/^(\.\.\/)+/, '').replace(/^\.\//, '').replace(/^\//, '');
165    return '/' + clean;
166  }
167
168  // -------------------------------------------------------------
169  // 1. HYDRATE BOOKS PAGE (/my-books)
170  // -------------------------------------------------------------
171  function hydrateBooksPage(books) {
172    if (!books || books.length === 0) return;
173
174    const targetContainer = document.getElementById('container-widget-1767811439526');
175    if (!targetContainer) return;
176
177    targetContainer.innerHTML = `
178      <div style="max-width: 1200px; margin: 0 auto; padding: 20px 20px 60px;">
179        <div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 32px;">
180          ${books.map(b => `
181            <div class="suchitra-book-card" style="background: #ffffff; border-radius: 16px; overflow: hidden; box-shadow: 0 6px 25px rgba(0,0,0,0.07); border: 1px solid #f1f5f9; display: flex; flex-direction: column; transition: transform 0.3s ease, box-shadow 0.3s ease;">
182              <div style="position: relative; overflow: hidden; height: 360px; background: #faf8f5; display: flex; align-items: center; justify-content: center; padding: 16px;">
183                <img src="${resolveAssetUrl(b.image)}" alt="${b.title}" style="max-height: 100%; max-width: 100%; object-fit: contain; filter: drop-shadow(0 10px 15px rgba(0,0,0,0.15)); transition: transform 0.3s ease;" onerror="this.src='/assets/images/wp-uploads/108-quotes-gita.webp'">
184                <span style="position: absolute; top: 14px; left: 14px; background: rgba(15, 23, 42, 0.85); color: #fff; font-size: 11px; font-weight: 700; text-transform: uppercase; padding: 4px 10px; border-radius: 20px; letter-spacing: 0.5px;">${b.category || 'Book'}</span>
185              </div>
186              <div style="padding: 24px; flex: 1; display: flex; flex-direction: column; justify-content: space-between;">
187                <div>
188                  <h3 style="font-family: 'DM Serif Display', serif; font-size: 21px; line-height: 1.35; margin: 0 0 10px; color: #1e293b;">${b.title}</h3>
189                  <p style="color: #64748b; font-size: 14px; line-height: 1.6; margin: 0 0 18px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;">${b.description || ''}</p>
190                </div>
191                <div>
192                  <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px;">
193                    <div style="font-size: 22px; font-weight: 800; color: #eb6a56;">${b.price ? '₹' + b.price : 'Special Edition'}</div>
194                    <span style="font-size: 12px; color: #10b981; font-weight: 700;"><i class="fas fa-check-circle"></i> In Stock</span>
195                  </div>
196                  <a href="/checkout?product=${b.id}" style="display: block; text-align: center; background: #eb6a56; color: #ffffff; padding: 12px 20px; border-radius: 30px; font-weight: 700; text-decoration: none; font-size: 14px; transition: background 0.2s ease;">
197                    <i class="fas fa-shopping-bag"></i> Order Signed Copy
198                  </a>
199                </div>
200              </div>
201            </div>
202          `).join('')}
203        </div>
204      </div>
205    `;
206  }
207
208  // -------------------------------------------------------------
209  // 2. HYDRATE HOMEPAGE (/)
210  // -------------------------------------------------------------
211  function hydrateHomePage(data) {
212    if (!data) return;
213
214    if (data.homepage) {
215      const hp = data.homepage;
216      const heroHead = document.querySelector('.theme-hero h1') || document.querySelector('h1');
217      if (heroHead && hp.hero_title_1) {
218        heroHead.innerHTML = hp.hero_title_1 + (hp.hero_title_2 ? '<br>' + hp.hero_title_2 : '');
219      }
220    }
221  }
222
223})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.