commit 1f4eaf271e480f382fc90e815c393bdeb09a80a5 parent a40072afeeaed50f6b19243470f71ffff08415bd Author: Reem H <42309026+reemhamz@users.noreply.github.com> Date: Fri, 9 Jan 2026 00:40:46 +0000 Bug 2006525 - Weather forecast widget scaffolding. r=home-newtab-reviewers,desktop-theme-reviewers,accessibility-frontend-reviewers,mstriemer,nina-py,frontend-codestyle-reviewers,ayeddi Differential Revision: https://phabricator.services.mozilla.com/D277967 Diffstat:
12 files changed, 766 insertions(+), 2 deletions(-)
diff --git a/browser/extensions/newtab/content-src/components/Widgets/WeatherForecast/WeatherForecast.jsx b/browser/extensions/newtab/content-src/components/Widgets/WeatherForecast/WeatherForecast.jsx @@ -0,0 +1,113 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +import { useSelector } from "react-redux"; + +function WeatherForecast() { + const prefs = useSelector(state => state.Prefs.values); + const weatherData = useSelector(state => state.Weather); + + const WEATHER_SUGGESTION = weatherData.suggestions?.[0]; + + const showDetailedView = prefs["weather.display"] === "detailed"; + + if (!showDetailedView || !weatherData?.initialized) { + return null; + } + + return ( + <article className="weather-forecast-widget"> + <div className="city-wrapper"> + <h3>{weatherData.locationData.city}</h3> + </div> + <div className="current-weather-wrapper"> + <div className="weather-icon-column"> + <span + className={`weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}`} + ></span> + </div> + <div className="weather-info-column"> + <span className="temperature-unit"> + { + WEATHER_SUGGESTION.current_conditions.temperature[ + prefs["weather.temperatureUnits"] + ] + } + °{prefs["weather.temperatureUnits"]} + </span> + <span className="temperature-description"> + {WEATHER_SUGGESTION.current_conditions.summary} + </span> + </div> + <div className="high-low-column"> + <span className="high-temperature"> + <span className="arrow-icon arrow-up" /> + { + WEATHER_SUGGESTION.forecast.high[ + prefs["weather.temperatureUnits"] + ] + } + ° + </span> + + <span className="low-temperature"> + <span className="arrow-icon arrow-down" /> + {WEATHER_SUGGESTION.forecast.low[prefs["weather.temperatureUnits"]]} + ° + </span> + </div> + </div> + <hr /> + <div className="forecast-row"> + <p className="today-forecast">Today's forecast</p> + <ul className="forecast-row-items"> + <li> + <span>80°</span> + <span + className={`weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}`} + ></span> + <span>7:00</span> + </li> + <li> + <span>80°</span> + <span + className={`weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}`} + ></span> + <span>7:00</span> + </li> + <li> + <span>80°</span> + <span + className={`weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}`} + ></span> + <span>7:00</span> + </li> + <li> + <span>80°</span> + <span + className={`weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}`} + ></span> + <span>7:00</span> + </li> + <li> + <span>80°</span> + <span + className={`weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}`} + ></span> + <span>7:00</span> + </li> + </ul> + </div> + + <div className="weather-forecast-footer"> + <a href="#" className="full-forecast"> + See full forecast + </a> + <span className="sponsored-text">Accuweather Sponsored</span> + </div> + </article> + ); +} + +export { WeatherForecast }; diff --git a/browser/extensions/newtab/content-src/components/Widgets/WeatherForecast/WeatherForecast.scss b/browser/extensions/newtab/content-src/components/Widgets/WeatherForecast/WeatherForecast.scss @@ -0,0 +1,279 @@ +.weather-forecast-widget { + @include newtab-card-style; + + grid-column: span 1; + width: var(--newtab-card-grid-layout-width); + + // Match the new card width if sections are enabled + .has-sections-grid & { + width: var(--newtab-card-width-medium); + } + + border-radius: var(--border-radius-large); + padding: var(--space-medium); + height: var(--newtab-card-height); + display: flex; + flex-direction: column; + box-shadow: var(--box-shadow-card); + + --weather-sunny-background-color: light-dark(var(--color-yellow-0), var(--color-yellow-90)); + --weather-cloudy-background-color: light-dark(var(--color-gray-20), var(--color-gray-80)); + --weather-rainy-background-color: light-dark(var(--color-blue-0), var(--color-blue-90)); + --weather-snowy-background-color: light-dark(var(--color-violet-0), var(--color-violet-90)); + --weather-hot-background-color: light-dark(var(--color-orange-0), var(--color-orange-90)); + + .city-wrapper { + display: flex; + align-items: center; + + h3 { + margin-block: 0; + font-weight: var(--font-weight-semibold); + } + } + + .current-weather-wrapper { + display: flex; + align-items: center; + margin-block: var(--space-small); + padding: var(--space-medium); + border-radius: var(--border-radius-medium); + width: 100%; + + // Setting background color based on temperature icon + &:has(.iconId1, .iconId2, .iconId3, .iconId4, .iconId5, .iconId6, .iconId33) { + background-color: var(--weather-sunny-background-color); + } + + &:has(.iconId7, .iconId8, .iconI11, .iconId32, .iconId34, .iconId35, .iconId36, .iconId37, .iconId38) { + background-color: var(--weather-cloudy-background-color); + } + + &:has(.iconId12, .iconId13, .iconId14, .iconId15, .iconId16, .iconId17, .iconId18, .iconId39, .iconId40, .iconId41, .iconId42) { + background-color: var(--weather-rainy-background-color); + } + + &:has(.iconId19, .iconId20, .iconId21, .iconId22, .iconId23, .iconId24, .iconId25, .iconId26, .iconId29, .iconId31, .iconId43, .iconId44 ) { + background-color: var(--weather-snowy-background-color); + } + + &:has(.iconId30) { + background-color: var(--weather-hot-background-color); + } + } + + // Weather Symbol Icons + .weather-icon-column { + width: var(--size-item-large); + height: var(--size-item-large); + display: flex; + align-items: center; + justify-content: center; + align-self: center; + } + + .weather-icon { + width: var(--size-item-large); + height: auto; + vertical-align: middle; + + @media (prefers-contrast) { + -moz-context-properties: fill, stroke; + fill: currentColor; + stroke: currentColor; + } + + &.iconId1 { + content: url('chrome://browser/skin/weather/sunny.svg'); + } + + &.iconId2 { + content: url('chrome://browser/skin/weather/mostly-sunny.svg'); + } + + &:is(.iconId3, .iconId4, .iconId6) { + content: url('chrome://browser/skin/weather/partly-sunny.svg'); + } + + &.iconId5 { + content: url('chrome://browser/skin/weather/hazy-sunshine.svg'); + } + + &:is(.iconId7, .iconId8) { + content: url('chrome://browser/skin/weather/cloudy.svg'); + } + + &.iconId11 { + content: url('chrome://browser/skin/weather/fog.svg'); + } + + &.iconId12 { + content: url('chrome://browser/skin/weather/showers.svg'); + } + + &:is(.iconId13, .iconId14) { + content: url('chrome://browser/skin/weather/mostly-cloudy-with-showers.svg'); + } + + &.iconId15 { + content: url('chrome://browser/skin/weather/thunderstorms.svg'); + } + + &:is(.iconId16, .iconId17) { + content: url('chrome://browser/skin/weather/mostly-cloudy-with-thunderstorms.svg'); + } + + &.iconId18 { + content: url('chrome://browser/skin/weather/rain.svg'); + } + + &:is(.iconId19, .iconId20, .iconId25) { + content: url('chrome://browser/skin/weather/flurries.svg'); + } + + &.iconId21 { + content: url('chrome://browser/skin/weather/partly-sunny-with-flurries.svg'); + } + + &:is(.iconId22, .iconId23) { + content: url('chrome://browser/skin/weather/snow.svg'); + } + + &:is(.iconId24, .iconId31) { + content: url('chrome://browser/skin/weather/ice.svg'); + } + + &:is(.iconId26, .iconId29) { + content: url('chrome://browser/skin/weather/freezing-rain.svg'); + } + + &.iconId30 { + content: url('chrome://browser/skin/weather/hot.svg'); + } + + &.iconId32 { + content: url('chrome://browser/skin/weather/windy.svg'); + } + + &.iconId33 { + content: url('chrome://browser/skin/weather/night-clear.svg'); + } + + &:is(.iconId34, .iconId35, .iconId36, .iconId38) { + content: url('chrome://browser/skin/weather/night-mostly-clear.svg'); + } + + &.iconId37 { + content: url('chrome://browser/skin/weather/night-hazy-moonlight.svg'); + } + + &:is(.iconId39, .iconId40) { + content: url('chrome://browser/skin/weather/night-partly-cloudy-with-showers.svg'); + height: var(--size-item-large); + } + + &:is(.iconId41, .iconId42) { + content: url('chrome://browser/skin/weather/night-partly-cloudy-with-thunderstorms.svg'); + } + + &:is(.iconId43, .iconId44) { + content: url('chrome://browser/skin/weather/night-mostly-cloudy-with-flurries.svg'); + } + } +} + +.weather-info-column { + display: flex; + flex-direction: column; + margin-inline: var(--space-medium); + + .temperature-unit { + text-transform: uppercase; + font-weight: var(--font-weight-semibold); + } + + .temperature-description { + font-size: var(--font-size-small); + color: var(--text-color-deemphasized); + } +} + +.high-low-column { + display: flex; + align-items: flex-end; + align-self: flex-start; + margin-inline-start: auto; + color: var(--text-color-deemphasized); + + .high-temperature { + margin-inline-end: var(--space-small); + } + + .arrow-icon { + display: inline-block; + width: var(--size-item-xsmall); + height: var(--size-item-xsmall); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + -moz-context-properties: fill, fill-opacity; + fill: currentColor; + + &.arrow-up { + background-image: url('chrome://global/skin/icons/shaft-arrow-up.svg'); + } + + &.arrow-down { + background-image: url('chrome://global/skin/icons/shaft-arrow-down.svg'); + } + } +} + +hr { + border: 0; + border-block-start: 1px solid var(--border-color); + width: 100%; +} + +.forecast-row { + .today-forecast { + margin-block-start: 0; + font-weight: var(--font-weight-semibold); + } + + .forecast-row-items { + list-style: none; + display: flex; + justify-content: center; + padding: 0; + margin-block-start: var(--space-small); + + li { + background: var(--newtab-background-color); + border-radius: var(--border-radius-small); + display: flex; + flex-direction: column; + align-items: center; + margin-inline: var(--space-xsmall); + padding-inline: var(--space-small); + padding-block: var(--space-xsmall); + font-size: var(--font-size-small); + } + } +} + +.weather-forecast-footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-block-start: auto; + + a { + font-size: var(--font-size-small); + } + + span { + font-size: var(--font-size-xsmall); + } +} + diff --git a/browser/extensions/newtab/content-src/components/Widgets/Widgets.jsx b/browser/extensions/newtab/content-src/components/Widgets/Widgets.jsx @@ -6,6 +6,7 @@ import React, { useEffect, useRef } from "react"; import { useDispatch, useSelector, batch } from "react-redux"; import { Lists } from "./Lists/Lists"; import { FocusTimer } from "./FocusTimer/FocusTimer"; +import { WeatherForecast } from "./WeatherForecast/WeatherForecast"; import { MessageWrapper } from "content-src/components/MessageWrapper/MessageWrapper"; import { WidgetsFeatureHighlight } from "../DiscoveryStreamComponents/FeatureHighlight/WidgetsFeatureHighlight"; import { actionCreators as ac, actionTypes as at } from "common/Actions.mjs"; @@ -14,6 +15,9 @@ const PREF_WIDGETS_LISTS_ENABLED = "widgets.lists.enabled"; const PREF_WIDGETS_SYSTEM_LISTS_ENABLED = "widgets.system.lists.enabled"; const PREF_WIDGETS_TIMER_ENABLED = "widgets.focusTimer.enabled"; const PREF_WIDGETS_SYSTEM_TIMER_ENABLED = "widgets.system.focusTimer.enabled"; +const PREF_WIDGETS_WEATHER_FORECAST_ENABLED = "widgets.weatherForecast.enabled"; +const PREF_WIDGETS_SYSTEM_WEATHER_FORECAST_ENABLED = + "widgets.system.weatherForecast.enabled"; const PREF_WIDGETS_MAXIMIZED = "widgets.maximized"; const PREF_WIDGETS_SYSTEM_MAXIMIZED = "widgets.system.maximized"; @@ -59,10 +63,14 @@ function Widgets() { const nimbusListsEnabled = prefs.widgetsConfig?.listsEnabled; const nimbusTimerEnabled = prefs.widgetsConfig?.timerEnabled; + const nimbusWeatherForecastEnabled = + prefs.widgetsConfig?.weatherForecastEnabled; const nimbusListsTrainhopEnabled = prefs.trainhopConfig?.widgets?.listsEnabled; const nimbusTimerTrainhopEnabled = prefs.trainhopConfig?.widgets?.timerEnabled; + const nimbusWeatherForecastTrainhopEnabled = + prefs.trainhopConfig?.widgets?.weatherForecastEnabled; const listsEnabled = (nimbusListsTrainhopEnabled || @@ -76,6 +84,12 @@ function Widgets() { prefs[PREF_WIDGETS_SYSTEM_TIMER_ENABLED]) && prefs[PREF_WIDGETS_TIMER_ENABLED]; + const weatherForecastEnabled = + (nimbusWeatherForecastTrainhopEnabled || + nimbusWeatherForecastEnabled || + prefs[PREF_WIDGETS_SYSTEM_WEATHER_FORECAST_ENABLED]) && + prefs[PREF_WIDGETS_WEATHER_FORECAST_ENABLED]; + // track previous timerEnabled state to detect when it becomes disabled const prevTimerEnabledRef = useRef(timerEnabled); @@ -134,7 +148,7 @@ function Widgets() { } } - if (!(listsEnabled || timerEnabled)) { + if (!(listsEnabled || timerEnabled || weatherForecastEnabled)) { return null; } @@ -186,6 +200,13 @@ function Widgets() { isMaximized={isMaximized} /> )} + {weatherForecastEnabled && ( + <WeatherForecast + dispatch={dispatch} + handleUserInteraction={handleUserInteraction} + isMaximized={isMaximized} + /> + )} </div> </div> {messageData?.content?.messageType === "WidgetMessage" && ( diff --git a/browser/extensions/newtab/content-src/styles/activity-stream.scss b/browser/extensions/newtab/content-src/styles/activity-stream.scss @@ -170,6 +170,7 @@ input { @import '../components/Widgets/Widgets'; @import '../components/Widgets/Lists/Lists'; @import '../components/Widgets/FocusTimer/FocusTimer'; +@import '../components/Widgets/WeatherForecast/WeatherForecast'; // Discovery Stream Components @import '../components/DiscoveryStreamComponents/CardGrid/CardGrid'; diff --git a/browser/extensions/newtab/css/activity-stream.css b/browser/extensions/newtab/css/activity-stream.css @@ -4684,6 +4684,237 @@ dialog:dir(rtl)::after { margin-block-start: var(--space-small); } +.weather-forecast-widget { + background: var(--newtab-background-card); + transition: opacity 0.2s ease; + grid-column: span 1; + width: var(--newtab-card-grid-layout-width); + border-radius: var(--border-radius-large); + padding: var(--space-medium); + height: var(--newtab-card-height); + display: flex; + flex-direction: column; + box-shadow: var(--box-shadow-card); + --weather-sunny-background-color: light-dark(var(--color-yellow-0), var(--color-yellow-90)); + --weather-cloudy-background-color: light-dark(var(--color-gray-20), var(--color-gray-80)); + --weather-rainy-background-color: light-dark(var(--color-blue-0), var(--color-blue-90)); + --weather-snowy-background-color: light-dark(var(--color-violet-0), var(--color-violet-90)); + --weather-hot-background-color: light-dark(var(--color-orange-0), var(--color-orange-90)); +} +.weather-forecast-widget:hover { + background: var(--newtab-background-color-secondary); +} +.has-sections-grid .weather-forecast-widget { + width: var(--newtab-card-width-medium); +} +.weather-forecast-widget .city-wrapper { + display: flex; + align-items: center; +} +.weather-forecast-widget .city-wrapper h3 { + margin-block: 0; + font-weight: var(--font-weight-semibold); +} +.weather-forecast-widget .current-weather-wrapper { + display: flex; + align-items: center; + margin-block: var(--space-small); + padding: var(--space-medium); + border-radius: var(--border-radius-medium); + width: 100%; +} +.weather-forecast-widget .current-weather-wrapper:has(.iconId1, .iconId2, .iconId3, .iconId4, .iconId5, .iconId6, .iconId33) { + background-color: var(--weather-sunny-background-color); +} +.weather-forecast-widget .current-weather-wrapper:has(.iconId7, .iconId8, .iconI11, .iconId32, .iconId34, .iconId35, .iconId36, .iconId37, .iconId38) { + background-color: var(--weather-cloudy-background-color); +} +.weather-forecast-widget .current-weather-wrapper:has(.iconId12, .iconId13, .iconId14, .iconId15, .iconId16, .iconId17, .iconId18, .iconId39, .iconId40, .iconId41, .iconId42) { + background-color: var(--weather-rainy-background-color); +} +.weather-forecast-widget .current-weather-wrapper:has(.iconId19, .iconId20, .iconId21, .iconId22, .iconId23, .iconId24, .iconId25, .iconId26, .iconId29, .iconId31, .iconId43, .iconId44) { + background-color: var(--weather-snowy-background-color); +} +.weather-forecast-widget .current-weather-wrapper:has(.iconId30) { + background-color: var(--weather-hot-background-color); +} +.weather-forecast-widget .weather-icon-column { + width: var(--size-item-large); + height: var(--size-item-large); + display: flex; + align-items: center; + justify-content: center; + align-self: center; +} +.weather-forecast-widget .weather-icon { + width: var(--size-item-large); + height: auto; + vertical-align: middle; +} +@media (prefers-contrast) { + .weather-forecast-widget .weather-icon { + -moz-context-properties: fill, stroke; + fill: currentColor; + stroke: currentColor; + } +} +.weather-forecast-widget .weather-icon.iconId1 { + content: url("chrome://browser/skin/weather/sunny.svg"); +} +.weather-forecast-widget .weather-icon.iconId2 { + content: url("chrome://browser/skin/weather/mostly-sunny.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId3, .iconId4, .iconId6) { + content: url("chrome://browser/skin/weather/partly-sunny.svg"); +} +.weather-forecast-widget .weather-icon.iconId5 { + content: url("chrome://browser/skin/weather/hazy-sunshine.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId7, .iconId8) { + content: url("chrome://browser/skin/weather/cloudy.svg"); +} +.weather-forecast-widget .weather-icon.iconId11 { + content: url("chrome://browser/skin/weather/fog.svg"); +} +.weather-forecast-widget .weather-icon.iconId12 { + content: url("chrome://browser/skin/weather/showers.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId13, .iconId14) { + content: url("chrome://browser/skin/weather/mostly-cloudy-with-showers.svg"); +} +.weather-forecast-widget .weather-icon.iconId15 { + content: url("chrome://browser/skin/weather/thunderstorms.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId16, .iconId17) { + content: url("chrome://browser/skin/weather/mostly-cloudy-with-thunderstorms.svg"); +} +.weather-forecast-widget .weather-icon.iconId18 { + content: url("chrome://browser/skin/weather/rain.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId19, .iconId20, .iconId25) { + content: url("chrome://browser/skin/weather/flurries.svg"); +} +.weather-forecast-widget .weather-icon.iconId21 { + content: url("chrome://browser/skin/weather/partly-sunny-with-flurries.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId22, .iconId23) { + content: url("chrome://browser/skin/weather/snow.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId24, .iconId31) { + content: url("chrome://browser/skin/weather/ice.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId26, .iconId29) { + content: url("chrome://browser/skin/weather/freezing-rain.svg"); +} +.weather-forecast-widget .weather-icon.iconId30 { + content: url("chrome://browser/skin/weather/hot.svg"); +} +.weather-forecast-widget .weather-icon.iconId32 { + content: url("chrome://browser/skin/weather/windy.svg"); +} +.weather-forecast-widget .weather-icon.iconId33 { + content: url("chrome://browser/skin/weather/night-clear.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId34, .iconId35, .iconId36, .iconId38) { + content: url("chrome://browser/skin/weather/night-mostly-clear.svg"); +} +.weather-forecast-widget .weather-icon.iconId37 { + content: url("chrome://browser/skin/weather/night-hazy-moonlight.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId39, .iconId40) { + content: url("chrome://browser/skin/weather/night-partly-cloudy-with-showers.svg"); + height: var(--size-item-large); +} +.weather-forecast-widget .weather-icon:is(.iconId41, .iconId42) { + content: url("chrome://browser/skin/weather/night-partly-cloudy-with-thunderstorms.svg"); +} +.weather-forecast-widget .weather-icon:is(.iconId43, .iconId44) { + content: url("chrome://browser/skin/weather/night-mostly-cloudy-with-flurries.svg"); +} + +.weather-info-column { + display: flex; + flex-direction: column; + margin-inline: var(--space-medium); +} +.weather-info-column .temperature-unit { + text-transform: uppercase; + font-weight: var(--font-weight-semibold); +} +.weather-info-column .temperature-description { + font-size: var(--font-size-small); + color: var(--text-color-deemphasized); +} + +.high-low-column { + display: flex; + align-items: flex-end; + align-self: flex-start; + margin-inline-start: auto; + color: var(--text-color-deemphasized); +} +.high-low-column .high-temperature { + margin-inline-end: var(--space-small); +} +.high-low-column .arrow-icon { + display: inline-block; + width: var(--size-item-xsmall); + height: var(--size-item-xsmall); + background-size: contain; + background-repeat: no-repeat; + background-position: center; + -moz-context-properties: fill, fill-opacity; + fill: currentColor; +} +.high-low-column .arrow-icon.arrow-up { + background-image: url("chrome://global/skin/icons/shaft-arrow-up.svg"); +} +.high-low-column .arrow-icon.arrow-down { + background-image: url("chrome://global/skin/icons/shaft-arrow-down.svg"); +} + +hr { + border: 0; + border-block-start: 1px solid var(--border-color); + width: 100%; +} + +.forecast-row .today-forecast { + margin-block-start: 0; + font-weight: var(--font-weight-semibold); +} +.forecast-row .forecast-row-items { + list-style: none; + display: flex; + justify-content: center; + padding: 0; + margin-block-start: var(--space-small); +} +.forecast-row .forecast-row-items li { + background: var(--newtab-background-color); + border-radius: var(--border-radius-small); + display: flex; + flex-direction: column; + align-items: center; + margin-inline: var(--space-xsmall); + padding-inline: var(--space-small); + padding-block: var(--space-xsmall); + font-size: var(--font-size-small); +} + +.weather-forecast-footer { + display: flex; + align-items: center; + justify-content: space-between; + margin-block-start: auto; +} +.weather-forecast-footer a { + font-size: var(--font-size-small); +} +.weather-forecast-footer span { + font-size: var(--font-size-xsmall); +} + .ds-card-grid .ds-card { background: var(--newtab-background-color-secondary); border-radius: var(--border-radius-small); diff --git a/browser/extensions/newtab/data/content/activity-stream.bundle.js b/browser/extensions/newtab/data/content/activity-stream.bundle.js @@ -13064,6 +13064,72 @@ function EditableTimerFields({ tabIndex: tabIndex }, formatTime(props.timeLeft).split(":")[1])); } +;// CONCATENATED MODULE: ./content-src/components/Widgets/WeatherForecast/WeatherForecast.jsx +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + + +function WeatherForecast() { + const prefs = (0,external_ReactRedux_namespaceObject.useSelector)(state => state.Prefs.values); + const weatherData = (0,external_ReactRedux_namespaceObject.useSelector)(state => state.Weather); + const WEATHER_SUGGESTION = weatherData.suggestions?.[0]; + const showDetailedView = prefs["weather.display"] === "detailed"; + if (!showDetailedView || !weatherData?.initialized) { + return null; + } + return /*#__PURE__*/React.createElement("article", { + className: "weather-forecast-widget" + }, /*#__PURE__*/React.createElement("div", { + className: "city-wrapper" + }, /*#__PURE__*/React.createElement("h3", null, weatherData.locationData.city)), /*#__PURE__*/React.createElement("div", { + className: "current-weather-wrapper" + }, /*#__PURE__*/React.createElement("div", { + className: "weather-icon-column" + }, /*#__PURE__*/React.createElement("span", { + className: `weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}` + })), /*#__PURE__*/React.createElement("div", { + className: "weather-info-column" + }, /*#__PURE__*/React.createElement("span", { + className: "temperature-unit" + }, WEATHER_SUGGESTION.current_conditions.temperature[prefs["weather.temperatureUnits"]], "\xB0", prefs["weather.temperatureUnits"]), /*#__PURE__*/React.createElement("span", { + className: "temperature-description" + }, WEATHER_SUGGESTION.current_conditions.summary)), /*#__PURE__*/React.createElement("div", { + className: "high-low-column" + }, /*#__PURE__*/React.createElement("span", { + className: "high-temperature" + }, /*#__PURE__*/React.createElement("span", { + className: "arrow-icon arrow-up" + }), WEATHER_SUGGESTION.forecast.high[prefs["weather.temperatureUnits"]], "\xB0"), /*#__PURE__*/React.createElement("span", { + className: "low-temperature" + }, /*#__PURE__*/React.createElement("span", { + className: "arrow-icon arrow-down" + }), WEATHER_SUGGESTION.forecast.low[prefs["weather.temperatureUnits"]], "\xB0"))), /*#__PURE__*/React.createElement("hr", null), /*#__PURE__*/React.createElement("div", { + className: "forecast-row" + }, /*#__PURE__*/React.createElement("p", { + className: "today-forecast" + }, "Today's forecast"), /*#__PURE__*/React.createElement("ul", { + className: "forecast-row-items" + }, /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("span", null, "80\xB0"), /*#__PURE__*/React.createElement("span", { + className: `weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}` + }), /*#__PURE__*/React.createElement("span", null, "7:00")), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("span", null, "80\xB0"), /*#__PURE__*/React.createElement("span", { + className: `weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}` + }), /*#__PURE__*/React.createElement("span", null, "7:00")), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("span", null, "80\xB0"), /*#__PURE__*/React.createElement("span", { + className: `weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}` + }), /*#__PURE__*/React.createElement("span", null, "7:00")), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("span", null, "80\xB0"), /*#__PURE__*/React.createElement("span", { + className: `weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}` + }), /*#__PURE__*/React.createElement("span", null, "7:00")), /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("span", null, "80\xB0"), /*#__PURE__*/React.createElement("span", { + className: `weather-icon iconId${WEATHER_SUGGESTION.current_conditions.icon_id}` + }), /*#__PURE__*/React.createElement("span", null, "7:00")))), /*#__PURE__*/React.createElement("div", { + className: "weather-forecast-footer" + }, /*#__PURE__*/React.createElement("a", { + href: "#", + className: "full-forecast" + }, "See full forecast"), /*#__PURE__*/React.createElement("span", { + className: "sponsored-text" + }, "Accuweather Sponsored"))); +} + ;// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/FeatureHighlight/WidgetsFeatureHighlight.jsx /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -13117,10 +13183,13 @@ function WidgetsFeatureHighlight({ + const PREF_WIDGETS_LISTS_ENABLED = "widgets.lists.enabled"; const PREF_WIDGETS_SYSTEM_LISTS_ENABLED = "widgets.system.lists.enabled"; const PREF_WIDGETS_TIMER_ENABLED = "widgets.focusTimer.enabled"; const PREF_WIDGETS_SYSTEM_TIMER_ENABLED = "widgets.system.focusTimer.enabled"; +const PREF_WIDGETS_WEATHER_FORECAST_ENABLED = "widgets.weatherForecast.enabled"; +const PREF_WIDGETS_SYSTEM_WEATHER_FORECAST_ENABLED = "widgets.system.weatherForecast.enabled"; const PREF_WIDGETS_MAXIMIZED = "widgets.maximized"; const PREF_WIDGETS_SYSTEM_MAXIMIZED = "widgets.system.maximized"; @@ -13162,10 +13231,13 @@ function Widgets() { const dispatch = (0,external_ReactRedux_namespaceObject.useDispatch)(); const nimbusListsEnabled = prefs.widgetsConfig?.listsEnabled; const nimbusTimerEnabled = prefs.widgetsConfig?.timerEnabled; + const nimbusWeatherForecastEnabled = prefs.widgetsConfig?.weatherForecastEnabled; const nimbusListsTrainhopEnabled = prefs.trainhopConfig?.widgets?.listsEnabled; const nimbusTimerTrainhopEnabled = prefs.trainhopConfig?.widgets?.timerEnabled; + const nimbusWeatherForecastTrainhopEnabled = prefs.trainhopConfig?.widgets?.weatherForecastEnabled; const listsEnabled = (nimbusListsTrainhopEnabled || nimbusListsEnabled || prefs[PREF_WIDGETS_SYSTEM_LISTS_ENABLED]) && prefs[PREF_WIDGETS_LISTS_ENABLED]; const timerEnabled = (nimbusTimerTrainhopEnabled || nimbusTimerEnabled || prefs[PREF_WIDGETS_SYSTEM_TIMER_ENABLED]) && prefs[PREF_WIDGETS_TIMER_ENABLED]; + const weatherForecastEnabled = (nimbusWeatherForecastTrainhopEnabled || nimbusWeatherForecastEnabled || prefs[PREF_WIDGETS_SYSTEM_WEATHER_FORECAST_ENABLED]) && prefs[PREF_WIDGETS_WEATHER_FORECAST_ENABLED]; // track previous timerEnabled state to detect when it becomes disabled const prevTimerEnabledRef = (0,external_React_namespaceObject.useRef)(timerEnabled); @@ -13221,7 +13293,7 @@ function Widgets() { dispatch(actionCreators.SetPref(prefName, true)); } } - if (!(listsEnabled || timerEnabled)) { + if (!(listsEnabled || timerEnabled || weatherForecastEnabled)) { return null; } return /*#__PURE__*/external_React_default().createElement("div", { @@ -13260,6 +13332,10 @@ function Widgets() { dispatch: dispatch, handleUserInteraction: handleUserInteraction, isMaximized: isMaximized + }), weatherForecastEnabled && /*#__PURE__*/external_React_default().createElement(WeatherForecast, { + dispatch: dispatch, + handleUserInteraction: handleUserInteraction, + isMaximized: isMaximized }))), messageData?.content?.messageType === "WidgetMessage" && /*#__PURE__*/external_React_default().createElement(MessageWrapper, { dispatch: dispatch }, /*#__PURE__*/external_React_default().createElement(WidgetsFeatureHighlight, { diff --git a/browser/extensions/newtab/karma.mc.config.js b/browser/extensions/newtab/karma.mc.config.js @@ -297,6 +297,13 @@ module.exports = function (config) { functions: 31.2, branches: 31.2, }, + "content-src/components/Widgets/WeatherForecast/WeatherForecast.jsx": + { + statements: 0, + lines: 0, + functions: 0, + branches: 0, + }, "content-src/components/Weather/LocationSearch.jsx": { statements: 0, lines: 0, diff --git a/browser/extensions/newtab/lib/ActivityStream.sys.mjs b/browser/extensions/newtab/lib/ActivityStream.sys.mjs @@ -1125,6 +1125,28 @@ export const PREFS_CONFIG = new Map([ }, ], [ + "widgets.weatherForecast.enabled", + { + title: "Enables the weather forecast widget", + value: true, + }, + ], + [ + "widgets.system.weatherForecast.enabled", + { + title: "Enables the weather forecast widget experiment in Nimbus", + value: false, + }, + ], + [ + "widgets.weatherForecast.interaction", + { + title: + "Boolean flag for determining if a user has interacted with the weather forecast widget", + value: false, + }, + ], + [ "improvesearch.noDefaultSearchTile", { title: "Remove tiles that are the same as the default search", diff --git a/stylelint-rollouts.config.js b/stylelint-rollouts.config.js @@ -123,6 +123,7 @@ module.exports = [ "browser/extensions/newtab/content-src/components/Weather/_Weather.scss", "browser/extensions/newtab/content-src/components/Widgets/FocusTimer/_FocusTimer.scss", "browser/extensions/newtab/content-src/components/Widgets/Lists/_Lists.scss", + "browser/extensions/newtab/content-src/components/Widgets/WeatherForecast/WeatherForecast.scss", "browser/extensions/newtab/content-src/components/Widgets/_Widgets.scss", "browser/extensions/newtab/content-src/styles/_icons.scss", "browser/extensions/newtab/content-src/styles/_mixins.scss", @@ -503,6 +504,7 @@ module.exports = [ "browser/extensions/newtab/content-src/components/Weather/_Weather.scss", "browser/extensions/newtab/content-src/components/Widgets/FocusTimer/_FocusTimer.scss", "browser/extensions/newtab/content-src/components/Widgets/Lists/_Lists.scss", + "browser/extensions/newtab/content-src/components/Widgets/WeatherForecast/WeatherForecast.scss", "browser/extensions/newtab/content-src/components/Widgets/_Widgets.scss", "browser/extensions/newtab/content-src/styles/_icons.scss", "browser/extensions/newtab/content-src/styles/_mixins.scss", diff --git a/toolkit/themes/shared/desktop-jar.inc.mn b/toolkit/themes/shared/desktop-jar.inc.mn @@ -126,6 +126,8 @@ skin/classic/global/icons/arrow-right-12.svg (../../shared/icons/arrow-right-12.svg) skin/classic/global/icons/arrow-up-12.svg (../../shared/icons/arrow-up-12.svg) skin/classic/global/icons/arrow-up.svg (../../shared/icons/arrow-up.svg) + skin/classic/global/icons/shaft-arrow-down.svg (../../shared/icons/shaft-arrow-down.svg) + skin/classic/global/icons/shaft-arrow-up.svg (../../shared/icons/shaft-arrow-up.svg) skin/classic/global/icons/warning.svg (../../shared/icons/warning.svg) skin/classic/global/icons/warning-fill-12.svg (../../shared/icons/warning-fill-12.svg) skin/classic/global/illustrations/about-license.svg (../../shared/illustrations/about-license.svg) diff --git a/toolkit/themes/shared/icons/shaft-arrow-down.svg b/toolkit/themes/shared/icons/shaft-arrow-down.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at https://mozilla.org/MPL/2.0/. --> +<svg width="12" height="12" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg"><path d="M6 1.219v8.495l3.23-3.232a.47.47 0 0 1 .664.664L5.79 11.25h-.517L1.168 7.146a.467.467 0 0 1 .332-.8c.124 0 .244.05.332.137l3.23 3.231V1.219a.469.469 0 0 1 .938 0Z"/></svg> +\ No newline at end of file diff --git a/toolkit/themes/shared/icons/shaft-arrow-up.svg b/toolkit/themes/shared/icons/shaft-arrow-up.svg @@ -0,0 +1,4 @@ +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at https://mozilla.org/MPL/2.0/. --> +<svg width="12" height="12" fill="context-fill" fill-opacity="context-fill-opacity" xmlns="http://www.w3.org/2000/svg"><path d="M6 10.781V2.286L2.77 5.518a.47.47 0 0 1-.664-.664L6.21.75h.517l4.105 4.104a.468.468 0 1 1-.664.663l-3.23-3.231v8.495a.469.469 0 1 1-.938 0Z"/></svg> +\ No newline at end of file