PageSourceSearch

https://ai-stack-hub-navy.vercel.app/js/app.js?v=1.0.1

js ai-stack-hub-navy.vercel.app collected 2026-10-03 06:13:20 UTC 35,927 bytes, 754 lines download raw bytes

1/**
2 * AIStackHub - Central App Controller & View Router
3 */
4
5window.AIStackApp = {
6  currentTheme: "dark",
7
8  init() {
9    // 1. Initialize Theme
10    const savedTheme = localStorage.getItem("aistack_theme") || "dark";
11    this.setTheme(savedTheme);
12
13    // 2. Inject Analytical Scripts
14    window.db.injectTrackingScripts();
15
16    // 3. Attach Routing Handlers
17    window.addEventListener("hashchange", () => this.handleRouting());
18    window.addEventListener("load", () => this.handleRouting());
19
20    // 4. Global Click Listener for Theme toggle
21    document.addEventListener("click", (e) => {
22      if (e.target.closest("#global-theme-toggle")) {
23        const nextTheme = this.currentTheme === "dark" ? "light" : "dark";
24        this.setTheme(nextTheme);
25      }
26    });
27
28    console.log("AIStackHub Application Core Loaded successfully.");
29  },
30
31  setTheme(theme) {
32    this.currentTheme = theme;
33    document.documentElement.setAttribute("data-theme", theme);
34    localStorage.setItem("aistack_theme", theme);
35    
36    // Update theme toggle icons
37    const toggle = document.getElementById("global-theme-toggle");
38    if (toggle) {
39      toggle.innerHTML = theme === "dark" 
40        ? `<svg style="width:18px; height:18px;" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364-6.364l-.707.707M6.343 17.657l-.707.707m0-12.728l.707.707m12.728 12.728l.707-.707M12 8a4 4 0 100 8 4 4 0 000-8z"/></svg>`
41        : `<svg style="width:18px; height:18px;" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"/></svg>`;
42    }
43  },
44
45  // Central Router Dispatcher
46  handleRouting() {
47    const rawHash = window.location.hash || "#home";
48    const routeParts = rawHash.split("/");
49    const primaryRoute = routeParts[0];
50    const parameter = routeParts[1];
51
52    // Scroll to top
53    window.scrollTo({ top: 0, behavior: "smooth" });
54
55    // Set layout frame
56    const shell = document.getElementById("app-shell-layout");
57    
58    // If routing to Admin panel, load isolated admin dashboard grid
59    if (primaryRoute === "#admin") {
60      shell.innerHTML = `
61        ${window.AIStackComponents.Header("admin")}
62        <div id="main-content-container"></div>
63        ${window.AIStackComponents.Footer()}
64      `;
65      window.AIStackAdmin.renderDashboard();
66      window.AIStackComponents.initNewsletterListener();
67      return;
68    }
69
70    // Default Public layout frame
71    shell.innerHTML = `
72      ${window.AIStackComponents.Header(primaryRoute.replace('#', ''))}
73      <div id="main-content-container" class="container" style="margin-top: calc(var(--header-height) + 20px);">
74        <!-- Active View Injected Here -->
75      </div>
76      ${window.AIStackComponents.Footer()}
77    `;
78
79    const viewParent = document.getElementById("main-content-container");
80
81    // Route Mappings
82    if (primaryRoute === "#home") {
83      this.renderHome(viewParent);
84    } else if (primaryRoute === "#blog") {
85      if (parameter) {
86        this.renderSingleArticle(viewParent, parameter);
87      } else {
88        this.renderBlogListing(viewParent);
89      }
90    } else if (primaryRoute === "#news") {
91      this.renderNewsListing(viewParent);
92    } else if (primaryRoute === "#tools") {
93      this.renderToolsDirectory(viewParent);
94    } else if (primaryRoute === "#models") {
95      this.renderModelsDirectory(viewParent);
96    } else if (primaryRoute === "#videos") {
97      this.renderVideosPage(viewParent);
98    } else if (primaryRoute === "#utility") {
99      this.renderUtilityToolsSection(viewParent, parameter);
100    } else if (["#about", "#contact", "#privacy", "#terms", "#disclaimer"].includes(primaryRoute)) {
101      this.renderStaticPage(viewParent, primaryRoute.replace('#', ''));
102    } else {
103      // Fallback to Home
104      window.location.hash = "#home";
105    }
106
107    // Initialize Global Component Event Listeners
108    window.AIStackComponents.initNewsletterListener();
109  },
110
111  // ==================== VIEW COMPILERS ====================
112
113  // 1. Homepage compiler
114  renderHome(el) {
115    const articles = window.db.getArticles().filter(a => a.status === 'Published');
116    const featured = articles.find(a => a.isFeatured) || articles[0];
117    const tools = window.db.getTools();
118    const models = window.db.getModels();
119    const videos = window.db.getVideos();
120
121    el.innerHTML = `
122      <!-- Glow Spots -->
123      <div class="glow-spot glow-blue"></div>
124      <div class="glow-spot glow-purple"></div>
125
126      <!-- Hero Banner -->
127      <section class="hero-section">
128        <div class="hero-tag">Enterprise AI Portal</div>
129        <h1 class="hero-title">Discover the Frontier of Artificial Intelligence</h1>
130        <p class="hero-subtitle">
130Comprehensive AI news, benchmark comparisons, interactive utilities, and developer playpens. Build the future, faster.</p>
131        <div style="display:flex; justify-content:center; gap:16px;">
132          <a href="#utility" class="btn btn-primary">Open Utilities Platform</a>
133          <a href="#tools" class="btn btn-secondary">Explore Tools Directory</a>
134        </div>
135      </section>
136
137      <!-- Simulated Ad space -->
138      ${window.AIStackComponents.AdZone("header")}
139
140      <!-- Featured Article & News Highlights -->
141      <section class="section-padding" style="padding-top:40px;">
142        <h2 style="font-size:32px; margin-bottom:32px; font-family:var(--font-heading);">Featured Release</h2>
143        ${featured ? `
144          <div class="glass-panel grid-2" style="padding:0; overflow:hidden; display:grid; grid-template-columns:1.2fr 1fr; align-items:center;">
145            <div class="card-img-wrap" style="aspect-ratio:16/10; margin-bottom:0; border-radius:0;">
146              <img src="https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&w=800&q=80" class="card-img" alt="${featured.title}" onerror="this.onerror=null; this.outerHTML = window.AIStackTools.createSvgFallback(\`${featured.title.replace(/'/g, "\\'")}\`);">
147              <span class="card-badge">Featured</span>
148            </div>
149            <div style="padding:40px; display:flex; flex-direction:column; gap:16px;">
150              <span style="font-size:12px; color:var(--accent-purple); font-weight:bold; text-transform:uppercase;">Latest News Deepdive</span>
151              <h3 style="font-size:32px; font-family:var(--font-heading); line-height:1.2;">
152                <a href="#blog/${featured.slug}">${featured.title}</a>
153              </h3>
154              <p style="color:var(--text-secondary); font-size:15px;">${featured.excerpt}</p>
155              <a href="#blog/${featured.slug}" class="btn btn-primary" style="align-self:flex-start; margin-top:10px;">Read Deep Analysis</a>
156            </div>
157          </div>
158        ` : ''}
159      </section>
160
161      <!-- Trending AI Models -->
162      <section class="section-padding" style="padding-top:0;">
163        <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:32px;">
164          <h2 style="font-size:32px; font-family:var(--font-heading);">Trending Foundation Models</h2>
165          <a href="#models" style="color:var(--accent-purple); font-weight:bold;">Compare All Benchmarks →</a>
166        </div>
167        <div class="grid-3">
168          ${models.slice(0, 3).map(m => `
169            <div class="glass-panel card">
170              <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:16px;">
171                <h3 class="card-title" style="margin-bottom:0;">${m.name}</h3>
172                <span class="tag-badge" style="background:rgba(15, 98, 254, 0.1); color:var(--accent-blue); font-weight:bold;">${m.developer}</span>
173              </div>
174              <p class="card-desc" style="font-size:13px;">${m.capabilities}</p>
175              <div style="display:flex; justify-content:space-between; border-top:1px solid var(--glass-border); padding-top:12px; margin-top:auto; font-size:12px;">
176                <span>MMLU Score: <strong style="color:#10b981;">${m.benchmarks.mmlu}</strong></span>
177                <span>Context: <strong>${(m.contextLength / 1000).toFixed(0)}k</strong></span>
178              </div>
179            </div>
180          `).join('')}
181        </div>
182      </section>
183
184      <!-- Featured Curated Tools -->
185      <section class="section-padding" style="padding-top:0;">
186        <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:32px;">
187          <h2 style="font-size:32px; font-family:var(--font-heading);">Featured Production Tools</h2>
188          <a href="#tools" style="color:var(--accent-purple); font-weight:bold;">View Complete Index →</a>
189        </div>
190        <div class="grid-4">
191          ${tools.slice(0, 4).map(t => `
192            <div class="glass-panel card">
193              <div class="tool-card-header">
194                <div class="tool-logo-box">${t.logo}</div>
195                <div>
196                  <h4 style="font-size:15px; font-weight:bold;">${t.name}</h4>
197                  <span style="font-size:11px; color:var(--text-muted);">${t.category}</span>
198                </div>
199              </div>
200              <p style="font-size:13px; color:var(--text-secondary); margin-bottom:12px; flex-grow:1;">${t.description}</p>
201              <div style="display:flex; justify-content:space-between; align-items:center; border-top:1px solid var(--glass-border); padding-top:10px; font-size:11px;">
202                <span style="color:#f59e0b; font-weight:bold;">★ ${t.ratings}</span>
203                <span class="tool-badge-pricing">${t.pricingType}</span>
204              </div>
205            </div>
206          `).join('')}
207        </div>
208      </section>
209
210      <!-- Newsletter subscription panel -->
211      ${window.AIStackComponents.NewsletterWidget()}
212
213      <!-- Curated YouTube Videos -->
214      <section class="section-padding" style="padding-top:0;">
215        <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:32px;">
216          <h2 style="font-size:32px; font-family:var(--font-heading);">Curated Videos & Masterclasses</h2>
217          <a href="#videos" style="color:var(--accent-purple); font-weight:bold;">View Playlists →</a>
218        </div>
219        <div class="grid-2">
220          ${videos.slice(0, 2).map(v => `
221            <div class="glass-panel card" style="padding:16px;">
222              ${window.AIStackComponents.VideoEmbed(v.youtubeUrl)}
223              <h3 style="font-size:16px; margin-top:12px; font-family:var(--font-heading);">${v.title}</h3>
224            </div>
225          `).join('')}
226        </div>
227      </section>
228
229      <!-- Ads layout bottom -->
230      ${window.AIStackComponents.AdZone("sidebar")}
231    `;
232  },
233
234  // 2. Blog Listing compiler with search and filters
235  renderBlogListing(el) {
236    const articles = window.db.getArticles().filter(a => a.status === 'Published');
237    const categories = window.db.getCategories();
238
239    el.innerHTML = `
240      <h2 style="font-size:36px; text-align:center; margin-bottom:12px; font-family:var(--font-heading);">Technology AI Blog</h2>
241      <p style="text-align:center; color:var(--text-secondary); max-width:600px; margin:0 auto 40px auto;">
242        Deep dive research papers, prompt blueprints, architectural explanations, and technical tutorials.
243      </p>
244
245      <!-- Global search panel -->
246      <div class="search-container">
247        <input type="text" id="blog-search" class="search-input" placeholder="Search articles, tags, tools...">
248        <span class="search-icon">🔍</span>
249      </div>
250
251      <!-- Filters Bar -->
252      <div class="filters-bar">
253        <div class="filters-group">
254          <select id="filter-cat" class="filter-select">
255            <option value="all">All Categories</option>
256            ${categories.map(c => `<option value="${c.id}">${c.name}</option>`).join('')}
257          </select>
258          <select id="filter-sort" class="filter-select">
259            <option value="recent">Most Recent</option>
260            <option value="views">Most Viewed</option>
261          </select>
262        </div>
263        <div style="font-size:13px; color:var(--text-secondary);">
264          Found <strong id="blog-count" style="color:var(--accent-purple);">${articles.length}</strong> analysis publications
265        </div>
266      </div>
267
268      <!-- Listing Cards -->
269      <div class="grid-3" id="blog-cards-grid">
270        <!-- Rendered dynamically -->
271      </div>
272    `;
273
274    const searchIn = document.getElementById("blog-search");
275    const catSelect = document.getElementById("filter-cat");
276    const sortSelect = document.getElementById("filter-sort");
277
278    const runFilters = () => {
279      const q = searchIn.value.trim().toLowerCase();
280      const cat = catSelect.value;
281      const sort = sortSelect.value;
282
283      let filtered = articles;
284
285      if (cat !== "all") {
286        filtered = filtered.filter(a => a.categoryId === cat);
287      }
288
289      if (q) {
290        filtered = filtered.filter(a => 
291          a.title.toLowerCase().includes(q) || 
292          a.excerpt.toLowerCase().includes(q) || 
293          a.tags.some(t => t.toLowerCase().includes(q))
294        );
295      }
296
297      if (sort === "views") {
298        filtered.sort((a,b) => (b.views || 0) - (a.views || 0));
299      } else {
300        filtered.sort((a,b) => new Date(b.publishedAt) - new Date(a.publishedAt));
301      }
302
303      document.getElementById("blog-count").innerText = filtered.length;
304      
305      const grid = document.getElementById("blog-cards-grid");
306      if (filtered.length === 0) {
307        grid.innerHTML = `<div style="grid-column:1/-1; text-align:center; padding:60px 0; color:var(--text-secondary);">No articles found matching search criteria.</div>`;
308        return;
309      }
310
311      grid.innerHTML = filtered.map(art => `
312        <div class="glass-panel card">
313          <div class="card-img-wrap">
314            <img src="https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&w=400&q=80" class="card-img" alt="${art.title}" onerror="this.onerror=null; this.outerHTML = window.AIStackTools.createSvgFallback(\`${art.title.replace(/'/g, "\\'")}\`);">
315            <span class="card-badge">${categories.find(c => c.id === art.categoryId)?.name || 'News'}</span>
316          </div>
317          <div class="card-meta">
318            <span>📅 ${new Date(art.publishedAt).toLocaleDateString()}</span>
319            <span>👁 ${art.views || 0} reads</span>
320          </div>
321          <h3 class="card-title">
322            <a href="#blog/${art.slug}">${art.title}</a>
323          </h3>
324          <p class="card-desc">${art.excerpt}</p>
325          
326          <div class="tool-card-tags" style="margin-bottom:20px;">
327            ${art.tags.slice(0, 3).map(t => `<span class="tag-badge">#${t}</span>`).join('')}
328          </div>
329          
330          <div class="card-author">
331            <img src="https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&w=150&q=80" class="author-avatar" alt="Author">
332            <span class="author-name">Alex Mercer</span>
333          </div>
334        </div>
335      `).join('');
336    };
337
338    [searchIn, catSelect, sortSelect].forEach(el => el.addEventListener("input", runFilters));
339    runFilters();
340  },
341
342  // 3. Single Article view compiler
343  renderSingleArticle(el, slug) {
344    const art = window.db.getArticleBySlug(slug);
345    if (!art) {
346      el.innerHTML = `<h2>Article Not Found</h2><p>This path does not map to any active post publication.</p>`;
347      return;
348    }
349
350    // Increment Views count
351    window.db.incrementViews(art.id);
352
353    const categories = window.db.getCategories();
354    const catName = categories.find(c => c.id === art.categoryId)?.name || "Tech News";
355    const comments = window.db.getComments(art.id).filter(c => c.status === "Approved");
356
357    // Breadcrumbs arrays
358    const crumbs = [
359      { name: "Home", url: "#home" },
360      { name: "Articles", url: "#blog" },
361      { name: art.title, url: "" }
362    ];
363
364    // Parse content
365    let contentHtml = "";
366    try {
367      const blocks = JSON.parse(art.content);
368      contentHtml = blocks.map(b => {
369        const idAnchor = (b.content || "").toLowerCase().replace(/[^a-z0-9]+/g, '-');
370        if (b.type === "heading") return `<h2 id="${idAnchor}" style="font-size:26px; margin:32px 0 16px 0; font-family:var(--font-heading);">${b.content}</h2>`;
371        if (b.type === "quote") return `<blockquote style="border-left:4px solid var(--accent-purple); padding:12px 24px; font-style:italic; font-size:16px; margin:24px 0; background:rgba(138, 63, 252, 0.03); border-radius:0 8px 8px 0;">${b.text || b.content}</blockquote>`;
372        if (b.type === "faq") return ``; // FAQ blocks are mapped to bottom accordion
373        return `<p style="font-size:15px; line-height:1.7; margin-bottom:20px; color:var(--text-secondary);">${b.content}</p>`;
374      }).join('');
375    } catch(e) {
376      contentHtml = `<p>${art.content}</p>`;
377    }
378
379    el.innerHTML = `
380      ${window.AIStackComponents.Breadcrumbs(crumbs)}
381
382      <div class="blog-layout">
383        <!-- Main Article Content column -->
384        <article style="display:flex; flex-direction:column; gap:20px;">
385          <h1 style="font-size:42px; line-height:1.2; font-family:var(--font-heading);">${art.title}</h1>
386          
387          <div style="display:flex; gap:16px; align-items:center; font-size:13px; color:var(--text-muted); border-bottom:1px solid var(--glass-border); padding-bottom:16px;">
388            <span>Category: <strong style="color:var(--accent-purple);">${catName}</strong></span>
389            <span>📅 Published: ${new Date(art.publishedAt).toLocaleDateString()}</span>
390            <span>👁 ${art.views + 1} views</span>
391          </div>
392
393          <div style="border-radius:16px; overflow:hidden; max-height:450px; border:1px solid var(--glass-border); box-shadow:var(--glass-shadow);">
394            <img src="https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&w=1200&q=80" style="width:100%; object-fit:cover; display:block;" alt="${art.title}" onerror="this.onerror=null; this.outerHTML = window.AIStackTools.createSvgFallback(\`${art.title.replace(/'/g, "\\'")}\`);">
395          </div>
396
397          <!-- Semantic Body Content markup -->
398          <div style="margin-top:24px;">
399            ${contentHtml}
400          </div>
401
402          <!-- YouTube curation embeds if present in DB -->
403          ${art.id === 'art_1' ? `
404            <div style="margin: 32px 0;">
405              <h4 style="font-size: 18px; margin-bottom:12px; font-family:var(--font-heading);">Video Explanation Case Study</h4>
406              ${window.AIStackComponents.VideoEmbed("https://www.youtube.com/watch?v=5rT88j2cZqI")}
407            </div>
408          ` : ''}
409
410          <!-- FAQ Component from article blocks -->
411          ${window.AIStackComponents.FAQAccordion(art.faqs)}
412
413          <!-- Social Share panel -->
414          ${window.AIStackComponents.SocialShare(window.location.href, art.title)}
415
416          <!-- Google AdSense Zone -->
417          ${window.AIStackComponents.AdZone("header")}
418
419          <!-- Comments Thread rendering -->
420          <div class="glass-panel" style="padding:32px; margin-top:40px; display:flex; flex-direction:column; gap:24px;">
421            <h3 style="font-size:22px; font-family:var(--font-heading);">Reader Discussion (${comments.length})</h3>
422            
423            <div style="display:flex; flex-direction:column; gap:16px;">
424              ${comments.length === 0 ? '<p style="font-size:13px; color:var(--text-muted);">No comments approved yet. Be the first to start the thread!</p>' : comments.map(c => `
425                <div style="border-bottom:1px solid var(--glass-border); padding-bottom:16px;">
426                  <div style="display:flex; justify-content:space-between; font-size:12px; font-weight:600;">
427                    <span>👤 ${c.name}</span>
428                    <span style="color:var(--text-muted);">${new Date(c.createdAt).toLocaleDateString()}</span>
429                  </div>
430                  <p style="font-size:14px; margin-top:6px; color:var(--text-secondary);">"${c.content}"</p>
431                </div>
432              `).join('')}
433            </div>
434
435            <!-- Submit Guest Comment Form -->
436            <div style="border-t:1px solid var(--glass-border); padding-top:24px; margin-top:16px;">
437              <h4 style="font-size:16px; font-family:var(--font-heading); margin-bottom:12px;">Add Guest Comment</h4>
438              <form id="comment-submission-form" style="display:flex; flex-direction:column; gap:12px;">
439                <div style="display:grid; grid-template-columns:1fr 1fr; gap:16px;">
440                  <input type="text" id="comm-name" class="form-control" placeholder="Name" required>
441                  <input type="email" id="comm-email" class="form-control" placeholder="Email (private)" required>
442                </div>
443                <textarea id="comm-content" class="form-control" style="height:80px;" placeholder="Join the discussion thread..." required></textarea>
444                <button type="submit" class="btn btn-primary" style="align-self:flex-start;">Submit for Review</button>
445              </form>
446            </div>
447          </div>
448        </article>
449
450        <!-- Right TOC Sticky sidebar -->
451        <aside>
452          ${window.AIStackComponents.TableOfContents(art.content)}
453          ${window.AIStackComponents.AdZone("sidebar")}
454        </aside>
455      </div>
456    `;
457
458    // Handle Comment Submit
459    document.getElementById("comment-submission-form").addEventListener("submit", (e) => {
460      e.preventDefault();
461      const name = document.getElementById("comm-name").value.trim();
462      const email = document.getElementById("comm-email").value.trim();
463      const content = document.getElementById("comm-content").value.trim();
464
465      window.db.saveComment({
466        articleId: art.id,
467        name,
468        email,
469        content,
470        status: "Pending" // Require moderate approval queue
471      });
472
473      window.AIStackTools.showToast("Comment submitted! Awaiting moderator validation.");
474      document.getElementById("comm-name").value = "";
475      document.getElementById("comm-email").value = "";
476      document.getElementById("comm-content").value = "";
477    });
478  },
479
480  // 4. News Listing Page compiler
481  renderNewsListing(el) {
482    const news = window.db.getArticles().filter(a => a.categoryId === "cat_news" && a.status === 'Published');
483    el.innerHTML = `
484      <h2 style="font-size:36px; text-align:center; margin-bottom:8px; font-family:var(--font-heading);">Breaking AI News</h2>
485      <p style="text-align:center; color:var(--text-secondary); max-width:600px; margin:0 auto 40px auto;">
486        Real-time releases, corporate upgrades, global safety policies, and model launches.
487      </p>
488
489      <div style="display:grid; grid-template-columns:2.5fr 1fr; gap:40px;">
490        <!-- Left: News streams -->
491        <div style="display:flex; flex-direction:column; gap:24px;">
492          ${news.map(art => `
493            <div class="glass-panel" style="padding:24px; display:grid; grid-template-columns:180px 1fr; gap:20px;">
494              <div style="height:120px; border-radius:8px; overflow:hidden;">
495                <img src="https://images.unsplash.com/photo-1620712943543-bcc4688e7485?auto=format&fit=crop&w=200&q=80" style="width:100%; height:100%; object-fit:cover;" onerror="this.onerror=null; this.outerHTML = window.AIStackTools.createSvgFallback(\`${art.title.replace(/'/g, "\\'")}\`);">
496              </div>
497              <div>
498                <span style="font-size:11px; text-transform:uppercase; color:var(--accent-purple); font-weight:bold;">News Bulletin</span>
499                <h3 style="font-size:20px; font-family:var(--font-heading); margin-top:4px;"><a href="#blog/${art.slug}">${art.title}</a></h3>
500                <p style="font-size:13px; color:var(--text-secondary); margin-top:8px;">${art.excerpt}</p>
501                <div style="display:flex; gap:16px; margin-top:12px; font-size:12px; color:var(--text-muted);">
502                  <span>👁 ${art.views || 0} reads</span>
503                  <span>📅 Published ${new Date(art.publishedAt).toLocaleDateString()}</span>
504                </div>
505              </div>
506            </div>
507          `).join('')}
508        </div>
509
510        <!-- Right: Editor Picks -->
511        <div>
512          <div class="glass-panel" style="padding:20px; position:sticky; top:90px;">
513            <h4 style="font-size:16px; font-family:var(--font-heading); margin-bottom:16px; border-bottom:1px solid var(--glass-border); padding-bottom:8px;">Weekly Bulletins</h4>
514            <ul style="list-style:none; display:flex; flex-direction:column; gap:12px;">
515              <li>
516                <span style="font-size:11px; color:#ef4444; font-weight:bold;">🔥 BREAKING</span>
517                <p style="font-size:13px; font-weight:500;">Google announces Gemini 2.0 specs release details next week.</p>
518              </li>
519              <li>
520                <span style="font-size:11px; color:var(--accent-blue); font-weight:bold;">💡 TRENDING</span>
521                <p style="font-size:13px; font-weight:500;">Mistral releases large codegen models competing with Llama weights.</p>
522              </li>
523            </ul>
524          </div>
525        </div>
526      </div>
527    `;
528  },
529
530  // 5. Tools Directory compiler
531  renderToolsDirectory(el) {
532    const tools = window.db.getTools();
533    const categories = ["Writing", "Coding", "Design", "Video", "Audio", "Productivity"];
534
535    el.innerHTML = `
536      <h2 style="font-size:36px; text-align:center; margin-bottom:8px; font-family:var(--font-heading);">AI Tools Directory</h2>
537      <p style="text-align:center; color:var(--text-secondary); max-width:600px; margin:0 auto 40px auto;">
538        Filter and explore the highest rated productivity tools to automate your workflows.
539      </p>
540
541      <div class="filters-bar" style="justify-content:center; gap:12px;">
542        <button class="btn btn-secondary active tool-cat-filter" style="padding:8px 16px; border-radius:100px;" data-cat="all">All Categories</button>
543        ${categories.map(cat => `
544          <button class="btn btn-secondary tool-cat-filter" style="padding:8px 16px; border-radius:100px;" data-cat="${cat}">${cat}</button>
545        `).join('')}
546      </div>
547
548      <div class="grid-4" id="tools-grid-render" style="margin-top:30px;">
549        <!-- Rendered via JS -->
550      </div>
551    `;
552
553    const grid = document.getElementById("tools-grid-render");
554    const filters = document.querySelectorAll(".tool-cat-filter");
555
556    const filterTools = (cat) => {
557      const filtered = cat === "all" ? tools : tools.filter(t => t.category === cat);
558      
559      grid.innerHTML = filtered.map(t => `
560        <div class="glass-panel card">
561          <div class="tool-card-header">
562            <div class="tool-logo-box">${t.logo}</div>
563            <div>
564              <h4 style="font-size:15px; font-weight:bold;">${t.name}</h4>
565              <span style="font-size:11px; color:var(--text-muted);">${t.category}</span>
566            </div>
567          </div>
568          <p style="font-size:13px; color:var(--text-secondary); margin-bottom:12px; flex-grow:1;">${t.description}</p>
569          <div style="display:flex; justify-content:space-between; align-items:center; border-top:1px solid var(--glass-border); padding-top:10px; font-size:11px;">
570            <span style="color:#f59e0b; font-weight:bold;">★ ${t.ratings}</span>
571            <span class="tool-badge-pricing">${t.pricingType}</span>
572          </div>
573          <a href="${t.websiteUrl}" target="_blank" class="btn btn-secondary" style="margin-top:16px; width:100%; font-size:12px; padding:6px 0;">Visit Website</a>
574        </div>
575      `).join('');
576    };
577
578    filters.forEach(btn => {
579      btn.addEventListener("click", () => {
580        filters.forEach(b => b.classList.remove("active"));
581        btn.classList.add("active");
582        filterTools(btn.getAttribute("data-cat"));
583      });
584    });
585
586    filterTools("all");
587  },
588
589  // 6. Models Directory comparison grid compiler
590  renderModelsDirectory(el) {
591    const list = window.db.getModels();
592    
593    el.innerHTML = `
594      <h2 style="font-size:36px; text-align:center; margin-bottom:8px; font-family:var(--font-heading);">LLM Benchmarks & Comparisons</h2>
595      <p style="text-align:center; color:var(--text-secondary); max-width:600px; margin:0 auto 40px auto;">
596        Objective technical breakdown comparing foundation parameters, strengths, weaknesses, and context lengths.
597      </p>
598
599      <div class="glass-panel" style="overflow-x:auto; padding:24px;">
600        <div style="min-width:750px;">
601          <!-- Header row -->
602          <div class="model-comparison-row" style="border-bottom:2px solid var(--glass-border); font-weight:bold; color:var(--text-muted);">
603            <div>Model Specs</div>
604            <div>Context Length</div>
605            <div>Core Strengths</div>
606            <div>MMLU / Benchmarks</div>
607          </div>
608          
609          <!-- Rows -->
610          ${list.map(m => `
611            <div class="model-comparison-row" style="align-items:center;">
612              <div>
613                <h4 style="font-size:16px; color:var(--accent-purple);">${m.name}</h4>
614                <span style="font-size:11px; color:var(--text-muted);">Dev: ${m.developer}</span>
615              </div>
616              <div style="font-weight:bold;">
617                ${(m.contextLength / 1000).toFixed(0)}k tokens
618              </div>
619              <div style="font-size:13px; color:var(--text-secondary);">
620                ${m.strengths}
621              </div>
622              <div>
623                <div style="display:flex; flex-direction:column; gap:4px; font-size:12px;">
624                  <span>MMLU: <strong>${m.benchmarks.mmlu}</strong></span>
625                  <span>Code Eval: <strong>${m.benchmarks.code}</strong></span>
626                </div>
627              </div>
628            </div>
629          `).join('')}
630        </div>
631      </div>
632    `;
633  },
634
635  // 7. YouTube curations page compiler
636  renderVideosPage(el) {
637    const list = window.db.getVideos();
638    el.innerHTML = `
639      <h2 style="font-size:36px; text-align:center; margin-bottom:8px; font-family:var(--font-heading);">Masterclasses & Explanations</h2>
640      <p style="text-align:center; color:var(--text-secondary); max-width:600px; margin:0 auto 40px auto;">
641        Watch step-by-step guides curated by the community to build custom models and automate operations.
642      </p>
643
644      <div class="grid-2" style="margin-top:30px;">
645        ${list.map(v => `
646          <div class="glass-panel card" style="padding:16px;">
647            ${window.AIStackComponents.VideoEmbed(v.youtubeUrl)}
648            <h3 style="font-size:17px; margin-top:14px; font-family:var(--font-heading);">${v.title}</h3>
649            <span class="tag-badge" style="align-self:flex-start; margin-top:8px;">📁 ${v.category}</span>
650          </div>
651        `).join('')}
652      </div>
653    `;
654  },
655
656  // 8. Interactive Utilities Section compiler
657  renderUtilityToolsSection(el, selectedTool) {
658    const cats = window.AIStackTools.categories;
659
660    el.innerHTML = `
661      <h2 style="font-size:36px; text-align:center; margin-bottom:8px; font-family:var(--font-heading);">Utilities & Developer Sandbox</h2>
662      <p style="text-align:center; color:var(--text-secondary); max-width:600px; margin:0 auto 30px auto;">
663        30 client-side diagnostic and formatting tools running entirely inside your browser sandboxes.
664      </p>
665
666      <div class="tools-playground">
667        <!-- Sidebar Navigation lists -->
668        <aside class="glass-panel" style="padding:20px; display:flex; flex-direction:column; gap:16px; max-height:75vh; overflow-y:auto;">
669          
670          <div>
671            <h4 style="font-size:11px; text-transform:uppercase; color:var(--text-muted); margin-bottom:8px;">🎨 Web & Design</h4>
672            ${cats.design.map(t => `
673              <button class="tools-cat-btn ${selectedTool === t.id ? 'active':''}" onclick="window.AIStackApp.routeTool('${t.id}')">
674                <span style="font-size:12px;">${t.name}</span>
675              </button>
676            `).join('')}
677          </div>
678
679          <div>
680            <h4 style="font-size:11px; text-transform:uppercase; color:var(--text-muted); margin-bottom:8px; margin-top:12px;">⚙ Developer Tools</h4>
681            ${cats.developer.map(t => `
682              <button class="tools-cat-btn ${selectedTool === t.id ? 'active':''}" onclick="window.AIStackApp.routeTool('${t.id}')">
683                <span style="font-size:12px;">${t.name}</span>
684              </button>
685            `).join('')}
686          </div>
687
688          <div>
689            <h4 style="font-size:11px; text-transform:uppercase; color:var(--text-muted); margin-bottom:8px; margin-top:12px;">🔍 SEO Tools</h4>
690            ${cats.seo.map(t => `
691              <button class="tools-cat-btn ${selectedTool === t.id ? 'active':''}" onclick="window.AIStackApp.routeTool('${t.id}')">
692                <span style="font-size:12px;">${t.name}</span>
693              </button>
694            `).join('')}
695          </div>
696
697          <div>
698            <h4 style="font-size:11px; text-transform:uppercase; color:var(--text-muted); margin-bottom:8px; margin-top:12px;">📋 Productivity</h4>
699            ${cats.productivity.map(t => `
700              <button class="tools-cat-btn ${selectedTool === t.id ? 'active':''}" onclick="window.AIStackApp.routeTool('${t.id}')">
701                <span style="font-size:12px;">${t.name}</span>
702              </button>
703            `).join('')}
704          </div>
705
706        </aside>
707
708        <!-- Right Active Work Panel -->
709        <div id="tool-workspace-content">
710          <!-- Loaded dynamically -->
711        </div>
712      </div>
713    `;
714
715    // Render active selection
716    const activeTool = selectedTool || "webp_converter";
717    window.AIStackTools.renderTool(activeTool);
718  },
719
720  routeTool(id) {
721    window.location.hash = `#utility/${id}`;
722  },
723
724  // 9. Static pages renderer (About, support, privacy, terms, disclaimers)
725  renderStaticPage(el, pageId) {
726    const titles = {
727      about: "About AIStackHub",
728      contact: "Contact Platform Support",
729      privacy: "Privacy & Data Protection Policy",
730      terms: "Terms & Conditions of Service",
731      disclaimer: "Legal Disclaimer Notices"
732    };
733
734    const content = {
735      about: "<p>AIStackHub is an enterprise SaaS platform showcasing next-generation developer sandbox tools, models comparisons, and structured marketing calculators. We deliver optimized Core Web Vitals to our global developer audiences.</p>",
736      contact: "<p>Have support queries or sponsorships proposals? Contact our engineering team: <strong>[email protected]</strong></p>",
737      privacy: "<p>All developer tool compilations, transcoder outputs, and format conversions occur strictly browser-side. We collect zero uploads or database credentials in local sandboxes.</p>",
738      terms: "<p>Usage of the utility components is completely free. We bear zero liabilities for estimate sheets or invoice files compiled via PDF generator tools.</p>",
739      disclaimer: "<p>
739Simulated analytical models and benchmarks do not guarantee specific local accuracy. Review official developers networks for API documentation changes.</p>"
740    };
741
742    el.innerHTML = `
743      <div class="glass-panel" style="padding:40px; max-width:800px; margin:40px auto; display:flex; flex-direction:column; gap:20px;">
744        <h2 style="font-size:32px; font-family:var(--font-heading);">${titles[pageId]}</h2>
745        <div style="line-height:1.7; color:var(--text-secondary); font-size:15px;">
746          ${content[pageId]}
747        </div>
748      </div>
749    `;
750  }
751};
752
753// Start
754document.addEventListener("DOMContentLoaded", () => window.AIStackApp.init());

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.