Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>App Store - LunOS</title> | |
| <style> | |
| /* --- CORE THEME VARIABLES --- */ | |
| :root { | |
| --primary-color: #01875f; | |
| --primary-dark: #00694a; | |
| --bg-color: #ffffff; | |
| --surface-color: #ffffff; | |
| --surface-variant: #f1f3f4; /* Search bar, buttons */ | |
| --text-main: #202124; | |
| --text-secondary: #5f6368; | |
| --border-color: #dadce0; | |
| --header-shadow: 0 1px 2px rgba(60,64,67,0.3), 0 1px 3px 1px rgba(60,64,67,0.15); | |
| --card-hover: #f8f9fa; | |
| --overlay-bg: rgba(0,0,0,0.5); | |
| --modal-bg: #ffffff; | |
| --header-height: 64px; | |
| --nav-height: 64px; | |
| } | |
| /* Dark Mode Overrides */ | |
| body.dark-mode { | |
| --primary-color: #00a073; | |
| --primary-dark: #00694a; | |
| --bg-color: #131314; | |
| --surface-color: #1f1f1f; | |
| --surface-variant: #303134; | |
| --text-main: #e8eaed; | |
| --text-secondary: #9aa0a6; | |
| --border-color: #3c4043; | |
| --header-shadow: 0 1px 2px rgba(0,0,0,0.5); | |
| --card-hover: #303134; | |
| --overlay-bg: rgba(0,0,0,0.7); | |
| --modal-bg: #2d2e30; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| font-family: 'Google Sans', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; | |
| background: var(--bg-color); | |
| color: var(--text-main); | |
| overflow-x: hidden; | |
| line-height: 1.5; | |
| transition: background-color 0.3s, color 0.3s; | |
| } | |
| /* --- HEADER --- */ | |
| .app-header { | |
| height: var(--header-height); | |
| padding: 0 16px; | |
| background: var(--bg-color); | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| z-index: 1000; | |
| box-shadow: var(--header-shadow); | |
| transition: background 0.3s; | |
| } | |
| .header-left { display: flex; align-items: center; gap: 16px; flex: 1; } | |
| .header-right { display: flex; align-items: center; gap: 8px; } | |
| .app-back-btn { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| position: relative; | |
| } | |
| .app-back-btn:active { background: var(--surface-variant); } | |
| .app-back-btn svg { fill: var(--text-secondary); } | |
| .app-title { | |
| font-size: 20px; | |
| color: var(--text-main); | |
| font-weight: 500; | |
| } | |
| .profile-icon { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 50%; | |
| background: linear-gradient(45deg, #4285F4, #34A853, #FBBC05, #EA4335); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: white; | |
| font-weight: bold; | |
| font-size: 14px; | |
| cursor: pointer; | |
| border: 2px solid var(--bg-color); | |
| box-shadow: 0 0 0 1px var(--border-color); | |
| margin-left: 8px; | |
| } | |
| /* --- BOTTOM NAVIGATION --- */ | |
| .bottom-nav { | |
| position: fixed; | |
| bottom: 0; | |
| left: 0; | |
| right: 0; | |
| height: var(--nav-height); | |
| background: var(--bg-color); | |
| display: flex; | |
| justify-content: space-around; | |
| align-items: center; | |
| z-index: 1000; | |
| border-top: 1px solid var(--border-color); | |
| box-shadow: 0 -1px 3px rgba(0,0,0,0.05); | |
| transition: background 0.3s; | |
| } | |
| .nav-item { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 4px; | |
| cursor: pointer; | |
| color: var(--text-secondary); | |
| transition: color 0.2s; | |
| height: 100%; | |
| } | |
| .nav-item.active { | |
| color: var(--primary-color); | |
| } | |
| .nav-icon-box { | |
| width: 64px; | |
| height: 32px; | |
| border-radius: 16px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: background 0.2s; | |
| } | |
| .nav-item.active .nav-icon-box { | |
| background: #e6f3ef; | |
| } | |
| body.dark-mode .nav-item.active .nav-icon-box { | |
| background: #003829; | |
| } | |
| .nav-item svg { | |
| width: 24px; | |
| height: 24px; | |
| fill: currentColor; | |
| } | |
| .nav-label { | |
| font-size: 12px; | |
| font-weight: 500; | |
| } | |
| /* --- CONTENT AREAS --- */ | |
| .main-content { | |
| margin-top: var(--header-height); | |
| margin-bottom: var(--nav-height); | |
| min-height: calc(100dvh - var(--header-height) - var(--nav-height)); | |
| } | |
| .tab-content { display: none; padding-bottom: 20px; } | |
| .tab-content.active { display: block; animation: fadeIn 0.3s ease; } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| /* --- SEARCH BAR --- */ | |
| .search-container { | |
| padding: 12px 16px; | |
| background: var(--bg-color); | |
| transition: background 0.3s; | |
| } | |
| .search-input { | |
| background: var(--surface-variant); | |
| border-radius: 24px; | |
| padding: 0 16px; | |
| height: 48px; | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| transition: background 0.2s, box-shadow 0.2s; | |
| } | |
| .search-input:focus-within { | |
| background: var(--bg-color); | |
| box-shadow: 0 1px 1px 0 rgba(65,69,73,0.3), 0 1px 3px 1px rgba(65,69,73,0.15); | |
| } | |
| .search-input input { | |
| flex: 1; | |
| border: none; | |
| background: transparent; | |
| font-size: 16px; | |
| color: var(--text-main); | |
| outline: none; | |
| height: 100%; | |
| } | |
| .search-icon { fill: var(--text-secondary); } | |
| /* --- LISTS & CARDS --- */ | |
| .app-card { | |
| display: flex; | |
| align-items: center; | |
| gap: 16px; | |
| padding: 16px; | |
| cursor: pointer; | |
| transition: background 0.2s; | |
| } | |
| .app-card:active { background: var(--card-hover); } | |
| .app-icon { | |
| width: 64px; | |
| height: 64px; | |
| border-radius: 14px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| font-size: 32px; | |
| flex-shrink: 0; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.12); | |
| } | |
| .app-info { flex: 1; min-width: 0; } | |
| .app-name { font-weight: 500; font-size: 16px; color: var(--text-main); margin-bottom: 2px; } | |
| .app-developer { font-size: 13px; color: var(--text-secondary); } | |
| .app-meta { font-size: 12px; color: var(--text-secondary); margin-top: 4px; display: flex; align-items: center; gap: 6px; } | |
| /* --- BUTTONS --- */ | |
| .install-btn { | |
| padding: 0 16px; | |
| height: 36px; | |
| background: var(--bg-color); | |
| color: var(--primary-color); | |
| border: 1px solid var(--border-color); | |
| border-radius: 18px; | |
| font-weight: 500; | |
| font-size: 14px; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.2s; | |
| min-width: 80px; | |
| } | |
| .install-btn.prominent { | |
| background: var(--primary-color); | |
| color: #fff; | |
| border: none; | |
| box-shadow: 0 1px 2px rgba(0,0,0,0.2); | |
| } | |
| .install-btn.installed { | |
| background: transparent; | |
| color: var(--primary-color); | |
| border: 1px solid var(--border-color); | |
| } | |
| .install-btn.danger { | |
| color: #d93025; | |
| border-color: #dadce0; | |
| } | |
| .button-group { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| /* --- FEATURED SECTION --- */ | |
| .section-title { padding: 16px 16px 8px; } | |
| .section-title h3 { font-size: 18px; font-weight: 500; color: var(--text-main); display: flex; justify-content: space-between; align-items: center;} | |
| .horizontal-scroll { | |
| overflow-x: auto; | |
| padding: 0 16px 16px; | |
| scrollbar-width: none; | |
| display: flex; | |
| gap: 16px; | |
| } | |
| .horizontal-scroll::-webkit-scrollbar { display: none; } | |
| .small-app-card { width: 104px; flex-shrink: 0; cursor: pointer; } | |
| .small-app-icon { | |
| width: 104px; height: 104px; border-radius: 22px; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 48px; margin-bottom: 8px; | |
| box-shadow: 0 2px 8px rgba(0,0,0,0.1); | |
| } | |
| /* --- DETAILS OVERLAY --- */ | |
| #appDetailsContainer { | |
| position: fixed; inset: 0; | |
| background: var(--bg-color); | |
| z-index: 2000; | |
| overflow-y: auto; | |
| display: none; | |
| animation: slideUp 0.3s ease-out; | |
| } | |
| @keyframes slideUp { from { transform: translateY(100%); } to { transform: translateY(0); } } | |
| .detail-hero { padding: 20px; padding-top: 84px; } | |
| .detail-header-row { display: flex; gap: 20px; margin-bottom: 24px; } | |
| .detail-stats { | |
| display: flex; justify-content: space-between; padding: 12px 24px; | |
| border-bottom: 1px solid var(--border-color); margin-bottom: 24px; | |
| } | |
| .stat-item { text-align: center; flex: 1; position: relative; } | |
| .stat-item:not(:last-child)::after { | |
| content: ''; position: absolute; right: 0; top: 10%; height: 80%; | |
| width: 1px; background: var(--border-color); | |
| } | |
| .stat-val { font-weight: 500; font-size: 15px; color: var(--text-main); display: flex; align-items: center; justify-content: center; gap: 4px; } | |
| .stat-lbl { font-size: 11px; color: var(--text-secondary); margin-top: 2px; } | |
| /* --- POPUP MENUS --- */ | |
| .popup-overlay { | |
| position: fixed; inset: 0; background: var(--overlay-bg); | |
| z-index: 3000; display: none; opacity: 0; transition: opacity 0.2s; | |
| } | |
| .popup-overlay.show { display: block; opacity: 1; } | |
| .popup-menu { | |
| position: absolute; | |
| background: var(--modal-bg); | |
| border-radius: 8px; | |
| padding: 8px 0; | |
| box-shadow: 0 4px 16px rgba(0,0,0,0.2); | |
| min-width: 200px; | |
| z-index: 3001; | |
| transform: scale(0.9); opacity: 0; | |
| transition: all 0.2s; | |
| pointer-events: none; | |
| } | |
| .popup-menu.show { transform: scale(1); opacity: 1; pointer-events: auto; } | |
| .popup-item { | |
| padding: 12px 16px; | |
| display: flex; align-items: center; gap: 16px; | |
| cursor: pointer; color: var(--text-main); font-size: 14px; | |
| } | |
| .popup-item:hover { background: var(--surface-variant); } | |
| .popup-item svg { fill: var(--text-secondary); width: 20px; height: 20px; } | |
| .profile-menu-container { | |
| position: absolute; top: 60px; right: 16px; width: 300px; transform-origin: top right; | |
| } | |
| .popup-header { | |
| padding: 16px; border-bottom: 1px solid var(--border-color); | |
| display: flex; align-items: center; gap: 12px; | |
| } | |
| /* Toast */ | |
| .toast { | |
| position: fixed; bottom: 80px; left: 50%; transform: translateX(-50%); | |
| background: var(--text-main); color: var(--bg-color); | |
| padding: 12px 24px; border-radius: 24px; font-size: 14px; | |
| z-index: 100000; box-shadow: 0 4px 12px rgba(0,0,0,0.15); | |
| display: none; animation: fadeUp 0.3s; | |
| } | |
| @keyframes fadeUp { from { opacity: 0; transform: translate(-50%, 20px); } to { opacity: 1; transform: translate(-50%, 0); } } | |
| </style> | |
| </head> | |
| <body> | |
| <!-- Header --> | |
| <div class="app-header"> | |
| <div class="header-left"> | |
| <div class="app-back-btn" onclick="goBack()"> | |
| <svg width="24" height="24" viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg> | |
| </div> | |
| <div class="app-title" id="pageTitle">Games</div> | |
| </div> | |
| <div class="header-right"> | |
| <div class="profile-icon" onclick="toggleProfileMenu()">L</div> | |
| </div> | |
| </div> | |
| <!-- Main Content --> | |
| <div class="main-content"> | |
| <!-- Games Tab --> | |
| <div id="gamesContent" class="tab-content active"></div> | |
| <!-- Apps Tab --> | |
| <div id="appsContent" class="tab-content"></div> | |
| <!-- Search Tab --> | |
| <div id="searchContent" class="tab-content"> | |
| <div class="search-container"> | |
| <div class="search-input"> | |
| <svg class="search-icon" width="20" height="20" viewBox="0 0 24 24"><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 apps & games" oninput="handleSearch(this.value)"> | |
| </div> | |
| </div> | |
| <div id="searchResults" style="padding-top: 10px;"></div> | |
| </div> | |
| <!-- E-books Tab --> | |
| <div id="booksContent" class="tab-content"> | |
| <div style="padding: 40px 20px; text-align: center;"> | |
| <svg width="64" height="64" viewBox="0 0 24 24" style="fill: var(--text-secondary); opacity: 0.5; margin-bottom: 16px;"><path d="M21 5c-1.11-.35-2.33-.5-3.5-.5-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5S2.45 4.9 1 6v14.65c0 .25.25.5.5.5.1 0 .15-.05.2-.05C3.1 20.45 5.05 20 6.5 20c1.95 0 4.05.4 5.5 1.5 1.35-.85 3.8-1.5 5.5-1.5 1.65 0 3.35.3 4.75 1.05.1.05.15.05.25.05.25 0 .5-.25.5-.5V6c-.6-.45-1.25-.75-2-1zm0 13.5c-1.1-.35-2.3-.5-3.5-.5-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5 1.2 0 2.4.15 3.5.5v11.5z"/></svg> | |
| <div style="font-size: 18px; font-weight: 500; color: var(--text-main);">Books is coming soon</div> | |
| <div style="font-size: 14px; color: var(--text-secondary); margin-top: 8px;">We're working on bringing your favorite e-books to LunOS.</div> | |
| </div> | |
| </div> | |
| <!-- You Tab --> | |
| <div id="youContent" class="tab-content"> | |
| <div style="padding: 20px;"> | |
| <div style="display: flex; align-items: center; gap: 16px; margin-bottom: 24px;"> | |
| <div class="profile-icon" style="width: 64px; height: 64px; font-size: 24px; margin: 0;">L</div> | |
| <div> | |
| <div style="font-size: 20px; font-weight: 500; color: var(--text-main);">LunOS User</div> | |
| <div style="font-size: 14px; color: var(--text-secondary);">user@lunos.os</div> | |
| </div> | |
| </div> | |
| <div style="background: var(--surface-variant); border-radius: 12px; overflow: hidden; margin-bottom: 20px;"> | |
| <div class="popup-item" onclick="if(window.parent !== window) { window.parent.postMessage({action:'openUploadApp'}, '*'); } else { window.location.href='upload-app.html'; }"> | |
| <svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg> | |
| Manage apps & device | |
| </div> | |
| <div class="popup-item"> | |
| <svg viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-5-9h10v2H7z"/></svg> | |
| Offers and notifications | |
| </div> | |
| <div class="popup-item"> | |
| <svg viewBox="0 0 24 24"><path d="M11.5 2C6.81 2 3 5.81 3 10.5S6.81 19 11.5 19h.5v3c0 .55.45 1 1 1h.11c.28 0 .55-.11.76-.32l3.83-3.83c1.94-1.12 3.3-3.14 3.3-5.45C21 5.81 17.19 2 12.5 2h-1z"/></svg> | |
| Payments & subscriptions | |
| </div> | |
| <div class="popup-item" onclick="toggleTheme()"> | |
| <svg viewBox="0 0 24 24"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/></svg> | |
| Switch Theme | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Bottom Navigation --> | |
| <div class="bottom-nav"> | |
| <div class="nav-item active" onclick="switchTab('games', this)"> | |
| <div class="nav-icon-box"> | |
| <svg viewBox="0 0 24 24"><path d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm-10 7H8v3H6v-3H3v-2h3V8h2v3h3v2zm4.5 2c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zm4-3c-.83 0-1.5-.67-1.5-1.5S18.67 11 19.5 11s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></svg> | |
| </div> | |
| <div class="nav-label">Games</div> | |
| </div> | |
| <div class="nav-item" onclick="switchTab('apps', this)"> | |
| <div class="nav-icon-box"> | |
| <svg viewBox="0 0 24 24"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"/></svg> | |
| </div> | |
| <div class="nav-label">Apps</div> | |
| </div> | |
| <div class="nav-item" onclick="switchTab('search', this)"> | |
| <div class="nav-icon-box"> | |
| <svg viewBox="0 0 24 24"><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> | |
| </div> | |
| <div class="nav-label">Search</div> | |
| </div> | |
| <div class="nav-item" onclick="switchTab('books', this)"> | |
| <div class="nav-icon-box"> | |
| <svg viewBox="0 0 24 24"><path d="M21 5c-1.11-.35-2.33-.5-3.5-.5-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5S2.45 4.9 1 6v14.65c0 .25.25.5.5.5.1 0 .15-.05.2-.05C3.1 20.45 5.05 20 6.5 20c1.95 0 4.05.4 5.5 1.5 1.35-.85 3.8-1.5 5.5-1.5 1.65 0 3.35.3 4.75 1.05.1.05.15.05.25.05.25 0 .5-.25.5-.5V6c-.6-.45-1.25-.75-2-1zm0 13.5c-1.1-.35-2.3-.5-3.5-.5-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5 1.2 0 2.4.15 3.5.5v11.5z"/></svg> | |
| </div> | |
| <div class="nav-label">Books</div> | |
| </div> | |
| <div class="nav-item" onclick="switchTab('you', this)"> | |
| <div class="nav-icon-box"> | |
| <svg viewBox="0 0 24 24"><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="nav-label">You</div> | |
| </div> | |
| </div> | |
| <!-- App Details Modal --> | |
| <div id="appDetailsContainer"></div> | |
| <!-- Profile Popup --> | |
| <div id="profilePopup" class="popup-overlay" onclick="toggleProfileMenu()"> | |
| <div class="popup-menu profile-menu-container" onclick="event.stopPropagation()"> | |
| <div class="popup-header"> | |
| <div class="profile-icon" style="margin:0;">L</div> | |
| <div style="flex:1;"> | |
| <div style="font-weight:500; font-size:14px; color:var(--text-main);">LunOS User</div> | |
| <div style="font-size:12px; color:var(--text-secondary);">user@lunos.os</div> | |
| </div> | |
| </div> | |
| <div class="popup-item" onclick="toggleTheme()">Switch Theme</div> | |
| <div class="popup-item">Manage Account</div> | |
| </div> | |
| </div> | |
| <div id="toast" class="toast"></div> | |
| <script> | |
| const availableApps = [ | |
| { id: '2048', name: '2048', developer: 'LunOS Foundation', category: 'Games', description: 'Classic 2048 puzzle game.', rating: 4.8, downloads: '1M+', reviews: '100K', icon: '🔢', color: '#edc22e', url: '2048.html', version: '1.0.0' }, | |
| { id: 'colortoss', name: 'Color Toss', developer: 'LunOS Foundation', category: 'Games', description: 'Fun color tossing game.', rating: 4.5, downloads: '500K+', reviews: '50K', icon: '🎨', color: '#ff4757', url: 'colortoss.html', version: '1.0.0' }, | |
| { id: 'colourblitz', name: 'Colour Blitz', developer: 'LunOS Foundation', category: 'Games', description: 'Fast-paced color matching game.', rating: 4.6, downloads: '750K+', reviews: '60K', icon: '⚡', color: '#2ed573', url: 'colourblitz.html', version: '1.0.0' }, | |
| { id: 'cubeX', name: 'CubeX', developer: 'LunOS Foundation', category: 'Games', description: '3D cube puzzle challenge.', rating: 4.7, downloads: '300K+', reviews: '30K', icon: '🧊', color: '#1e90ff', url: 'cubeX.html', version: '1.0.0' }, | |
| { id: 'fruitninja', name: 'Fruit Ninja', developer: 'LunOS Foundation', category: 'Games', description: 'Slice fruits in this action game.', rating: 4.9, downloads: '10M+', reviews: '1M', icon: '🍉', color: '#ff6b81', url: 'fruitninja.html', version: '1.1.0' }, | |
| { id: 'helix', name: 'Helix Jump', developer: 'LunOS Foundation', category: 'Games', description: 'Jump through the helix tower.', rating: 4.4, downloads: '5M+', reviews: '400K', icon: '🌀', color: '#ffa502', url: 'helix.html', version: '1.0.0' }, | |
| { id: 'infinityevo', name: 'Infinity Evo', developer: 'LunOS Foundation', category: 'Games', description: 'Evolve infinitely in this idle game.', rating: 4.3, downloads: '100K+', reviews: '10K', icon: '♾️', color: '#747d8c', url: 'infinityevo.html', version: '1.0.0' }, | |
| { id: 'knifehit', name: 'Knife Hit', developer: 'LunOS Foundation', category: 'Games', description: 'Hit the target with knives.', rating: 4.6, downloads: '2M+', reviews: '150K', icon: '🔪', color: '#ced4da', url: 'knifehit.html', version: '1.0.0' }, | |
| { id: 'mathmaster', name: 'Math Master', developer: 'LunOS Foundation', category: 'Games', description: 'Test your math skills.', rating: 4.8, downloads: '1M+', reviews: '80K', icon: '➕', color: '#2ed573', url: 'mathmaster.html', version: '1.0.0' }, | |
| { id: 'memorymaster', name: 'Memory Master', developer: 'LunOS Foundation', category: 'Games', description: 'Train your memory.', rating: 4.5, downloads: '500K+', reviews: '40K', icon: '🧠', color: '#a29bfe', url: 'memorymaster.html', version: '1.0.0' }, | |
| { id: 'numberquest', name: 'Number Quest', developer: 'LunOS Foundation', category: 'Games', description: 'Solve number puzzles.', rating: 4.4, downloads: '200K+', reviews: '15K', icon: '🔢', color: '#fdcb6e', url: 'numberquest.html', version: '1.0.0' }, | |
| { id: 'papertoss', name: 'Paper Toss', developer: 'LunOS Foundation', category: 'Games', description: 'Toss paper into the bin.', rating: 4.2, downloads: '1M+', reviews: '90K', icon: '🗑️', color: '#dfe6e9', url: 'papertoss.html', version: '1.0.0' }, | |
| { id: 'pixelflow', name: 'Pixel Flow', developer: 'LunOS Foundation', category: 'Games', description: 'Connect pixels in this puzzle.', rating: 4.6, downloads: '400K+', reviews: '35K', icon: '👾', color: '#e84393', url: 'pixelflow.html', version: '1.0.0' }, | |
| { id: 'popio', name: 'Pop.io', developer: 'LunOS Foundation', category: 'Games', description: 'Multiplayer popping game.', rating: 4.1, downloads: '2M+', reviews: '120K', icon: '🎈', color: '#55efc4', url: 'popio.html', version: '1.0.0' }, | |
| { id: 'puff', name: 'Puff', developer: 'LunOS Foundation', category: 'Games', description: 'Blow the clouds away.', rating: 4.3, downloads: '100K+', reviews: '8K', icon: '☁️', color: '#81ecec', url: 'puff.html', version: '1.0.0' }, | |
| { id: 'puffpilot', name: 'Puff the Pilot', developer: 'LunOS Foundation', category: 'Games', description: 'Fly through obstacles.', rating: 4.7, downloads: '500K+', reviews: '45K', icon: '🛩️', color: '#fab1a0', url: 'Puff the Pilot!.html', version: '1.0.0' }, | |
| { id: 'reactionpro', name: 'Reaction Pro', developer: 'LunOS Foundation', category: 'Games', description: 'Test your reaction speed.', rating: 4.8, downloads: '300K+', reviews: '25K', icon: '⏱️', color: '#ff7675', url: 'reactionpro.html', version: '1.0.0' }, | |
| { id: 'rockpapersccisor', name: 'Rock Paper Scissors', developer: 'LunOS Foundation', category: 'Games', description: 'Classic RPS game.', rating: 4.0, downloads: '1M+', reviews: '50K', icon: '✊', color: '#b2bec3', url: 'rockpapersccisor.html', version: '1.0.0' }, | |
| { id: 'snakemax', name: 'Snake Max', developer: 'LunOS Foundation', category: 'Games', description: 'Modern snake game.', rating: 4.6, downloads: '2M+', reviews: '180K', icon: '🐍', color: '#2ecc71', url: 'snakemax.html', version: '1.2.0' }, | |
| { id: 'stacktheblocks', name: 'Stack Blocks', developer: 'LunOS Foundation', category: 'Games', description: 'Stack blocks as high as you can.', rating: 4.5, downloads: '1M+', reviews: '70K', icon: '🧱', color: '#e67e22', url: 'stacktheblocks.html', version: '1.0.0' }, | |
| { id: 'tetrabuddies', name: 'Tetra Buddies', developer: 'LunOS Foundation', category: 'Games', description: 'Block puzzle with friends.', rating: 4.7, downloads: '500K+', reviews: '40K', icon: '🔲', color: '#9b59b6', url: 'tetrabuddies.html', version: '1.0.0' }, | |
| { id: 'tic-tac-toe', name: 'Tic Tac Toe', developer: 'LunOS Foundation', category: 'Games', description: 'Classic Noughts and Crosses.', rating: 4.1, downloads: '1M+', reviews: '60K', icon: '❌', color: '#34495e', url: 'tic-tac-toe.html', version: '1.0.0' }, | |
| { id: 'wordscramble', name: 'Word Scramble', developer: 'LunOS Foundation', category: 'Games', description: 'Unscramble words to win.', rating: 4.8, downloads: '800K+', reviews: '55K', icon: '🔤', color: '#f1c40f', url: 'wordscramble.html', version: '1.0.0' }, | |
| { id: 'sudoku', name: 'Pro Sudoku', developer: 'LunOS Games', category: 'Games', description: 'Classic Sudoku puzzle.', rating: 4.9, downloads: '5M+', reviews: '560K', icon: '🔢', color: '#f6d365', url: 'sudoku.html', version: '1.0.5' }, | |
| { id: 'fynwriteApp', name: 'FynWrite', developer: 'LunOS Team', category: 'Productivity', description: 'Blogging platform.', rating: 4.7, downloads: '100K+', reviews: '12K', icon: '📝', color: '#667eea', url: 'fynwrite.html', version: '1.0.0' } | |
| ]; | |
| function switchTab(tabId, el) { | |
| document.querySelectorAll('.nav-item').forEach(item => item.classList.remove('active')); | |
| el.classList.add('active'); | |
| document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active')); | |
| document.getElementById(tabId + 'Content').classList.add('active'); | |
| const titleMap = { 'games': 'Games', 'apps': 'Apps', 'search': 'Search', 'books': 'Books', 'you': 'You' }; | |
| document.getElementById('pageTitle').innerText = titleMap[tabId]; | |
| if (tabId === 'games') loadGames(); | |
| else if (tabId === 'apps') loadApps(); | |
| } | |
| function loadGames() { | |
| const container = document.getElementById('gamesContent'); | |
| const games = availableApps.filter(a => a.category === 'Games'); | |
| container.innerHTML = ` | |
| <div class="section-title"><h3>Top Games</h3></div> | |
| ${games.map(app => createAppCard(app)).join('')} | |
| `; | |
| } | |
| function loadApps() { | |
| const container = document.getElementById('appsContent'); | |
| const apps = availableApps.filter(a => a.category !== 'Games'); | |
| container.innerHTML = ` | |
| <div class="section-title"><h3>Top Apps</h3></div> | |
| ${apps.map(app => createAppCard(app)).join('')} | |
| `; | |
| } | |
| function handleSearch(query) { | |
| const results = availableApps.filter(a => a.name.toLowerCase().includes(query.toLowerCase())); | |
| const container = document.getElementById('searchResults'); | |
| container.innerHTML = results.map(app => createAppCard(app)).join(''); | |
| } | |
| function createAppCard(app) { | |
| const installed = JSON.parse(localStorage.getItem('installedStoreApps') || '[]'); | |
| const versions = JSON.parse(localStorage.getItem('installedAppVersions') || '{}'); | |
| const isInstalled = installed.includes(app.id); | |
| const needsUpdate = isInstalled && app.version && versions[app.id] !== app.version; | |
| let buttonHTML = ''; | |
| if (!isInstalled) { | |
| buttonHTML = `<button class="install-btn prominent" onclick="event.stopPropagation(); installApp('${app.id}')">Install</button>`; | |
| } else if (needsUpdate) { | |
| buttonHTML = `<button class="install-btn prominent" onclick="event.stopPropagation(); updateApp('${app.id}')">Update</button>`; | |
| } else { | |
| buttonHTML = ` | |
| <div class="button-group"> | |
| <button class="install-btn" onclick="event.stopPropagation(); openApp('${app.id}')">Open</button> | |
| </div> | |
| `; | |
| } | |
| 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-meta">⭐ ${app.rating} • ${app.size || '2.0 MB'}</div> | |
| </div> | |
| ${buttonHTML} | |
| </div> | |
| `; | |
| } | |
| function openApp(appId) { | |
| const app = availableApps.find(a => a.id === appId); | |
| if (!app) return; | |
| if (window.parent !== window) { | |
| window.parent.postMessage({ | |
| action: 'launchApp', | |
| appId: app.id, | |
| url: app.url, | |
| name: app.name, | |
| icon: app.icon, | |
| color: app.color | |
| }, '*'); | |
| } else { | |
| window.location.href = app.url; | |
| } | |
| } | |
| function installApp(appId) { | |
| const app = availableApps.find(a => a.id === appId); | |
| if (!app) return; | |
| const installed = JSON.parse(localStorage.getItem('installedStoreApps') || '[]'); | |
| if (installed.includes(appId)) return; | |
| installed.push(appId); | |
| localStorage.setItem('installedStoreApps', JSON.stringify(installed)); | |
| const versions = JSON.parse(localStorage.getItem('installedAppVersions') || '{}'); | |
| versions[appId] = app.version || '1.0.0'; | |
| localStorage.setItem('installedAppVersions', JSON.stringify(versions)); | |
| 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, | |
| url: app.url | |
| }); | |
| localStorage.setItem('homeScreenApps', JSON.stringify(homeApps)); | |
| } | |
| if (window.parent !== window) { | |
| window.parent.postMessage({ type: 'install_app_instant', appId: appId }, '*'); | |
| } | |
| showToast('Installed!'); | |
| } | |
| async function updateApp(appId) { | |
| const app = availableApps.find(a => a.id === appId); | |
| if (!app) return; | |
| showToast('Updating...'); | |
| if ('caches' in window) { | |
| try { | |
| const keys = await caches.keys(); | |
| await Promise.all(keys.map(k => caches.delete(k))); | |
| } catch(e) {} | |
| } | |
| const versions = JSON.parse(localStorage.getItem('installedAppVersions') || '{}'); | |
| versions[appId] = app.version; | |
| localStorage.setItem('installedAppVersions', JSON.stringify(versions)); | |
| showToast('Updated successfully!'); | |
| setTimeout(() => location.reload(), 800); | |
| } | |
| function uninstallApp(appId) { | |
| let installed = JSON.parse(localStorage.getItem('installedStoreApps') || '[]'); | |
| installed = installed.filter(id => id !== appId); | |
| localStorage.setItem('installedStoreApps', JSON.stringify(installed)); | |
| let homeApps = JSON.parse(localStorage.getItem('homeScreenApps') || '[]'); | |
| homeApps = homeApps.filter(a => a.id !== appId); | |
| localStorage.setItem('homeScreenApps', JSON.stringify(homeApps)); | |
| let versions = JSON.parse(localStorage.getItem('installedAppVersions') || '{}'); | |
| delete versions[appId]; | |
| localStorage.setItem('installedAppVersions', JSON.stringify(versions)); | |
| showToast('Uninstalled'); | |
| setTimeout(() => location.reload(), 500); | |
| } | |
| function showAppDetails(id) { | |
| const app = availableApps.find(a => a.id === id); | |
| if (!app) return; | |
| const installed = JSON.parse(localStorage.getItem('installedStoreApps') || '[]'); | |
| const versions = JSON.parse(localStorage.getItem('installedAppVersions') || '{}'); | |
| const isInstalled = installed.includes(app.id); | |
| const needsUpdate = isInstalled && app.version && versions[app.id] !== app.version; | |
| const details = document.getElementById('appDetailsContainer'); | |
| details.innerHTML = ` | |
| <div class="app-header" style="box-shadow:none;"> | |
| <div class="header-left"> | |
| <div class="app-back-btn" onclick="closeDetails()"> | |
| <svg width="24" height="24" viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="detail-hero"> | |
| <div class="detail-header-row"> | |
| <div class="app-icon" style="width:80px; height:80px; border-radius:18px; font-size:40px; background:${app.color}">${app.icon}</div> | |
| <div style="flex:1;"> | |
| <div style="font-size:24px; font-weight:500; margin-bottom:4px;">${app.name}</div> | |
| <div style="color:var(--primary-color); font-weight:500; font-size:14px;">${app.developer}</div> | |
| <div style="font-size:12px; color:var(--text-secondary); margin-top:4px;">Version ${app.version || '1.0.0'}</div> | |
| </div> | |
| </div> | |
| <div class="button-group" style="width:100%;"> | |
| ${!isInstalled ? ` | |
| <button class="install-btn prominent" style="flex:1; height:40px;" onclick="installApp('${app.id}')">Install</button> | |
| ` : ` | |
| <button class="install-btn danger" style="flex:1; height:40px;" onclick="uninstallApp('${app.id}')">Uninstall</button> | |
| ${needsUpdate ? ` | |
| <button class="install-btn prominent" style="flex:1; height:40px;" onclick="updateApp('${app.id}')">Update</button> | |
| ` : ` | |
| <button class="install-btn prominent" style="flex:1; height:40px;" onclick="openApp('${app.id}')">Open</button> | |
| `} | |
| `} | |
| </div> | |
| </div> | |
| <div class="detail-stats"> | |
| <div class="stat-item"><div class="stat-val">${app.rating} ⭐</div><div class="stat-lbl">${app.reviews} reviews</div></div> | |
| <div class="stat-item"><div class="stat-val">📥</div><div class="stat-lbl">${app.downloads}</div></div> | |
| <div class="stat-item"><div class="stat-val">4+</div><div class="stat-lbl">Everyone</div></div> | |
| </div> | |
| <div style="padding:20px;"> | |
| <h3 style="margin-bottom:12px;">About this app</h3> | |
| <p style="color:var(--text-secondary); font-size:14px; line-height:1.6;">${app.description || 'No description available.'}</p> | |
| </div> | |
| `; | |
| details.style.display = 'block'; | |
| } | |
| function closeDetails() { document.getElementById('appDetailsContainer').style.display = 'none'; } | |
| function goBack() { if (window.parent !== window) window.parent.postMessage({action: 'closeApp', appId: 'appstore'}, '*'); } | |
| function toggleProfileMenu() { document.getElementById('profilePopup').classList.toggle('show'); } | |
| function toggleTheme() { | |
| const isDark = document.body.classList.toggle('dark-mode'); | |
| localStorage.setItem('lunos_theme', isDark ? 'dark' : 'light'); | |
| showToast(`Theme switched to ${isDark ? 'Dark' : 'Light'}`); | |
| } | |
| function showToast(msg) { | |
| const t = document.getElementById('toast'); | |
| t.innerText = msg; | |
| t.style.display = 'block'; | |
| setTimeout(() => t.style.display = 'none', 3000); | |
| } | |
| window.onload = () => { | |
| const theme = localStorage.getItem('lunos_theme'); | |
| if (theme === 'dark') document.body.classList.add('dark-mode'); | |
| loadGames(); | |
| }; | |
| </script> | |
| </body> | |
| </html> |