Conversation
Introduces a new customizable new tab page with clock, greeting, and search bar. Adds settings for enabling/disabling the homepage, choosing between default or custom URL, toggling clock and greeting, and selecting time format. Implements new internal protocols for 'min://newtab' and 'min://blank', updates localization, and refines related CSS and JS for the new tab and settings pages.
Updated the new tab page to use the currently selected search engine instead of a hardcoded DuckDuckGo URL. Added the searchEngine utility script to index.html and modified performSearch to construct the search URL dynamically.
|
That sounds good to me. I'll remove the new tab page and make it so that in the settings, you can choose either the NTP or a custom URL. A better implemetion of the NTP and the search bar interaction is something I will look into. I think the outline you gave will work well. I'll try to work on this sometime soon, but it might be a week or two. |
This reverts commit 08bf957.
Removed legacy homepage and new tab page code, including blank and custom homepage files and settings. Added new settings for new tab page: blank, custom URL, or background image, with UI and logic updates throughout the app. Updated CSS and JS to support new background image and custom URL options, and removed unused homepage-related code and translations.
|
Everything should be done. I moved the Custom URL into the Additional Settings. There is now a dropdown menu which has three options one for Blank, Custom URL, and NTP. I made sure that both the NTP widget and the preferences functionality are in sync. The changes to the new tab design have been made as well. I think the outline you gave worked great. Let me know if there are any changes or tweaks needed—its looking pretty good to me though. 9b59089 |
PalmerAL
left a comment
There was a problem hiding this comment.
This looks pretty good! I left some comments on the code, but I think the functionality is working well.
| @@ -43,14 +43,28 @@ function addTab (tabId = tabs.add(), options = {}) { | |||
| destroyTab(tabs.getSelected()) | |||
There was a problem hiding this comment.
I think there should be a case added to this if statement to destroy the current tab if it equals the NTP URL. Currently, if I close all my tabs, I get a single tab with the NTP; then if I create a new private tab, I get two tabs: one with the NTP, and a second with the private tab. I'd expect that the NTP would close when I create the new tab.
There was a problem hiding this comment.
It seems the desired functionality is already achieved for the New Tab Picture. Are you asking for this behavior to be applied for the custom URL as well?
2026-01-04.20-04-10.mp4
There was a problem hiding this comment.
Thanks for clarifying; I'll get on it!
|
|
||
| // if the tab is a new, blank tab, replace it with the custom new tab page | ||
| let isCustomUrl = false | ||
| if (!tabs.get(tabId).url && !tabs.get(tabId).private) { |
There was a problem hiding this comment.
I think it might be possible for a site to create a popup with no URL (I'm not sure exactly), in which case we shouldn't show the NTP. Perhaps we could solve that by also checking enterEditMode here, and only showing the NTP if it's true.
| // if the tab is a new, blank tab, replace it with the custom new tab page | ||
| let isCustomUrl = false | ||
| if (!tabs.get(tabId).url && !tabs.get(tabId).private) { | ||
| const newTabUrl = settings.get('newTabUrl') |
There was a problem hiding this comment.
Since this setting isn't a URL, could we rename it to something like newTabType?
| (newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl')) | ||
|
|
||
| if (isNTP) { | ||
| searchbar.el.classList.add('searchbar-hidden') |
There was a problem hiding this comment.
I think we could just skip calling searchbar.showResults in this case (perhaps calling searchbar.hide instead if that's necessary), and then we no longer need the hidden class.
| blobInstance: null, | ||
| reloadBackground: function () { | ||
| const newTabUrl = settings.get('newTabUrl') | ||
| if (newTabUrl === 'blank') { |
There was a problem hiding this comment.
If the setting has never been modified, settings.get will return undefined, which this also needs to check for (ie since a blank page is the default value, undefined and "blank" should be treated the same way)
| "settingsNewTabUrlBlank": "Blank Page", | ||
| "settingsNewTabUrlCustomUrl": "Custom URL", | ||
| "settingsNewTabUrlBackgroundImage": "Background Image", | ||
| "settingsNewTabUrlUploadImage": "Upload Image", |
There was a problem hiding this comment.
It would be useful to also add these as the title attributes of the camera and delete buttons on the new tab page.
| sendIPCToWindow(window, 'zoomOut') | ||
| } | ||
| }, | ||
| // Hidden item to enable shortcut on numpad |
There was a problem hiding this comment.
This seems like an accidental change, can you revert it?
Sets the default #ntp-background scale to 1.03 and removes the scale transform from the blurred state, ensuring a more consistent background appearance.
There was a problem hiding this comment.
Pull request overview
This PR introduces a customizable new tab page feature that allows users to choose between a blank page, a custom URL, or a background image for new tabs. The implementation includes new settings UI, background image upload/removal functionality, and visual enhancements with blur effects and searchbar transitions.
- Adds new tab page customization with three modes: blank, custom URL, and background image
- Implements settings interface with dropdown selection and custom URL input field
- Integrates background image picker with automatic file handling and visual blur effects
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| pages/settings/settings.js | Adds event handlers for new tab URL dropdown and custom URL input, including auto-prompt for background image selection |
| pages/settings/index.html | Adds UI elements for new tab page settings with dropdown and text input field |
| main/menu.js | Removes numpad zoom shortcuts (appears unrelated to the PR's main purpose) |
| localization/languages/en-US.json | Adds localization strings for new tab page settings options |
| js/preload/default.js | Adds IPC message handlers for uploading and removing new tab background images |
| js/newTabPage.js | Refactors background handling to support multiple new tab modes and adds image picker/removal functions |
| js/navbar/tabEditor.js | Implements searchbar hiding logic for new tab pages and blur effect when typing |
| js/browserUI.js | Adds logic to set custom URL when creating new tabs and prevents entering edit mode for custom URLs |
| css/searchbar.css | Adds transition and visibility classes for searchbar hiding animation |
| css/newTabPage.css | Adds blur effect and scale transform for background images |
Comments suppressed due to low confidence (1)
main/menu.js:276
- The removal of the numpad zoom shortcuts appears unrelated to the PR's stated purpose of adding a customizable homepage. If this change is intentional, it should be in a separate PR or explained in the description. Otherwise, this may be an accidental deletion.
{
label: l('appMenuActualSize'),
accelerator: 'CmdOrCtrl+0',
click: function (item, window) {
sendIPCToWindow(window, 'zoomReset')
}
},
{
type: 'separator'
},
{
label: l('appMenuFocusMode'),
accelerator: undefined,
type: 'checkbox',
checked: false,
click: function (item, window) {
if (isFocusMode) {
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return | ||
| } | ||
|
|
||
| await fs.promises.copyFile(filePath[0], newTabPage.imagePath) |
There was a problem hiding this comment.
Missing error handling for the file copy operation. If copying the file fails (e.g., due to permissions, disk space, or invalid file path), the error will be unhandled and may cause unexpected behavior. Consider wrapping this in a try-catch block and handling errors appropriately.
| await fs.promises.copyFile(filePath[0], newTabPage.imagePath) | |
| try { | |
| await fs.promises.copyFile(filePath[0], newTabPage.imagePath) | |
| } catch (err) { | |
| console.error('Failed to copy new tab background image:', err) | |
| return | |
| } |
| newTabPage.reloadBackground() | ||
| }, | ||
| removeImage: async function () { | ||
| await fs.promises.unlink(newTabPage.imagePath) |
There was a problem hiding this comment.
Missing error handling for the file unlink operation. If removing the file fails (e.g., file doesn't exist, permissions issue), the error will be unhandled. Consider wrapping this in a try-catch block to handle errors gracefully.
| await fs.promises.unlink(newTabPage.imagePath) | |
| try { | |
| await fs.promises.unlink(newTabPage.imagePath) | |
| } catch (err) { | |
| // Ignore if the file does not exist; log and abort for other errors. | |
| if (err && err.code === 'ENOENT') { | |
| // File is already gone; continue to update settings/UI. | |
| } else { | |
| console.error('Failed to remove new tab background image:', err) | |
| return | |
| } | |
| } |
| (newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl')) | ||
|
|
There was a problem hiding this comment.
The NTP (New Tab Page) detection logic is incomplete. It only checks for 'backgroundImage' and 'customUrl' modes, but doesn't account for the 'blank' mode. When newTabUrl is set to 'blank' and currentURL is empty, this should also be considered an NTP scenario. The current logic may show the searchbar when it should be hidden in blank mode.
| (newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl')) | |
| (newTabUrlMode === 'customUrl' && currentURL === settings.get('newTabCustomUrl')) || | |
| (newTabUrlMode === 'blank' && currentURL === '') |
| type="text" | ||
| id="new-tab-custom-url-input" | ||
| style="margin-left: 0.5em; min-width: 325px" | ||
| hidden |
There was a problem hiding this comment.
The custom URL input field lacks input validation. Users can enter any text, including invalid URLs, which may cause issues when the browser tries to navigate to them. Consider adding validation to ensure the input is a valid URL, or at least provide user feedback when an invalid URL is entered.
| type="text" | |
| id="new-tab-custom-url-input" | |
| style="margin-left: 0.5em; min-width: 325px" | |
| hidden | |
| type="url" | |
| id="new-tab-custom-url-input" | |
| style="margin-left: 0.5em; min-width: 325px" | |
| hidden | |
| placeholder="https://example.com" |
|
|
||
| newTabUrlDropdown.addEventListener('change', function () { | ||
| settings.set('newTabUrl', this.value) | ||
| newTabCustomUrlInput.hidden = true |
There was a problem hiding this comment.
The statement newTabCustomUrlInput.hidden = true is unnecessary here. When the dropdown value changes, the code already handles the visibility of the custom URL input field in the subsequent conditional (lines 271-276). This line sets it to hidden unconditionally, only to potentially set it to false again immediately after, which is redundant.
| newTabCustomUrlInput.hidden = true |


Introduces a new customizable new tab page with clock, greeting, and search bar. Adds settings for enabling/disabling the homepage, choosing between default or custom URL, toggling clock and greeting, and selecting time format. Implements new internal protocols for 'min://newtab' and 'min://blank', updates localization, and refines related CSS and JS for the new tab and settings pages.



