diff options
Diffstat (limited to 'components/Posts')
-rw-r--r-- | components/Posts/PostLink.stories.js | 21 | ||||
-rw-r--r-- | components/Posts/PostLink.vue | 74 | ||||
-rw-r--r-- | components/Posts/PostList/PostList.vue | 34 | ||||
-rw-r--r-- | components/Posts/PostList/PurePostList.stories.js | 30 | ||||
-rw-r--r-- | components/Posts/PostList/PurePostList.vue | 91 | ||||
-rw-r--r-- | components/Posts/PostList/README.md | 42 | ||||
-rw-r--r-- | components/Posts/PostList/index.js | 22 | ||||
-rw-r--r-- | components/Posts/PostList/parentMixin.js | 9 |
8 files changed, 323 insertions, 0 deletions
diff --git a/components/Posts/PostLink.stories.js b/components/Posts/PostLink.stories.js new file mode 100644 index 0000000..9b12c29 --- /dev/null +++ b/components/Posts/PostLink.stories.js @@ -0,0 +1,21 @@ +import { storiesOf } from '@storybook/vue' +import { center } from '../../.storybook/decorators' + +import PostLink from './PostLink' + +export const postLink = { + title: 'Test PostLink', + description: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pulvinar non ex non sagittis. Quisque in enim tellus. Aliquam consequat mi id sapien congue, sit amet vulputate tortor viverra. Donec.', + route: '/kronika/2019/20/11/test' +} + +storiesOf('Posts/PostLink', module) + .addDecorator(center) + .add('default', () => { + return { + components: { PostLink }, + template: `<post-link :title="title" :description="description" :route="route"/>`, + data: () => postLink + } + }) diff --git a/components/Posts/PostLink.vue b/components/Posts/PostLink.vue new file mode 100644 index 0000000..54cd934 --- /dev/null +++ b/components/Posts/PostLink.vue @@ -0,0 +1,74 @@ +<template> + <div class="post-link"> + <a :href="route"> + <div class="post-container"> + <h4 class="post-title">{{ title }}</h4> + <p class="post-description">{{ shortenedDescription }}...</p> + </div> + </a> + </div> +</template> + +<script> +export default { + name: 'PostLink', + props: { + title: { + type: String, + required: true + }, + description: { + type: String, + default: '' + }, + route: { + type: String, + required: true + } + }, + computed: { + shortenedDescription() { + const first30Words = this.description.split(' ').slice(0, 30) + return first30Words.join(' ') + } + } +} +</script> + +<style scoped> +.post-link { + margin: 20px; + flex-basis: 410px; + max-width: 410px; + /* height: 250px; */ + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.25); + background: #ffffff; + text-align: left; + transition: transform 300ms ease-in-out; +} + +.post-link:hover { + box-shadow: 0 0 20px rgba(0, 0, 0, 0.15); + transform: scale(1.02); +} + +.post-link > a { + text-decoration: none; + height: 100%; +} + +.post-link .post-container { + padding: 20px; + height: 100%; +} + +.post-link .post-title { + color: #181818; + font-size: 1.3em; +} + +.post-link .post-description { + color: #484848; + font-size: 0.9em; +} +</style> diff --git a/components/Posts/PostList/PostList.vue b/components/Posts/PostList/PostList.vue new file mode 100644 index 0000000..80369a8 --- /dev/null +++ b/components/Posts/PostList/PostList.vue @@ -0,0 +1,34 @@ +<template> + <pure-post-list v-if="posts" :posts="parsedPosts" :loading="loading" /> +</template> + +<script> +import PurePostList from './PurePostList' + +export default { + name: 'PostList', + components: { PurePostList }, + props: { + max: { + type: Number, + required: false, + default: () => 4 + }, + posts: { + type: Array, + required: false + } + }, + computed: { + parsedPosts() { + if (this.max) { + return this.posts.slice(0, this.max) + } + return this.posts + }, + loading() { + return this.posts === undefined + } + } +} +</script> diff --git a/components/Posts/PostList/PurePostList.stories.js b/components/Posts/PostList/PurePostList.stories.js new file mode 100644 index 0000000..e2c39de --- /dev/null +++ b/components/Posts/PostList/PurePostList.stories.js @@ -0,0 +1,30 @@ +import { storiesOf } from '@storybook/vue' + +import { postLink } from '../PostLink.stories' + +import PurePostList from './PurePostList' + +export const posts = Array(5).fill(postLink) + +storiesOf('Posts/PurePostList', module) + .add('default', () => { + return { + components: { PurePostList }, + template: `<pure-post-list :posts="posts"/>`, + data: () => ({ posts }) + } + }) + .add('loading', () => { + return { + components: { PurePostList }, + template: `<pure-post-list :posts="posts" loading/>`, + data: () => ({ posts: [] }) + } + }) + .add('no posts', () => { + return { + components: { PurePostList }, + template: `<pure-post-list :posts="posts"/>`, + data: () => ({ posts: [] }) + } + }) diff --git a/components/Posts/PostList/PurePostList.vue b/components/Posts/PostList/PurePostList.vue new file mode 100644 index 0000000..ace069f --- /dev/null +++ b/components/Posts/PostList/PurePostList.vue @@ -0,0 +1,91 @@ +<template> + <div class="post-list"> + <div v-if="loading" class="post-list-container"> + <div class="loading-post" v-for="(_, index) in 4" :key="index"></div> + </div> + <div v-else-if="!posts" class="no-posts">Brak wpisów</div> + <transition name="fade-in"> + <div v-if="posts && !loading" class="post-list-container"> + <post-link + v-for="(post, index) in posts" + :key="index" + :route="post.route" + :title="post.title" + :description="post.description" + /> + </div> + </transition> + </div> +</template> + +<script> +import PostLink from '../PostLink' + +export default { + name: 'PurePostList', + components: { PostLink }, + props: { + posts: { + type: Array, + required: true + }, + loading: { + type: Boolean, + required: false, + default: () => false + } + } +} +</script> + +<style scoped> +.post-list { + width: 100%; + max-width: 900px; + justify-content: center; + margin: 0 auto; +} + +.post-list-container { + display: flex; + flex-wrap: wrap; + justify-content: center; +} + +@keyframes loading { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +.loading-post { + background: #efefef; + animation: loading 1.5s ease-in-out infinite; + margin: 20px; + flex-basis: 410px; + width: 410px; + height: 250px; + text-align: left; +} + +.no-posts { + text-align: center; +} + +@keyframes fade-in { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} + +.fade-in-enter-active { + animation: fade-in 0.3s reverse; +} +</style> diff --git a/components/Posts/PostList/README.md b/components/Posts/PostList/README.md new file mode 100644 index 0000000..839f9c2 --- /dev/null +++ b/components/Posts/PostList/README.md @@ -0,0 +1,42 @@ +## PostList + +This component creates a list of posts + +### Usage + +```html +<template> + <post-list :posts="posts"> +</template> + +<script> +import PostList, { getPosts } from '~/components/Posts/PostList'; + +export default { + components: { PostList }, + async asyncData() { + return { + posts: await getPosts() + } + } +} +</script> +``` + +Or by using the mixin + +```html +<template> + <post-list :posts="posts"> +</template> + +<script> +import PostList from '~/components/Posts/PostList'; +import postListParentMixin from '~/components/Posts/PostList/parentMixin'; + +export default { + components: { PostList }, + mixins: [postListParentMixin] +} +</script> +``` diff --git a/components/Posts/PostList/index.js b/components/Posts/PostList/index.js new file mode 100644 index 0000000..11d44ff --- /dev/null +++ b/components/Posts/PostList/index.js @@ -0,0 +1,22 @@ +import axios from 'axios' + +import k from '~/api' +import PostList from './PostList' + +export const getPosts = async () => { + if (process.client) { + let posts = await axios.get(`${window.location.origin}/api/posts.json`) + return parsePosts(posts.data) + } else { + return parsePosts(k.getPosts()) + } +} + +export const parsePosts = posts => + posts.map(post => ({ + title: post.content.meta.title, + description: post.content.description, + route: post.route + })) + +export default PostList diff --git a/components/Posts/PostList/parentMixin.js b/components/Posts/PostList/parentMixin.js new file mode 100644 index 0000000..e5b06ed --- /dev/null +++ b/components/Posts/PostList/parentMixin.js @@ -0,0 +1,9 @@ +import { getPosts } from './index' + +export default { + async asyncData() { + return { + posts: await getPosts() + } + } +} |