ngzbydze commited on
Commit
eb53162
·
1 Parent(s): 905a701

Add app previewer and improve app installation flow

Browse files

Create a new `appforge_preview.html` file to handle the rendering of user-submitted apps, and update `appstore.html` to correctly find and link to these apps, including passing the app ID to the previewer.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 359ff6bd-3611-43f4-80bb-8e00dffa9b94
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: cc1073e6-ac4d-48dc-98c5-a55510394ec2
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/4f63ac58-4cb9-42c8-9fb2-13fd8b1964a3/359ff6bd-3611-43f4-80bb-8e00dffa9b94/MhNANtD
Replit-Helium-Checkpoint-Created: true

Files changed (3) hide show
  1. appforge.html +2 -1
  2. appforge_preview.html +110 -0
  3. appstore.html +4 -2
appforge.html CHANGED
@@ -1540,7 +1540,8 @@
1540
  rating: 5.0,
1541
  downloads: '0+',
1542
  approved: true,
1543
- url: '#', // In a real scenario, this would link to the built app
 
1544
  submittedDate: new Date().toISOString()
1545
  };
1546
 
 
1540
  rating: 5.0,
1541
  downloads: '0+',
1542
  approved: true,
1543
+ url: 'appforge_preview.html', // Point to a generic previewer
1544
+ sections: appSections, // Include the actual sections
1545
  submittedDate: new Date().toISOString()
1546
  };
1547
 
appforge_preview.html ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>App Preview</title>
7
+ <style>
8
+ body { margin: 0; font-family: sans-serif; background: #000; color: #fff; height: 100vh; display: flex; flex-direction: column; }
9
+ #header { padding: 15px; background: #1a1a2e; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid #333; }
10
+ #content { flex: 1; position: relative; }
11
+ iframe { width: 100%; height: 100%; border: none; }
12
+ #tabs { display: flex; background: #1a1a2e; border-top: 1px solid #333; }
13
+ .tab { flex: 1; padding: 15px; text-align: center; cursor: pointer; font-size: 12px; opacity: 0.6; }
14
+ .tab.active { opacity: 1; border-top: 2px solid #ff6b6b; color: #ff6b6b; }
15
+ #password-gate { position: absolute; inset: 0; background: #000; display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 100; }
16
+ input { padding: 10px; border-radius: 5px; border: 1px solid #444; background: #222; color: #fff; margin-bottom: 10px; }
17
+ button { padding: 10px 20px; background: #ff6b6b; border: none; border-radius: 5px; color: #fff; cursor: pointer; }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <div id="header">
22
+ <span id="app-name">App</span>
23
+ <span id="section-title">Loading...</span>
24
+ <div style="width: 20px;"></div>
25
+ </div>
26
+ <div id="content">
27
+ <div id="password-gate" style="display: none;">
28
+ <h3>Section Locked</h3>
29
+ <input type="password" id="pass-input" placeholder="Enter password">
30
+ <button onclick="checkPassword()">Unlock</button>
31
+ </div>
32
+ <iframe id="app-frame"></iframe>
33
+ </div>
34
+ <div id="tabs"></div>
35
+
36
+ <script>
37
+ let currentApp = null;
38
+ let currentSectionIdx = 0;
39
+
40
+ function loadApp() {
41
+ const urlParams = new URLSearchParams(window.location.search);
42
+ const appId = urlParams.get('id');
43
+ const userApps = JSON.parse(localStorage.getItem('userSubmittedApps') || '[]');
44
+ currentApp = userApps.find(a => a.id === appId);
45
+
46
+ if (!currentApp) {
47
+ document.body.innerHTML = '<div style="padding:20px; text-align:center;">App not found</div>';
48
+ return;
49
+ }
50
+
51
+ document.getElementById('app-name').innerText = currentApp.name;
52
+ renderTabs();
53
+ switchSection(0);
54
+ }
55
+
56
+ function renderTabs() {
57
+ const tabsContainer = document.getElementById('tabs');
58
+ tabsContainer.innerHTML = currentApp.sections.map((s, idx) => `
59
+ <div class="tab ${idx === 0 ? 'active' : ''}" onclick="switchSection(${idx})">
60
+ ${s.title}
61
+ </div>
62
+ `).join('');
63
+ }
64
+
65
+ function switchSection(idx) {
66
+ currentSectionIdx = idx;
67
+ const section = currentApp.sections[idx];
68
+ document.getElementById('section-title').innerText = section.title;
69
+
70
+ document.querySelectorAll('.tab').forEach((t, i) => {
71
+ t.classList.toggle('active', i === idx);
72
+ });
73
+
74
+ const gate = document.getElementById('password-gate');
75
+ if (section.data.password) {
76
+ gate.style.display = 'flex';
77
+ document.getElementById('app-frame').src = 'about:blank';
78
+ } else {
79
+ gate.style.display = 'none';
80
+ loadSectionContent(section);
81
+ }
82
+ }
83
+
84
+ function checkPassword() {
85
+ const input = document.getElementById('pass-input').value;
86
+ const section = currentApp.sections[currentSectionIdx];
87
+ if (input === section.data.password) {
88
+ document.getElementById('password-gate').style.display = 'none';
89
+ loadSectionContent(section);
90
+ } else {
91
+ alert('Wrong password');
92
+ }
93
+ }
94
+
95
+ function loadSectionContent(section) {
96
+ const iframe = document.getElementById('app-frame');
97
+ if (section.type === 'web') {
98
+ iframe.src = section.data.url;
99
+ } else if (section.type === 'html') {
100
+ const doc = iframe.contentWindow.document;
101
+ doc.open();
102
+ doc.write(section.data.html || '');
103
+ doc.close();
104
+ }
105
+ }
106
+
107
+ window.onload = loadApp;
108
+ </script>
109
+ </body>
110
+ </html>
appstore.html CHANGED
@@ -654,7 +654,9 @@
654
 
655
  function installApp(appId) {
656
  const installed = getInstalledApps();
657
- const app = availableApps.find(a => a.id === appId);
 
 
658
 
659
  if (!app) return;
660
 
@@ -667,7 +669,7 @@
667
  icon: app.icon,
668
  color: app.color,
669
  category: app.category,
670
- url: app.url || null
671
  });
672
  localStorage.setItem('homeScreenApps', JSON.stringify(homeApps));
673
  localStorage.setItem('installedStoreApps', JSON.stringify([...getInstalledApps(), appId]));
 
654
 
655
  function installApp(appId) {
656
  const installed = getInstalledApps();
657
+ const userSubmittedApps = JSON.parse(localStorage.getItem('userSubmittedApps') || '[]');
658
+ const allPossibleApps = [...availableApps, ...userSubmittedApps];
659
+ const app = allPossibleApps.find(a => a.id === appId);
660
 
661
  if (!app) return;
662
 
 
669
  icon: app.icon,
670
  color: app.color,
671
  category: app.category,
672
+ url: app.url === 'appforge_preview.html' ? `appforge_preview.html?id=${app.id}` : (app.url || null)
673
  });
674
  localStorage.setItem('homeScreenApps', JSON.stringify(homeApps));
675
  localStorage.setItem('installedStoreApps', JSON.stringify([...getInstalledApps(), appId]));