added export/import settubgs

This commit is contained in:
2026-02-11 09:19:19 +03:00
parent 576ab77fe6
commit 05209cd049
17 changed files with 299 additions and 1 deletions

View File

@@ -322,5 +322,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Liste umbenennen" "message": "Liste umbenennen"
},
"export_settings": {
"message": "Exportieren"
},
"import_settings": {
"message": "Importieren"
},
"export_import_settings_label": {
"message": "Export / Import"
},
"export_import_settings_hint": {
"message": "Listen und Website-Ausnahmen sichern oder wiederherstellen."
} }
} }

View File

@@ -358,5 +358,17 @@
}, },
"close": { "close": {
"message": "Close" "message": "Close"
},
"export_settings": {
"message": "Export"
},
"import_settings": {
"message": "Import"
},
"export_import_settings_label": {
"message": "Export / Import"
},
"export_import_settings_hint": {
"message": "Back up or restore lists and site exceptions."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Renombrar lista" "message": "Renombrar lista"
},
"export_settings": {
"message": "Exportar"
},
"import_settings": {
"message": "Importar"
},
"export_import_settings_label": {
"message": "Exportar / Importar"
},
"export_import_settings_hint": {
"message": "Hacer copia de seguridad o restaurar listas y excepciones de sitios."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Renommer la liste" "message": "Renommer la liste"
},
"export_settings": {
"message": "Exporter"
},
"import_settings": {
"message": "Importer"
},
"export_import_settings_label": {
"message": "Exporter / Importer"
},
"export_import_settings_hint": {
"message": "Sauvegarder ou restaurer les listes et les exceptions de sites."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "सूची का नाम बदलें" "message": "सूची का नाम बदलें"
},
"export_settings": {
"message": "निर्यात"
},
"import_settings": {
"message": "आयात"
},
"export_import_settings_label": {
"message": "निर्यात / आयात"
},
"export_import_settings_hint": {
"message": "सूचियों और साइट अपवादों का बैकअप लें या पुनर्स्थापित करें।"
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Rinomina elenco" "message": "Rinomina elenco"
},
"export_settings": {
"message": "Esporta"
},
"import_settings": {
"message": "Importa"
},
"export_import_settings_label": {
"message": "Esporta / Importa"
},
"export_import_settings_hint": {
"message": "Backup o ripristino di elenchi e eccezioni di siti."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "リスト名を変更" "message": "リスト名を変更"
},
"export_settings": {
"message": "エクスポート"
},
"import_settings": {
"message": "インポート"
},
"export_import_settings_label": {
"message": "エクスポート / インポート"
},
"export_import_settings_hint": {
"message": "リストとサイトの例外をバックアップまたは復元します。"
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "리스트 이름 변경" "message": "리스트 이름 변경"
},
"export_settings": {
"message": "내보내기"
},
"import_settings": {
"message": "가져오기"
},
"export_import_settings_label": {
"message": "내보내기 / 가져오기"
},
"export_import_settings_hint": {
"message": "목록 및 사이트 예외를 백업하거나 복원합니다."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Lijst hernoemen" "message": "Lijst hernoemen"
},
"export_settings": {
"message": "Exporteren"
},
"import_settings": {
"message": "Importeren"
},
"export_import_settings_label": {
"message": "Exporteren / Importeren"
},
"export_import_settings_hint": {
"message": "Back-up maken of lijsten en site-uitzonderingen herstellen."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Zmień nazwę listy" "message": "Zmień nazwę listy"
},
"export_settings": {
"message": "Eksportuj"
},
"import_settings": {
"message": "Importuj"
},
"export_import_settings_label": {
"message": "Eksport / Import"
},
"export_import_settings_hint": {
"message": "Utwórz kopię zapasową lub przywróć listy i wyjątki witryn."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Renomear lista" "message": "Renomear lista"
},
"export_settings": {
"message": "Exportar"
},
"import_settings": {
"message": "Importar"
},
"export_import_settings_label": {
"message": "Exportar / Importar"
},
"export_import_settings_hint": {
"message": "Fazer backup ou restaurar listas e exceções de sites."
} }
} }

View File

@@ -329,5 +329,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Переименовать список" "message": "Переименовать список"
},
"export_settings": {
"message": "Экспорт"
},
"import_settings": {
"message": "Импорт"
},
"export_import_settings_label": {
"message": "Экспорт / Импорт"
},
"export_import_settings_hint": {
"message": "Резервное копирование или восстановление списков и исключений сайтов."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "Listeyi Yeniden Adlandır" "message": "Listeyi Yeniden Adlandır"
},
"export_settings": {
"message": "Dışa Aktar"
},
"import_settings": {
"message": "İçe Aktar"
},
"export_import_settings_label": {
"message": "Dışa Aktar / İçe Aktar"
},
"export_import_settings_hint": {
"message": "Listeleri ve site istisnalarını yedekleyin veya geri yükleyin."
} }
} }

View File

@@ -328,5 +328,17 @@
}, },
"rename_list": { "rename_list": {
"message": "重命名列表" "message": "重命名列表"
},
"export_settings": {
"message": "导出"
},
"import_settings": {
"message": "导入"
},
"export_import_settings_label": {
"message": "导出 / 导入"
},
"export_import_settings_hint": {
"message": "备份或恢复列表和站点例外。"
} }
} }

View File

@@ -1214,6 +1214,30 @@ body {
opacity: 0.6; opacity: 0.6;
} }
.settings-export-import-section {
padding: 8px 10px;
background: var(--input-bg);
border: 1px solid var(--input-border);
border-radius: 6px;
display: flex;
flex-direction: column;
gap: 8px;
}
.settings-export-import-label {
font-size: var(--text-md);
font-weight: 500;
color: var(--text-color);
margin: 0;
}
.settings-export-import-hint {
font-size: var(--text-sm);
color: var(--text-color);
opacity: 0.6;
margin: 0;
}
.options-buttons { .options-buttons {
display: flex; display: flex;
gap: 8px; gap: 8px;

View File

@@ -276,6 +276,22 @@
</div> </div>
</div> </div>
<div class="settings-export-import-section">
<p class="settings-export-import-label" data-i18n="export_import_settings_label">Export / Import</p>
<p class="settings-export-import-hint" data-i18n="export_import_settings_hint">Back up or restore lists and site exceptions.</p>
<div class="list-export-import-row">
<button type="button" class="list-export-import-btn" id="exportSettingsBtn">
<i class="fa-solid fa-download"></i>
<span data-i18n="export_settings">Export</span>
</button>
<button type="button" class="list-export-import-btn" id="importSettingsBtn">
<i class="fa-solid fa-upload"></i>
<span data-i18n="import_settings">Import</span>
</button>
<input type="file" id="importSettingsInput" accept="application/json" hidden />
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -1,4 +1,4 @@
import { HighlightList, HighlightWord, HighlightInfo } from '../types.js'; import { HighlightList, HighlightWord, HighlightInfo, ExportData } from '../types.js';
import { StorageService } from '../services/StorageService.js'; import { StorageService } from '../services/StorageService.js';
import { MessageService } from '../services/MessageService.js'; import { MessageService } from '../services/MessageService.js';
import { DOMUtils } from '../utils/DOMUtils.js'; import { DOMUtils } from '../utils/DOMUtils.js';
@@ -231,6 +231,7 @@ export class PopupController {
this.setupTabs(); this.setupTabs();
this.setupScrollListeners(); this.setupScrollListeners();
this.setupSettingsOverlay(); this.setupSettingsOverlay();
this.setupSettingsExportImport();
this.setupListManagement(); this.setupListManagement();
this.setupWordManagement(); this.setupWordManagement();
this.setupSettings(); this.setupSettings();
@@ -261,6 +262,95 @@ export class PopupController {
}); });
} }
private setupSettingsExportImport(): void {
const importSettingsInput = document.getElementById('importSettingsInput') as HTMLInputElement;
document.getElementById('exportSettingsBtn')?.addEventListener('click', () => {
const data: ExportData = {
lists: this.lists,
exceptionsList: [...this.exceptionsList]
};
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'goose-highlighter-settings.json';
a.click();
URL.revokeObjectURL(url);
});
document.getElementById('importSettingsBtn')?.addEventListener('click', () => {
importSettingsInput?.click();
});
importSettingsInput?.addEventListener('change', (e) => {
const file = (e.target as HTMLInputElement).files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = async (event) => {
try {
const raw = event.target?.result as string;
const data = JSON.parse(raw) as unknown;
if (!data || typeof data !== 'object') {
alert(chrome.i18n.getMessage('invalid_import_format') || 'Invalid file format. Please select a valid export file.');
importSettingsInput.value = '';
return;
}
const obj = data as Record<string, unknown>;
let listsApplied = false;
let exceptionsApplied = false;
if (Array.isArray(obj.lists) && obj.lists.length > 0) {
const baseId = Date.now();
const validLists = obj.lists
.filter((item: unknown) => this.isValidList(item))
.map((item: HighlightList, i: number) => ({ ...item, id: baseId + i }));
if (validLists.length > 0) {
this.lists = validLists;
this.currentListIndex = Math.min(this.currentListIndex, this.lists.length - 1);
listsApplied = true;
}
}
if (Array.isArray(obj.exceptionsList)) {
this.exceptionsList = obj.exceptionsList.filter((d): d is string => typeof d === 'string');
exceptionsApplied = true;
}
if (!listsApplied && !exceptionsApplied) {
alert(chrome.i18n.getMessage('invalid_import_format') || 'Invalid file format. Please select a valid export file.');
importSettingsInput.value = '';
return;
}
if (listsApplied && this.lists.length === 0) {
this.lists.push({
id: Date.now(),
name: chrome.i18n.getMessage('default_list_name') || 'Default List',
background: '#ffff00',
foreground: '#000000',
active: true,
words: []
});
}
await this.save();
MessageService.sendToAllTabs({ type: 'WORD_LIST_UPDATED' });
MessageService.sendToAllTabs({ type: 'EXCEPTIONS_LIST_UPDATED' });
this.render();
importSettingsInput.value = '';
} catch (err) {
alert((chrome.i18n.getMessage('invalid_json_error') || 'Invalid JSON file') + ': ' + (err as Error).message);
importSettingsInput.value = '';
}
};
reader.readAsText(file);
});
}
private setupTabs(): void { private setupTabs(): void {
document.querySelectorAll('.tab-button').forEach(button => { document.querySelectorAll('.tab-button').forEach(button => {
button.addEventListener('click', () => { button.addEventListener('click', () => {