Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3783,6 +3783,65 @@ function setupEventListeners() {
document.getElementById('delete-project-modal').classList.remove('visible');
});

// Export project backup
document.getElementById('export-project-btn').addEventListener('click', async () => {
if (!db) return;
try {
const dump = {};
for (const name of db.objectStoreNames) {
const tx = db.transaction(name, 'readonly');
const store = tx.objectStore(name);
dump[name] = await new Promise((resolve) => {
const req = store.getAll();
req.onsuccess = () => resolve(req.result);
req.onerror = () => resolve([]);
});
}
const json = JSON.stringify(dump, null, 2);
const blob = new Blob([json], { type: 'application/json' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'appscreen-backup-' + new Date().toISOString().slice(0, 10) + '.json';
a.click();
URL.revokeObjectURL(a.href);
} catch (e) {
console.error('Export failed:', e);
alert('Export failed: ' + e.message);
}
});

// Import project backup
const importInput = document.getElementById('import-project-input');
document.getElementById('import-project-btn').addEventListener('click', () => {
importInput.click();
});
importInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
if (!file || !db) return;
try {
const text = await file.text();
const dump = JSON.parse(text);
for (const storeName of Object.keys(dump)) {
if (!db.objectStoreNames.contains(storeName)) continue;
const tx = db.transaction(storeName, 'readwrite');
const store = tx.objectStore(storeName);
for (const record of dump[storeName]) {
store.put(record);
}
await new Promise((resolve, reject) => {
tx.oncomplete = resolve;
tx.onerror = () => reject(tx.error);
});
}
alert('Import complete! Reloading...');
location.reload();
} catch (e) {
console.error('Import failed:', e);
alert('Import failed: ' + e.message);
}
importInput.value = '';
});

// Apply style to all modal buttons
document.getElementById('apply-style-cancel').addEventListener('click', () => {
document.getElementById('apply-style-modal').classList.remove('visible');
Expand Down
15 changes: 15 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,21 @@ <h2>Project</h2>
<path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
</svg>
</button>
<button class="project-btn" id="export-project-btn" title="Export Project Backup">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/>
<polyline points="7 10 12 15 17 10"/>
<line x1="12" y1="15" x2="12" y2="3"/>
</svg>
</button>
<button class="project-btn" id="import-project-btn" title="Import Project Backup">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>
</button>
<input type="file" id="import-project-input" accept=".json" hidden>
</div>
</div>

Expand Down
Loading