| <script>if(window===top) location.href="/?app=appstore";</script> |
|
|
| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>App Store - LunOS</title> |
| <script src="/static/lunid-auth.js"></script> |
| <style> |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| } |
| |
| body { |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; |
| background: #fff; |
| overflow-x: hidden; |
| } |
| |
| .app-header { |
| padding: 30px 20px 15px; |
| background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| position: fixed; |
| top: 0; |
| left: 0; |
| right: 0; |
| z-index: 100; |
| } |
| |
| .app-back-btn { |
| width: 36px; |
| height: 36px; |
| border-radius: 50%; |
| background: rgba(255, 255, 255, 0.2); |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| cursor: pointer; |
| } |
| |
| .app-title { |
| font-size: 24px; |
| color: #fff; |
| font-weight: 600; |
| } |
| |
| .search-bar { |
| background: #fff; |
| padding: 12px 16px; |
| border-bottom: 1px solid #e0e0e0; |
| margin-top: 75px; |
| padding-bottom: 65px; |
| } |
| |
| .search-input { |
| background: #f1f3f4; |
| border-radius: 8px; |
| padding: 10px 16px; |
| display: flex; |
| align-items: center; |
| gap: 12px; |
| } |
| |
| .search-input input { |
| flex: 1; |
| border: none; |
| background: transparent; |
| font-size: 16px; |
| color: #202124; |
| outline: none; |
| } |
| |
| .store-tabs { |
| background: #fff; |
| display: flex; |
| border-bottom: 2px solid #e0e0e0; |
| position: sticky; |
| top: 137px; |
| z-index: 99; |
| } |
| |
| .store-tab { |
| flex: 1; |
| text-align: center; |
| padding: 14px 0; |
| font-weight: 500; |
| color: #5f6368; |
| cursor: pointer; |
| border-bottom: 3px solid transparent; |
| } |
| |
| .store-tab.active { |
| color: #3b82f6; |
| border-bottom-color: #3b82f6; |
| } |
| |
| .tab-content { |
| display: none; |
| min-height: calc(100vh - 200px); |
| padding-bottom: 80px; |
| } |
| |
| .tab-content.active { |
| display: block; |
| } |
| |
| .app-card { |
| display: flex; |
| align-items: center; |
| gap: 16px; |
| padding: 12px 16px; |
| cursor: pointer; |
| border-bottom: 1px solid #e8eaed; |
| } |
| |
| .app-icon { |
| width: 56px; |
| height: 56px; |
| border-radius: 14px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| font-size: 28px; |
| flex-shrink: 0; |
| } |
| |
| .app-info { |
| flex: 1; |
| min-width: 0; |
| } |
| |
| .app-name { |
| font-weight: 500; |
| font-size: 14px; |
| color: #202124; |
| margin-bottom: 2px; |
| } |
| |
| .app-developer { |
| font-size: 12px; |
| color: #5f6368; |
| margin-bottom: 4px; |
| } |
| |
| .app-rating { |
| display: flex; |
| align-items: center; |
| gap: 6px; |
| font-size: 11px; |
| color: #5f6368; |
| } |
| |
| .install-btn { |
| padding: 6px 16px; |
| background: #3b82f6; |
| color: #fff; |
| border: none; |
| border-radius: 20px; |
| font-weight: 600; |
| font-size: 12px; |
| cursor: pointer; |
| } |
| |
| .install-btn.installed { |
| background: #e8eaed; |
| color: #3b82f6; |
| } |
| |
| .featured-section { |
| padding: 16px 0; |
| } |
| |
| .section-title { |
| display: flex; |
| align-items: center; |
| justify-content: space-between; |
| padding: 0 16px 12px; |
| } |
| |
| .section-title h3 { |
| font-size: 16px; |
| font-weight: 600; |
| color: #202124; |
| } |
| |
| .horizontal-scroll { |
| overflow-x: auto; |
| -webkit-overflow-scrolling: touch; |
| padding: 0 16px; |
| } |
| |
| .horizontal-scroll::-webkit-scrollbar { |
| display: none; |
| } |
| |
| .apps-row { |
| display: flex; |
| gap: 12px; |
| width: max-content; |
| } |
| |
| .small-app-card { |
| width: 120px; |
| cursor: pointer; |
| } |
| |
| .small-app-icon { |
| width: 120px; |
| height: 120px; |
| border-radius: 16px; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| font-size: 48px; |
| margin-bottom: 8px; |
| } |
| |
| .category-grid { |
| display: grid; |
| grid-template-columns: repeat(2, 1fr); |
| gap: 12px; |
| padding: 16px; |
| } |
| |
| .category-card { |
| background: #f8f9fa; |
| border-radius: 12px; |
| padding: 20px; |
| text-align: center; |
| cursor: pointer; |
| transition: background 0.2s; |
| } |
| |
| .category-card:hover { |
| background: #e8eaed; |
| } |
| |
| .category-icon { |
| font-size: 40px; |
| margin-bottom: 8px; |
| } |
| |
| .toast { |
| position: fixed; |
| bottom: 20px; |
| left: 50%; |
| transform: translateX(-50%); |
| background: rgba(0, 0, 0, 0.8); |
| color: white; |
| padding: 12px 24px; |
| border-radius: 20px; |
| font-size: 14px; |
| z-index: 10000; |
| display: none; |
| } |
| </style> |
| </head> |
| <body> |
| <div class="app-header"> |
| <div class="app-back-btn" onclick="goBack()"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"> |
| <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/> |
| </svg> |
| </div> |
| <div class="app-title">App Store</div> |
| <div style="display: flex; gap: 8px;"> |
| <div class="app-back-btn" onclick="showLunIDModal()" id="authBtn" style="background: rgba(255, 255, 255, 0.3);"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="#fff"> |
| <path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/> |
| </svg> |
| </div> |
| <div class="app-back-btn" onclick="if(window.parent !== window) { window.parent.postMessage({action:'openUploadApp'}, '*'); } else { window.location.href='upload-app.html'; }" style="background: rgba(255, 255, 255, 0.3);"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"> |
| <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> |
| </svg> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="lunidModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.9); z-index:20000; overflow-y:auto;"> |
| <div style="max-width:400px; margin:40px auto; padding:20px;"> |
| <div style="display:flex; justify-content:flex-end; margin-bottom:10px;"> |
| <button onclick="closeLunIDModal()" style="background:none; border:none; color:#fff; font-size:28px; cursor:pointer;">×</button> |
| </div> |
| <div id="lunidAuthContainer"></div> |
| </div> |
| </div> |
|
|
| <div class="search-bar"> |
| <div class="search-input"> |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="#5f6368"> |
| <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/> |
| </svg> |
| <input type="text" id="appStoreSearch" placeholder="Search for apps & games"> |
| </div> |
| </div> |
|
|
| <div class="store-tabs"> |
| <div class="store-tab active" onclick="switchTab('forYou')">For you</div> |
| <div class="store-tab" onclick="switchTab('topCharts')">Top charts</div> |
| <div class="store-tab" onclick="switchTab('categories')">Categories</div> |
| </div> |
|
|
| <div id="forYouContent" class="tab-content active"></div> |
| <div id="topChartsContent" class="tab-content"></div> |
| <div id="categoriesContent" class="tab-content"></div> |
|
|
| <div id="toast" class="toast"></div> |
|
|
|
|
| <script> |
| // Load user-submitted apps from localStorage |
| const userSubmittedApps = JSON.parse(localStorage.getItem('userSubmittedApps') || '[]'); |
| const approvedUserApps = userSubmittedApps.filter(app => app.approved).map(app => ({ |
| ...app, |
| rating: app.rating || 4.5, |
| downloads: app.downloads || '100+' |
| })); |
| |
| const availableApps = [ |
| { |
| id: 'fynwriteApp', |
| name: 'FynWrite', |
| developer: 'LunOS Team', |
| category: 'Productivity', |
| description: 'Write, share, and discover amazing stories. FynWrite is your personal blog platform on LunOS.', |
| rating: 4.7, |
| downloads: '100K+', |
| icon: '📝', |
| color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', |
| featured: true, |
| size: '2.5 MB', |
| ageRating: '12+', |
| url: 'fynwrite.html' |
| }, |
| { |
| id: 'sudoku', |
| name: 'Pro Sudoku', |
| developer: 'LunOS Games', |
| category: 'Games', |
| description: 'Classic Sudoku puzzle with 4 difficulty levels. Train your brain with daily challenges, hints, and beautiful UI. Track your stats and improve your skills!', |
| rating: 4.9, |
| downloads: '5M+', |
| icon: '<svg viewBox="0 0 60 60" style="width:100%;height:100%"><defs><linearGradient id="sudokuGrad" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#667eea"/><stop offset="100%" style="stop-color:#764ba2"/></linearGradient></defs><rect width="60" height="60" rx="12" fill="url(#sudokuGrad)"/><rect x="6" y="6" width="16" height="16" fill="white" opacity="0.9" rx="2"/><rect x="22" y="6" width="16" height="16" fill="white" opacity="0.7" rx="2"/><rect x="38" y="6" width="16" height="16" fill="white" opacity="0.9" rx="2"/><rect x="6" y="22" width="16" height="16" fill="white" opacity="0.7" rx="2"/><rect x="22" y="22" width="16" height="16" fill="white" opacity="0.9" rx="2"/><rect x="38" y="22" width="16" height="16" fill="white" opacity="0.7" rx="2"/><rect x="6" y="38" width="16" height="16" fill="white" opacity="0.9" rx="2"/><rect x="22" y="38" width="16" height="16" fill="white" opacity="0.7" rx="2"/><rect x="38" y="38" width="16" height="16" fill="white" opacity="0.9" rx="2"/></svg>', |
| color: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)', |
| featured: true, |
| topFree: true, |
| size: '2.1 MB', |
| ageRating: '4+', |
| inAppPurchases: false, |
| url: 'sudoku.html', |
| screenshots: ['📱 Clean interface', '🎯 4 difficulty levels', '💡 Smart hints', '📊 Track progress'] |
| }, |
| ...approvedUserApps, |
| { |
| id: 'game-snake', |
| name: 'Snake Game', |
| developer: 'FynNX Games', |
| category: 'Games', |
| description: 'Classic snake game with modern graphics.', |
| rating: 4.5, |
| downloads: '500K+', |
| icon: '🐍', |
| color: 'linear-gradient(135deg, #22c55e 0%, #16a34a 100%)', |
| featured: true, |
| size: '1.5 MB', |
| ageRating: '4+' |
| }, |
| { |
| id: 'app-todo', |
| name: 'Todo List Pro', |
| developer: 'Productivity Pro', |
| category: 'Productivity', |
| description: 'Simple todo list app to organize your tasks.', |
| rating: 4.8, |
| downloads: '1M+', |
| icon: '✓', |
| color: 'linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)', |
| featured: true, |
| size: '0.8 MB', |
| ageRating: '4+' |
| }, |
| { |
| id: 'game-puzzle', |
| name: 'Puzzle Master', |
| developer: 'FynNX Games', |
| category: 'Games', |
| description: 'Challenging puzzle game with hundreds of levels.', |
| rating: 4.6, |
| downloads: '2M+', |
| icon: '🧩', |
| color: 'linear-gradient(135deg, #8b5cf6 0%, #6d28d9 100%)', |
| topFree: true, |
| size: '3.2 MB', |
| ageRating: '9+' |
| } |
| ]; |
| |
| function switchTab(tabName) { |
| document.querySelectorAll('.store-tab').forEach(tab => { |
| tab.classList.remove('active'); |
| }); |
| document.querySelectorAll('.tab-content').forEach(content => { |
| content.classList.remove('active'); |
| }); |
| |
| event.target.classList.add('active'); |
| document.getElementById(tabName + 'Content').classList.add('active'); |
| |
| if (tabName === 'forYou') loadForYou(); |
| else if (tabName === 'topCharts') loadTopCharts(); |
| else if (tabName === 'categories') loadCategories(); |
| } |
| |
| function loadForYou() { |
| const container = document.getElementById('forYouContent'); |
| const featured = availableApps.filter(app => app.featured); |
| |
| container.innerHTML = ` |
| <div class="featured-section"> |
| <div class="section-title"> |
| <h3>Featured Apps</h3> |
| </div> |
| <div class="horizontal-scroll"> |
| <div class="apps-row"> |
| ${featured.map(app => ` |
| <div class="small-app-card" onclick="installApp('${app.id}')"> |
| <div class="small-app-icon" style="background: ${app.color}">${app.icon}</div> |
| <div style="font-size: 13px; font-weight: 500; color: #202124;">${app.name}</div> |
| <div style="font-size: 11px; color: #5f6368;">⭐ ${app.rating}</div> |
| </div> |
| `).join('')} |
| </div> |
| </div> |
| </div> |
| <div style="padding: 16px;"> |
| ${availableApps.map(app => createAppCard(app)).join('')} |
| </div> |
| `; |
| } |
| |
| function loadTopCharts() { |
| const container = document.getElementById('topChartsContent'); |
| const topApps = availableApps.filter(app => app.topFree); |
| |
| container.innerHTML = ` |
| <div style="padding: 16px;"> |
| <h3 style="margin-bottom: 16px;">Top Free Apps</h3> |
| ${topApps.map(app => createAppCard(app)).join('')} |
| </div> |
| `; |
| } |
| |
| function loadCategories() { |
| const container = document.getElementById('categoriesContent'); |
| const categories = [ |
| { name: 'Games', icon: '🎮' }, |
| { name: 'Productivity', icon: '💼' }, |
| { name: 'Music', icon: '🎵' }, |
| { name: 'Creative', icon: '🎨' } |
| ]; |
| |
| container.innerHTML = ` |
| <div class="category-grid"> |
| ${categories.map(cat => ` |
| <div class="category-card"> |
| <div class="category-icon">${cat.icon}</div> |
| <div style="font-weight: 500;">${cat.name}</div> |
| </div> |
| `).join('')} |
| </div> |
| `; |
| } |
| |
| function createAppCard(app) { |
| const isInstalled = getInstalledApps().includes(app.id); |
| return ` |
| <div class="app-card" onclick="showAppDetails('${app.id}')"> |
| <div class="app-icon" style="background: ${app.color}">${app.icon}</div> |
| <div class="app-info"> |
| <div class="app-name">${app.name}</div> |
| <div class="app-developer">${app.developer}</div> |
| <div class="app-rating">⭐ ${app.rating} • ${app.downloads || '1K+'} downloads</div> |
| </div> |
| <button class="install-btn ${isInstalled ? 'installed' : ''}" onclick="event.stopPropagation(); installApp('${app.id}')"> |
| ${isInstalled ? 'OPEN' : 'GET'} |
| </button> |
| </div> |
| `; |
| } |
| |
| function showAppDetails(appId) { |
| const app = availableApps.find(a => a.id === appId); |
| if (!app) return; |
| |
| const isInstalled = getInstalledApps().includes(app.id); |
| const detailsHTML = ` |
| <div style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: #fff; z-index: 10001; overflow-y: auto;"> |
| <div class="app-header"> |
| <div class="app-back-btn" onclick="closeAppDetails()"> |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="#fff"> |
| <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/> |
| </svg> |
| </div> |
| <div class="app-title">${app.name}</div> |
| <div style="width: 36px;"></div> |
| </div> |
| |
| <div style="padding: 20px; padding-top: 80px;"> |
| <div style="display: flex; gap: 16px; margin-bottom: 20px;"> |
| <div style="width: 80px; height: 80px; border-radius: 18px; background: ${app.color}; display: flex; align-items: center; justify-content: center; font-size: 40px; flex-shrink: 0;">${app.icon}</div> |
| <div style="flex: 1;"> |
| <div style="font-size: 20px; font-weight: 600; margin-bottom: 4px;">${app.name}</div> |
| <div style="color: #5f6368; margin-bottom: 8px;">${app.developer}</div> |
| <div style="display: flex; gap: 12px; font-size: 12px; color: #5f6368;"> |
| <div>${app.downloads} downloads</div> |
| <div>⭐ ${app.rating}</div> |
| <div>${app.ageRating || '4+'}</div> |
| </div> |
| </div> |
| </div> |
| |
| <button class="install-btn ${isInstalled ? 'installed' : ''}" onclick="installApp('${app.id}')" style="width: 100%; padding: 12px; font-size: 16px; margin-bottom: 20px;"> |
| ${isInstalled ? 'OPEN' : 'INSTALL'} |
| </button> |
| |
| ${app.screenshots ? ` |
| <div style="margin-bottom: 20px;"> |
| <div style="font-weight: 600; margin-bottom: 12px;">Screenshots & Features</div> |
| <div style="display: flex; gap: 12px; overflow-x: auto; padding-bottom: 10px; -webkit-overflow-scrolling: touch;"> |
| ${app.screenshots.map((ss, idx) => ` |
| <div style="min-width: 160px; height: 280px; background: linear-gradient(180deg, #667eea 0%, #764ba2 100%); border-radius: 12px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; position: relative; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.1);"> |
| <div style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255,255,255,0.1); backdrop-filter: blur(20px);"></div> |
| <div style="position: relative; text-align: center; color: white; font-size: 13px; padding: 16px; font-weight: 500;"> |
| ${ss} |
| </div> |
| </div> |
| `).join('')} |
| </div> |
| </div> |
| ` : ''} |
| |
| <div style="margin-bottom: 20px;"> |
| <div style="font-weight: 600; margin-bottom: 8px;">About this app</div> |
| <div style="color: #5f6368; line-height: 1.6;">${app.description}</div> |
| </div> |
| |
| <div style="padding: 16px; background: #f8f9fa; border-radius: 12px; margin-bottom: 20px;"> |
| <div style="display: flex; justify-content: space-between; margin-bottom: 12px;"> |
| <span style="color: #5f6368;">Size</span> |
| <span style="font-weight: 500;">${app.size || 'N/A'}</span> |
| </div> |
| <div style="display: flex; justify-content: space-between; margin-bottom: 12px;"> |
| <span style="color: #5f6368;">Category</span> |
| <span style="font-weight: 500;">${app.category}</span> |
| </div> |
| <div style="display: flex; justify-content: space-between;"> |
| <span style="color: #5f6368;">In-app purchases</span> |
| <span style="font-weight: 500;">${app.inAppPurchases ? 'Yes' : 'No'}</span> |
| </div> |
| </div> |
| |
| <div style="margin-bottom: 20px;"> |
| <div style="font-weight: 600; margin-bottom: 8px;">Ratings and reviews</div> |
| <div style="display: flex; align-items: center; gap: 16px;"> |
| <div style="font-size: 48px; font-weight: 600;">${app.rating}</div> |
| <div style="flex: 1;"> |
| <div style="color: #fbbf24; margin-bottom: 4px;">★★★★★</div> |
| <div style="color: #5f6368; font-size: 12px;">${app.downloads} reviews</div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| `; |
| |
| const detailsDiv = document.createElement('div'); |
| detailsDiv.id = 'appDetails'; |
| detailsDiv.innerHTML = detailsHTML; |
| document.body.appendChild(detailsDiv); |
| } |
| |
| function closeAppDetails() { |
| const details = document.getElementById('appDetails'); |
| if (details) details.remove(); |
| } |
| |
| function installApp(appId) { |
| const installed = getInstalledApps(); |
| const app = availableApps.find(a => a.id === appId); |
| |
| if (!app) return; |
| |
| // Add app to home screen |
| const homeApps = JSON.parse(localStorage.getItem('homeScreenApps') || '[]'); |
| if (!homeApps.find(a => a.id === app.id)) { |
| homeApps.push({ |
| id: app.id, |
| name: app.name, |
| icon: app.icon, |
| color: app.color, |
| category: app.category, |
| url: app.url || null |
| }); |
| localStorage.setItem('homeScreenApps', JSON.stringify(homeApps)); |
| localStorage.setItem('installedStoreApps', JSON.stringify([...getInstalledApps(), appId])); |
| |
| // Refresh parent UI immediately |
| if (window.parent !== window) { |
| window.parent.location.reload(); |
| } |
| } |
| |
| if (!installed.includes(appId)) { |
| installed.push(appId); |
| localStorage.setItem('installedStoreApps', JSON.stringify(installed)); |
| |
| // Add app to home screen if not already there |
| const homeApps = JSON.parse(localStorage.getItem('homeScreenApps') || '[]'); |
| if (!homeApps.find(a => a.id === app.id)) { |
| homeApps.push({ |
| id: app.id, |
| name: app.name, |
| icon: app.icon, |
| color: app.color, |
| category: app.category, |
| url: app.url || null |
| }); |
| localStorage.setItem('homeScreenApps', JSON.stringify(homeApps)); |
| } |
| |
| showToast('App installed successfully!'); |
| |
| // Refresh local UI |
| loadForYou(); |
| |
| // Notify parent for live home screen/drawer update |
| if (window.parent !== window) { |
| window.parent.postMessage({ |
| type: 'appInstalled', |
| app: { |
| id: app.id, |
| name: app.name, |
| icon: app.icon, |
| color: app.color, |
| url: app.url |
| } |
| }, '*'); |
| } |
| } else { |
| // If already installed, open it via parent message to avoid iframe nesting issues |
| if (window.parent !== window) { |
| window.parent.postMessage({ |
| action: 'openApp', |
| app: app.id |
| }, '*'); |
| } else if (app.url) { |
| window.location.href = app.url; |
| } else { |
| showToast('App already installed'); |
| } |
| } |
| } |
| |
| function getInstalledApps() { |
| return JSON.parse(localStorage.getItem('installedStoreApps') || '[]'); |
| } |
| |
| function showToast(message) { |
| const toast = document.getElementById('toast'); |
| toast.textContent = message; |
| toast.style.display = 'block'; |
| setTimeout(() => toast.style.display = 'none', 2000); |
| } |
| |
| function goBack() { |
| if (window.parent !== window) { |
| window.parent.postMessage({action: 'closeApp'}, '*'); |
| } else { |
| window.location.href = 'index.html'; |
| } |
| } |
| |
| // LunID Authentication with Account Picker |
| function showLunIDModal() { |
| const modal = document.getElementById('lunidModal'); |
| modal.style.display = 'block'; |
| if (window.lunidAuth) { |
| lunidAuth.createAccountPickerUI('lunidAuthContainer', { |
| appName: 'App Store', |
| onContinue: (user) => { |
| closeLunIDModal(); |
| updateAuthUI(); |
| showToast('Welcome, ' + user.username + '!'); |
| }, |
| onCancel: closeLunIDModal |
| }); |
| } |
| } |
| |
| function closeLunIDModal() { document.getElementById('lunidModal').style.display = 'none'; } |
| |
| function handleLogout() { window.lunidAuth.logout(); closeLunIDModal(); updateAuthUI(); showToast('Signed out'); } |
| |
| function updateAuthUI() { |
| const btn = document.getElementById('authBtn'); |
| if (window.lunidAuth && window.lunidAuth.isAuthenticated) { |
| btn.innerHTML = `<span style="font-size:14px; font-weight:600;">${window.lunidAuth.currentUser.username.charAt(0).toUpperCase()}</span>`; |
| btn.style.background = 'linear-gradient(135deg,#667eea,#764ba2)'; |
| } else { |
| btn.innerHTML = '<svg width="20" height="20" viewBox="0 0 24 24" fill="#fff"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>'; |
| btn.style.background = 'rgba(255,255,255,0.3)'; |
| } |
| } |
| |
| // Add LunID styles |
| const styleEl = document.createElement('style'); |
| styleEl.textContent = window.LunIDAuth ? window.LunIDAuth.getStyles() : ''; |
| document.head.appendChild(styleEl); |
| |
| // Initialize |
| updateAuthUI(); |
| loadForYou(); |
| |
| document.getElementById('appStoreSearch').oninput = (e) => { |
| const query = e.target.value.toLowerCase(); |
| if (query) { |
| const results = availableApps.filter(app => |
| app.name.toLowerCase().includes(query) || |
| app.category.toLowerCase().includes(query) |
| ); |
| const container = document.getElementById('forYouContent'); |
| container.innerHTML = ` |
| <div style="padding: 16px;"> |
| <div style="color: #5f6368; margin-bottom: 16px;">${results.length} results</div> |
| ${results.map(app => createAppCard(app)).join('')} |
| </div> |
| `; |
| } else { |
| loadForYou(); |
| } |
| }; |
| </script> |
| </body> |
| </html> |
|
|