diff --git a/dotcom-rendering/src/components/Weather.stories.tsx b/dotcom-rendering/src/components/Weather.stories.tsx
deleted file mode 100644
index 030a0f5f39..0000000000
--- a/dotcom-rendering/src/components/Weather.stories.tsx
+++ /dev/null
@@ -1,68 +0,0 @@
-import type { Meta, StoryObj } from '@storybook/react';
-import { splitTheme } from '../../.storybook/decorators/splitThemeDecorator';
-import { Weather as WeatherComponent } from './Weather';
-
-const meta: Meta = {
- title: 'Components/Weather',
- component: WeatherComponent,
-};
-
-type Story = StoryObj;
-export const Weather: Story = {
- args: {
- edition: 'UK',
- location: {
- id: '712993',
- city: 'Ickleford',
- country: 'United Kingdom',
- },
- now: {
- description: 'Sunny',
- icon: 1,
- link: 'http://www.accuweather.com/en/gb/ickleford/sg5-3/current-weather/712993?lang=en-us',
- dateTime: null,
- temperature: { metric: 27, imperial: 81 },
- },
- forecast: {
- '3h': {
- description: 'Mostly sunny',
- icon: 2,
- link: '',
- dateTime: '2024-07-31T20:00:00+01:00',
- temperature: { metric: 23, imperial: 74 },
- },
- '6h': {
- description: 'Partly cloudy',
- icon: 35,
- link: '',
- dateTime: '2024-07-31T23:00:00+01:00',
- temperature: { metric: 18, imperial: 65 },
- },
- '9h': {
- description: 'Cloudy',
- icon: 7,
- link: '',
- dateTime: '2024-08-01T02:00:00+01:00',
- temperature: { metric: 15, imperial: 59 },
- },
- '12h': {
- description: 'Intermittent clouds',
- icon: 36,
- link: '',
- dateTime: '2024-08-01T05:00:00+01:00',
- temperature: { metric: 16, imperial: 61 },
- },
- },
- },
- decorators: [splitTheme()],
-};
-
-export const WeatherUS: Story = {
- ...Weather,
- args: {
- ...Weather.args,
- edition: 'US',
- },
-};
-
-export default meta;
diff --git a/dotcom-rendering/src/components/Weather.tsx b/dotcom-rendering/src/components/Weather.tsx
deleted file mode 100644
index b1ca8b5aaa..0000000000
--- a/dotcom-rendering/src/components/Weather.tsx
+++ /dev/null
@@ -1,293 +0,0 @@
-/**
- * "WEATHER"
- *
- * Whether the weather be fine,
- * Or whether the weather be not,
- * Whether the weather be cold,
- * Or whether the weather be hot,
- * We'll weather the weather
- * Whatever the weather,
- * Whether we like it or not!
- *
- * Author: Anonymous British
- */
-
-import { css, keyframes } from '@emotion/react';
-import {
- between,
- from,
- space,
- textSans15,
- textSans17,
- until,
- visuallyHidden,
-} from '@guardian/source/foundations';
-import {
- SvgChevronDownSingle,
- SvgChevronUpSingle,
- SvgExternal,
-} from '@guardian/source/react-components';
-import { useId } from 'react';
-import type { EditionId } from '../lib/edition';
-import { palette } from '../palette';
-import type { WeatherApiData, WeatherData } from '../types/weather';
-import { WeatherSlot } from './WeatherSlot';
-
-const visuallyHiddenCSS = css`
- ${visuallyHidden}
-`;
-
-const weatherCSS = css`
- animation: ${keyframes`from { opacity: 0; } to { opacity: 1; }`} 250ms;
- --border: 1px solid ${palette('--article-border')};
- width: 100%;
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- align-items: center;
- letter-spacing: -0.56px;
-
- ${between.tablet.and.leftCol} {
- padding-top: 6px;
- height: 52px;
- }
-`;
-
-const locationCSS = css`
- flex: 1;
- ${textSans17};
- padding: 12px 0;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
-
- ${until.tablet} {
- flex-basis: 100%;
- border-bottom: var(--border);
- }
-
- ${between.tablet.and.leftCol} {
- padding-right: 1ch;
- }
-
- ${from.leftCol} {
- flex-basis: 100%;
- border-bottom: var(--border);
- }
-`;
-
-const nowCSS = css`
- ${until.tablet} {
- justify-content: flex-end;
- flex-basis: 100%;
- border-bottom: var(--border);
- order: -1;
- padding-bottom: 4px;
- margin-top: -${space[9]}px;
- }
-
- ${from.leftCol} {
- flex-basis: 100%;
- border-bottom: var(--border);
- padding-top: 8px;
- padding-bottom: 24px;
- }
-`;
-
-const slotCSS = css`
- display: flex;
- flex: 1;
- padding-top: 6px;
-
- border-left: var(--border);
- padding-left: 6px;
-
- ${until.mobileLandscape} {
- &.forecast-4 {
- display: none;
- }
- }
-
- ${until.tablet} {
- &.now,
- &.forecast-1 {
- border-left: none;
- }
- }
-
- ${between.tablet.and.desktop} {
- padding-left: 6px;
- padding-right: 6px;
- &.forecast-3,
- &.forecast-4 {
- display: none;
- }
- }
-
- ${between.desktop.and.wide} {
- padding-left: 4px;
- padding-right: 4px;
- &.forecast-4 {
- display: none;
- }
- }
-
- ${from.leftCol} {
- &.now,
- &.forecast-1 {
- border-left: none;
- }
- }
-`;
-
-const linkCSS = css`
- a {
- ${textSans15};
- color: inherit;
- text-decoration: none;
- display: block;
- display: flex;
- flex-direction: row;
- align-items: center;
-
- &:hover {
- text-decoration: underline;
- }
- }
-
- ${until.tablet} {
- flex-basis: 100%;
- padding-top: 12px;
- }
-
- ${from.leftCol} {
- padding-top: 24px;
- flex-basis: 100%;
- }
-`;
-
-const ExternalLinkIcon = () => (
-
-
-
-);
-
-export interface WeatherProps
- extends Pick {
- now: WeatherData;
- edition: EditionId;
- link?: string;
-}
-
-const collapsibleStyles = css`
- .checkbox-label {
- display: none;
- }
-
- .checkbox {
- display: none;
- }
-
- ${until.tablet} {
- .checkbox-label {
- display: inherit;
- }
-
- .checkbox:not(:checked) ~ .now {
- border-bottom: none;
- }
-
- .checkbox:not(:checked) ~ .now > .checkbox-label {
- svg:first-child {
- display: none;
- }
- }
-
- .checkbox:checked ~ .now > .checkbox-label {
- svg:last-child {
- display: none;
- }
- }
-
- .checkbox:not(:checked) ~ .collapsible {
- display: none;
- }
- }
-`;
-
-export const WeatherPlaceholder = () => (
-
-);
-
-export const Weather = ({
- location,
- now,
- forecast,
- edition,
- link,
-}: WeatherProps) => {
- const checkboxId = useId();
-
- return (
-
- );
-};
diff --git a/dotcom-rendering/src/components/WeatherSlot.tsx b/dotcom-rendering/src/components/WeatherSlot.tsx
deleted file mode 100644
index 581e8ad3b3..0000000000
--- a/dotcom-rendering/src/components/WeatherSlot.tsx
+++ /dev/null
@@ -1,229 +0,0 @@
-import type { SerializedStyles } from '@emotion/react';
-import { css, keyframes } from '@emotion/react';
-import { isString } from '@guardian/libs';
-import {
- from,
- palette,
- textSans12,
- textSans17,
- textSans24,
- until,
- visuallyHidden,
-} from '@guardian/source/foundations';
-import { lazy, Suspense } from 'react';
-import { type EditionId, getEditionFromId } from '../lib/edition';
-import type { WeatherData } from '../types/weather';
-
-interface IconProps {
- size?: number;
-}
-
-const formatTemperature = (value: number, unit: string) =>
- `${value}°${unit.toLocaleUpperCase()}`;
-
-const formatTime = (dateTime: string, edition: EditionId) =>
- new Date(dateTime).toLocaleTimeString(
- getEditionFromId(edition).dateLocale,
- {
- hour: 'numeric',
- // US and AU dates include AM/PM markers that cause the timestamp to
- // wrap onto the next line, which we don't want for the design.
- // Given that the times are always on the hour, i.e. the minutes are
- // always "00", we can choose to show the hour only without losing
- // information. This shortens the timestamp and keeps it on one line.
- minute:
- edition === 'US' || edition === 'AU' ? undefined : 'numeric',
- },
- );
-
-const visuallyHiddenCSS = css`
- ${visuallyHidden}
-`;
-
-const slotCSS = css`
- animation: ${keyframes`from { opacity: 0; } to { opacity: 1; }`} 250ms;
- position: relative;
- display: inline-flex;
- flex-direction: column;
- align-items: flex-start;
- justify-content: center;
- padding-left: 40px;
- min-height: 40px; /* icon height (32) + 4 + 4 */
-
- ${from.leftCol} {
- padding-left: 0;
- }
-`;
-
-const timeCSS = css`
- ${textSans12};
- display: block;
-`;
-
-const nowCSS = [
- timeCSS,
- css`
- ${until.tablet} {
- display: none;
- }
-
- ${from.leftCol} {
- padding-bottom: 4px;
- }
- `,
-];
-
-const tempCSS = (isNow: boolean) => [
- css`
- display: block;
- ${textSans17};
-
- ${from.leftCol} {
- order: 1;
- padding-top: 4px;
- }
- `,
- isNow &&
- css`
- ${from.leftCol} {
- ${textSans24};
- line-height: 1;
- }
- `,
-];
-
-const iconCSS = (size: number) => css`
- position: absolute;
- top: 50%;
- left: 0px;
- margin-top: -16px;
-
- ${from.leftCol} {
- position: static;
- margin-top: 0;
- height: ${size}px;
- width: ${size}px;
- margin-right: ${size === 50 ? 8 : 0}px;
- }
-`;
-
-const flexRow = css`
- display: flex;
- flex-direction: row;
-`;
-
-const flexColumn = css`
- display: flex;
- flex-direction: column;
-`;
-
-const flexRowBelowLeftCol = css`
- ${until.leftCol} {
- ${flexRow}
- }
-`;
-
-const flexColumnBelowLeftCol = css`
- ${until.leftCol} {
- ${flexColumn}
- }
-`;
-
-const LoadingIcon = () => (
-
-);
-
-export type WeatherSlotProps = WeatherData & {
- edition: EditionId;
- css?: SerializedStyles;
-};
-
-export const WeatherSlot = ({
- icon,
- temperature,
- dateTime,
- description,
- edition,
- ...props
-}: WeatherSlotProps) => {
- const isNow = !isString(dateTime);
-
- const Icon = lazy(() =>
- import(`../static/icons/weather/weather-${icon}.svg`).then(
- ({ default: Component }) => {
- return {
- default: ({ size = 32 }: IconProps) => (
-
- ),
- };
- },
- ),
- );
-
- return (
-
-
- {isNow ? 'The current weather' : 'The forecast for'}
-
- {isNow ? (
-
-
- }>
-
-
-
-
-
- Now
-
- is
-
- {formatTemperature(
- edition === 'US'
- ? temperature.imperial
- : temperature.metric,
- edition === 'US' ? 'F' : 'C',
- )}
-
-
- , {description.toLowerCase()}.
-
-
-
- ) : (
-
-
-
- is
-
- {formatTemperature(
- edition === 'US'
- ? temperature.imperial
- : temperature.metric,
- edition === 'US' ? 'F' : 'C',
- )}
-
-
- , {description.toLowerCase()}.
-
-
-
}>
-
-
-
- )}
-
- );
-};
diff --git a/dotcom-rendering/src/components/WeatherWrapper.importable.tsx b/dotcom-rendering/src/components/WeatherWrapper.importable.tsx
deleted file mode 100644
index 007b2c2294..0000000000
--- a/dotcom-rendering/src/components/WeatherWrapper.importable.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import type { EditionId } from '../lib/edition';
-import { useApi } from '../lib/useApi';
-import { parseWeatherData } from '../types/weather';
-import { Weather, WeatherPlaceholder } from './Weather';
-
-const appendPartnerCodeToUrl = (
- url: string | undefined,
-): string | undefined => {
- if (!url) return undefined;
-
- try {
- const link = new URL(url);
- link.searchParams.append('partner', 'web_guardian_adc');
- return link.href;
- } catch {
- return undefined;
- }
-};
-
-type Props = {
- ajaxUrl: string;
- edition: EditionId;
-};
-
-export const WeatherWrapper = ({ ajaxUrl, edition }: Props) => {
- const { data, error } = useApi(`${ajaxUrl}/weather.json`);
-
- if (error) {
- window.guardian.modules.sentry.reportError(error, 'weather');
- }
-
- const result = parseWeatherData(data);
-
- if (result.kind === 'error' && result.error === 'ParsingError') {
- window.guardian.modules.sentry.reportError(
- Error('Invalid weather data'),
- 'weather',
- );
- }
-
- return result.kind === 'error' ? (
-
- ) : (
-
- );
-};
diff --git a/dotcom-rendering/src/layouts/FrontLayout.tsx b/dotcom-rendering/src/layouts/FrontLayout.tsx
index bf08ad5b3a..21bd5320be 100644
--- a/dotcom-rendering/src/layouts/FrontLayout.tsx
+++ b/dotcom-rendering/src/layouts/FrontLayout.tsx
@@ -93,7 +93,6 @@ const isToggleable = (
const decideLeftContent = (
front: DCRFrontType,
collection: DCRCollectionType,
- hasPageSkin: boolean,
) => {
// show CPScott?
if (
@@ -105,24 +104,6 @@ const decideLeftContent = (
return ;
}
- // show weather?
- if (
- front.config.switches['weather'] &&
- isNetworkFrontPageId(front.config.pageId) &&
- // based on https://github.com/guardian/frontend/blob/473aafd168fec7f2a578a52c8e84982e3ec10fea/common/app/views/support/GetClasses.scala#L107
- collection.displayName.toLowerCase() === 'headlines' &&
- !hasPageSkin
- ) {
- return (
-
-
-
- );
- }
-
// show nothing!
return null;
};
@@ -661,7 +642,6 @@ export const FrontLayout = ({ front, NAV }: Props) => {
leftContent={decideLeftContent(
front,
collection,
- hasPageSkin,
)}
sectionId={ophanName}
collectionId={collection.id}
diff --git a/dotcom-rendering/src/paletteDeclarations.ts b/dotcom-rendering/src/paletteDeclarations.ts
index 121fae015e..18b7c77d20 100644
--- a/dotcom-rendering/src/paletteDeclarations.ts
+++ b/dotcom-rendering/src/paletteDeclarations.ts
@@ -7246,10 +7246,6 @@ const paletteColours = {
light: () => sourcePalette.news[400],
dark: () => '#DC2E1C',
},
- '--weather-icon': {
- light: () => sourcePalette.neutral[97],
- dark: () => sourcePalette.neutral[7],
- },
'--witness-title-author': {
light: witnessTitleAuthor,
dark: witnessTitleAuthor,
diff --git a/dotcom-rendering/src/types/weather.ts b/dotcom-rendering/src/types/weather.ts
deleted file mode 100644
index 6afd6cad43..0000000000
--- a/dotcom-rendering/src/types/weather.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import type { Output } from 'valibot';
-import {
- nullable,
- number,
- object,
- optional,
- safeParse,
- string,
- transform,
- tuple,
- unknown,
-} from 'valibot';
-import type { Result } from '../lib/result';
-import { error, ok } from '../lib/result';
-
-const weatherDataSchema = object({
- description: string(),
- icon: number(),
- link: nullable(string(), ''),
- dateTime: nullable(string()),
- temperature: object({
- metric: number(),
- imperial: number(),
- }),
-});
-export type WeatherData = Output;
-
-const weatherApiDataSchema = object({
- location: object({
- id: string(),
- city: string(),
- country: string(),
- }),
- weather: weatherDataSchema,
- /**
- * Our weather API returns 24h forecast.
- * Each forecast is 1 hour offset from the previous forecast, and the first forecast is 1 hour offset from now.
- */
- forecast: transform(
- tuple([
- unknown(),
- unknown(),
- unknown(),
- weatherDataSchema,
- unknown(),
- unknown(),
- weatherDataSchema,
- unknown(),
- unknown(),
- weatherDataSchema,
- unknown(),
- unknown(),
- weatherDataSchema,
- ]),
- (forecast) => ({
- '3h': forecast[3],
- '6h': forecast[6],
- '9h': forecast[9],
- '12h': forecast[12],
- }),
- ),
-});
-export type WeatherApiData = Output;
-
-export const parseWeatherData = (
- data: unknown,
-): Result<'Loading' | 'ParsingError', WeatherApiData> => {
- const result = safeParse(optional(weatherApiDataSchema), data);
- if (!result.success) return error('ParsingError');
- return result.output ? ok(result.output) : error('Loading');
-};