about summary refs log tree commit diff
path: root/components/Posts
diff options
context:
space:
mode:
Diffstat (limited to 'components/Posts')
-rw-r--r--components/Posts/PostLink.stories.js21
-rw-r--r--components/Posts/PostLink.vue74
-rw-r--r--components/Posts/PostList/PostList.vue34
-rw-r--r--components/Posts/PostList/PurePostList.stories.js30
-rw-r--r--components/Posts/PostList/PurePostList.vue91
-rw-r--r--components/Posts/PostList/README.md42
-rw-r--r--components/Posts/PostList/index.js22
-rw-r--r--components/Posts/PostList/parentMixin.js9
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()
+    }
+  }
+}