add post preview card

This commit is contained in:
michey 2021-05-07 21:00:01 +03:00
parent 58c880bf18
commit a6a7eaf20c
No known key found for this signature in database
GPG Key ID: 7D4BF433F4970657
19 changed files with 318 additions and 4 deletions

View File

@ -1,6 +1,6 @@
import { storiesOf } from '@storybook/react';
import PersonalCard from './PersonalCard';
storiesOf('Components/Personal Card', module).add('with emoji', () => {
storiesOf('Components/Personal Card', module).add('static', () => {
return <PersonalCard />;
});

View File

@ -2,7 +2,6 @@ import * as React from 'react';
import '@fortawesome/fontawesome-svg-core';
import { faEnvelope } from '@fortawesome/free-solid-svg-icons';
import {
faTelegram,
faTwitter,
faGithub,
faLinkedin,
@ -32,7 +31,7 @@ const ContactComp = ({ id, type }: Contact) => {
return (
<div className={'p-3'}>
<a
className={'text-5xl text-gray-600' + ' ' + iconDescr[1]}
className={'text-5xl text-gray-500' + ' ' + iconDescr[1]}
href={contactToLink({ id, type })}
target="_blank">
<FontAwesomeIcon key={type} icon={iconDescr[0]} />

View File

@ -0,0 +1,56 @@
import { storiesOf } from '@storybook/react';
// import { DateTime } from 'luxon';
// import PostOverviewCard, { PostOverviewCardProps } from './PostOverviewCard';
// storiesOf('Components/Post Overview Card', module)
// .add('static', () => {
// const defaultPreview: PostOverviewCardProps = {
// createdAt: DateTime.now(),
// createdBy: {
// name: 'fido_node',
// avatar: 'avatar.jpg'
// },
// path: '/blog/asdasdasdasd',
// title: 'Awesome title',
// preview: {},
// tags: [{ text: 'asdf' }, { text: 'ghjkl' }, { text: 'qwertyuioio' }]
// };
// return <PostOverviewCard {...defaultPreview} />;
// })
// .add('with preview', () => {
// const defaultPreview: PostOverviewCardProps = {
// createdAt: DateTime.now(),
// createdBy: {
// name: 'fido_node',
// avatar: 'avatar.jpg'
// },
// path: '/blog/asdasdasdasd',
// title: 'Awesome title',
// preview: {
// headerMedia: {
// key: 'Image',
// url: './pattern.png',
// alt: 'awesome pattern'
// }
// },
// tags: [{ text: 'asdf' }, { text: 'ghjkl' }, { text: 'qwertyuioio' }]
// };
// return <PostOverviewCard {...defaultPreview} />;
// })
// .add('without tags', () => {
// const defaultPreview: PostOverviewCardProps = {
// createdAt: DateTime.now(),
// createdBy: {
// name: 'fido_node',
// avatar: 'avatar.jpg'
// },
// path: '/blog/asdasdasdasd',
// title: 'Awesome title',
// preview: {},
// tags: []
// };
// return <PostOverviewCard {...defaultPreview} />;
// });

View File

@ -0,0 +1,8 @@
import * as React from 'react';
import { PostOverviewCardProps } from '../post-overview/PostOverviewCard';
export type PostFeedProps = {
posts: PostOverviewCardProps[];
};
export default ({ posts }: PostFeedProps) => <div></div>;

View File

@ -0,0 +1,61 @@
import { storiesOf } from '@storybook/react';
import { DateTime } from 'luxon';
import PostOverviewCard, { PostOverviewCardProps } from './PostOverviewCard';
storiesOf('Components/Post Overview Card', module)
.add('static', () => {
const defaultPreview: PostOverviewCardProps = {
createdAt: DateTime.now(),
createdBy: {
name: 'fido_node',
avatar: 'avatar.jpg'
},
path: '/blog/asdasdasdasd',
title: ' The Ultimate Web Developer Resources List 🔥Awesome 200+ Resources',
preview: {},
tags: [{ text: 'asdf' }, { text: 'ghjkl' }, { text: 'qwertyuioio' }]
};
return <PostOverviewCard {...defaultPreview} />;
})
.add('with preview', () => {
const defaultPreview: PostOverviewCardProps = {
createdAt: DateTime.now(),
createdBy: {
name: 'fido_node',
avatar: 'avatar.jpg'
},
path: '/blog/asdasdasdasd',
title: 'How to create your personal static blog and do not lost your mind. 🔥',
preview: {
headerMedia: {
key: 'Image',
url: './pattern.png',
alt: 'awesome pattern'
}
},
tags: [
{ text: 'next.js' },
{ text: 'typescript' },
{ text: 'tailwind' },
{ text: 'storybook' }
]
};
return <PostOverviewCard {...defaultPreview} />;
})
.add('without tags', () => {
const defaultPreview: PostOverviewCardProps = {
createdAt: DateTime.now(),
createdBy: {
name: 'fido_node',
avatar: 'avatar.jpg'
},
path: '/blog/asdasdasdasd',
title: ' The Ultimate Web Developer Resources List 🔥Awesome 200+ Resources',
preview: {},
tags: []
};
return <PostOverviewCard {...defaultPreview} />;
});

View File

@ -0,0 +1,50 @@
import { DateTime } from 'luxon';
import * as React from 'react';
import { PostBody, Preview, Tag } from '../../src/posts/post';
import { User } from '../../src/user/user';
import { isDefined } from '../../src/util/types';
import Avatar from './elements/Avatar';
import NameAndData from './elements/NameAndData';
import Share from './elements/Share';
import Tags from './elements/Tags';
export type PostOverviewCardProps = {
createdAt: DateTime;
createdBy: User;
path: string;
title: string;
preview: Preview;
tags: Tag[];
};
export default ({ createdBy, createdAt, title, tags, path, preview }: PostOverviewCardProps) => (
<div className={'flex flex-col border rounded-2xl border-gray-300 overflow-hidden max-w-4xl'}>
{isDefined(preview.headerMedia) ? (
<img
src={preview.headerMedia.url}
alt={preview.headerMedia.alt}
className={'object-cover h-52 w-full'}></img>
) : null}
<div className={'flex flex-row pt-2 pl-2'}>
<Avatar imgUrl={createdBy.avatar} />
<NameAndData name={createdBy.name} date={createdAt} />
</div>
<div className={'flex flex-row px-16'}>
<a className={'text-4xl font-bold hover:text-purple-500 '} href={path}>
{title}
</a>
</div>
{tags.length > 0 ? (
<div className={'flex flex-row pl-16 pt-2'}>
<Tags tags={tags} />
</div>
) : null}
<div className={'flex flex-row px-16 self-end'}>
<Share link={path} text={title} />
</div>
<div className={'flex flex-row pl-16 pb-6'}></div>
</div>
);

View File

@ -0,0 +1,9 @@
import * as React from 'react';
type Props = {
imgUrl: string;
};
export default ({ imgUrl }: Props) => (
<img src={imgUrl} className={'border rounded-full w-10 h-10 m-2'}></img>
);

View File

@ -0,0 +1,16 @@
import { DateTime } from 'luxon';
import * as React from 'react';
type Props = {
name: string;
date: DateTime;
};
export default ({ name, date }: Props) => (
<div className="flex-row pt-1 text-gray-500">
<div className={'hover:text-black'}>{name}</div>
<div className={'text-sm hover:text-black'}>
{date.toLocaleString({ month: 'long', day: 'numeric' })}
</div>
</div>
);

View File

@ -0,0 +1,31 @@
import { DateTime } from 'luxon';
import * as React from 'react';
import { faTwitter } from '@fortawesome/free-brands-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
const twitterShareLink = 'https://twitter.com/intent/tweet';
type Props = {
link: string;
text: string;
};
function buildTwitterShareLink(link: string, text: string): string {
return `${twitterShareLink}?text=${escape(text.slice(0, 279))}&url=${encodeURI(link)}`;
}
export default ({ link, text }: Props) => {
const twitterUrl = buildTwitterShareLink(link, text);
return (
<div className={'text-gray-500 flex flex-row space-x-3 items-center'}>
<div>Share:</div>
<a
className={'text-blue-500 hover:text-blue-700 text-3xl '}
href={twitterUrl}
target="_blank">
<FontAwesomeIcon icon={faTwitter} />
</a>
</div>
);
};

View File

@ -0,0 +1,16 @@
import * as React from 'react';
import { Tag } from '../../../src/posts/post';
type Props = {
tags: Tag[];
};
export default ({ tags }: Props) => (
<div className={'flex flex-row py-2 space-x-2'}>
{tags.map((t) => (
<div className={'flex rounded-md text-sm text-gray-500 hover:text-black underline'}>
<a>{'#' + t.text}</a>
</div>
))}
</div>
);

View File

@ -7,7 +7,7 @@
"export": "next build && next export",
"build": "next build",
"start": "next start",
"storybook": "start-storybook -s ./public -p 6006 ",
"storybook": "start-storybook -s ./story-static -p 6006 ",
"build-storybook": "build-storybook"
},
"dependencies": {
@ -15,6 +15,9 @@
"@fortawesome/free-brands-svg-icons": "^5.15.3",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.14",
"@types/luxon": "^1.26.5",
"install": "^0.13.0",
"luxon": "^1.26.0",
"next": "^10.1.0",
"react": "17.0.1",
"react-dom": "17.0.1"

4
src/posts/paging.ts Normal file
View File

@ -0,0 +1,4 @@
export type Paging = {
totalPages: number;
currentPage: number;
};

39
src/posts/post.ts Normal file
View File

@ -0,0 +1,39 @@
import { DateTime } from 'luxon';
import { User } from '../user/user';
export type Post = {
createdAt: DateTime;
createdBy: User;
title: string;
preview: Preview;
tags: Tag[];
postBody: PostBody;
};
export type Preview = {
readTime?: number;
headerMedia?: MediaElement;
};
export type Tag = {
text: string;
};
export type PostBody = {
elements: Element[];
};
type Paragraph = {
key: 'Paragraph';
text: string;
};
type Image = {
key: 'Image';
url: string;
alt: string;
};
type MediaElement = Image;
type Element = Paragraph | MediaElement;

4
src/user/user.ts Normal file
View File

@ -0,0 +1,4 @@
export type User = {
name: string;
avatar: string;
};

3
src/util/types.ts Normal file
View File

@ -0,0 +1,3 @@
export function isDefined<T>(t: T | undefined | null): t is T {
return t != null && typeof t !== undefined;
}

BIN
story-static/avatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
story-static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
story-static/pattern.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@ -2334,6 +2334,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
"@types/luxon@^1.26.5":
version "1.26.5"
resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-1.26.5.tgz#843fb705e16e4d2a90847a351b799ea9d879859e"
integrity sha512-XeQxxRMyJi1znfzHw4CGDLyup/raj84SnjjkI2fDootZPGlB0yqtvlvEIAmzHDa5wiEI5JJevZOWxpcofsaV+A==
"@types/markdown-to-jsx@^6.11.3":
version "6.11.3"
resolved "https://registry.yarnpkg.com/@types/markdown-to-jsx/-/markdown-to-jsx-6.11.3.tgz#cdd1619308fecbc8be7e6a26f3751260249b020e"
@ -6237,6 +6242,11 @@ inline-style-parser@0.1.1:
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==
install@^0.13.0:
version "0.13.0"
resolved "https://registry.yarnpkg.com/install/-/install-0.13.0.tgz#6af6e9da9dd0987de2ab420f78e60d9c17260776"
integrity sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==
internal-slot@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
@ -7174,6 +7184,11 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"
luxon@^1.26.0:
version "1.26.0"
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.26.0.tgz#d3692361fda51473948252061d0f8561df02b578"
integrity sha512-+V5QIQ5f6CDXQpWNICELwjwuHdqeJM1UenlZWx5ujcRMc9venvluCjFb4t5NYLhb6IhkbMVOxzVuOqkgMxee2A==
make-dir@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"