support export and import
This commit is contained in:
@@ -52,6 +52,13 @@
|
|||||||
<div id="presetList" class="mt-4 space-y-2 max-h-40 overflow-y-auto pr-1">
|
<div id="presetList" class="mt-4 space-y-2 max-h-40 overflow-y-auto pr-1">
|
||||||
<!-- Saved presets -->
|
<!-- Saved presets -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Import/Export Presets -->
|
||||||
|
<div class="flex gap-2 pt-2 border-t border-gray-100">
|
||||||
|
<button id="exportPresets" class="flex-1 bg-white text-gray-600 text-[10px] py-1 rounded border border-gray-300 hover:bg-gray-50 transition-colors font-medium">导出预设</button>
|
||||||
|
<button id="importPresets" class="flex-1 bg-white text-gray-600 text-[10px] py-1 rounded border border-gray-300 hover:bg-gray-50 transition-colors font-medium">导入预设</button>
|
||||||
|
<input type="file" id="importInput" class="hidden" accept=".json">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
58
sidepanel.js
58
sidepanel.js
@@ -16,6 +16,11 @@ const presetList = document.getElementById('presetList');
|
|||||||
const presetSelect = document.getElementById('presetSelect');
|
const presetSelect = document.getElementById('presetSelect');
|
||||||
const runPresetBtn = document.getElementById('runPreset');
|
const runPresetBtn = document.getElementById('runPreset');
|
||||||
|
|
||||||
|
// Import/Export Elements
|
||||||
|
const exportBtn = document.getElementById('exportPresets');
|
||||||
|
const importBtn = document.getElementById('importPresets');
|
||||||
|
const importInput = document.getElementById('importInput');
|
||||||
|
|
||||||
// Collapsible logic
|
// Collapsible logic
|
||||||
const toggleConfig = document.getElementById('toggleConfig');
|
const toggleConfig = document.getElementById('toggleConfig');
|
||||||
const configContent = document.getElementById('configContent');
|
const configContent = document.getElementById('configContent');
|
||||||
@@ -101,6 +106,58 @@ addPresetBtn.addEventListener('click', async () => {
|
|||||||
|
|
||||||
cancelEditBtn.addEventListener('click', stopEditing);
|
cancelEditBtn.addEventListener('click', stopEditing);
|
||||||
|
|
||||||
|
// Export/Import Logic
|
||||||
|
exportBtn.addEventListener('click', async () => {
|
||||||
|
const { userPresets = DEFAULT_PRESETS } = await chrome.storage.local.get('userPresets');
|
||||||
|
const blob = new Blob([JSON.stringify(userPresets, null, 2)], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `hardware-presets-${new Date().toISOString().split('T')[0]}.json`;
|
||||||
|
a.click();
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
importBtn.addEventListener('click', () => importInput.click());
|
||||||
|
|
||||||
|
importInput.addEventListener('change', (e) => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = async (event) => {
|
||||||
|
try {
|
||||||
|
const importedPresets = JSON.parse(event.target.result);
|
||||||
|
if (!Array.isArray(importedPresets)) throw new Error('无效的预设文件格式');
|
||||||
|
|
||||||
|
const { userPresets = DEFAULT_PRESETS } = await chrome.storage.local.get('userPresets');
|
||||||
|
|
||||||
|
const choice = confirm('导入成功!\n点击 [确定] 将导入的预设合并到当前列表。\n点击 [取消] 将替换整个预设列表。');
|
||||||
|
|
||||||
|
let finalPresets;
|
||||||
|
if (choice) {
|
||||||
|
// Merge: Append with new IDs to prevent conflicts
|
||||||
|
const newItems = importedPresets.map(p => ({
|
||||||
|
...p,
|
||||||
|
id: Date.now().toString() + Math.random().toString(36).substr(2, 5)
|
||||||
|
}));
|
||||||
|
finalPresets = [...userPresets, ...newItems];
|
||||||
|
} else {
|
||||||
|
finalPresets = importedPresets;
|
||||||
|
}
|
||||||
|
|
||||||
|
await chrome.storage.local.set({ userPresets: finalPresets });
|
||||||
|
currentPresets = finalPresets;
|
||||||
|
renderPresets(currentPresets);
|
||||||
|
alert('预设导入完成!');
|
||||||
|
} catch (err) {
|
||||||
|
alert('导入失败: ' + err.message);
|
||||||
|
}
|
||||||
|
importInput.value = ''; // Reset input
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
});
|
||||||
|
|
||||||
function startEditing(preset) {
|
function startEditing(preset) {
|
||||||
editingPresetId = preset.id;
|
editingPresetId = preset.id;
|
||||||
newPresetName.value = preset.name;
|
newPresetName.value = preset.name;
|
||||||
@@ -112,7 +169,6 @@ function startEditing(preset) {
|
|||||||
addPresetBtn.classList.replace('text-indigo-700', 'text-white');
|
addPresetBtn.classList.replace('text-indigo-700', 'text-white');
|
||||||
cancelEditBtn.classList.remove('hidden');
|
cancelEditBtn.classList.remove('hidden');
|
||||||
|
|
||||||
// Ensure config is expanded so user can see inputs
|
|
||||||
configContent.classList.remove('hidden');
|
configContent.classList.remove('hidden');
|
||||||
configChevron.classList.add('rotate-180');
|
configChevron.classList.add('rotate-180');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user