SiteHeader
This commit is contained in:
parent
e0b9da1b29
commit
6fd7b88696
11 changed files with 112 additions and 96 deletions
|
|
@ -4,13 +4,15 @@
|
|||
import { normalizeUrl } from '../NavBar/utils/index.js';
|
||||
|
||||
interface Props {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
data?: any;
|
||||
isMobileMenuOpen?: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
releaseMobileMenu?: any;
|
||||
}
|
||||
|
||||
let {
|
||||
data = [],
|
||||
data = {},
|
||||
isMobileMenuOpen = false,
|
||||
releaseMobileMenu = () => {},
|
||||
}: Props = $props();
|
||||
|
|
|
|||
|
|
@ -13,12 +13,19 @@
|
|||
<span>{story.title}</span>
|
||||
<time datetime={story.display_time}>{getTime(story.display_time)}</time>
|
||||
</div>
|
||||
{#if thumbnail}
|
||||
{#if thumbnail && (thumbnail.resizer_url || thumbnail?.renditions?.square?.['120w'])}
|
||||
<div class="thumbnail">
|
||||
<img
|
||||
src={thumbnail.renditions.square['120w']}
|
||||
alt={thumbnail.alt_text}
|
||||
/>
|
||||
{#if thumbnail.resizer_url}
|
||||
<img
|
||||
src="{thumbnail.resizer_url}&width=120&quality=80"
|
||||
alt={thumbnail.alt_text}
|
||||
/>
|
||||
{:else}
|
||||
<img
|
||||
src={thumbnail.renditions.square['120w']}
|
||||
alt={thumbnail.alt_text}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</a>
|
||||
|
|
@ -39,9 +46,6 @@
|
|||
text-decoration: none;
|
||||
.story-text span {
|
||||
text-decoration: underline;
|
||||
&.label {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,14 +66,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
span.label {
|
||||
font-size: 14px;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 8px;
|
||||
display: block;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
time {
|
||||
@include font-sans;
|
||||
margin-top: 8px;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ dayjs.updateLocale('en', {
|
|||
},
|
||||
});
|
||||
|
||||
const getTimeZone = (local) => {
|
||||
const getTimeZone = (local: boolean) => {
|
||||
if (local) {
|
||||
return dayjs.tz.guess();
|
||||
}
|
||||
|
|
@ -39,15 +39,19 @@ const getTimeZone = (local) => {
|
|||
return 'UTC';
|
||||
};
|
||||
|
||||
const diff = (dateFrom, dateTo, measurement = 'day') => {
|
||||
const diff = (
|
||||
dateFrom: Date,
|
||||
dateTo: number,
|
||||
measurement: 'day' | 'hour' = 'day'
|
||||
) => {
|
||||
return dayjs(dateFrom).diff(dayjs(dateTo), measurement, true);
|
||||
};
|
||||
|
||||
const olderThanHour = (dateFrom, dateTo, hours = 1) => {
|
||||
const olderThanHour = (dateFrom: Date, dateTo: number, hours = 1) => {
|
||||
return diff(dateFrom, dateTo, 'hour') < -hours;
|
||||
};
|
||||
|
||||
const isSameDay = (dateFrom, dateTo) => {
|
||||
const isSameDay = (dateFrom: Date, dateTo: number) => {
|
||||
const first = new Date(dateFrom);
|
||||
const second = new Date(dateTo);
|
||||
return (
|
||||
|
|
@ -57,10 +61,10 @@ const isSameDay = (dateFrom, dateTo) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const getTime = (datetime) => {
|
||||
export const getTime = (datetime: dayjs.ConfigType) => {
|
||||
const publishTime = dayjs(datetime, { utc: true });
|
||||
const showRelativeTime = !olderThanHour(publishTime, Date.now());
|
||||
const showTime = isSameDay(publishTime, Date.now());
|
||||
const showRelativeTime = !olderThanHour(publishTime.toDate(), Date.now());
|
||||
const showTime = isSameDay(publishTime.toDate(), Date.now());
|
||||
const timezone = getTimeZone(false);
|
||||
if (showRelativeTime) {
|
||||
return dayjs().to(publishTime);
|
||||
|
|
@ -1,20 +1,34 @@
|
|||
<!-- @migration-task Error while migrating Svelte code: Can't migrate code with afterUpdate. Please migrate by hand. -->
|
||||
<script>
|
||||
import { afterUpdate } from 'svelte';
|
||||
<script lang="ts">
|
||||
import StoryCard from './StoryCard/index.svelte';
|
||||
import Spinner from './Spinner/index.svelte';
|
||||
import { getContext } from 'svelte';
|
||||
import { getContext, type Snippet } from 'svelte';
|
||||
import type { Writable } from 'svelte/store';
|
||||
|
||||
const activeSection = getContext('nav-active-section');
|
||||
interface Props {
|
||||
headingText?: string;
|
||||
children: Snippet;
|
||||
}
|
||||
|
||||
export let headingText = 'Trending Stories';
|
||||
let { headingText = 'Trending Stories', children }: Props = $props();
|
||||
|
||||
let stories = [];
|
||||
let lastFetched = null;
|
||||
const activeSection =
|
||||
getContext<Writable<null | string>>('nav-active-section');
|
||||
|
||||
afterUpdate(async () => {
|
||||
if (lastFetched === $activeSection) return;
|
||||
if ($activeSection === 'more') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
let stories = $state<any[]>([]);
|
||||
let lastFetched = $state<null | string>(null);
|
||||
|
||||
$effect(() => {
|
||||
try {
|
||||
fetchSection($activeSection);
|
||||
} catch {
|
||||
console.log('Error fetching articles');
|
||||
}
|
||||
});
|
||||
|
||||
const fetchSection = async (activeSection: null | string) => {
|
||||
if (lastFetched === activeSection) return;
|
||||
if (activeSection === 'more') {
|
||||
await fetch(
|
||||
'https://www.reuters.com/pf/api/v3/content/fetch/articles-by-trends-v1?' +
|
||||
new URLSearchParams({
|
||||
|
|
@ -27,14 +41,17 @@
|
|||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
stories = data.result.articles;
|
||||
lastFetched = $activeSection;
|
||||
lastFetched = activeSection;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('Error fetching articles');
|
||||
});
|
||||
} else {
|
||||
await fetch(
|
||||
'https://www.reuters.com/pf/api/v3/content/fetch/recent-stories-by-sections-v1?' +
|
||||
new URLSearchParams({
|
||||
query: JSON.stringify({
|
||||
section_ids: $activeSection,
|
||||
section_ids: activeSection,
|
||||
size: 4,
|
||||
website: 'reuters',
|
||||
}),
|
||||
|
|
@ -43,10 +60,13 @@
|
|||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
stories = data.result.articles;
|
||||
lastFetched = $activeSection;
|
||||
lastFetched = activeSection;
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('Error fetching articles');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="dropdown">
|
||||
|
|
@ -54,7 +74,7 @@
|
|||
<div class="inner">
|
||||
<div class="submenu">
|
||||
<div class="inner">
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
</div>
|
||||
<div class="stories-container">
|
||||
|
|
|
|||
|
|
@ -4,10 +4,12 @@
|
|||
import MoreDropdown from './NavDropdown/MoreDropdown.svelte';
|
||||
import { normalizeUrl } from './utils/index';
|
||||
import { getContext } from 'svelte';
|
||||
import type { Writable } from 'svelte/store';
|
||||
|
||||
let { sections = [] } = $props();
|
||||
|
||||
const activeSection = getContext('nav-active-section');
|
||||
const activeSection =
|
||||
getContext<Writable<null | string>>('nav-active-section');
|
||||
|
||||
let windowWidth = $state(1200);
|
||||
|
||||
|
|
@ -16,7 +18,7 @@
|
|||
return 5;
|
||||
});
|
||||
|
||||
let navTimeout = $state();
|
||||
let navTimeout = $state<ReturnType<typeof setTimeout>>();
|
||||
const timeout = 250;
|
||||
|
||||
let displayCount = $derived(getDisplayCount());
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
export const normalizeUrl = (url) =>
|
||||
export const normalizeUrl = (url: string) =>
|
||||
/^http/.test(url) ? url : `https://www.reuters.com${url}`;
|
||||
33
src/components/SiteHeader/SiteHeader.mdx
Normal file
33
src/components/SiteHeader/SiteHeader.mdx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { Meta } from '@storybook/blocks';
|
||||
|
||||
import * as SiteHeaderStories from './SiteHeader.stories.svelte';
|
||||
|
||||
<Meta of={SiteHeaderStories} />
|
||||
|
||||
# SiteHeader
|
||||
|
||||
Reuters dotcom site header, ported from [Raptor UI components](https://github.com/tr/rcom-arc_raptor-ui/tree/develop/packages/rcom-raptor-ui_common/src/components/site-header).
|
||||
|
||||
> **Note:** In the Graphics Kit, you can find this component in `pages/+page.svelte`. Customise it there for the default page.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { SiteHeader } from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<SiteHeader />
|
||||
```
|
||||
|
||||
## Dark theme
|
||||
|
||||
Colours are customised by the [`Theme`](?path=/docs/theming-theme--default) component. ([Demo](?path=/story/components-page-furniture-siteheader--customised-theme))
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { SiteHeader, Theme } from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<Theme base="dark">
|
||||
<SiteHeader />
|
||||
</Theme>
|
||||
```
|
||||
|
|
@ -1,43 +1,24 @@
|
|||
<script module lang="ts">
|
||||
// @ts-ignore raw
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
// @ts-ignore raw
|
||||
import darkThemeDocs from './stories/docs/darkTheme.md?raw';
|
||||
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import SiteHeader from './SiteHeader.svelte';
|
||||
import Theme from '../Theme/Theme.svelte';
|
||||
|
||||
import {
|
||||
withComponentDocs,
|
||||
withStoryDocs,
|
||||
} from '$lib/docs/utils/withParams.js';
|
||||
|
||||
export const meta = {
|
||||
const { Story } = defineMeta({
|
||||
title: 'Components/Page furniture/SiteHeader',
|
||||
component: SiteHeader,
|
||||
...withComponentDocs(componentDocs),
|
||||
argsTypes: {
|
||||
argTypes: {
|
||||
themes: { control: { disable: true } },
|
||||
},
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { Template, Story } from '@storybook/addon-svelte-csf';
|
||||
<Story name="Demo">
|
||||
<div>
|
||||
<SiteHeader />
|
||||
</div>
|
||||
</Story>
|
||||
|
||||
import Theme from '../Theme/Theme.svelte';
|
||||
</script>
|
||||
|
||||
<Template>
|
||||
{#snippet children({ args })}
|
||||
<div>
|
||||
<SiteHeader {...args} />
|
||||
</div>
|
||||
{/snippet}
|
||||
</Template>
|
||||
|
||||
<Story name="Default" />
|
||||
|
||||
<Story name="Customised theme" {...withStoryDocs(darkThemeDocs)}>
|
||||
<Story name="Customised theme">
|
||||
<div>
|
||||
<Theme base="dark">
|
||||
<SiteHeader />
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
import MenuIcon from './svgs/Menu.svelte';
|
||||
import MobileMenu from './MobileMenu/index.svelte';
|
||||
|
||||
setContext('nav-active-section', writable(null));
|
||||
setContext('nav-active-section', writable<null | string>(null));
|
||||
|
||||
let data = $state(starterData);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
Reuters dotcom site header, ported from [Raptor UI components](https://github.com/tr/rcom-arc_raptor-ui/tree/develop/packages/rcom-raptor-ui_common/src/components/site-header).
|
||||
|
||||
> **Note:** In the Graphics Kit, you can find this component in `pages/+page.svelte`. Customise it there for the default page.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { SiteHeader } from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<SiteHeader />
|
||||
```
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
Colours are customised by the [`Theme`](?path=/docs/theming-theme--default) component.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { SiteHeader, Theme } from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<Theme base="dark">
|
||||
<SiteHeader />
|
||||
</Theme>
|
||||
```
|
||||
Loading…
Reference in a new issue