referral block
This commit is contained in:
parent
deac3476bf
commit
b065cf254d
5 changed files with 310 additions and 0 deletions
55
src/components/ReferralBlock/ReferralBlock.stories.svelte
Normal file
55
src/components/ReferralBlock/ReferralBlock.stories.svelte
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
<script>
|
||||||
|
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
|
||||||
|
|
||||||
|
// Don't lose the "?raw" in markdown imports!
|
||||||
|
// @ts-ignore
|
||||||
|
import componentDocs from './stories/docs/component.md?raw';
|
||||||
|
|
||||||
|
import ReferralBlock from './ReferralBlock.svelte';
|
||||||
|
|
||||||
|
import { withComponentDocs } from '$docs/utils/withParams.js';
|
||||||
|
|
||||||
|
const meta = {
|
||||||
|
title: 'Components/ReferralBlock',
|
||||||
|
component: ReferralBlock,
|
||||||
|
...withComponentDocs(componentDocs),
|
||||||
|
// https://storybook.js.org/docs/svelte/essentials/controls
|
||||||
|
argTypes: {
|
||||||
|
width: {
|
||||||
|
control: 'select',
|
||||||
|
options: ['normal', 'wide', 'wider', 'widest', 'fluid'],
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
control: 'select',
|
||||||
|
options: [
|
||||||
|
'/world/',
|
||||||
|
'/world/europe/',
|
||||||
|
'/lifestyle/',
|
||||||
|
'/lifestyle/sports/',
|
||||||
|
'/legal/',
|
||||||
|
'/business/',
|
||||||
|
'/business/energy/',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
number: {
|
||||||
|
control: 'select',
|
||||||
|
options: [2, 4, 6, 8],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Meta {...meta} />
|
||||||
|
|
||||||
|
<Template let:args>
|
||||||
|
<ReferralBlock {...args} />
|
||||||
|
</Template>
|
||||||
|
|
||||||
|
<Story
|
||||||
|
name="Default"
|
||||||
|
args="{{
|
||||||
|
section: '/lifestyle/sports/',
|
||||||
|
number: 4,
|
||||||
|
cls: 'my-3',
|
||||||
|
}}"
|
||||||
|
/>
|
||||||
238
src/components/ReferralBlock/ReferralBlock.svelte
Normal file
238
src/components/ReferralBlock/ReferralBlock.svelte
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
<!-- @component `ReferralBlock` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ReferralBlock--default) -->
|
||||||
|
<script lang="ts">
|
||||||
|
/** ✏️ DOCUMENT your chart's props using TypeScript and JSDoc comments like below! */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Section ID, which is often the URL path to the section page on reuters.com.
|
||||||
|
*
|
||||||
|
* Note that not all section pages will be available in the recent stories by section API.
|
||||||
|
* @required
|
||||||
|
*/
|
||||||
|
export let section: string = '/world/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of referrals to show.
|
||||||
|
* @required
|
||||||
|
*/
|
||||||
|
export let number: number = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link [target](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-target), e.g., `_blank` or `_parent`.
|
||||||
|
*/
|
||||||
|
export let linkTarget: string = '_self';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a heading to the referral block.
|
||||||
|
*/
|
||||||
|
export let heading: string = '';
|
||||||
|
|
||||||
|
type ContainerWidth = 'normal' | 'wide' | 'wider' | 'widest' | 'fluid';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Width of the component within the text well.
|
||||||
|
* @required
|
||||||
|
*/
|
||||||
|
export let width: ContainerWidth = 'wide';
|
||||||
|
|
||||||
|
/** Add an ID to target with SCSS. */
|
||||||
|
export let id: string = '';
|
||||||
|
|
||||||
|
/** Add a class to target with SCSS. */
|
||||||
|
export let cls: string = '';
|
||||||
|
|
||||||
|
import Block from '../Block/Block.svelte';
|
||||||
|
import { referrals } from './stores.js';
|
||||||
|
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { getTime } from '../SiteHeader/NavBar/NavDropdown/StoryCard/time';
|
||||||
|
|
||||||
|
let clientWidth;
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(
|
||||||
|
'https://www.reuters.com/pf/api/v3/content/fetch/recent-stories-by-sections-v1?' +
|
||||||
|
new URLSearchParams({
|
||||||
|
query: JSON.stringify({
|
||||||
|
section_ids: section,
|
||||||
|
size: 20,
|
||||||
|
website: 'reuters',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const articles = (await response.json()).result.articles
|
||||||
|
.filter((a) => a?.kicker?.name)
|
||||||
|
.filter((a) => a?.thumbnail?.renditions?.landscape?.['240w'])
|
||||||
|
.filter((a) => !a?.content?.third_party)
|
||||||
|
.slice(0, number);
|
||||||
|
referrals.set(articles);
|
||||||
|
} catch (e) {
|
||||||
|
console.warn('Unable to fetch referral links.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
getTime();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $referrals.length === number}
|
||||||
|
<Block width="{width}" id="{id}" cls="referrals-block {cls}">
|
||||||
|
{#if heading}
|
||||||
|
<h4 class:stacked="{clientWidth && clientWidth < 750}">{heading}</h4>
|
||||||
|
{/if}
|
||||||
|
<div
|
||||||
|
class="referral-container"
|
||||||
|
class:stacked="{clientWidth && clientWidth < 750}"
|
||||||
|
class:xs="{clientWidth && clientWidth < 450}"
|
||||||
|
bind:clientWidth
|
||||||
|
>
|
||||||
|
{#each $referrals as referral}
|
||||||
|
<div class="referral">
|
||||||
|
<a
|
||||||
|
href="https://www.reuters.com{referral.canonical_url}"
|
||||||
|
target="{linkTarget}"
|
||||||
|
rel="{linkTarget === '_blank' ? 'noreferrer' : null}"
|
||||||
|
>
|
||||||
|
<div class="referral-pack">
|
||||||
|
<div
|
||||||
|
class="headline"
|
||||||
|
class:xs="{clientWidth && clientWidth < 450}"
|
||||||
|
>
|
||||||
|
<div class="kicker">{referral.kicker.name}</div>
|
||||||
|
<div class="title">{referral.title}</div>
|
||||||
|
<div class="publish-time">
|
||||||
|
{getTime(new Date(referral.display_time))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="image-container"
|
||||||
|
class:xs="{clientWidth && clientWidth < 450}"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="{referral.thumbnail.renditions.landscape['240w']}"
|
||||||
|
alt="{referral.thumbnail.caption ||
|
||||||
|
referral.thumbnail.alt_text}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</Block>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../scss/fonts/mixins';
|
||||||
|
@import '../../scss/colours/thematic/tr';
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-family: var(--theme-font-family-subhed);
|
||||||
|
color: var(--theme-colour-text-primary, #404040);
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin: 0 0 5px;
|
||||||
|
font-weight: bold;
|
||||||
|
&.stacked {
|
||||||
|
max-width: 450px;
|
||||||
|
margin: 0 auto 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.referral-container {
|
||||||
|
width: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 10px 40px;
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
&.stacked {
|
||||||
|
.referral {
|
||||||
|
width: 100%;
|
||||||
|
.headline {
|
||||||
|
padding: 0 10px 0 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.referral {
|
||||||
|
display: block;
|
||||||
|
width: calc(50% - 20px);
|
||||||
|
max-width: 450px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.title {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
filter: brightness(85%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.referral-pack {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
max-width: 450px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
.headline {
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100% - 140px);
|
||||||
|
padding: 0 10px 0 0;
|
||||||
|
&.xs {
|
||||||
|
width: calc(100% - 80px);
|
||||||
|
.kicker {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.kicker {
|
||||||
|
font-family: var(--theme-font-family-subhed);
|
||||||
|
color: var(--theme-colour-text-secondary, #666666);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-family: var(--theme-font-family-subhed);
|
||||||
|
color: var(--theme-colour-text-primary, #404040);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
line-height: 1.15rem;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.publish-time {
|
||||||
|
font-family: var(--theme-font-family-subhed);
|
||||||
|
color: var(--theme-colour-text-secondary, #666666);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
margin: 2px 0 0;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.image-container {
|
||||||
|
margin: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid var(--theme-colour-brand-rules, #d0d0d0);
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
width: 140px;
|
||||||
|
height: 90px;
|
||||||
|
&.xs {
|
||||||
|
width: 80px;
|
||||||
|
height: 60px;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
transition: filter 0.1s;
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: inherit;
|
||||||
|
object-fit: cover;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
3
src/components/ReferralBlock/stores.js
Normal file
3
src/components/ReferralBlock/stores.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
export const referrals = writable([]);
|
||||||
13
src/components/ReferralBlock/stories/docs/component.md
Normal file
13
src/components/ReferralBlock/stories/docs/component.md
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
The `ReferralBlock` component creates a set of referral links from recent dotcom stories using the [recent stories by section API](https://www.reuters.com/pf/api/v3/content/fetch/recent-stories-by-sections-v1?query=%7B%22section_ids%22%3A%22%2Fworld%2F%22%2C%22size%22%3A20%2C%22website%22%3A%22reuters%22%7D).
|
||||||
|
|
||||||
|
> The `section` prop determines which section stories are from.
|
||||||
|
>
|
||||||
|
> You can get the section ID from the section page on dotcom. For example, the section ID for World - Europe stories at `www.reuters.com/world/europe/` would be `/world/europe/`. (The leading and trailing slashes are required!)
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script>
|
||||||
|
import { ReferralBlock } from '@reuters-graphics/graphics-components';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ReferralBlock section="/lifestyle/sports/" />
|
||||||
|
```
|
||||||
|
|
@ -15,6 +15,7 @@ export { default as PaddingReset } from './components/PaddingReset/PaddingReset.
|
||||||
export { default as PhotoPack } from './components/PhotoPack/PhotoPack.svelte';
|
export { default as PhotoPack } from './components/PhotoPack/PhotoPack.svelte';
|
||||||
export { default as PymChild } from './components/PymChild/PymChild.svelte';
|
export { default as PymChild } from './components/PymChild/PymChild.svelte';
|
||||||
export { pymChildStore } from './components/PymChild/stores.js';
|
export { pymChildStore } from './components/PymChild/stores.js';
|
||||||
|
export { default as ReferralBlock } from './components/ReferralBlock/ReferralBlock.svelte';
|
||||||
export { default as ReutersLogo } from './components/ReutersLogo/ReutersLogo.svelte';
|
export { default as ReutersLogo } from './components/ReutersLogo/ReutersLogo.svelte';
|
||||||
export { default as Scroller } from './components/Scroller/Scroller.svelte';
|
export { default as Scroller } from './components/Scroller/Scroller.svelte';
|
||||||
export { default as SEO } from './components/SEO/SEO.svelte';
|
export { default as SEO } from './components/SEO/SEO.svelte';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue