Mobile-emulator / appstore.html
ngiactcp
Make installed apps appear instantly on the home screen
9896f8a
<!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>
<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>