-
Notifications
You must be signed in to change notification settings - Fork 10
add settings support to dark theme #129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dark-theme
Are you sure you want to change the base?
Conversation
Co-authored-by: BanOcean <47253870+banocean@users.noreply.github.com>
banocean
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Branch chyba wymaga updata
nie wymaga |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds comprehensive settings support to the browser extension, enabling users to configure patch behavior through a new settings interface. The most significant change is making the dark theme configurable with auto/enabled/disabled options, replacing the previous media query-only approach.
Key changes:
- Introduces a complete settings infrastructure with storage synchronization, UI components for desktop and mobile, and an API for getting/saving settings
- Converts the dark theme from media query-based to a configurable setting with three modes (auto, enabled, disabled)
- Adds configurable plus/minus grade values to the "Count averages" patch
Reviewed changes
Copilot reviewed 14 out of 18 changed files in this pull request and generated 16 comments.
Show a summary per file
| File | Description |
|---|---|
settingsSaver.js |
Synchronizes settings between Chrome storage and sessionStorage, handles patches.json loading |
patches/apis/settings.js |
Core API for getting and saving patch settings with type conversion and validation |
patches/patchesSettings/settingRenderers.js |
HTML template generators for different setting input types (text, boolean, select, etc.) |
patches/patchesSettings/generateSettingsList.js |
Generates the settings UI with search functionality and event handlers |
patches/patchesSettings/markers.js |
Utility functions for highlighting search terms in the settings UI |
patches/patchesSettings/desktop.js |
Desktop modal implementation for settings interface |
patches/patchesSettings/mobile.js |
Mobile-specific settings interface implementation |
patches/patchesSettings/style.css |
Complete styling for the settings UI components |
patches/darkTheme/index.js |
New JavaScript implementation to apply dark theme based on settings |
patches/darkTheme/main.css |
Changes selector from media query to class-based and adds dark theme styles for settings UI |
patches/darkTheme/evHome.css |
Updates selector from media query to class-based for eduVulcan homepage |
patches/countAverage.js |
Integrates settings API to use configurable plus/minus values |
patches.json |
Adds settings schema definitions for dark theme and count averages patches |
manifest.json |
Includes settingsSaver.js in content scripts |
assets/icons/*.svg |
Adds UI icons for settings, search, close, and clear buttons |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @param {Node} element element, z którego usuwamy znaczniki <mark> | ||
| * @returns {void} | ||
| */ | ||
| export async function removeMarks(element) { |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is declared as async but doesn't contain any await expressions or return a Promise. Remove the async keyword as it's unnecessary and misleading.
| * @param {string} textQueryToHighlight string do wyszukania | ||
| * @returns {void} | ||
| */ | ||
| export async function markTextInElement(element, textQueryToHighlight) { |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is declared as async but doesn't contain any await expressions or return a Promise. Remove the async keyword as it's unnecessary and misleading.
| } | ||
| } | ||
|
|
||
| nodesToModify.forEach(async ({ node, text, query }) => { |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The async keyword is used on the forEach callback, but the function doesn't await anything and async forEach doesn't wait for async operations to complete. Remove the async keyword from the callback as it serves no purpose here.
| fetch(chrome.runtime.getURL("patches.json")) | ||
| .then((response) => response.json()) | ||
| .then((data) => | ||
| data.sort((a, b) => a.name.localeCompare(b.name, "pl")) | ||
| ) | ||
| .then((data) => { | ||
| sessionStorage.setItem("IFV_PATCHES", JSON.stringify(data)); |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a potential race condition: the patches.json fetch is asynchronous, but getSetting can be called before IFV_PATCHES is stored in sessionStorage (line 39). This could cause getSetting to return an empty array for patches, leading to "Patch not found" errors. Consider ensuring patches are loaded before other code runs, or add appropriate error handling.
| fetch(chrome.runtime.getURL("patches.json")) | |
| .then((response) => response.json()) | |
| .then((data) => | |
| data.sort((a, b) => a.name.localeCompare(b.name, "pl")) | |
| ) | |
| .then((data) => { | |
| sessionStorage.setItem("IFV_PATCHES", JSON.stringify(data)); | |
| // Ensure there is always some value for IFV_PATCHES in sessionStorage | |
| if (!sessionStorage.getItem("IFV_PATCHES")) { | |
| sessionStorage.setItem("IFV_PATCHES", JSON.stringify([])); | |
| } | |
| // Expose a shared promise so other code can wait for patches to be loaded | |
| window.ifvPatchesPromise = fetch(chrome.runtime.getURL("patches.json")) | |
| .then((response) => response.json()) | |
| .then((data) => | |
| data.sort((a, b) => a.name.localeCompare(b.name, "pl")) | |
| ) | |
| .then((data) => { | |
| sessionStorage.setItem("IFV_PATCHES", JSON.stringify(data)); | |
| return data; | |
| }) | |
| .catch((error) => { | |
| console.error("Failed to load patches.json", error); | |
| // Fall back to whatever is already in sessionStorage or an empty array | |
| const existing = sessionStorage.getItem("IFV_PATCHES"); | |
| try { | |
| return existing ? JSON.parse(existing) : []; | |
| } catch { | |
| return []; | |
| } |
| function applyDarkTheme() { | ||
| if ( | ||
| (getSetting("Dark theme", "darkThemeEnabled") === "auto" && | ||
| window.matchMedia("(prefers-color-scheme: dark)").matches) || | ||
| getSetting("Dark theme", "darkThemeEnabled") === "enabled" | ||
| ) { | ||
| if (window.location.hostname === "eduvulcan.pl") { | ||
| document.documentElement.classList.add("evHome-dark"); | ||
| } else { | ||
| document.documentElement.classList.add("dark"); | ||
| } | ||
| } |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If getSetting throws an error (e.g., when settings haven't loaded yet or patch isn't found), the entire applyDarkTheme function will fail and no dark theme will be applied. Consider wrapping the getSetting calls in a try-catch block and providing a fallback behavior, such as using the system preference or a default value.
| color: (setting, patchName, currentValue) => ` | ||
| <input type="color" class="setting-color" data-patch="${patchName}" data-setting="${setting.id}" value="${currentValue}"> |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the text input, currentValue is directly interpolated into the value attribute without escaping. This could break the HTML structure if currentValue contains quotes or other special characters. Consider using proper HTML escaping.
| @@ -1,4 +1,4 @@ | |||
| @media (prefers-color-scheme: dark) { | |||
| :root.dark { | |||
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CSS selector changed from @media (prefers-color-scheme: dark) to :root.dark, which means the dark theme will only apply when the .dark class is added to the root element. However, the old media query selector is completely removed, so users who had the automatic dark theme enabled via system preferences will lose that functionality unless they explicitly enable it through the new settings. Consider maintaining backward compatibility or communicating this breaking change clearly.
| * @param {Node} patchesSettingsDiv | ||
| * @returns {void} | ||
| */ | ||
| function addBttmButtons(patchesSettingsDiv, patches) { |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The abbreviation 'Bttm' in the function name is unclear and inconsistent with naming conventions. Consider renaming to addBottomButtons for better clarity and readability.
| .setting-boolean-toggle .toggle-input:checked + .toggle-switch::before { | ||
| transform: translateX(16px); | ||
| } | ||
|
|
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The duplicate rule for .setting-boolean-toggle .toggle-input:checked + .toggle-switch::before (lines 394 and 402) applies the same transform. This is redundant - consider removing one of these duplicate rules.
| .setting-boolean-toggle .toggle-input:checked + .toggle-switch::before { | |
| transform: translateX(16px); | |
| } |
| text: (setting, patchName, currentValue) => ` | ||
| <input type="text" class="setting-text" data-patch="${patchName}" data-setting="${setting.id}" value="${currentValue}" placeholder="${setting.default}"> |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The currentValue is directly interpolated into HTML attributes without escaping. If currentValue contains special HTML characters (like quotes or angle brackets), it could break the HTML structure or potentially lead to XSS vulnerabilities. Consider using proper HTML escaping or creating elements programmatically with textContent/value properties instead of string interpolation.
No description provided.