diff --git a/sidepanel.html b/sidepanel.html
index d6b7d99..211f6ed 100644
--- a/sidepanel.html
+++ b/sidepanel.html
@@ -52,6 +52,13 @@
+
+
+
+
+
+
+
diff --git a/sidepanel.js b/sidepanel.js
index e953507..b8ba5a7 100644
--- a/sidepanel.js
+++ b/sidepanel.js
@@ -16,6 +16,11 @@ const presetList = document.getElementById('presetList');
const presetSelect = document.getElementById('presetSelect');
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
const toggleConfig = document.getElementById('toggleConfig');
const configContent = document.getElementById('configContent');
@@ -101,6 +106,58 @@ addPresetBtn.addEventListener('click', async () => {
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) {
editingPresetId = preset.id;
newPresetName.value = preset.name;
@@ -112,7 +169,6 @@ function startEditing(preset) {
addPresetBtn.classList.replace('text-indigo-700', 'text-white');
cancelEditBtn.classList.remove('hidden');
- // Ensure config is expanded so user can see inputs
configContent.classList.remove('hidden');
configChevron.classList.add('rotate-180');
}