diff --git a/.gitignore b/.gitignore index 0db4891..1273cab 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.crx node_modules/* CLAUDE.md +.claude/* diff --git a/content.js b/content.js index a96d443..c11adb8 100644 --- a/content.js +++ b/content.js @@ -1,10 +1,14 @@ -// Clear active filter when page loads (prevents confusion on page refresh) +// Pull and apply active filter when page loads (prevents confusion on page refresh) // This runs only on NotebookLM pages as defined in manifest.json if (typeof FilterState !== 'undefined') { - FilterState.clearActiveFilter(function () { - // After clearing, visually clear any applied filters on the page - if (document.readyState === 'loading') { - document.addEventListener('DOMContentLoaded', showAllNotebooks); + FilterState.getActiveFilter(function (activeFilter) { + // apply filter if present + if (document.readyState === 'loading' && activeFilter) { + document.addEventListener('DOMContentLoaded', () => { + filterNotebooks(activeFilter); + }); + } else if (activeFilter) { + filterNotebooks(activeFilter); } else { showAllNotebooks(); } diff --git a/filterState.js b/filterState.js index ada1d01..24b3cf2 100644 --- a/filterState.js +++ b/filterState.js @@ -13,17 +13,28 @@ const FilterState = { callback(null); return; } - - // retrieve from local storage - chrome.storage.local.get(['activeFilter'], function (localResult) { + // Try sync storage first + chrome.storage.sync.get(['activeFilter'], function (result) { if (chrome.runtime.lastError) { - console.error( - 'Failed to load activeFilter from local storage:', + console.warn( + 'Failed to load activeFilter from sync storage, trying local:', chrome.runtime.lastError ); - callback(null); + + // Fall back to local storage + chrome.storage.local.get(['activeFilter'], function (localResult) { + if (chrome.runtime.lastError) { + console.error( + 'Failed to load activeFilter from local storage:', + chrome.runtime.lastError + ); + callback(null); + } else { + callback(localResult.activeFilter || null); + } + }); } else { - callback(localResult.activeFilter || null); + callback(result.activeFilter || null); } }); }, @@ -41,7 +52,17 @@ const FilterState = { const data = { activeFilter: filter }; - // Save to local storage + // Save to sync storage first + chrome.storage.sync.set(data, function () { + if (chrome.runtime.lastError) { + console.warn( + 'Failed to save activeFilter to sync storage:', + chrome.runtime.lastError + ); + } + }); + + // Also save to local storage as backup chrome.storage.local.set(data, function () { if (chrome.runtime.lastError) { console.error( @@ -132,8 +153,3 @@ const FilterState = { }); }, }; - -// Export for both browser extension and Node.js (testing) -if (typeof module !== 'undefined' && module.exports) { - module.exports = { FilterState }; -} diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..f31719d --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "types": ["chrome"], + "checkJs": false, + "module": "none", + "moduleResolution": "node" + }, + "exclude": ["node_modules"] +} diff --git a/package-lock.json b/package-lock.json index 1ff9ce4..011dbcf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "notebooklm-filter-extension", "version": "1.0.0", "devDependencies": { + "@types/chrome": "^0.1.24", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0" } @@ -959,6 +960,34 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/chrome": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.1.24.tgz", + "integrity": "sha512-9iO9HL2bMeGS4C8m6gNFWUyuPE5HEUFk+rGh+7oriUjg+ata4Fc9PoVlu8xvGm7yoo3AmS3J6fAjoFj61NL2rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filesystem": "*", + "@types/har-format": "*" + } + }, + "node_modules/@types/filesystem": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/filesystem/-/filesystem-0.0.36.tgz", + "integrity": "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/filewriter": "*" + } + }, + "node_modules/@types/filewriter": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/filewriter/-/filewriter-0.0.33.tgz", + "integrity": "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/graceful-fs": { "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", @@ -969,6 +998,13 @@ "@types/node": "*" } }, + "node_modules/@types/har-format": { + "version": "1.2.16", + "resolved": "https://registry.npmjs.org/@types/har-format/-/har-format-1.2.16.tgz", + "integrity": "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", diff --git a/package.json b/package.json index 14fd629..97dcf52 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,15 @@ "test:coverage": "jest --coverage" }, "devDependencies": { + "@types/chrome": "^0.1.24", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0" }, "jest": { "testEnvironment": "jsdom", - "testMatch": ["**/tests/**/*.test.js"], + "testMatch": [ + "**/tests/**/*.test.js" + ], "collectCoverageFrom": [ "*.js", "!*.test.js" diff --git a/popup.js b/popup.js index a7cf6ad..2dfc249 100644 --- a/popup.js +++ b/popup.js @@ -71,10 +71,11 @@ document.addEventListener('DOMContentLoaded', async function () { async function init() { try { - loadFilters(); - renderFilters(); - setupEventListeners(); - showFilterView(); + loadFilters(() => { + renderFilters(); + setupEventListeners(); + showFilterView(); + }); } catch (error) { console.error('Failed to initialize:', error); // Show error or fallback @@ -100,7 +101,7 @@ document.addEventListener('DOMContentLoaded', async function () { }); } - function loadFilters() { + function loadFilters(callback) { if (typeof FilterState === 'undefined') { // Fallback for development/testing PopupState.setFilters([ @@ -110,7 +111,7 @@ document.addEventListener('DOMContentLoaded', async function () { 'Personal', 'Shopping', ]); - renderFilters(); + callback(); return; } @@ -121,7 +122,7 @@ document.addEventListener('DOMContentLoaded', async function () { // Load active filter FilterState.getActiveFilter(function (activeFilter) { PopupState.setActiveFilter(activeFilter); - renderFilters(); + callback(); }); }); }