diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/contentScopeIsolated.js b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/contentScopeIsolated.js index 5ecd57fe8ff..7a78ecf0e1b 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/contentScopeIsolated.js +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/contentScopeIsolated.js @@ -12314,7 +12314,7 @@ ul.messages { } }); } - async function getExpandedPerformanceMetrics() { + async function getExpandedPerformanceMetrics(timeoutMs = 500) { try { if (document.readyState !== "complete") { return returnError("Document not ready"); @@ -12331,7 +12331,7 @@ ul.messages { const fcp = paint.find((p) => p.name === "first-contentful-paint"); let largestContentfulPaint = null; if (PerformanceObserver.supportedEntryTypes.includes("largest-contentful-paint")) { - largestContentfulPaint = await waitForLCP(); + largestContentfulPaint = await waitForLCP(timeoutMs); } const totalResourceSize = resources.reduce((sum, r) => sum + (r.transferSize || 0), 0); if (navigation) { @@ -12552,7 +12552,8 @@ ul.messages { } } async triggerExpandedPerformanceMetrics() { - const expandedPerformanceMetrics = await getExpandedPerformanceMetrics(); + const permissableDelayMs = this.getFeatureSetting("expandedTimeoutMs") ?? 5e3; + const expandedPerformanceMetrics = await getExpandedPerformanceMetrics(permissableDelayMs); this.messaging.notify("expandedPerformanceMetricsResult", expandedPerformanceMetrics); } }; diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/index.html b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/index.html index 0f6befc66c7..0f7e5e5d977 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/index.html +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/index.html @@ -74,9 +74,32 @@ color: rgb(210, 210, 210); } } + +/* TODO: Use colour variables from design-tokens */ + +/* Theme variants - light mode */ +[data-theme-variant="coolGray"] { background: #d2d5e3; } +[data-theme-variant="slateBlue"] { background: #d2e5f3; } +[data-theme-variant="green"] { background: #e3eee1; } +[data-theme-variant="violet"] { background: #e7e4f5; } +[data-theme-variant="rose"] { background: #f8ebf5; } +[data-theme-variant="orange"] { background: #fcedd8; } +[data-theme-variant="desert"] { background: #eee9e1; } + +/* Theme variants - dark mode */ +@media (prefers-color-scheme: dark) { + [data-theme-variant="coolGray"] { background: #2b2f45; } + [data-theme-variant="slateBlue"] { background: #1e3347; } + [data-theme-variant="green"] { background: #203b30; } + [data-theme-variant="violet"] { background: #2e2158; } + [data-theme-variant="rose"] { background: #5b194b; } + [data-theme-variant="orange"] { background: #54240c; } + [data-theme-variant="desert"] { background: #3c3833; } +} + - +
@@ -90,5 +113,16 @@

$HEADER$

DuckDuckGo
+ diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/style.css b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/style.css index 87d0488c935..c8449bd9f13 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/style.css +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/errorpage/style.css @@ -65,4 +65,26 @@ body { .error-description, .error-header { color: rgb(210, 210, 210); } -} \ No newline at end of file +} + +/* TODO: Use colour variables from design-tokens */ + +/* Theme variants - light mode */ +[data-theme-variant="coolGray"] { background: #d2d5e3; } +[data-theme-variant="slateBlue"] { background: #d2e5f3; } +[data-theme-variant="green"] { background: #e3eee1; } +[data-theme-variant="violet"] { background: #e7e4f5; } +[data-theme-variant="rose"] { background: #f8ebf5; } +[data-theme-variant="orange"] { background: #fcedd8; } +[data-theme-variant="desert"] { background: #eee9e1; } + +/* Theme variants - dark mode */ +@media (prefers-color-scheme: dark) { + [data-theme-variant="coolGray"] { background: #2b2f45; } + [data-theme-variant="slateBlue"] { background: #1e3347; } + [data-theme-variant="green"] { background: #203b30; } + [data-theme-variant="violet"] { background: #2e2158; } + [data-theme-variant="rose"] { background: #5b194b; } + [data-theme-variant="orange"] { background: #54240c; } + [data-theme-variant="desert"] { background: #3c3833; } +} diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/history/index.html b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/history/index.html index c17fd166bf2..1456b50bbbf 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/history/index.html +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/history/index.html @@ -11,6 +11,15 @@ } } + History diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.css b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.css index b4bb0ba883c..0824e2b068f 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.css +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.css @@ -1995,7 +1995,7 @@ body:not([data-background-kind=default]) .TabSwitcher_tabSwitcher { --background: rgba(255, 255, 255, 0.09); } .Protections_block { - margin-top: 32px; + margin-top: 16px; } .Protections_blockLegacy { margin-top: 24px; @@ -2090,6 +2090,7 @@ body:not([data-background-kind=default]) .TabSwitcher_tabSwitcher { height: 16px; display: inline-block; vertical-align: middle; + margin-top: 2px; } .PrivacyStats_widgetExpander { position: relative; @@ -2229,6 +2230,24 @@ body:not([data-background-kind=default]) .TabSwitcher_tabSwitcher { background: var(--color-white-at-9); } +/* pages/new-tab/app/components/NewBadge.module.css */ +.NewBadge_badge { + display: inline-flex; + align-items: center; + justify-content: center; + width: fit-content; + height: 16px; + padding: 0 8px; + background-color: #F9BE1A; + border-radius: 4px; + font-family: var(--theme-font-family, system-ui); + font-weight: 700; + font-size: 11px; + color: var(--color-black-at-96); + letter-spacing: -0.015em; + flex-shrink: 0; +} + /* pages/new-tab/app/components/Tooltip/Tooltip.module.css */ .Tooltip_tooltipContainer { position: relative; @@ -2956,9 +2975,9 @@ body:not([data-background-kind=default]) .TabSwitcher_tabSwitcher { .TickPill_tickPill { display: flex; align-items: center; - gap: 6px; - padding: 8px 10px; - border-radius: 100px; + gap: 4px; + padding: 8px 8px; + border-radius: 1000px; background-color: var(--color-white-at-3); border: 1px solid var(--color-white-at-12); height: 20px; @@ -2982,8 +3001,8 @@ body:not([data-background-kind=default]) .TabSwitcher_tabSwitcher { white-space: nowrap; } [data-theme=light] .TickPill_tickPill { - background-color: var(--color-black-at-4); - border: 1px solid var(--color-black-at-12); + background-color: var(--color-black-at-1); + border: 1px solid var(--color-black-at-9); } [data-theme=light] .TickPill_text { color: var(--color-black-at-84); diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.js b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.js index b7d78c5ada3..3a0cdcf9e91 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.js +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/dist/index.js @@ -1858,36 +1858,6 @@ } )); } - function NewBadgeIcon(props) { - return /* @__PURE__ */ _("svg", { xmlns: "http://www.w3.org/2000/svg", width: "42", height: "16", viewBox: "0 0 42 16", fill: "none", ...props }, /* @__PURE__ */ _( - "path", - { - d: "M0 3.99792C0 1.78879 1.79086 -0.0020752 4 -0.0020752H38C40.2091 -0.0020752 42 1.78879 42 3.99792V11.9979C42 14.2071 40.2091 15.9979 38 15.9979H4C1.79086 15.9979 0 14.2071 0 11.9979V3.99792Z", - fill: "#F9BE1A" - } - ), /* @__PURE__ */ _( - "path", - { - d: "M13.0913 9.1073H13.1812V3.94617H14.8032V12.0497H13.3999L9.64893 6.86707H9.55908V12.0497H7.93604V3.94617H9.35107L13.0913 9.1073Z", - fill: "black", - "fill-opacity": "0.96" - } - ), /* @__PURE__ */ _( - "path", - { - d: "M22.144 5.3446H18.4722V7.29871H21.936V8.60144H18.4722V10.6512H22.144V12.0497H16.7759V3.94617H22.144V5.3446Z", - fill: "black", - "fill-opacity": "0.96" - } - ), /* @__PURE__ */ _( - "path", - { - d: "M26.4663 9.73621H26.5562L28.0337 3.94617H29.4653L30.9702 9.73621H31.0601L32.312 3.94617H34.064L31.9136 12.0497H30.3247L28.7915 6.59167H28.7017L27.1851 12.0497H25.5854L23.4399 3.94617H25.2036L26.4663 9.73621Z", - fill: "black", - "fill-opacity": "0.96" - } - )); - } function InfoIcon(props) { return /* @__PURE__ */ _("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", class: "info-icon", ...props }, /* @__PURE__ */ _( "path", @@ -9753,6 +9723,28 @@ } }); + // pages/new-tab/app/components/NewBadge.module.css + var NewBadge_default; + var init_NewBadge = __esm({ + "pages/new-tab/app/components/NewBadge.module.css"() { + NewBadge_default = { + badge: "NewBadge_badge" + }; + } + }); + + // pages/new-tab/app/components/NewBadge.js + function NewBadge({ text: text2, ...rest }) { + return /* @__PURE__ */ _("span", { class: NewBadge_default.badge, ...rest }, text2?.toUpperCase() || "NEW"); + } + var init_NewBadge2 = __esm({ + "pages/new-tab/app/components/NewBadge.js"() { + "use strict"; + init_preact_module(); + init_NewBadge(); + } + }); + // pages/new-tab/app/components/Tooltip/Tooltip.module.css var Tooltip_default; var init_Tooltip = __esm({ @@ -9874,7 +9866,14 @@ function update(currentTime) { const elapsed = currentTime - startTime; const progress = Math.min(elapsed * inverseDuration, 1); - const eased = progress < 0.5 ? 4 * progress * progress * progress : 1 - Math.pow(-2 * progress + 2, 3) / 2; + let eased; + if (progress < 0.5) { + const p22 = progress * progress; + eased = 4 * p22 * progress; + } else { + const t4 = -2 * progress + 2; + eased = 1 - t4 * t4 * t4 / 2; + } const currentValue = Math.floor(startValue + animationRange * eased); onUpdate(currentValue); if (progress < 1) { @@ -9907,12 +9906,24 @@ }); // pages/new-tab/app/protections/utils/useAnimatedCount.js - function useAnimatedCount(targetValue) { + function useAnimatedCount(targetValue, elementRef) { const [animatedValue, setAnimatedValue] = d2(0); const animatedValueRef = A2( /** @type {number} */ 0 ); + const [isInViewport, setIsInViewport] = d2(false); + const hasAnimatedRef = A2(false); + const lastSeenValueRef = A2( + /** @type {number | null} */ + null + ); + const wasInViewportRef = A2(false); + const observerSetupRef = A2(false); + const observerRef = A2( + /** @type {IntersectionObserver | null} */ + null + ); const updateAnimatedCount = q2( /** @type {import('./animateCount.js').AnimationUpdateCallback} */ ((value2) => { @@ -9921,23 +9932,91 @@ }), [] ); + const setupIntersectionObserver = q2((element) => { + if (observerSetupRef.current || observerRef.current) { + return; + } + observerSetupRef.current = true; + observerRef.current = new IntersectionObserver( + (entries4) => { + entries4.forEach((entry) => { + const wasInViewport = wasInViewportRef.current; + const isNowInViewport = entry.isIntersecting; + if (wasInViewport && !isNowInViewport) { + lastSeenValueRef.current = animatedValueRef.current; + } + wasInViewportRef.current = isNowInViewport; + setIsInViewport(isNowInViewport); + }); + }, + { + // Trigger when any part of the element is visible + threshold: 0, + // Optional: add some margin to trigger slightly before visible + rootMargin: "0px" + } + ); + observerRef.current.observe(element); + }, []); + y2(() => { + if (!elementRef) { + setIsInViewport(true); + return; + } + const element = elementRef.current; + let cancelled = false; + if (element) { + setupIntersectionObserver(element); + } else { + (async () => { + await Promise.resolve(); + if (cancelled) { + return; + } + const delayedElement = elementRef.current; + if (delayedElement) { + setupIntersectionObserver(delayedElement); + } + })(); + } + return () => { + cancelled = true; + observerSetupRef.current = false; + if (observerRef.current) { + observerRef.current.disconnect(); + observerRef.current = null; + } + }; + }, []); y2(() => { let cancelAnimation = () => { }; - if (document.visibilityState === "visible") { - cancelAnimation = animateCount(targetValue, updateAnimatedCount, void 0, animatedValueRef.current); - } else { + const shouldAnimate = document.visibilityState === "visible" && isInViewport; + if (shouldAnimate) { + let startValue = animatedValueRef.current; + if (lastSeenValueRef.current !== null && lastSeenValueRef.current !== targetValue) { + startValue = lastSeenValueRef.current; + lastSeenValueRef.current = null; + } + cancelAnimation = animateCount(targetValue, updateAnimatedCount, void 0, startValue); + hasAnimatedRef.current = true; + } else if (hasAnimatedRef.current) { setAnimatedValue(targetValue); animatedValueRef.current = targetValue; + lastSeenValueRef.current = null; } const handleVisibilityChange = () => { - if (document.visibilityState === "visible") { + if (document.visibilityState === "visible" && isInViewport) { cancelAnimation(); cancelAnimation = animateCount(targetValue, updateAnimatedCount, void 0, animatedValueRef.current); - } else { + hasAnimatedRef.current = true; + } else if (document.visibilityState === "hidden") { cancelAnimation(); - setAnimatedValue(targetValue); - animatedValueRef.current = targetValue; + if (hasAnimatedRef.current) { + setAnimatedValue(targetValue); + animatedValueRef.current = targetValue; + lastSeenValueRef.current = null; + } } }; document.addEventListener("visibilitychange", handleVisibilityChange); @@ -9945,7 +10024,7 @@ cancelAnimation(); document.removeEventListener("visibilitychange", handleVisibilityChange); }; - }, [targetValue, updateAnimatedCount]); + }, [targetValue, updateAnimatedCount, isInViewport]); return animatedValue; } var init_useAnimatedCount = __esm({ @@ -9969,15 +10048,29 @@ /** @type {Strings} */ {} ); + const ntp = useMessaging(); + const headingRef = A2( + /** @type {HTMLDivElement|null} */ + null + ); + const counterContainerRef = A2( + /** @type {HTMLDivElement|null} */ + null + ); const totalTrackersBlocked = blockedCountSignal.value; const totalCookiePopUpsBlockedValue = totalCookiePopUpsBlockedSignal.value; const totalCookiePopUpsBlocked = typeof totalCookiePopUpsBlockedValue === "number" && Number.isFinite(totalCookiePopUpsBlockedValue) ? Math.max(0, Math.floor(totalCookiePopUpsBlockedValue)) : 0; - const animatedTrackersBlocked = useAnimatedCount(totalTrackersBlocked); - const animatedCookiePopUpsBlocked = useAnimatedCount(totalCookiePopUpsBlocked); + const animatedTrackersBlocked = useAnimatedCount(totalTrackersBlocked, counterContainerRef); + const animatedCookiePopUpsBlocked = useAnimatedCount(totalCookiePopUpsBlocked, counterContainerRef); + y2(() => { + return ntp.messaging.subscribe("protections_scroll", () => { + headingRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); + }); + }, [ntp]); const isCpmEnabled = totalCookiePopUpsBlockedValue !== void 0 && totalCookiePopUpsBlockedValue !== null; const trackersBlockedHeading = animatedTrackersBlocked === 1 ? t4("stats_countBlockedSingular") : t4("stats_countBlockedPlural"); const cookiePopUpsBlockedHeading = animatedCookiePopUpsBlocked === 1 ? t4("stats_totalCookiePopUpsBlockedSingular") : t4("stats_totalCookiePopUpsBlockedPlural"); - return /* @__PURE__ */ _("div", { class: PrivacyStats_default.heading, "data-testid": "ProtectionsHeading" }, /* @__PURE__ */ _("div", { class: (0, import_classnames9.default)(PrivacyStats_default.control, animatedTrackersBlocked === 0 && PrivacyStats_default.noTrackers) }, /* @__PURE__ */ _("span", { class: PrivacyStats_default.headingIcon }, /* @__PURE__ */ _("img", { src: "./icons/Shield-Check-Color-16.svg", alt: "Privacy Shield" })), /* @__PURE__ */ _("h2", { class: PrivacyStats_default.caption }, t4("protections_menuTitle")), /* @__PURE__ */ _(Tooltip, { content: t4("stats_protectionsReportInfo") }, /* @__PURE__ */ _(InfoIcon, { class: PrivacyStats_default.infoIcon })), canExpand && /* @__PURE__ */ _("span", { class: PrivacyStats_default.widgetExpander }, /* @__PURE__ */ _( + return /* @__PURE__ */ _("div", { class: PrivacyStats_default.heading, "data-testid": "ProtectionsHeading", ref: headingRef }, /* @__PURE__ */ _("div", { class: (0, import_classnames9.default)(PrivacyStats_default.control, animatedTrackersBlocked === 0 && PrivacyStats_default.noTrackers) }, /* @__PURE__ */ _("span", { class: PrivacyStats_default.headingIcon }, /* @__PURE__ */ _("img", { src: "./icons/Shield-Check-Color-16.svg", alt: "Privacy Shield" })), /* @__PURE__ */ _("h2", { class: PrivacyStats_default.caption }, t4("protections_menuTitle")), /* @__PURE__ */ _(Tooltip, { content: t4("stats_protectionsReportInfo") }, /* @__PURE__ */ _(InfoIcon, { class: PrivacyStats_default.infoIcon })), canExpand && /* @__PURE__ */ _("span", { class: PrivacyStats_default.widgetExpander }, /* @__PURE__ */ _( ShowHideButtonCircle, { buttonAttrs: { @@ -9988,7 +10081,7 @@ onClick: onToggle, label: expansion === "expanded" ? t4("stats_hideLabel") : t4("stats_toggleLabel") } - ))), /* @__PURE__ */ _("div", { class: PrivacyStats_default.counterContainer }, /* @__PURE__ */ _("div", { class: PrivacyStats_default.counter }, animatedTrackersBlocked === 0 && /* @__PURE__ */ _("h3", { class: PrivacyStats_default.noRecentTitle }, t4("protections_noRecent")), animatedTrackersBlocked > 0 && /* @__PURE__ */ _("h3", { class: PrivacyStats_default.title }, animatedTrackersBlocked, " ", /* @__PURE__ */ _("span", null, trackersBlockedHeading))), isCpmEnabled && animatedTrackersBlocked > 0 && totalCookiePopUpsBlocked > 0 && /* @__PURE__ */ _("div", { class: PrivacyStats_default.counter }, /* @__PURE__ */ _("h3", { class: PrivacyStats_default.title }, animatedCookiePopUpsBlocked, " ", /* @__PURE__ */ _("span", null, cookiePopUpsBlockedHeading)), /* @__PURE__ */ _(NewBadgeIcon, null)))); + ))), /* @__PURE__ */ _("div", { class: PrivacyStats_default.counterContainer, ref: counterContainerRef }, /* @__PURE__ */ _("div", { class: PrivacyStats_default.counter }, animatedTrackersBlocked === 0 && /* @__PURE__ */ _("h3", { class: PrivacyStats_default.noRecentTitle }, t4("protections_noRecent")), animatedTrackersBlocked > 0 && /* @__PURE__ */ _("h3", { class: PrivacyStats_default.title }, animatedTrackersBlocked, " ", /* @__PURE__ */ _("span", null, trackersBlockedHeading))), isCpmEnabled && animatedTrackersBlocked > 0 && totalCookiePopUpsBlocked > 0 && /* @__PURE__ */ _("div", { class: PrivacyStats_default.counter }, /* @__PURE__ */ _("h3", { class: PrivacyStats_default.title }, animatedCookiePopUpsBlocked, " ", /* @__PURE__ */ _("span", null, cookiePopUpsBlockedHeading)), /* @__PURE__ */ _(NewBadge, { text: t4("protections_newBadge") })))); } var import_classnames9; var init_ProtectionsHeading = __esm({ @@ -10000,8 +10093,10 @@ import_classnames9 = __toESM(require_classnames(), 1); init_preact_module(); init_Icons2(); + init_NewBadge2(); init_Tooltip2(); init_useAnimatedCount(); + init_hooks_module(); } }); @@ -30464,6 +30559,10 @@ title: "No recent tracking activity", note: "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + protections_newBadge: { + title: "NEW", + note: "Text displayed in a badge to indicate a new feature or statistic." + }, stats_menuTitle: { title: "Blocked Tracking Attempts", note: "Used as a label in a customization menu" @@ -30521,7 +30620,7 @@ note: "The heading indicating multiple cookie pop-ups were handled by the CPM" }, stats_protectionsReportInfo: { - title: "Displays tracking attempts blocked in the last 7 days, and the number of cookie pop-ups blocked since you started using the browser. You can reset these stats using the Fire Button.", + title: "Displays tracking attempts blocked in the last 7 days, and the number of cookie pop-ups blocked since you started using the browser.", note: "Text explaining how to reset the protections stats" }, stats_feedCountBlockedSingular: { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/de/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/de/new-tab.json index d0591f92f54..d5b8c307166 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/de/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/de/new-tab.json @@ -60,6 +60,10 @@ "title" : "Keine aktuellen Tracking-Aktivitäten", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Neu", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Blockierte Tracking-Versuche", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Zeigt die in den letzten 7 Tagen blockierten Tracking-Versuche sowie die Anzahl der seit deiner ersten Nutzung des Browsers blockierten Cookie-Pop-ups an. Du kannst diese Werte mit dem Fire Button zurücksetzen.", + "title" : "Zeigt die in den letzten 7 Tagen blockierten Tracking-Versuche sowie die Anzahl der seit deiner ersten Nutzung des Browsers blockierten Cookie-Pop-ups an.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/en/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/en/new-tab.json index 04f3159954a..42f0b89deba 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/en/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/en/new-tab.json @@ -61,6 +61,10 @@ "title": "No recent tracking activity", "note": "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge": { + "title": "NEW", + "note": "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle": { "title": "Blocked Tracking Attempts", "note": "Used as a label in a customization menu" @@ -118,7 +122,7 @@ "note": "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo": { - "title": "Displays tracking attempts blocked in the last 7 days, and the number of cookie pop-ups blocked since you started using the browser. You can reset these stats using the Fire Button.", + "title": "Displays tracking attempts blocked in the last 7 days, and the number of cookie pop-ups blocked since you started using the browser.", "note": "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular": { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/es/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/es/new-tab.json index 37df1903601..57999d24a9c 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/es/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/es/new-tab.json @@ -60,6 +60,10 @@ "title" : "No hay actividad de rastreo reciente", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Nuevo", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Intentos de rastreo bloqueados", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Muestra los intentos de rastreo bloqueados en los últimos 7 días y el número de ventanas emergentes de cookies bloqueadas desde que empezaste a usar el navegador. Puedes restablecer estas estadísticas usando el Fire Button.", + "title" : "Muestra los intentos de rastreo bloqueados en los últimos 7 días y el número de ventanas emergentes de cookies bloqueadas desde que empezaste a usar el navegador.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/fr/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/fr/new-tab.json index bc62c3bc31d..bc3c4783b19 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/fr/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/fr/new-tab.json @@ -60,6 +60,10 @@ "title" : "Aucune activité de pistage récente", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Nouveau", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Tentatives de pistage bloquées", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Affiche les tentatives de pistage bloquées au cours des 7 derniers jours et le nombre de fenêtres contextuelles de cookies bloquées depuis que vous avez commencé à utiliser le navigateur. Vous pouvez réinitialiser ces statistiques en utilisant le Fire Button.", + "title" : "Affiche les tentatives de pistage bloquées au cours des 7 derniers jours et le nombre de fenêtres contextuelles de cookies bloquées depuis que vous avez commencé à utiliser le navigateur.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/it/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/it/new-tab.json index bbd47ea3c96..02fb1c67612 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/it/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/it/new-tab.json @@ -60,6 +60,10 @@ "title" : "Nessuna attività di tracciamento recente", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Nuova", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Tentativi di tracciamento bloccati", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Mostra i tentativi di tracciamento bloccati negli ultimi 7 giorni e il numero di pop-up di cookie bloccati da quando hai iniziato a usare il browser. Puoi reimpostare queste statistiche usando il Fire Button.", + "title" : "Mostra i tentativi di tracciamento bloccati negli ultimi 7 giorni e il numero di pop-up di cookie bloccati da quando hai iniziato a usare il browser.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/nl/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/nl/new-tab.json index f778ab5cae9..60bc1a91ddf 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/nl/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/nl/new-tab.json @@ -60,6 +60,10 @@ "title" : "Geen recente trackingactiviteit", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Nieuw", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Geblokkeerde trackingpogingen", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Toont trackingpogingen die in de afgelopen 7 dagen zijn geblokkeerd en het aantal cookiepop-ups dat is geblokkeerd sinds je de browser bent gaan gebruiken. Je kunt deze statistieken resetten met de Fire Button.", + "title" : "Toont trackingpogingen die in de afgelopen 7 dagen zijn geblokkeerd en het aantal cookiepop-ups dat is geblokkeerd sinds je de browser bent gaan gebruiken.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pl/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pl/new-tab.json index 124b6223718..eeb5895ab9c 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pl/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pl/new-tab.json @@ -60,6 +60,10 @@ "title" : "Brak ostatniej aktywności w zakresie śledzenia", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Nowa", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Zablokowane próby śledzenia", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Wyświetla próby śledzenia zablokowane w ciągu ostatnich 7 dni oraz liczbę wyskakujących okienek z informacją o plikach cookie zablokowanych od czasu rozpoczęcia korzystania z przeglądarki. Możesz zresetować te statystyki za pomocą przycisku Fire Button.", + "title" : "Wyświetla próby śledzenia zablokowane w ciągu ostatnich 7 dni oraz liczbę wyskakujących okienek z informacją o plikach cookie zablokowanych od czasu rozpoczęcia korzystania z przeglądarki.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pt/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pt/new-tab.json index f04f37555ea..4c2d782deda 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pt/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/pt/new-tab.json @@ -60,6 +60,10 @@ "title" : "Nenhuma atividade de rastreamento recente", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Novo", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Tentativas de rastreamento bloqueadas", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Mostra as tentativas de rastreamento bloqueadas nos últimos 7 dias e o número de pop-ups de cookies bloqueados desde que começaste a usar o navegador. Podes repor estas estatísticas usando o Fire Button.", + "title" : "Mostra as tentativas de rastreamento bloqueadas nos últimos 7 dias e o número de pop-ups de cookies bloqueados desde que começaste a usar o navegador.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/ru/new-tab.json b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/ru/new-tab.json index 71bf69b6120..bef8eda1e2c 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/ru/new-tab.json +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/new-tab/locales/ru/new-tab.json @@ -60,6 +60,10 @@ "title" : "Нет недавних отслеживаний", "note" : "Placeholder text shown in the Details view when no tracking activity was blocked in the last 7 days. Keep concise if possible." }, + "protections_newBadge" : { + "title" : "Новинка", + "note" : "Text displayed in a badge to indicate a new feature or statistic." + }, "stats_menuTitle" : { "title" : "Заблокированные попытки отслеживания", "note" : "Used as a label in a customization menu" @@ -117,7 +121,7 @@ "note" : "The heading indicating multiple cookie pop-ups were handled by the CPM" }, "stats_protectionsReportInfo" : { - "title" : "Отображает попытки отслеживания, заблокированные за последние 7 дней, а также количество всплывающих окон куки, заблокированных с начала использования браузера. Эту статистику можно сбросить с помощью кнопки Fire Button.", + "title" : "Отображает попытки отслеживания, заблокированные за последние 7 дней, а также количество всплывающих окон куки, заблокированных с начала использования браузера.", "note" : "Text explaining how to reset the protections stats" }, "stats_feedCountBlockedSingular" : { diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.css b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.css index 472b2b508c0..49ba13fb4a8 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.css +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.css @@ -966,7 +966,11 @@ li { /* pages/special-error/app/styles/variables.css */ :root { - --theme-background-color: var(--color-gray-20); + --default-light-background-color: var(--color-gray-20); + --default-dark-background-color: var(--color-gray-85); +} +body[data-theme=light] { + --theme-background-color: var(--default-light-background-color); --theme-text-primary-color: var(--color-black-at-84); --link-color: var(--color-black); --border-color: rgba(0, 0, 0, 0.1); @@ -974,17 +978,43 @@ li { --advanced-info-bg: var(--color-black-at-3); --visit-site-color: var(--color-black); } -@media (prefers-color-scheme: dark) { - :root { - --theme-background-color: var(--color-gray-85); - --theme-text-primary-color: var(--color-white-at-84); - --link-color: var(--color-gray-40); - --border-color: var(--color-white-at-18); - --container-bg: var(--color-gray-90); - --advanced-info-bg: #2f2f2f; - --visit-site-color: var(--color-gray-40); - } - [data-platform-name=ios] { - --theme-background-color: #222; - } +body[data-theme=dark] { + --theme-background-color: var(--default-dark-background-color); + --theme-text-primary-color: var(--color-white-at-84); + --link-color: var(--color-gray-40); + --border-color: var(--color-white-at-18); + --container-bg: var(--color-gray-90); + --advanced-info-bg: #2f2f2f; + --visit-site-color: var(--color-gray-40); +} +body[data-theme=dark][data-platform-name=ios][data-theme-variant=default] { + --theme-background-color: #222; +} +body[data-theme-variant=coolGray] { + --default-light-background-color: #d2d5e3; + --default-dark-background-color: #2b2f45; +} +body[data-theme-variant=slateBlue] { + --default-light-background-color: #d2e5f3; + --default-dark-background-color: #1e3347; +} +body[data-theme-variant=green] { + --default-light-background-color: #e3eee1; + --default-dark-background-color: #203b30; +} +body[data-theme-variant=violet] { + --default-light-background-color: #e7e4f5; + --default-dark-background-color: #2e2158; +} +body[data-theme-variant=rose] { + --default-light-background-color: #f8ebf5; + --default-dark-background-color: #5b194b; +} +body[data-theme-variant=orange] { + --default-light-background-color: #fcedd8; + --default-dark-background-color: #54240c; +} +body[data-theme-variant=desert] { + --default-light-background-color: #eee9e1; + --default-dark-background-color: #3c3833; } diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.js b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.js index 897c20dba56..f6958baa82a 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.js +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/dist/index.js @@ -2601,13 +2601,12 @@ } function App() { const { messaging: messaging2 } = useMessaging(); - const { isDarkMode } = useEnv(); function didCatch(error) { const message = error?.message || "unknown"; console.error("ErrorBoundary", message); messaging2?.reportPageException({ message }); } - return /* @__PURE__ */ _("main", { className: App_default.main, "data-theme": isDarkMode ? "dark" : "light" }, /* @__PURE__ */ _(PageTitle, null), /* @__PURE__ */ _(ErrorBoundary, { didCatch: ({ error }) => didCatch(error), fallback: /* @__PURE__ */ _(ErrorFallback, null) }, /* @__PURE__ */ _(SpecialErrorView, null), /* @__PURE__ */ _(WillThrow, null))); + return /* @__PURE__ */ _("main", { className: App_default.main }, /* @__PURE__ */ _(PageTitle, null), /* @__PURE__ */ _(ErrorBoundary, { didCatch: ({ error }) => didCatch(error), fallback: /* @__PURE__ */ _(ErrorFallback, null) }, /* @__PURE__ */ _(SpecialErrorView, null), /* @__PURE__ */ _(WillThrow, null))); } function WillThrow() { const env = useEnv(); @@ -2667,6 +2666,43 @@ } }))), /* @__PURE__ */ _("section", null, /* @__PURE__ */ _("h2", null, "Advanced Info"), /* @__PURE__ */ _("div", null, /* @__PURE__ */ _(AdvancedInfo, null))), /* @__PURE__ */ _("section", null, /* @__PURE__ */ _("h2", null, "Special Error View"), /* @__PURE__ */ _("div", null, /* @__PURE__ */ _(SpecialErrorView, null))))); } + // pages/special-error/app/providers/ThemeProvider.js + var ThemeContext = K({ + /** @type {BrowserTheme} */ + theme: "light", + /** @type {ThemeVariant} */ + themeVariant: "default" + }); + function ThemeProvider({ children, initialTheme, initialThemeVariant }) { + const { isDarkMode } = useEnv(); + const { messaging: messaging2 } = useMessaging(); + const [explicitTheme, setExplicitTheme] = d2( + /** @type {BrowserTheme | undefined} */ + void 0 + ); + const [explicitThemeVariant, setExplicitThemeVariant] = d2( + /** @type {ThemeVariant | undefined} */ + void 0 + ); + y2(() => { + if (!messaging2) return; + const unsubscribe = messaging2.onThemeUpdate((data) => { + setExplicitTheme(data.theme); + setExplicitThemeVariant(data.themeVariant); + }); + return unsubscribe; + }, [messaging2]); + const theme = explicitTheme ?? initialTheme ?? (isDarkMode ? "dark" : "light"); + const themeVariant = explicitThemeVariant ?? initialThemeVariant ?? "default"; + y2(() => { + document.body.dataset.theme = theme; + }, [theme]); + y2(() => { + document.body.dataset.themeVariant = themeVariant; + }, [themeVariant]); + return /* @__PURE__ */ _(ThemeContext.Provider, { value: { theme, themeVariant } }, children); + } + // shared/call-with-retry.js async function callWithRetry(fn, params = {}) { const { maxAttempts = 10, intervalMs = 300 } = params; @@ -2734,12 +2770,12 @@ if (!root) throw new Error("could not render, root element missing"); if (environment.display === "app") { E( - /* @__PURE__ */ _(EnvironmentProvider, { debugState: environment.debugState, injectName: environment.injectName, willThrow: environment.willThrow }, /* @__PURE__ */ _(UpdateEnvironment, { search: window.location.search }), /* @__PURE__ */ _(TranslationProvider, { translationObject: strings, fallback: special_error_default, textLength: environment.textLength }, /* @__PURE__ */ _(MessagingProvider, { messaging: messaging2 }, /* @__PURE__ */ _(SettingsProvider, { settings }, /* @__PURE__ */ _(SpecialErrorProvider, { specialError }, /* @__PURE__ */ _(App, null)))))), + /* @__PURE__ */ _(EnvironmentProvider, { debugState: environment.debugState, injectName: environment.injectName, willThrow: environment.willThrow }, /* @__PURE__ */ _(UpdateEnvironment, { search: window.location.search }), /* @__PURE__ */ _(TranslationProvider, { translationObject: strings, fallback: special_error_default, textLength: environment.textLength }, /* @__PURE__ */ _(MessagingProvider, { messaging: messaging2 }, /* @__PURE__ */ _(ThemeProvider, { initialTheme: init2.theme, initialThemeVariant: init2.themeVariant }, /* @__PURE__ */ _(SettingsProvider, { settings }, /* @__PURE__ */ _(SpecialErrorProvider, { specialError }, /* @__PURE__ */ _(App, null))))))), root ); } else if (environment.display === "components") { E( - /* @__PURE__ */ _(EnvironmentProvider, { debugState: false, injectName: environment.injectName }, /* @__PURE__ */ _(TranslationProvider, { translationObject: strings, fallback: special_error_default, textLength: environment.textLength }, /* @__PURE__ */ _(SettingsProvider, { settings }, /* @__PURE__ */ _(SpecialErrorProvider, { specialError }, /* @__PURE__ */ _(Components, null))))), + /* @__PURE__ */ _(EnvironmentProvider, { debugState: false, injectName: environment.injectName }, /* @__PURE__ */ _(TranslationProvider, { translationObject: strings, fallback: special_error_default, textLength: environment.textLength }, /* @__PURE__ */ _(ThemeProvider, { initialTheme: init2.theme, initialThemeVariant: init2.themeVariant }, /* @__PURE__ */ _(SettingsProvider, { settings }, /* @__PURE__ */ _(SpecialErrorProvider, { specialError }, /* @__PURE__ */ _(Components, null)))))), root ); } @@ -2822,6 +2858,14 @@ advancedInfo() { this.messaging.notify("advancedInfo"); } + /** + * Subscribe to theme update notifications from the native layer. + * @param {(data: import('../types/special-error.ts').OnThemeUpdateSubscribe) => void} callback + * @returns {() => void} Unsubscribe function + */ + onThemeUpdate(callback) { + return this.messaging.subscribe("onThemeUpdate", callback); + } }; var baseEnvironment = new Environment().withInjectName(document.documentElement.dataset.platform).withEnv("production"); var messaging = createSpecialPageMessaging({ diff --git a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/index.html b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/index.html index 71b68acf6f2..0c06028c2fb 100644 --- a/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/index.html +++ b/SharedPackages/BrowserServicesKit/Sources/ContentScopeScripts/Resources/pages/special-error/index.html @@ -4,6 +4,13 @@ Error +