diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4e12bb5f..a591f7ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,16 +18,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Added support for touch-swipe and mouse-wheel gestures on the search engine icon to switch search engines when they are hidden ([@prem-k-r](https://github.com/prem-k-r)) ([#145](https://github.com/prem-k-r/MaterialYouNewTab/pull/145))
+- Migrated storage from `localStorage` to browser Storage API (`chrome.storage.sync` on Chrome, `browser.storage.local` on Firefox) with automatic one-time migration of existing user data ([@basupatil1213](https://github.com/basupatil1213))
### Improved
- Introduced collapsible sections in the settings menu for improved organization and easier navigation ([@prem-k-r](https://github.com/prem-k-r)) ([#109](https://github.com/prem-k-r/MaterialYouNewTab/pull/109))
+- Settings now sync across devices via `chrome.storage.sync`; large/ephemeral data (quotes, weather cache) kept local to respect sync quotas ([@basupatil1213](https://github.com/basupatil1213))
- Redesigned the theme selector from dropdown to buttons for easier switching between Light, Dark, and System modes ([@prem-k-r](https://github.com/prem-k-r)) ([#112](https://github.com/prem-k-r/MaterialYouNewTab/pull/112))
- Added expanding animations to todo and Google apps panels and some other minor UI changes ([@prem-k-r](https://github.com/prem-k-r)) ([#118](https://github.com/prem-k-r/MaterialYouNewTab/pull/118))
### Fixed
- Fixed an issue where rapid clicks on the AI Tools icon caused race conditions, leading to inconsistent shortcuts panel visibility. ([#118](https://github.com/prem-k-r/MaterialYouNewTab/pull/118))
+- Fixed flash of wrong theme color on page load by awaiting storage initialization before applying theme ([@basupatil1213](https://github.com/basupatil1213))
### Localized
diff --git a/index.html b/index.html
index 2819962b..99ff992c 100644
--- a/index.html
+++ b/index.html
@@ -20,6 +20,7 @@
+
diff --git a/manifest(firefox).json b/manifest(firefox).json
index 4f8e3e54..9612b858 100644
--- a/manifest(firefox).json
+++ b/manifest(firefox).json
@@ -5,6 +5,7 @@
"description": "A Simple New Tab (browser's home page) inspired by Google's 'Material You' design.",
"permissions": [
"search",
+ "storage",
"bookmarks",
"https://www.google.com/complete/search?client=*",
"https://duckduckgo.com/ac/?q=*",
diff --git a/manifest.json b/manifest.json
index b13b9d12..37728bb6 100644
--- a/manifest.json
+++ b/manifest.json
@@ -3,7 +3,7 @@
"name": "MYNT: Material You New Tab",
"version": "3.3.6",
"description": "A Simple New Tab (browser's home page) inspired by Google's 'Material You' design.",
- "permissions": ["search"],
+ "permissions": ["search", "storage"],
"optional_permissions": ["bookmarks", "favicon"],
"optional_host_permissions": [
"https://www.google.com/complete/search?client=*",
diff --git a/scripts/ai-tools.js b/scripts/ai-tools.js
index c113d736..28d6d9ae 100644
--- a/scripts/ai-tools.js
+++ b/scripts/ai-tools.js
@@ -122,19 +122,19 @@ function saveAIToolsSettings() {
}
});
- // Save settings to localStorage
- localStorage.setItem("aiToolsSettings", JSON.stringify(aiToolsSettings));
+ // Save settings to Storage
+ Storage.setItem("aiToolsSettings", JSON.stringify(aiToolsSettings));
}
// Function to apply saved settings (visibility and order)
function applyAIToolsSettings() {
- const savedSettings = JSON.parse(localStorage.getItem("aiToolsSettings") || "null");
+ const savedSettings = JSON.parse(Storage.getItem("aiToolsSettings") || "null");
let settingsToApply;
if (!savedSettings || !Array.isArray(savedSettings)) {
// Initialize with default values if no settings exist
settingsToApply = aiTools.map(tool => tool.visible ? tool.id : { [tool.id]: false });
- localStorage.setItem("aiToolsSettings", JSON.stringify(settingsToApply));
+ Storage.setItem("aiToolsSettings", JSON.stringify(settingsToApply));
} else {
settingsToApply = savedSettings;
}
@@ -243,7 +243,7 @@ function showAIToolsSettings() {
aiToolsForm.innerHTML = "";
// Load saved tool order and visibility or initialize from defaults
- let savedSettings = JSON.parse(localStorage.getItem("aiToolsSettings") || "null");
+ let savedSettings = JSON.parse(Storage.getItem("aiToolsSettings") || "null");
// If no settings exist, create from aiTools
if (!savedSettings || !Array.isArray(savedSettings)) {
@@ -444,8 +444,8 @@ document.addEventListener("DOMContentLoaded", function () {
}
});
- // Save settings to localStorage
- localStorage.setItem("aiToolsSettings", JSON.stringify(newSettings));
+ // Save settings to Storage
+ Storage.setItem("aiToolsSettings", JSON.stringify(newSettings));
// Apply new settings
applyAIToolsSettings();
diff --git a/scripts/backup-restore.js b/scripts/backup-restore.js
index d7af8214..37e230d1 100644
--- a/scripts/backup-restore.js
+++ b/scripts/backup-restore.js
@@ -11,18 +11,21 @@ document.getElementById("backupBtn").addEventListener("click", backupData);
document.getElementById("restoreBtn").addEventListener("click", () => document.getElementById("fileInput").click());
document.getElementById("fileInput").addEventListener("change", validateAndRestoreData);
-// Backup data from localStorage and IndexedDB
+// Backup data from Storage API, localStorage (local-only keys) and IndexedDB
async function backupData() {
try {
- const backup = { localStorage: {}, indexedDB: {} };
+ const backup = { localStorage: {}, chromeStorage: {}, indexedDB: {} };
- // Backup localStorage
+ // Backup local-only keys from localStorage (quotes, weather cache, etc.)
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
backup.localStorage[key] = localStorage.getItem(key);
}
}
+ // Backup all synced settings from chrome.storage via Storage wrapper
+ backup.chromeStorage = await Storage.getAll();
+
// Backup IndexedDB (ImageDB)
backup.indexedDB = await backupIndexedDB();
@@ -150,16 +153,57 @@ async function restoreIndexedDB(data) {
});
}
-// Restore data for both localStorage and IndexedDB
+// Restore data for Storage API, localStorage and IndexedDB.
+// Supports both the old (localStorage-only) and new (chromeStorage) backup formats.
async function restoreData(backup) {
- // Clear localStorage before restoring
- localStorage.clear();
+ // Clear all synced settings from chrome.storage
+ await Storage.clearForRestore();
+
+ // Clear local-only localStorage data (quotes, weather cache)
+ // We'll selectively restore only what's in the backup
+ const localOnlyKeys = Object.keys(localStorage);
+ localOnlyKeys.forEach(key => localStorage.removeItem(key));
- // Restore localStorage from backup
+ // --- Restore local-only keys (quotes, weather cache, etc.) ---
if (backup.localStorage) {
Object.keys(backup.localStorage).forEach(key => {
- localStorage.setItem(key, backup.localStorage[key]);
+ // Restore only keys that belong in localStorage
+ // (local-only keys: quotes_*, LoadingScreenColor, weatherParsed*)
+ if (
+ key.startsWith("quotes_") ||
+ key === "LoadingScreenColor" ||
+ key === "weatherParsedData" ||
+ key === "weatherParsedTime" ||
+ key === "weatherParsedLocation" ||
+ key === "weatherParsedLang"
+ ) {
+ localStorage.setItem(key, backup.localStorage[key]);
+ }
+ });
+ }
+
+ // --- Restore synced settings ---
+ if (backup.chromeStorage && Object.keys(backup.chromeStorage).length > 0) {
+ // New backup format: restore from chromeStorage field
+ await Storage.setAll(backup.chromeStorage);
+ } else if (backup.localStorage) {
+ // Old backup format: migrate non-local-only keys to chrome.storage
+ const settingsToRestore = {};
+ Object.keys(backup.localStorage).forEach(key => {
+ if (
+ !key.startsWith("quotes_") &&
+ key !== "LoadingScreenColor" &&
+ key !== "weatherParsedData" &&
+ key !== "weatherParsedTime" &&
+ key !== "weatherParsedLocation" &&
+ key !== "weatherParsedLang"
+ ) {
+ settingsToRestore[key] = backup.localStorage[key];
+ }
});
+ if (Object.keys(settingsToRestore).length > 0) {
+ await Storage.setAll(settingsToRestore);
+ }
}
// Restore IndexedDB from backup
@@ -183,13 +227,19 @@ function base64ToBlob(base64) {
// ------------------- Reset Settings ----------------------------
const resetbtn = document.getElementById("resetsettings");
-// Clear localStorage and reload the page
+// Clear all settings and reload the page
resetbtn.addEventListener("click", async () => {
const confirmationMessage = translations[currentLanguage]?.confirmRestore || translations["en"].confirmRestore;
if (await confirmPrompt(confirmationMessage)) {
- localStorage.clear();
+ await Storage.reset();
+ // Also clear local-only localStorage data
+ const localKeys = Object.keys(localStorage).filter(k =>
+ !k.startsWith("quotes_") && k !== "LoadingScreenColor" &&
+ k !== "weatherParsedData" && k !== "weatherParsedTime" &&
+ k !== "weatherParsedLocation" && k !== "weatherParsedLang"
+ );
+ localKeys.forEach(k => localStorage.removeItem(k));
location.reload();
}
});
-
diff --git a/scripts/bookmarks.js b/scripts/bookmarks.js
index 5b0d0e56..0fbcaa18 100644
--- a/scripts/bookmarks.js
+++ b/scripts/bookmarks.js
@@ -27,7 +27,7 @@ let currentBookmarkId = null;
const sortAlphabetical = document.getElementById("sortAlphabetical");
const sortTimeAdded = document.getElementById("sortTimeAdded");
-let currentSortMethod = localStorage.getItem("bookmarkSortMethod") || 'title';
+let currentSortMethod = Storage.getItem("bookmarkSortMethod") || 'title';
var bookmarksAPI;
if (isFirefox) {
@@ -135,7 +135,7 @@ bookmarkSearch.addEventListener("input", function () {
sortAlphabetical.addEventListener("click", function () {
if (!this.classList.contains("active")) {
currentSortMethod = 'title';
- localStorage.setItem("bookmarkSortMethod", "title");
+ Storage.setItem("bookmarkSortMethod", "title");
updateSortButtons();
loadBookmarks();
}
@@ -144,7 +144,7 @@ sortAlphabetical.addEventListener("click", function () {
sortTimeAdded.addEventListener("click", function () {
if (!this.classList.contains("active")) {
currentSortMethod = 'date';
- localStorage.setItem("bookmarkSortMethod", "date");
+ Storage.setItem("bookmarkSortMethod", "date");
updateSortButtons();
loadBookmarks();
}
diff --git a/scripts/clock.js b/scripts/clock.js
index 2f108a13..1ccf38df 100644
--- a/scripts/clock.js
+++ b/scripts/clock.js
@@ -45,8 +45,8 @@ function handleClockVisibility() {
rightDiv.classList.remove("clock-padding-adjusted");
}
else {
- // Retrieve saved state from localStorage
- const isClockHidden = localStorage.getItem("hideClockVisible") === "true";
+ // Retrieve saved state from Storage
+ const isClockHidden = Storage.getItem("hideClockVisible") === "true";
hideClockCheckbox.checked = isClockHidden;
// Apply initial state
@@ -59,7 +59,7 @@ function handleClockVisibility() {
hideClockCheckbox.addEventListener("change", function () {
const isChecked = hideClockCheckbox.checked;
- localStorage.setItem("hideClockVisible", isChecked);
+ Storage.setItem("hideClockVisible", isChecked);
applyClockState(isChecked);
toggleHideState(isChecked);
@@ -113,9 +113,9 @@ async function initializeClock() {
document.getElementById("hour").style.transform = `rotate(${cumulativeHourRotation}deg)`;
function initializeClockType() {
- const savedClockType = localStorage.getItem("clocktype");
+ const savedClockType = Storage.getItem("clocktype");
clocktype = savedClockType ? savedClockType : "analog"; // Default to "analog" if nothing is saved
- localStorage.setItem("clocktype", clocktype); // Ensure it's set in local storage
+ Storage.setItem("clocktype", clocktype); // Ensure it's set in local storage
}
// Call this function to initialize the clock type
@@ -258,10 +258,10 @@ async function initializeClock() {
}
function updatedigiClock() {
- const hourformatstored = localStorage.getItem("hourformat");
+ const hourformatstored = Storage.getItem("hourformat");
let hourformat = hourformatstored === "true"; // Default to false if null
const greetingCheckbox = document.getElementById("greetingcheckbox");
- const isGreetingEnabled = localStorage.getItem("greetingEnabled") === "true";
+ const isGreetingEnabled = Storage.getItem("greetingEnabled") === "true";
greetingCheckbox.checked = isGreetingEnabled;
const now = new Date();
@@ -389,7 +389,7 @@ async function initializeClock() {
document.getElementById("amPm").textContent = ""; // Clear AM/PM for 24-hour format
}
- const clocktype1 = localStorage.getItem("clocktype");
+ const clocktype1 = Storage.getItem("clocktype");
const dateElement = document.getElementById("date");
if (clocktype1 === "digital" && isGreetingEnabled) {
const newGreeting = getGreeting();
@@ -496,12 +496,12 @@ async function initializeClock() {
const greetingCheckbox = document.getElementById("greetingcheckbox");
const greetingField = document.getElementById("greetingField");
- if (localStorage.getItem("greetingEnabled") === null) {
- localStorage.setItem("greetingEnabled", "true");
+ if (Storage.getItem("greetingEnabled") === null) {
+ Storage.setItem("greetingEnabled", "true");
}
- greetingCheckbox.checked = localStorage.getItem("greetingEnabled") === "true";
- greetingCheckbox.disabled = localStorage.getItem("clocktype") !== "digital";
+ greetingCheckbox.checked = Storage.getItem("greetingEnabled") === "true";
+ greetingCheckbox.disabled = Storage.getItem("clocktype") !== "digital";
digitalCheckbox.addEventListener("change", function () {
saveCheckboxState("digitalCheckboxState", digitalCheckbox);
@@ -509,8 +509,8 @@ async function initializeClock() {
timeformatField.classList.remove("inactive");
greetingField.classList.remove("inactive");
greetingCheckbox.disabled = false; // Enable greeting toggle
- localStorage.setItem("clocktype", "digital");
- clocktype = localStorage.getItem("clocktype");
+ Storage.setItem("clocktype", "digital");
+ clocktype = Storage.getItem("clocktype");
displayClock();
stopAnalogClock();
startDigitalClock();
@@ -521,8 +521,8 @@ async function initializeClock() {
timeformatField.classList.add("inactive");
greetingField.classList.add("inactive");
greetingCheckbox.disabled = true; // Disable greeting toggle
- localStorage.setItem("clocktype", "analog");
- clocktype = localStorage.getItem("clocktype");
+ Storage.setItem("clocktype", "analog");
+ clocktype = Storage.getItem("clocktype");
stopDigitalClock();
startAnalogClock();
updateanalogclock();
@@ -536,14 +536,14 @@ async function initializeClock() {
hourcheckbox.addEventListener("change", function () {
saveCheckboxState("hourcheckboxState", hourcheckbox);
if (hourcheckbox.checked) {
- localStorage.setItem("hourformat", "true");
+ Storage.setItem("hourformat", "true");
} else {
- localStorage.setItem("hourformat", "false");
+ Storage.setItem("hourformat", "false");
}
});
greetingCheckbox.addEventListener("change", () => {
- localStorage.setItem("greetingEnabled", greetingCheckbox.checked);
+ Storage.setItem("greetingEnabled", greetingCheckbox.checked);
updatedigiClock();
});
diff --git a/scripts/custom-text.js b/scripts/custom-text.js
index 8f405677..105619b1 100644
--- a/scripts/custom-text.js
+++ b/scripts/custom-text.js
@@ -12,7 +12,7 @@ document.addEventListener("DOMContentLoaded", () => {
const userTextCheckbox = document.getElementById("userTextCheckbox");
// Load and apply the checkbox state
- const isUserTextVisible = localStorage.getItem("userTextVisible") !== "false";
+ const isUserTextVisible = Storage.getItem("userTextVisible") !== "false";
userTextCheckbox.checked = isUserTextVisible;
userTextDiv.style.display = isUserTextVisible ? "block" : "none";
@@ -20,15 +20,15 @@ document.addEventListener("DOMContentLoaded", () => {
userTextCheckbox.addEventListener("change", () => {
const isVisible = userTextCheckbox.checked;
userTextDiv.style.display = isVisible ? "block" : "none";
- localStorage.setItem("userTextVisible", isVisible);
+ Storage.setItem("userTextVisible", isVisible);
});
// Set the default language to English if no language is saved
- const savedLang = localStorage.getItem("selectedLanguage") || "en";
+ const savedLang = Storage.getItem("selectedLanguage") || "en";
applyLanguage(savedLang);
// Load the stored text if it exists
- const storedValue = localStorage.getItem("userText");
+ const storedValue = Storage.getItem("userText");
if (storedValue) {
userTextDiv.textContent = storedValue;
} else {
@@ -39,7 +39,7 @@ document.addEventListener("DOMContentLoaded", () => {
// Handle input event
userTextDiv.addEventListener("input", function () {
- localStorage.setItem("userText", userTextDiv.textContent);
+ Storage.setItem("userText", userTextDiv.textContent);
});
// Remove placeholder text when the user starts editing
diff --git a/scripts/languages.js b/scripts/languages.js
index 39c3f315..4d6ca2ae 100644
--- a/scripts/languages.js
+++ b/scripts/languages.js
@@ -302,8 +302,8 @@ function applyLanguage(lang) {
if (translations[lang]) {
const placeholder = translations[lang]?.userText || translations["en"].userText;
userTextDiv.dataset.placeholder = placeholder; // Update the placeholder in data attribute
- // Only set the text content if there's nothing in localStorage
- if (!localStorage.getItem("userText")) {
+ // Only set the text content if there's nothing in Storage
+ if (!Storage.getItem("userText")) {
userTextDiv.innerText = placeholder;
}
}
@@ -383,7 +383,7 @@ function applyLanguage(lang) {
// quotesText.style.textAlign = isRTL ? "right" : "left";
quotesText.style.fontFamily = commonFontStack;
- // Save the selected language in localStorage
+ // Save the selected language in Storage
document.documentElement.lang = currentLanguage;
saveLanguageStatus("selectedLanguage", lang);
}
@@ -401,12 +401,12 @@ window.onload = function () {
applyLanguage(savedLanguage);
};
-// Function to save the language status in localStorage
+// Function to save the language status to Storage
function saveLanguageStatus(key, languageStatus) {
- localStorage.setItem(key, languageStatus);
+ Storage.setItem(key, languageStatus);
}
-// Function to get the language status from localStorage
+// Function to get the language status from Storage
function getLanguageStatus(key) {
- return localStorage.getItem(key);
+ return Storage.getItem(key);
}
diff --git a/scripts/menu-shortcut-page.js b/scripts/menu-shortcut-page.js
index ff27854c..070effa6 100644
--- a/scripts/menu-shortcut-page.js
+++ b/scripts/menu-shortcut-page.js
@@ -7,8 +7,8 @@
*/
-// Get the current language from localStorage
-const currentLanguage = localStorage.getItem("selectedLanguage") || "en";
+// Get the current language from Storage
+const currentLanguage = Storage.getItem("selectedLanguage") || "en";
const isRTL = rtlLanguages.includes(currentLanguage);
// ------------Showing & Hiding Menu-bar ---------------
diff --git a/scripts/save-load-states.js b/scripts/save-load-states.js
index 1d90ad41..341a25b9 100644
--- a/scripts/save-load-states.js
+++ b/scripts/save-load-states.js
@@ -8,15 +8,15 @@
/* ------ Helper functions for saving and loading states ------ */
-// Function to save checkbox state to localStorage
+// Function to save checkbox state to Storage
function saveCheckboxState(key, checkbox) {
- localStorage.setItem(key, checkbox.checked ? "checked" : "unchecked");
+ Storage.setItem(key, checkbox.checked ? "checked" : "unchecked");
}
const bookmarkGridCheckbox = document.getElementById("bookmarkGridCheckbox");
-// Function to load and apply checkbox state from localStorage
+// Function to load and apply checkbox state from Storage
function loadCheckboxState(key, checkbox) {
- const savedState = localStorage.getItem(key);
+ const savedState = Storage.getItem(key);
checkbox.checked = savedState === "checked";
if (key === "bookmarkGridCheckboxState") {
if (!savedState) {
@@ -28,14 +28,14 @@ function loadCheckboxState(key, checkbox) {
}
}
-// Function to save display status to localStorage
+// Function to save display status to Storage
function saveDisplayStatus(key, displayStatus) {
- localStorage.setItem(key, displayStatus);
+ Storage.setItem(key, displayStatus);
}
-// Function to load and apply display status from localStorage
+// Function to load and apply display status from Storage
function loadDisplayStatus(key, element) {
- const savedStatus = localStorage.getItem(key);
+ const savedStatus = Storage.getItem(key);
if (savedStatus === "flex") {
element.style.display = "flex";
} else {
@@ -43,14 +43,14 @@ function loadDisplayStatus(key, element) {
}
}
-// Function to save activeness status to localStorage
+// Function to save activeness status to Storage
function saveActiveStatus(key, activeStatus) {
- localStorage.setItem(key, activeStatus);
+ Storage.setItem(key, activeStatus);
}
-// Function to load and apply activeness status from localStorage
+// Function to load and apply activeness status from Storage
function loadActiveStatus(key, element) {
- const savedStatus = localStorage.getItem(key);
+ const savedStatus = Storage.getItem(key);
if (savedStatus === "active") {
element.classList.remove("inactive");
} else {
diff --git a/scripts/script.js b/scripts/script.js
index 65c5e4cf..8f207a19 100644
--- a/scripts/script.js
+++ b/scripts/script.js
@@ -45,14 +45,14 @@ document.addEventListener("DOMContentLoaded", function () {
const dontShowButton = document.getElementById("dontShowTips");
// Check if the user has previously disabled tips
- if (localStorage.getItem("hideTips") === "true") {
+ if (Storage.getItem("hideTips") === "true") {
tips.style.display = "none";
}
// Hide tips and save preference when button is clicked
dontShowButton.addEventListener("click", function () {
tips.style.display = "none";
- localStorage.setItem("hideTips", "true"); // Save preference
+ Storage.setItem("hideTips", "true"); // Save preference
});
});
@@ -75,11 +75,11 @@ document.addEventListener("DOMContentLoaded", function () {
function showToast() {
// Check if toast has been shown before
- const hasShown = localStorage.getItem(STORAGE_KEY);
+ const hasShown = Storage.getItem(STORAGE_KEY);
if (hasShown) return;
// Mark as shown
- localStorage.setItem(STORAGE_KEY, 'true');
+ Storage.setItem(STORAGE_KEY, 'true');
// Show toast after brief delay
setTimeout(() => {
diff --git a/scripts/search-suggestions.js b/scripts/search-suggestions.js
index 539aa9c3..6a46cae8 100644
--- a/scripts/search-suggestions.js
+++ b/scripts/search-suggestions.js
@@ -11,7 +11,7 @@ let proxyurl;
document.addEventListener("DOMContentLoaded", () => {
const userProxyInput = document.getElementById("userproxy");
const saveProxyButton = document.getElementById("saveproxy");
- const savedProxy = localStorage.getItem("proxy");
+ const savedProxy = Storage.getItem("proxy");
const defaultProxyURL = "https://mynt-proxy.rhythmcorehq.com/proxy?url="; //Default proxy url
@@ -26,7 +26,7 @@ document.addEventListener("DOMContentLoaded", () => {
}
});
- // Save the proxy to localStorage
+ // Save the proxy to Storage
saveProxyButton.addEventListener("click", () => {
proxyurl = userProxyInput.value.trim();
@@ -39,8 +39,8 @@ document.addEventListener("DOMContentLoaded", () => {
proxyurl = "https://" + proxyurl;
}
}
- // Set the proxy in localStorage, clear the input, and reload the page
- localStorage.setItem("proxy", proxyurl);
+ // Set the proxy in Storage, clear the input, and reload the page
+ Storage.setItem("proxy", proxyurl);
userProxyInput.value = "";
location.reload();
});
diff --git a/scripts/search.js b/scripts/search.js
index 3c600972..88f6c00d 100644
--- a/scripts/search.js
+++ b/scripts/search.js
@@ -9,7 +9,7 @@
const searchbar = document.getElementById("searchbar");
const searchInput = document.getElementById("searchQ");
-const languageCode = (localStorage.getItem("selectedLanguage") || "en").slice(0, 2);
+const languageCode = (Storage.getItem("selectedLanguage") || "en").slice(0, 2);
const searchQueryURLs = {
engine1: "https://www.google.com/search?q=",
engine2: "https://duckduckgo.com/?q=",
@@ -43,7 +43,7 @@ document.addEventListener("click", function (event) {
const searchWith = document.getElementById("searchWithHint");
const searchEngines = document.querySelectorAll(".searchEnginesContainer .search-engine");
const searchEnginesContainer = document.querySelector(".searchEnginesContainer");
-let activeSearchMode = localStorage.getItem("activeSearchMode") || "search-with";
+let activeSearchMode = Storage.getItem("activeSearchMode") || "search-with";
searchWith.addEventListener("click", function (event) {
activeSearchMode = (activeSearchMode === "search-with") ? "search-on" : "search-with";
@@ -64,7 +64,7 @@ function toggleSearchEngines(category) {
"search-with": "engine0",
"search-on": "engine5",
};
- const checkeditem = localStorage.getItem(`selectedSearchEngine-${category}`) || defaultItems[category];
+ const checkeditem = Storage.getItem(`selectedSearchEngine-${category}`) || defaultItems[category];
const searchModeName = category === "search-with" ? "searchWithHint" : "searchOnHint";
searchWith.innerText = translations[currentLanguage][searchModeName] || translations["en"][searchModeName];
@@ -153,8 +153,8 @@ searchDropdowns.forEach(element => {
swapDropdown(selector);
sortDropdown()
- localStorage.setItem(`selectedSearchEngine-${radioButton.parentElement.dataset.category}`, radioButton.value);
- localStorage.setItem(`activeSearchMode`, radioButton.parentElement.dataset.category);
+ Storage.setItem(`selectedSearchEngine-${radioButton.parentElement.dataset.category}`, radioButton.value);
+ Storage.setItem(`activeSearchMode`, radioButton.parentElement.dataset.category);
});
});
@@ -174,8 +174,8 @@ document.querySelectorAll(".search-engine").forEach((engineDiv) => {
swapDropdown(selector);
sortDropdown();
- localStorage.setItem(`selectedSearchEngine-${radioButton.parentElement.dataset.category}`, radioButton.value);
- localStorage.setItem(`activeSearchMode`, radioButton.parentElement.dataset.category);
+ Storage.setItem(`selectedSearchEngine-${radioButton.parentElement.dataset.category}`, radioButton.value);
+ Storage.setItem(`activeSearchMode`, radioButton.parentElement.dataset.category);
searchInput.focus();
searchbar.classList.add("active");
@@ -232,7 +232,7 @@ enterBTN.addEventListener("click", () => performSearch());
// Enter key handling is managed in the search suggestions keydown listener
// Set selected search engine from local storage
-const storedSearchEngine = localStorage.getItem(`selectedSearchEngine-${activeSearchMode}`);
+const storedSearchEngine = Storage.getItem(`selectedSearchEngine-${activeSearchMode}`);
toggleSearchEngines(activeSearchMode);
@@ -310,7 +310,7 @@ document.querySelector(".dropdown").addEventListener("keydown", function (event)
swapDropdown(`*[data-engine="${engine}"]`);
sortDropdown();
- localStorage.setItem("selectedSearchEngine", radioButton.value);
+ Storage.setItem("selectedSearchEngine", radioButton.value);
// Close the dropdown after selection
dropdown.classList.remove("show");
@@ -327,8 +327,8 @@ updateSelection();
searchEngineRadio.forEach((radio) => {
radio.addEventListener("change", () => {
const selectedOption = document.querySelector('input[name="search-engine"]:checked');
- localStorage.setItem(`selectedSearchEngine-${selectedOption.parentElement.dataset.category}`, selectedOption.value);
- localStorage.setItem(`activeSearchMode`, selectedOption.parentElement.dataset.category);
+ Storage.setItem(`selectedSearchEngine-${selectedOption.parentElement.dataset.category}`, selectedOption.value);
+ Storage.setItem(`activeSearchMode`, selectedOption.parentElement.dataset.category);
});
});
@@ -350,10 +350,10 @@ const hideEngineContainer = () => {
const initShortCutSwitch = (element) => {
if (element.checked) {
hideEngineContainer();
- localStorage.setItem("showShortcutSwitch", true)
+ Storage.setItem("showShortcutSwitch", true)
} else {
showEngineContainer();
- localStorage.setItem("showShortcutSwitch", false)
+ Storage.setItem("showShortcutSwitch", false)
}
}
@@ -363,11 +363,11 @@ hideSearchWith.addEventListener("change", (e) => {
initShortCutSwitch(e.target);
// Fetch active search mode from storage
- let activeSearchMode = localStorage.getItem("activeSearchMode") || "search-with";
+ let activeSearchMode = Storage.getItem("activeSearchMode") || "search-with";
toggleSearchEngines(activeSearchMode);
- // Get the selected search engine from localStorage
- const storedSearchEngine = localStorage.getItem(`selectedSearchEngine-${activeSearchMode}`);
+ // Get the selected search engine from Storage
+ const storedSearchEngine = Storage.getItem(`selectedSearchEngine-${activeSearchMode}`);
// Find the corresponding radio button
const selectedRadioButton = document.querySelector(`input[name="search-engine"][value="${storedSearchEngine}"]`);
@@ -382,8 +382,8 @@ hideSearchWith.addEventListener("change", (e) => {
});
// Intialize shortcut switch
-if (localStorage.getItem("showShortcutSwitch")) {
- const isShortCutSwitchEnabled = localStorage.getItem("showShortcutSwitch").toString() === "true";
+if (Storage.getItem("showShortcutSwitch")) {
+ const isShortCutSwitchEnabled = Storage.getItem("showShortcutSwitch").toString() === "true";
document.getElementById("shortcut_switchcheckbox").checked = isShortCutSwitchEnabled;
if (isShortCutSwitchEnabled) {
@@ -392,7 +392,7 @@ if (localStorage.getItem("showShortcutSwitch")) {
showEngineContainer()
}
} else {
- localStorage.setItem("showShortcutSwitch", false);
+ Storage.setItem("showShortcutSwitch", false);
}
initShortCutSwitch(hideSearchWith);
@@ -455,8 +455,8 @@ function switchEngine(direction) {
swapDropdown(selector);
sortDropdown();
- localStorage.setItem(`selectedSearchEngine-${radioButton.parentElement.dataset.category}`, radioButton.value);
- localStorage.setItem(`activeSearchMode`, radioButton.parentElement.dataset.category);
+ Storage.setItem(`selectedSearchEngine-${radioButton.parentElement.dataset.category}`, radioButton.value);
+ Storage.setItem(`activeSearchMode`, radioButton.parentElement.dataset.category);
// Update the search mode hint text
const newCategory = radioButton.parentElement.dataset.category;
diff --git a/scripts/shortcuts.js b/scripts/shortcuts.js
index 362241fd..fb7dec0f 100644
--- a/scripts/shortcuts.js
+++ b/scripts/shortcuts.js
@@ -81,7 +81,7 @@ document.addEventListener("DOMContentLoaded", function () {
setupEventListeners();
loadShortcuts();
- // Loads all settings from localStorage and applies them
+ // Loads all settings from Storage and applies them
function loadSettings() {
loadCheckboxState("shortcutsCheckboxState", dom.shortcutsCheckbox);
loadCheckboxState("adaptiveIconToggle", dom.adaptiveIconToggle);
@@ -113,7 +113,7 @@ document.addEventListener("DOMContentLoaded", function () {
function handleNewShortcutClick() {
if (this.classList.contains("inactive")) return;
- const currentAmount = parseInt(localStorage.getItem("shortcutAmount")) || shortcutsCache.length;
+ const currentAmount = parseInt(Storage.getItem("shortcutAmount")) || shortcutsCache.length;
if (currentAmount >= MAX_SHORTCUTS) return;
addNewShortcut();
@@ -133,16 +133,16 @@ document.addEventListener("DOMContentLoaded", function () {
}, 800);
}
- // Loads shortcuts from localStorage or uses presets if none exist
+ // Loads shortcuts from Storage or uses presets if none exist
function loadShortcuts() {
- const amount = localStorage.getItem("shortcutAmount") || presets.length;
+ const amount = Storage.getItem("shortcutAmount") || presets.length;
const deleteInactive = amount <= 1;
shortcutsCache = [];
for (let i = 0; i < amount; i++) {
- const name = localStorage.getItem(`shortcutName${i}`) || (presets[i] ? presets[i].name : PLACEHOLDER.name);
- const url = localStorage.getItem(`shortcutURL${i}`) || (presets[i] ? presets[i].url : PLACEHOLDER.url);
+ const name = Storage.getItem(`shortcutName${i}`) || (presets[i] ? presets[i].name : PLACEHOLDER.name);
+ const url = Storage.getItem(`shortcutURL${i}`) || (presets[i] ? presets[i].url : PLACEHOLDER.url);
shortcutsCache.push({ name, url });
@@ -559,7 +559,7 @@ document.addEventListener("DOMContentLoaded", function () {
});
}
- // Saves the new shortcut order to localStorage
+ // Saves the new shortcut order to Storage
function saveShortcutOrder() {
const entries = dom.shortcutSettingsContainer.querySelectorAll(".shortcutSettingsEntry");
const newOrder = Array.from(entries).map(entry => ({
@@ -569,10 +569,10 @@ document.addEventListener("DOMContentLoaded", function () {
// Only save if order has changed
if (hasOrderChanged(newOrder)) {
- localStorage.setItem("shortcutAmount", newOrder.length.toString());
+ Storage.setItem("shortcutAmount", newOrder.length.toString());
newOrder.forEach((item, index) => {
- localStorage.setItem(`shortcutName${index}`, item.name);
- localStorage.setItem(`shortcutURL${index}`, item.url);
+ Storage.setItem(`shortcutName${index}`, item.name);
+ Storage.setItem(`shortcutURL${index}`, item.url);
});
shortcutsCache = newOrder;
@@ -629,11 +629,11 @@ document.addEventListener("DOMContentLoaded", function () {
// Adds a new shortcut
function addNewShortcut() {
- const currentAmount = parseInt(localStorage.getItem("shortcutAmount")) || shortcutsCache.length;
+ const currentAmount = parseInt(Storage.getItem("shortcutAmount")) || shortcutsCache.length;
if (currentAmount >= MAX_SHORTCUTS) return;
const newAmount = currentAmount + 1;
- localStorage.setItem("shortcutAmount", newAmount.toString());
+ Storage.setItem("shortcutAmount", newAmount.toString());
if (currentAmount >= 1) {
document.querySelectorAll(".delete button.inactive").forEach(b => {
@@ -654,22 +654,22 @@ document.addEventListener("DOMContentLoaded", function () {
// Deletes a shortcut
function deleteShortcut(entry) {
- const currentAmount = parseInt(localStorage.getItem("shortcutAmount")) || shortcutsCache.length;
+ const currentAmount = parseInt(Storage.getItem("shortcutAmount")) || shortcutsCache.length;
if (currentAmount <= 1) return;
const index = entry._index;
entry.remove();
dom.shortcutsContainer.removeChild(dom.shortcutsContainer.children[index]);
- // Update localStorage
- localStorage.setItem("shortcutAmount", (currentAmount - 1).toString());
+ // Update Storage
+ Storage.setItem("shortcutAmount", (currentAmount - 1).toString());
for (let i = index; i < currentAmount - 1; i++) {
const nextEntry = dom.shortcutSettingsContainer.children[i];
nextEntry._index = i;
saveShortcut(nextEntry);
}
- localStorage.removeItem(`shortcutName${currentAmount - 1}`);
- localStorage.removeItem(`shortcutURL${currentAmount - 1}`);
+ Storage.removeItem(`shortcutName${currentAmount - 1}`);
+ Storage.removeItem(`shortcutURL${currentAmount - 1}`);
if (currentAmount - 1 === 1) {
document.querySelectorAll(".delete button").forEach(b => {
@@ -694,11 +694,11 @@ document.addEventListener("DOMContentLoaded", function () {
svg.classList.add("rotate-animation");
// Clear storage
- for (let i = 0; i < (localStorage.getItem("shortcutAmount") || 0); i++) {
- localStorage.removeItem(`shortcutName${i}`);
- localStorage.removeItem(`shortcutURL${i}`);
+ for (let i = 0; i < (Storage.getItem("shortcutAmount") || 0); i++) {
+ Storage.removeItem(`shortcutName${i}`);
+ Storage.removeItem(`shortcutURL${i}`);
}
- localStorage.removeItem("shortcutAmount");
+ Storage.removeItem("shortcutAmount");
// Wait for animations of shortcut elements to complete
await new Promise(resolve => setTimeout(resolve, 300));
@@ -713,9 +713,9 @@ document.addEventListener("DOMContentLoaded", function () {
loadShortcuts();
}
- // Saves a single shortcut to localStorage
+ // Saves a single shortcut to Storage
function saveShortcut(entry) {
- localStorage.setItem(`shortcutName${entry._index}`, entry.querySelector(".shortcutName").value);
- localStorage.setItem(`shortcutURL${entry._index}`, entry.querySelector(".URL").value);
+ Storage.setItem(`shortcutName${entry._index}`, entry.querySelector(".shortcutName").value);
+ Storage.setItem(`shortcutURL${entry._index}`, entry.querySelector(".URL").value);
}
});
diff --git a/scripts/storage.js b/scripts/storage.js
new file mode 100644
index 00000000..9d2872ff
--- /dev/null
+++ b/scripts/storage.js
@@ -0,0 +1,177 @@
+/*
+ * Material You NewTab
+ * Copyright (c) 2023-2025 XengShi
+ * Licensed under the GNU General Public License v3.0 (GPL-3.0)
+ * You should have received a copy of the GNU General Public License along with this program.
+ * If not, see .
+ */
+
+// --------------- Centralized Storage Wrapper ---------------
+// Uses chrome.storage.sync on Chrome, browser.storage.local on Firefox.
+// Falls back to localStorage if chrome.storage is unavailable (e.g., website preview).
+
+(function () {
+ // Keys that must remain in localStorage (not synced):
+ // quotes_* : large quote arrays, exceed chrome.storage.sync item quota
+ // LoadingScreenColor : computed value used by preload.js for fast synchronous read
+ // weatherParsed* : ephemeral API cache, not worth syncing across devices
+ function _isLocalOnly(key) {
+ return key.startsWith("quotes_")
+ || key === "LoadingScreenColor"
+ || key === "weatherParsedData"
+ || key === "weatherParsedTime"
+ || key === "weatherParsedLocation"
+ || key === "weatherParsedLang";
+ }
+
+ // Firefox detection (browser-utils.js has not loaded yet at this point)
+ const _isFirefox = typeof browser !== "undefined" && /firefox/i.test(navigator.userAgent);
+
+ // Return the appropriate storage area for settings
+ function _getStorageArea() {
+ if (_isFirefox) {
+ return (typeof browser !== "undefined" && browser.storage && browser.storage.local) || null;
+ }
+ if (typeof chrome !== "undefined" && chrome.storage) {
+ return chrome.storage.sync || chrome.storage.local || null;
+ }
+ return null;
+ }
+
+ // Internal key to track whether migration from localStorage has been done
+ const MIGRATION_KEY = "_storage_migrated";
+
+ // In-memory cache: synchronously pre-populated from localStorage so that
+ // defer scripts can read settings immediately before chrome.storage resolves.
+ const _cache = {};
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+ if (!_isLocalOnly(key)) _cache[key] = localStorage.getItem(key);
+ }
+
+ // One-time migration: copy all non-local-only localStorage keys to chrome.storage,
+ // then remove them from localStorage so there is a single source of truth.
+ async function _migrate(storageArea) {
+ const result = await storageArea.get(MIGRATION_KEY);
+ if (result[MIGRATION_KEY]) return; // Already migrated
+
+ const toMigrate = { [MIGRATION_KEY]: true };
+ for (let i = 0; i < localStorage.length; i++) {
+ const key = localStorage.key(i);
+ if (!_isLocalOnly(key)) toMigrate[key] = localStorage.getItem(key);
+ }
+
+ await storageArea.set(toMigrate);
+
+ // Remove migrated keys from localStorage (preserves local-only keys)
+ Object.keys(toMigrate).forEach(key => {
+ if (key !== MIGRATION_KEY) localStorage.removeItem(key);
+ });
+ }
+
+ // Promise that resolves once chrome.storage is loaded and cache is up-to-date.
+ // DOMContentLoaded handlers that need accurate settings should await this.
+ window.storageReady = (async () => {
+ const storageArea = _getStorageArea();
+ if (!storageArea) return; // No chrome.storage available; cache serves as localStorage proxy
+
+ await _migrate(storageArea);
+
+ // Load all settings from chrome.storage into the in-memory cache
+ const items = await storageArea.get(null);
+ Object.assign(_cache, items);
+
+ // Listen for external changes (e.g., sync data arriving from another device)
+ const onChanged = _isFirefox
+ ? (typeof browser !== "undefined" && browser.storage && browser.storage.onChanged)
+ : (typeof chrome !== "undefined" && chrome.storage && chrome.storage.onChanged);
+
+ if (onChanged) {
+ onChanged.addListener((changes) => {
+ for (const [key, { newValue }] of Object.entries(changes)) {
+ if (newValue !== undefined) _cache[key] = newValue;
+ else delete _cache[key];
+ }
+ });
+ }
+ })();
+
+ // ---------- Public Storage API ----------
+
+ window.Storage = {
+ // Synchronous read from cache (or localStorage for local-only keys).
+ // Safe to call at any time; returns null if key does not exist.
+ getItem(key) {
+ if (_isLocalOnly(key)) return localStorage.getItem(key);
+ return Object.prototype.hasOwnProperty.call(_cache, key) ? _cache[key] : null;
+ },
+
+ // Write to cache immediately and persist to chrome.storage (fire-and-forget).
+ // Callers do not need to await this.
+ setItem(key, value) {
+ if (_isLocalOnly(key)) { localStorage.setItem(key, value); return; }
+ _cache[key] = value;
+ const storageArea = _getStorageArea();
+ if (storageArea) storageArea.set({ [key]: value });
+ else localStorage.setItem(key, value);
+ },
+
+ // Remove from cache and from chrome.storage (fire-and-forget).
+ removeItem(key) {
+ if (_isLocalOnly(key)) { localStorage.removeItem(key); return; }
+ delete _cache[key];
+ const storageArea = _getStorageArea();
+ if (storageArea) storageArea.remove(key);
+ else localStorage.removeItem(key);
+ },
+
+ // Clear all synced settings but keep the migration marker so re-migration
+ // is not triggered on next load. Used by the reset-settings button.
+ reset() {
+ const storageArea = _getStorageArea();
+ const keysToRemove = Object.keys(_cache).filter(k => k !== MIGRATION_KEY);
+ keysToRemove.forEach(key => delete _cache[key]);
+ if (storageArea) return storageArea.remove(keysToRemove);
+ keysToRemove.forEach(key => localStorage.removeItem(key));
+ },
+
+ // Clear ALL chrome.storage including the migration marker. Used before
+ // restoring a backup so old data does not bleed through.
+ clearForRestore() {
+ const storageArea = _getStorageArea();
+ Object.keys(_cache).forEach(key => delete _cache[key]);
+ if (storageArea) return storageArea.clear();
+ // Fallback: clear only non-local-only keys from localStorage
+ const toKeep = {};
+ for (let i = 0; i < localStorage.length; i++) {
+ const k = localStorage.key(i);
+ if (_isLocalOnly(k)) toKeep[k] = localStorage.getItem(k);
+ }
+ localStorage.clear();
+ Object.entries(toKeep).forEach(([k, v]) => localStorage.setItem(k, v));
+ },
+
+ // Return all synced settings as a plain object (used for backup).
+ async getAll() {
+ const storageArea = _getStorageArea();
+ let items;
+ if (storageArea) {
+ items = await storageArea.get(null);
+ } else {
+ items = { ..._cache };
+ }
+ const result = { ...items };
+ delete result[MIGRATION_KEY];
+ return result;
+ },
+
+ // Write a batch of settings and mark migration as done (used for restore).
+ async setAll(obj) {
+ const dataWithMarker = { ...obj, [MIGRATION_KEY]: true };
+ Object.entries(dataWithMarker).forEach(([key, val]) => { _cache[key] = val; });
+ const storageArea = _getStorageArea();
+ if (storageArea) return storageArea.set(dataWithMarker);
+ Object.entries(dataWithMarker).forEach(([key, val]) => localStorage.setItem(key, val));
+ }
+ };
+})();
diff --git a/scripts/theme.js b/scripts/theme.js
index 365ab938..0e187e78 100644
--- a/scripts/theme.js
+++ b/scripts/theme.js
@@ -7,8 +7,6 @@
const themeStorageKey = "selectedTheme";
const customThemeStorageKey = "customThemeColor";
const darkModeCheckboxKey = "enableDarkModeCheckboxState";
-const storedTheme = localStorage.getItem(themeStorageKey);
-const storedCustomColor = localStorage.getItem(customThemeStorageKey);
const radioButtons = document.querySelectorAll(".colorPlate");
const colorPicker = document.getElementById("colorPicker");
const colorPickerLabel = document.getElementById("rangColor");
@@ -24,7 +22,9 @@ const syncThemeChange = (MediaQuery) => {
syncThemeChange(systemTheme);
// ===== Segmented Control for Dark Mode =====
-(function () {
+(async function () {
+ await window.storageReady;
+
const preferredThemeKey = "preferredTheme";
const segment = document.getElementById("themeSegment");
const indicator = segment.querySelector(".themeIndicator");
@@ -40,7 +40,7 @@ syncThemeChange(systemTheme);
// Apply theme mode (light/dark/system)
function applyThemeMode(theme) {
- localStorage.setItem(preferredThemeKey, theme);
+ Storage.setItem(preferredThemeKey, theme);
segment.dataset.active = theme;
moveIndicator(theme);
@@ -61,16 +61,16 @@ syncThemeChange(systemTheme);
systemTheme.addEventListener('change', syncThemeChange);
function initializeThemeMode() {
- const darkModeCheckboxState = localStorage.getItem(darkModeCheckboxKey);
- const savedPreferredTheme = localStorage.getItem(preferredThemeKey);
+ const darkModeCheckboxState = Storage.getItem(darkModeCheckboxKey);
+ const savedPreferredTheme = Storage.getItem(preferredThemeKey);
let initialTheme;
if (darkModeCheckboxState === "checked") {
// Migrate old checkbox users to "dark" mode
initialTheme = "dark";
- localStorage.removeItem(darkModeCheckboxKey);
- localStorage.setItem(preferredThemeKey, "dark");
+ Storage.removeItem(darkModeCheckboxKey);
+ Storage.setItem(preferredThemeKey, "dark");
} else if (savedPreferredTheme) {
initialTheme = savedPreferredTheme; // Use saved preference
} else {
@@ -84,9 +84,11 @@ syncThemeChange(systemTheme);
initializeThemeMode();
})();
-document.addEventListener("DOMContentLoaded", () => {
+document.addEventListener("DOMContentLoaded", async () => {
+ await window.storageReady;
+
// Check for custom color
- const storedCustomColor = localStorage.getItem(customThemeStorageKey);
+ const storedCustomColor = Storage.getItem(customThemeStorageKey);
if (storedCustomColor) {
applyCustomTheme(storedCustomColor);
// Uncheck all radio buttons
@@ -96,7 +98,7 @@ document.addEventListener("DOMContentLoaded", () => {
}
// Check for regular theme
else {
- const storedTheme = localStorage.getItem(themeStorageKey);
+ const storedTheme = Storage.getItem(themeStorageKey);
if (storedTheme) {
applySelectedTheme(storedTheme);
const selectedRadioButton = document.querySelector(`.colorPlate[value="${storedTheme}"]`);
@@ -115,10 +117,10 @@ document.addEventListener("DOMContentLoaded", () => {
}, 25);
});
-// Function to load background color
+// Function to load background color
function ApplyLoadingColor() {
let LoadingScreenColor = getComputedStyle(document.body).getPropertyValue("background-color");
- localStorage.setItem("LoadingScreenColor", LoadingScreenColor);
+ Storage.setItem("LoadingScreenColor", LoadingScreenColor);
}
const resetDarkTheme = () => {
@@ -258,8 +260,8 @@ const applyCustomTheme = (color) => {
const handleThemeChange = function () {
if (this.checked) {
const colorValue = this.value;
- localStorage.setItem(themeStorageKey, colorValue);
- localStorage.removeItem(customThemeStorageKey); // Clear custom theme
+ Storage.setItem(themeStorageKey, colorValue);
+ Storage.removeItem(customThemeStorageKey); // Clear custom theme
applySelectedTheme(colorValue);
}
};
@@ -274,8 +276,8 @@ radioButtons.forEach(radioButton => {
const handleColorPickerChange = function (event) {
const selectedColor = event.target.value;
resetDarkTheme(); // Clear dark theme if active
- localStorage.setItem(customThemeStorageKey, selectedColor); // Save custom color
- localStorage.removeItem(themeStorageKey); // Clear predefined theme
+ Storage.setItem(customThemeStorageKey, selectedColor); // Save custom color
+ Storage.removeItem(themeStorageKey); // Clear predefined theme
applyCustomTheme(selectedColor);
// Uncheck all radio buttons
@@ -306,4 +308,4 @@ const throttle = (func, limit) => {
// Add listeners for color picker
colorPicker.removeEventListener("input", handleColorPickerChange); // Ensure no duplicate listeners
-colorPicker.addEventListener("input", throttle(handleColorPickerChange, 10));
\ No newline at end of file
+colorPicker.addEventListener("input", throttle(handleColorPickerChange, 10));
diff --git a/scripts/todo-list.js b/scripts/todo-list.js
index 8e22aabd..02315397 100644
--- a/scripts/todo-list.js
+++ b/scripts/todo-list.js
@@ -181,13 +181,13 @@ todoulList.addEventListener("click", (event) => {
// Save JSON to local Storage
function SaveToDoData() {
- localStorage.setItem("todoList", JSON.stringify(todoList));
+ Storage.setItem("todoList", JSON.stringify(todoList));
}
// Fetch saved JSON and create list items using it
function ShowToDoList() {
try {
- todoList = JSON.parse(localStorage.getItem("todoList")) || {}; // Parse stored data or initialize empty
+ todoList = JSON.parse(Storage.getItem("todoList")) || {}; // Parse stored data or initialize empty
const fragment = document.createDocumentFragment(); // Create a DocumentFragment
for (let id in todoList) {
@@ -198,21 +198,21 @@ function ShowToDoList() {
todoulList.appendChild(fragment); // Append all `li` to the `ul` at once
} catch (error) {
- console.error("Error loading from localStorage:", error);
- localStorage.setItem("todoList", "{}"); // Reset corrupted data
+ console.error("Error loading from Storage:", error);
+ Storage.setItem("todoList", "{}"); // Reset corrupted data
}
}
// Code to reset the List on the Next Day
-let todoLastUpdateDate = localStorage.getItem("todoLastUpdateDate"); // Get the date of last update
+let todoLastUpdateDate = Storage.getItem("todoLastUpdateDate"); // Get the date of last update
let todoCurrentDate = new Date().toLocaleDateString(); // Get current date
if (todoLastUpdateDate === todoCurrentDate) {
ShowToDoList();
} else {
// Modify the list when last update date and the current date does not match
- localStorage.setItem("todoLastUpdateDate", todoCurrentDate);
- todoList = JSON.parse(localStorage.getItem("todoList")) || {};
+ Storage.setItem("todoLastUpdateDate", todoCurrentDate);
+ todoList = JSON.parse(Storage.getItem("todoList")) || {};
for (let id in todoList) {
if (todoList[id].pinned === false) {
diff --git a/scripts/voice-search.js b/scripts/voice-search.js
index 3e4f09ff..91d53355 100644
--- a/scripts/voice-search.js
+++ b/scripts/voice-search.js
@@ -15,8 +15,8 @@ function isSupportedBrowser() {
const micIcon = document.getElementById("micIcon");
const micIconCheckbox = document.getElementById("micIconCheckbox");
-// Check if there's a saved state in localStorage
-const savedState = localStorage.getItem("micIconVisible");
+// Check if there's a saved state in Storage
+const savedState = Storage.getItem("micIconVisible");
let isMicIconVisible;
// If saved state exists, use it; otherwise, fallback to initial state based on browser support
@@ -26,7 +26,7 @@ if (savedState !== null) {
// Default state: Hide mic icon if browser is not supported
isMicIconVisible = isSupportedBrowser();
// Save the initial state based on the user agent
- localStorage.setItem("micIconVisible", isMicIconVisible);
+ Storage.setItem("micIconVisible", isMicIconVisible);
}
// Set the checkbox state based on the saved or default state
@@ -40,7 +40,7 @@ if (isMicIconVisible) {
// Function to toggle mic icon visibility
function toggleMicIconVisibility(isVisible) {
micIcon.style.display = isVisible ? "block" : "none";
- localStorage.setItem("micIconVisible", isVisible); // Save to localStorage
+ Storage.setItem("micIconVisible", isVisible); // Save to Storage
}
// Toggle mic icon display based on checkbox state
diff --git a/scripts/weather.js b/scripts/weather.js
index b2992f5a..78acbb12 100644
--- a/scripts/weather.js
+++ b/scripts/weather.js
@@ -13,7 +13,7 @@ document.addEventListener("DOMContentLoaded", function () {
const weatherOptions = document.querySelector(".weatherOptions");
// Retrieve saved state
- const isHidden = localStorage.getItem("hideWeatherVisible") === "true";
+ const isHidden = Storage.getItem("hideWeatherVisible") === "true";
hideWeatherCheckbox.checked = isHidden;
function applyWeatherState(hidden) {
@@ -38,7 +38,7 @@ document.addEventListener("DOMContentLoaded", function () {
hideWeatherCheckbox.addEventListener("change", () => {
const hidden = hideWeatherCheckbox.checked;
- localStorage.setItem("hideWeatherVisible", hidden);
+ Storage.setItem("hideWeatherVisible", hidden);
applyWeatherState(hidden);
@@ -63,16 +63,16 @@ async function getWeatherData() {
const locationCont = document.getElementById("locationCont");
const locationSuggestions = document.getElementById("locationSuggestions");
- // Load saved data from localStorage
- const savedApiKey = localStorage.getItem("weatherApiKey");
- const savedLocation = localStorage.getItem("weatherLocation");
+ // Load saved data from Storage
+ const savedApiKey = Storage.getItem("weatherApiKey");
+ const savedLocation = Storage.getItem("weatherLocation");
// Pre-fill input fields with saved data
if (savedLocation) userLocInput.value = savedLocation;
if (savedApiKey) userAPIInput.value = savedApiKey;
const minMaxTempCheckbox = document.getElementById("minMaxTempCheckbox");
- const isMinMaxEnabled = localStorage.getItem("minMaxTempEnabled") === "true";
+ const isMinMaxEnabled = Storage.getItem("minMaxTempEnabled") === "true";
minMaxTempCheckbox.checked = isMinMaxEnabled;
document.getElementById("feelsLike").textContent = isMinMaxEnabled
@@ -90,10 +90,10 @@ async function getWeatherData() {
userAPIInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveAPI"));
userLocInput.addEventListener("keydown", (event) => handleEnterPress(event, "saveLoc"));
- // Save API key to localStorage
+ // Save API key to Storage
saveAPIButton.addEventListener("click", () => {
const apiKey = userAPIInput.value.trim();
- localStorage.setItem("weatherApiKey", apiKey);
+ Storage.setItem("weatherApiKey", apiKey);
userAPIInput.value = "";
location.reload();
});
@@ -108,10 +108,10 @@ async function getWeatherData() {
gpsToggle.checked = false; // Revert toggle if user cancels
return;
}
- localStorage.setItem("useGPS", true);
+ Storage.setItem("useGPS", true);
locationCont.classList.add("inactive");
} else {
- localStorage.setItem("useGPS", false);
+ Storage.setItem("useGPS", false);
locationCont.classList.remove("inactive");
}
location.reload();
@@ -120,8 +120,8 @@ async function getWeatherData() {
// Handle manual location input
saveLocButton.addEventListener("click", () => {
const userLocation = userLocInput.value.trim();
- localStorage.setItem("weatherLocation", userLocation);
- localStorage.setItem("useGPS", false);
+ Storage.setItem("weatherLocation", userLocation);
+ Storage.setItem("useGPS", false);
userLocInput.value = "";
fetchWeather();
location.reload();
@@ -248,7 +248,7 @@ async function getWeatherData() {
userLocInput.value = locationText;
locationSuggestions.style.display = "none";
- localStorage.setItem("weatherLocation", JSON.stringify(selectedLocation));
+ Storage.setItem("weatherLocation", JSON.stringify(selectedLocation));
saveLocButton.click();
suggestions = [];
toggleAutocomplete();
@@ -300,8 +300,8 @@ async function getWeatherData() {
// Determine the location to use
let currentUserLocation = savedLocation;
- // Load the saved GPS state from localStorage
- const useGPS = JSON.parse(localStorage.getItem("useGPS")) || false;
+ // Load the saved GPS state from Storage
+ const useGPS = JSON.parse(Storage.getItem("useGPS")) || false;
gpsToggle.checked = useGPS;
if (useGPS) locationCont.classList.add("inactive");
@@ -356,10 +356,10 @@ async function getWeatherData() {
// Fetch weather data based on a location
async function fetchWeather() {
try {
- let parsedData = JSON.parse(localStorage.getItem("weatherParsedData"));
- const weatherParsedTime = parseInt(localStorage.getItem("weatherParsedTime"));
- const weatherParsedLocation = localStorage.getItem("weatherParsedLocation");
- const weatherParsedLang = localStorage.getItem("weatherParsedLang");
+ let parsedData = JSON.parse(Storage.getItem("weatherParsedData"));
+ const weatherParsedTime = parseInt(Storage.getItem("weatherParsedTime"));
+ const weatherParsedLocation = Storage.getItem("weatherParsedLocation");
+ const weatherParsedLang = Storage.getItem("weatherParsedLang");
const retentionTime = savedApiKey ? 435000 : 960000; // 7.25 min for user-entered API key, 16 min otherwise
@@ -407,11 +407,11 @@ async function getWeatherData() {
}
};
- // Save filtered weather data to localStorage
- localStorage.setItem("weatherParsedData", JSON.stringify(filteredData));
- localStorage.setItem("weatherParsedTime", Date.now()); // Save time of last fetching
- localStorage.setItem("weatherParsedLocation", currentUserLocation); // Save user location
- localStorage.setItem("weatherParsedLang", currentLanguage); // Save language preference
+ // Save filtered weather data to Storage
+ Storage.setItem("weatherParsedData", JSON.stringify(filteredData));
+ Storage.setItem("weatherParsedTime", Date.now()); // Save time of last fetching
+ Storage.setItem("weatherParsedLocation", currentUserLocation); // Save user location
+ Storage.setItem("weatherParsedLang", currentLanguage); // Save language preference
}
}
@@ -538,7 +538,7 @@ async function getWeatherData() {
// Update location
let city = parsedData.location.name;
let maxLength = 10;
- let isLocationHidden = localStorage.getItem("locationHidden") === "true";
+ let isLocationHidden = Storage.getItem("locationHidden") === "true";
const locationTile = document.querySelector(".tiles.location");
const locationIcon = locationTile.querySelector(".location-icon");
@@ -580,7 +580,7 @@ async function getWeatherData() {
locationIcon.addEventListener("click", (e) => {
e.stopPropagation();
isLocationHidden = !isLocationHidden;
- localStorage.setItem("locationHidden", isLocationHidden);
+ Storage.setItem("locationHidden", isLocationHidden);
updateLocationText();
// Update icon immediately
@@ -613,6 +613,6 @@ loadCheckboxState("fahrenheitCheckboxState", fahrenheitCheckbox);
// Handle min-max temp checkbox state change
minMaxTempCheckbox.addEventListener("change", () => {
const isChecked = minMaxTempCheckbox.checked;
- localStorage.setItem("minMaxTempEnabled", isChecked);
+ Storage.setItem("minMaxTempEnabled", isChecked);
location.reload();
});
diff --git a/scripts/widgets-transparency.js b/scripts/widgets-transparency.js
index b7cc8ff1..1f3b33fb 100644
--- a/scripts/widgets-transparency.js
+++ b/scripts/widgets-transparency.js
@@ -18,7 +18,7 @@ function setSliderPosition(percentage) {
slider.style.width = `${posPercent}%`;
opacityLevel.textContent = `${localizeNumbers(Math.round(posPercent).toString(), currentLanguage)}%`;
document.documentElement.style.setProperty("--transparency", `${Math.round(posPercent)}%`);
- localStorage.setItem("bgOpacity", posPercent);
+ Storage.setItem("bgOpacity", posPercent);
}
// Handle drag or click interaction on opacity bar
@@ -55,5 +55,5 @@ function startDrag() {
});
// Initialize with saved opacity value or default to 90%
-const savedOpacity = localStorage.getItem("bgOpacity") || 90;
+const savedOpacity = Storage.getItem("bgOpacity") || 90;
setSliderPosition(Number(savedOpacity));