diff --git a/special-pages/pages/new-tab/app/components/App.module.css b/special-pages/pages/new-tab/app/components/App.module.css
index d80c41919..ed1e36174 100644
--- a/special-pages/pages/new-tab/app/components/App.module.css
+++ b/special-pages/pages/new-tab/app/components/App.module.css
@@ -20,6 +20,9 @@ body {
body:has([data-reset-layout="true"]) .tube {
padding-top: 0;
}
+body[data-animate-background="true"] {
+ transition: background-color .3s;
+}
:global(.layout-centered) {
margin-inline: auto;
diff --git a/special-pages/pages/new-tab/app/components/BackgroundProvider.js b/special-pages/pages/new-tab/app/components/BackgroundProvider.js
index 920dab70b..815590cda 100644
--- a/special-pages/pages/new-tab/app/components/BackgroundProvider.js
+++ b/special-pages/pages/new-tab/app/components/BackgroundProvider.js
@@ -5,6 +5,7 @@ import { values } from '../customizer/values.js';
import { useContext, useState } from 'preact/hooks';
import { CustomizerContext } from '../customizer/CustomizerProvider.js';
import { detectThemeFromHex } from '../customizer/utils.js';
+import { useSignalEffect } from '@preact/signals';
/**
* @import { BackgroundVariant, BrowserTheme } from "../../types/new-tab"
@@ -59,40 +60,56 @@ export function BackgroundConsumer({ browser }) {
const { data } = useContext(CustomizerContext);
const background = data.value.background;
- switch (background.kind) {
- case 'default': {
- return
;
+ useSignalEffect(() => {
+ const background = data.value.background;
+
+ // reflect some values onto the tag
+ document.body.dataset.backgroundKind = background.kind;
+ let nextBodyBackground = '';
+
+ if (background.kind === 'gradient') {
+ const gradient = values.gradients[background.value];
+ nextBodyBackground = gradient.fallback;
+ }
+ if (background.kind === 'color') {
+ const color = values.colors[background.value];
+ nextBodyBackground = color.hex;
+ }
+ if (background.kind === 'hex') {
+ nextBodyBackground = background.value;
}
+ if (background.kind === 'userImage') {
+ const isDark = background.value.colorScheme === 'dark';
+ nextBodyBackground = isDark ? 'var(--default-dark-bg)' : 'var(--default-light-bg)';
+ }
+ if (background.kind === 'default') {
+ nextBodyBackground = browser.value === 'dark' ? 'var(--default-dark-bg)' : 'var(--default-light-bg)';
+ }
+
+ document.body.style.setProperty('background-color', nextBodyBackground);
+
+ // let animations occur, after properties above have been flushed to the DOM
+ if (!document.body.dataset.animateBackground) {
+ requestAnimationFrame(() => {
+ document.body.dataset.animateBackground = 'true';
+ });
+ }
+ });
+
+ switch (background.kind) {
+ case 'color':
+ case 'default':
case 'hex': {
- return (
-
- );
+ return null;
}
- case 'color': {
- const color = values.colors[background.value];
- return (
-
- );
+ case 'userImage': {
+ const img = background.value;
+ return ;
}
case 'gradient': {
const gradient = values.gradients[background.value];
return (
-
+
+ />
);
}
- case 'userImage': {
- const img = background.value;
- return ;
- }
default: {
console.warn('Unreachable!');
- return ;
+ return null;
}
}
}
diff --git a/special-pages/pages/new-tab/app/components/BackgroundReceiver.module.css b/special-pages/pages/new-tab/app/components/BackgroundReceiver.module.css
index 9060ff8b1..2cdfd6918 100644
--- a/special-pages/pages/new-tab/app/components/BackgroundReceiver.module.css
+++ b/special-pages/pages/new-tab/app/components/BackgroundReceiver.module.css
@@ -8,13 +8,7 @@
pointer-events: none;
&[data-animate="true"] {
- transition: background .25s ease-in-out;
- }
- &[data-background-kind="default"][data-theme=dark] {
- background: var(--default-dark-bg);
- }
- &[data-background-kind="default"][data-theme=light] {
- background: var(--default-light-bg);
+ transition: background .3s;
}
}
diff --git a/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.page.js b/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.page.js
index fe06a64fc..7e2200ef1 100644
--- a/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.page.js
+++ b/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.page.js
@@ -129,21 +129,20 @@ export class CustomizerPage {
async hasDefaultBackground() {
const { page } = this.ntp;
- await expect(page.getByTestId('BackgroundConsumer')).toHaveCSS('background-color', 'rgb(250, 250, 250)');
+ await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(250, 250, 250)');
}
async hasDefaultDarkBackground() {
const { page } = this.ntp;
- await expect(page.getByTestId('BackgroundConsumer')).toHaveCSS('background-color', 'rgb(51, 51, 51)');
+ await expect(page.locator('body')).toHaveCSS('background-color', 'rgb(51, 51, 51)');
}
/**
- * @param {keyof typeof values.colors} color
+ * @param {string} expectedRGB
*/
- async hasColorBackground(color) {
+ async hasColorBackground(expectedRGB) {
const { page } = this.ntp;
- const value = values.colors[color];
- await expect(page.getByTestId('BackgroundConsumer')).toHaveAttribute('data-background-color', value.hex);
+ await expect(page.locator('body')).toHaveCSS('background-color', expectedRGB);
}
async selectsColor() {
diff --git a/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.spec.js b/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.spec.js
index bc55a1c22..df14f2891 100644
--- a/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.spec.js
+++ b/special-pages/pages/new-tab/app/customizer/integration-tests/customizer.spec.js
@@ -80,7 +80,7 @@ test.describe('newtab customizer', () => {
kind: 'color',
value: 'color01',
});
- await cp.hasColorBackground('color01');
+ await cp.hasColorBackground('rgb(0, 0, 0)');
});
test('loads with the default background and accepts theme update', async ({ page }, workerInfo) => {
const ntp = NewtabPage.create(page, workerInfo);
diff --git a/special-pages/pages/new-tab/app/favorites/components/Tile.module.css b/special-pages/pages/new-tab/app/favorites/components/Tile.module.css
index b830d7e92..42a8bd955 100644
--- a/special-pages/pages/new-tab/app/favorites/components/Tile.module.css
+++ b/special-pages/pages/new-tab/app/favorites/components/Tile.module.css
@@ -1,4 +1,6 @@
.item {
+ --icon-width: 4rem;
+
display: block;
position: relative;
text-decoration: none;
@@ -29,8 +31,8 @@
display: grid;
align-content: center;
justify-items: center;
- width: 4rem;
- height: 4rem;
+ width: var(--icon-width);
+ height: var(--icon-width);
margin-bottom: 4px;
border-radius: var(--border-radius-lg);
}
@@ -89,6 +91,7 @@
}
.text {
+ width: var(--icon-width);
text-align: center;
font-size: calc(10 * var(--px-in-rem));
line-height: 1.1;