Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

<!-- SCRIPTS -->
<script src="scripts/preload.js"></script>
<script src="scripts/storage.js"></script>
<script defer src="scripts/languages.js"></script>
<script defer src="scripts/save-load-states.js"></script>
<script defer src="scripts/menu-shortcut-page.js"></script>
Expand Down
1 change: 1 addition & 0 deletions manifest(firefox).json
Original file line number Diff line number Diff line change
Expand Up @@ -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=*",
Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -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=*",
Expand Down
14 changes: 7 additions & 7 deletions scripts/ai-tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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();
Expand Down
72 changes: 61 additions & 11 deletions scripts/backup-restore.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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
Expand All @@ -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();
}
});

6 changes: 3 additions & 3 deletions scripts/bookmarks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
}
Expand All @@ -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();
}
Expand Down
38 changes: 19 additions & 19 deletions scripts/clock.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -496,21 +496,21 @@ 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);
if (digitalCheckbox.checked) {
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();
Expand All @@ -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();
Expand All @@ -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();
});

Expand Down
10 changes: 5 additions & 5 deletions scripts/custom-text.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,23 @@ 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";

// Toggle userText display based on checkbox state
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 {
Expand All @@ -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
Expand Down
Loading
Loading