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.