updated Byline, added snippet examples
This commit is contained in:
parent
9b555434b4
commit
607e4af159
3 changed files with 111 additions and 85 deletions
|
|
@ -6,7 +6,7 @@ import * as BylineStories from './Byline.stories.svelte';
|
||||||
|
|
||||||
# Byline
|
# Byline
|
||||||
|
|
||||||
Easily add a byline and dateline.
|
Easily add a byline and dateline to your story.
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script>
|
<script>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,11 @@
|
||||||
<script module lang="ts">
|
<script module lang="ts">
|
||||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
import Byline from './Byline.svelte';
|
import Byline from './Byline.svelte';
|
||||||
// @ts-ignore raw
|
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
|
||||||
|
|
||||||
import { withComponentDocs } from '$docs/utils/withParams.js';
|
|
||||||
|
|
||||||
import type { ComponentProps } from 'svelte';
|
|
||||||
|
|
||||||
const { Story } = defineMeta({
|
const { Story } = defineMeta({
|
||||||
title: 'Components/Text elements/Byline',
|
title: 'Components/Text elements/Byline',
|
||||||
component: Byline,
|
component: Byline,
|
||||||
...withComponentDocs(componentDocs),
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
align: {
|
align: {
|
||||||
control: 'select',
|
control: 'select',
|
||||||
|
|
@ -21,17 +15,12 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet template(args: ComponentProps<Byline>)}
|
|
||||||
<Byline {...args} />
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
<Story
|
<Story
|
||||||
name="Default"
|
name="Default"
|
||||||
args={{
|
args={{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
authors: [
|
authors: [
|
||||||
'Dea Bankova',
|
'Dea Bankova',
|
||||||
'Aditi Bhandari',
|
|
||||||
'Prasanta Kumar Dutta',
|
'Prasanta Kumar Dutta',
|
||||||
'Anurag Rao',
|
'Anurag Rao',
|
||||||
'Mariano Zafra',
|
'Mariano Zafra',
|
||||||
|
|
@ -39,5 +28,20 @@
|
||||||
publishTime: new Date('2021-09-12').toISOString(),
|
publishTime: new Date('2021-09-12').toISOString(),
|
||||||
updateTime: new Date('2021-09-12T13:57:00').toISOString(),
|
updateTime: new Date('2021-09-12T13:57:00').toISOString(),
|
||||||
}}
|
}}
|
||||||
children={template}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Story name="Custom datelines">
|
||||||
|
<Byline
|
||||||
|
authors={['Reuters Graphics staff']}
|
||||||
|
getAuthorPage={() => `https://www.reuters.com/graphics/`}
|
||||||
|
publishTime="2021-09-12T00:00:00Z"
|
||||||
|
updateTime="2021-09-12T13:57:00Z"
|
||||||
|
>
|
||||||
|
{#snippet customPublished()}
|
||||||
|
PUBLISHED on some custom date and time
|
||||||
|
{/snippet}
|
||||||
|
{#snippet customUpdated()}
|
||||||
|
<em>Updated every 5 minutes</em>
|
||||||
|
{/snippet}
|
||||||
|
</Byline>
|
||||||
|
</Story>
|
||||||
|
|
|
||||||
|
|
@ -4,63 +4,86 @@
|
||||||
import Block from '../Block/Block.svelte';
|
import Block from '../Block/Block.svelte';
|
||||||
import slugify from 'slugify';
|
import slugify from 'slugify';
|
||||||
import { apdate } from 'journalize';
|
import { apdate } from 'journalize';
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/**
|
||||||
|
* Array of author names, which will be slugified to create links to Reuters author pages
|
||||||
|
*/
|
||||||
|
authors: string[];
|
||||||
|
/**
|
||||||
|
* Publish time as a datetime string.
|
||||||
|
*/
|
||||||
|
publishTime: string;
|
||||||
|
/**
|
||||||
|
* Update time as a datetime string.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
updateTime: string;
|
||||||
|
/**
|
||||||
|
* Alignment of the byline.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
align?: 'left' | 'center';
|
||||||
|
/**
|
||||||
|
* Add an id to to target with custom CSS.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
id?: string;
|
||||||
|
/**
|
||||||
|
* Add extra classes to target with custom CSS.
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
cls?: string;
|
||||||
|
/**
|
||||||
|
* Custom function that returns an author page URL.
|
||||||
|
*/
|
||||||
|
getAuthorPage?: (author: string) => string;
|
||||||
|
/**
|
||||||
|
* Optional snippet for a custom published dateline.
|
||||||
|
*/
|
||||||
|
// Specify that this prop should have the type of a Svelte snippet, i.e. basic html
|
||||||
|
customPublished?: Snippet | null;
|
||||||
|
/**
|
||||||
|
* Optional snippet for a custom updated dateline.
|
||||||
|
*/
|
||||||
|
customUpdated?: Snippet | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let {
|
||||||
|
authors = [],
|
||||||
|
publishTime = '',
|
||||||
|
updateTime = '',
|
||||||
|
align = 'left',
|
||||||
|
id = '',
|
||||||
|
cls = '',
|
||||||
|
getAuthorPage = (author: string): string => {
|
||||||
|
const authorSlug = slugify(author.trim(), { lower: true });
|
||||||
|
return `https://www.reuters.com/authors/${authorSlug}/`;
|
||||||
|
},
|
||||||
|
customPublished = null,
|
||||||
|
customUpdated = null,
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
|
let alignmentClass = $derived(align === 'left' ? 'text-left' : 'text-center');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of author names, which will be slugified to create links to Reuters author pages
|
/* Date validation and formatter functions
|
||||||
*/
|
*/
|
||||||
export let authors: string[] = [];
|
const isValidDate = (datetime: string) => {
|
||||||
/**
|
|
||||||
* Publish time as a datetime string.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export let publishTime: string = '';
|
|
||||||
/**
|
|
||||||
* Update time as a datetime string.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export let updateTime: string = '';
|
|
||||||
/**
|
|
||||||
* Alignment of the byline.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export let align: 'left' | 'center' = 'left';
|
|
||||||
/**
|
|
||||||
* Add an id to to target with custom CSS.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export let id: string = '';
|
|
||||||
/**
|
|
||||||
* Add extra classes to target with custom CSS.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
let cls: string = '';
|
|
||||||
export { cls as class };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Custom function that returns an author page URL.
|
|
||||||
* @param author
|
|
||||||
*/
|
|
||||||
export let getAuthorPage = (author: string): string => {
|
|
||||||
const authorSlug = slugify(author.trim(), { lower: true });
|
|
||||||
return `https://www.reuters.com/authors/${authorSlug}/`;
|
|
||||||
};
|
|
||||||
|
|
||||||
$: alignmentClass = align === 'left' ? 'text-left' : 'text-center';
|
|
||||||
|
|
||||||
const isValidDate = (datetime) => {
|
|
||||||
if (!datetime) return false;
|
if (!datetime) return false;
|
||||||
if (!Date.parse(datetime)) return false;
|
if (!Date.parse(datetime)) return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTime = (datetime) =>
|
const formatTime = (datetime: string) =>
|
||||||
new Date(datetime).toLocaleTimeString([], {
|
new Date(datetime).toLocaleTimeString([], {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
timeZoneName: 'short',
|
timeZoneName: 'short',
|
||||||
});
|
});
|
||||||
|
|
||||||
const areSameDay = (first, second) =>
|
const areSameDay = (first: Date, second: Date) =>
|
||||||
first.getFullYear() === second.getFullYear() &&
|
first.getFullYear() === second.getFullYear() &&
|
||||||
first.getMonth() === second.getMonth() &&
|
first.getMonth() === second.getMonth() &&
|
||||||
first.getDate() === second.getDate();
|
first.getDate() === second.getDate();
|
||||||
|
|
@ -69,41 +92,38 @@
|
||||||
<Block {id} class="byline-container {alignmentClass} {cls}" width="normal">
|
<Block {id} class="byline-container {alignmentClass} {cls}" width="normal">
|
||||||
<aside class="article-metadata font-subhed">
|
<aside class="article-metadata font-subhed">
|
||||||
<div class="byline body-caption fmb-1">
|
<div class="byline body-caption fmb-1">
|
||||||
{#if $$slots.byline}
|
By
|
||||||
<!-- Custom byline -->
|
{#if authors.length > 0}
|
||||||
<slot name="byline" />
|
{#each authors as author, i}
|
||||||
{:else}
|
|
||||||
By
|
|
||||||
{#if authors.length > 0}
|
|
||||||
{#each authors as author, i}
|
|
||||||
<a
|
|
||||||
class="no-underline whitespace-nowrap text-primary font-bold"
|
|
||||||
href="{getAuthorPage(author)}"
|
|
||||||
rel="author"
|
|
||||||
>
|
|
||||||
{author.trim()}</a
|
|
||||||
>{#if authors.length > 1 && i < authors.length - 2},{/if}
|
|
||||||
{#if authors.length > 1 && i === authors.length - 2}and {/if}
|
|
||||||
{/each}
|
|
||||||
{:else}
|
|
||||||
<a
|
<a
|
||||||
href="https://www.reuters.com"
|
|
||||||
class="no-underline whitespace-nowrap text-primary font-bold"
|
class="no-underline whitespace-nowrap text-primary font-bold"
|
||||||
>Reuters</a
|
href={getAuthorPage(author)}
|
||||||
|
rel="author"
|
||||||
>
|
>
|
||||||
{/if}
|
{author.trim()}</a
|
||||||
|
>{#if authors.length > 1 && i < authors.length - 2},{/if}
|
||||||
|
{#if authors.length > 1 && i === authors.length - 2}and {/if}
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
<a
|
||||||
|
href="https://www.reuters.com"
|
||||||
|
class="no-underline whitespace-nowrap text-primary font-bold"
|
||||||
|
>Reuters</a
|
||||||
|
>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="dateline body-caption fmt-0">
|
<div class="dateline body-caption fmt-0">
|
||||||
{#if $$slots.published}
|
{#if customPublished}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
<!-- Custom published dateline -->
|
<!-- Custom published dateline snippet -->
|
||||||
<slot name="published" />
|
<time datetime={publishTime}>
|
||||||
|
{@render customPublished()}
|
||||||
|
</time>
|
||||||
</div>
|
</div>
|
||||||
{:else if isValidDate(publishTime)}
|
{:else if isValidDate(publishTime)}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
Published
|
Published
|
||||||
<time datetime="{publishTime}">
|
<time datetime={publishTime}>
|
||||||
{#if isValidDate(updateTime)}
|
{#if isValidDate(updateTime)}
|
||||||
{apdate(new Date(publishTime))}
|
{apdate(new Date(publishTime))}
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -114,15 +134,17 @@
|
||||||
</time>
|
</time>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $$slots.updated}
|
{#if customUpdated}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
<!-- Custom updated dateline -->
|
<!-- Custom updated dateline snippet -->
|
||||||
<slot name="updated" />
|
<time datetime={updateTime}>
|
||||||
|
{@render customUpdated()}
|
||||||
|
</time>
|
||||||
</div>
|
</div>
|
||||||
{:else if isValidDate(publishTime) && isValidDate(updateTime)}
|
{:else if isValidDate(publishTime) && isValidDate(updateTime)}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
Last updated
|
Last updated
|
||||||
<time datetime="{updateTime}">
|
<time datetime={updateTime}>
|
||||||
{#if areSameDay(new Date(publishTime), new Date(updateTime))}
|
{#if areSameDay(new Date(publishTime), new Date(updateTime))}
|
||||||
{formatTime(updateTime)}
|
{formatTime(updateTime)}
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue