refactor PostCard (wip)

This commit is contained in:
Alina Beck 2020-02-11 09:20:45 +01:00
parent cea538e2f1
commit 6671d893e6
5 changed files with 131 additions and 134 deletions

View File

@ -8,7 +8,7 @@
size="small" size="small"
circle circle
ghost ghost
@click="toggleMenu" @click.prevent="toggleMenu()"
/> />
</slot> </slot>
</template> </template>

View File

@ -63,7 +63,7 @@ describe('Notification', () => {
it('renders reason', () => { it('renders reason', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.find('.reason-text-for-test').text()).toEqual( expect(wrapper.find('.notification > .description').text()).toEqual(
'notifications.reason.commented_on_post', 'notifications.reason.commented_on_post',
) )
}) })
@ -79,9 +79,9 @@ describe('Notification', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.') expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.')
}) })
it('has no class "read"', () => { it('has no class "--read"', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.classes()).not.toContain('read') expect(wrapper.classes()).not.toContain('--read')
}) })
describe('that is read', () => { describe('that is read', () => {
@ -90,8 +90,8 @@ describe('Notification', () => {
wrapper = Wrapper() wrapper = Wrapper()
}) })
it('has class "read"', () => { it('has class "--read"', () => {
expect(wrapper.classes()).toContain('read') expect(wrapper.classes()).toContain('--read')
}) })
}) })
}) })
@ -113,7 +113,7 @@ describe('Notification', () => {
it('renders reason', () => { it('renders reason', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.find('.reason-text-for-test').text()).toEqual( expect(wrapper.find('.notification > .description').text()).toEqual(
'notifications.reason.mentioned_in_post', 'notifications.reason.mentioned_in_post',
) )
}) })
@ -125,9 +125,9 @@ describe('Notification', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.text()).toContain('@jenny-rostock is the best on this post.') expect(wrapper.text()).toContain('@jenny-rostock is the best on this post.')
}) })
it('has no class "read"', () => { it('has no class "--read"', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.classes()).not.toContain('read') expect(wrapper.classes()).not.toContain('--read')
}) })
describe('that is read', () => { describe('that is read', () => {
@ -136,8 +136,8 @@ describe('Notification', () => {
wrapper = Wrapper() wrapper = Wrapper()
}) })
it('has class "read"', () => { it('has class "--read"', () => {
expect(wrapper.classes()).toContain('read') expect(wrapper.classes()).toContain('--read')
}) })
}) })
}) })
@ -163,7 +163,7 @@ describe('Notification', () => {
it('renders reason', () => { it('renders reason', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.find('.reason-text-for-test').text()).toEqual( expect(wrapper.find('.notification > .description').text()).toEqual(
'notifications.reason.mentioned_in_comment', 'notifications.reason.mentioned_in_comment',
) )
}) })
@ -182,9 +182,9 @@ describe('Notification', () => {
expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.') expect(wrapper.text()).toContain('@dagobert-duck is the best on this comment.')
}) })
it('has no class "read"', () => { it('has no class "--read"', () => {
wrapper = Wrapper() wrapper = Wrapper()
expect(wrapper.classes()).not.toContain('read') expect(wrapper.classes()).not.toContain('--read')
}) })
describe('that is read', () => { describe('that is read', () => {
@ -193,8 +193,8 @@ describe('Notification', () => {
wrapper = Wrapper() wrapper = Wrapper()
}) })
it('has class "read"', () => { it('has class "--read"', () => {
expect(wrapper.classes()).toContain('read') expect(wrapper.classes()).toContain('--read')
}) })
}) })
}) })

View File

@ -1,5 +1,5 @@
<template> <template>
<article :class="{ read: notification.read, notification: true }"> <article :class="{ '--read': notification.read, notification: true }">
<client-only> <client-only>
<user-teaser :user="from.author" :date-time="from.createdAt" /> <user-teaser :user="from.author" :date-time="from.createdAt" />
</client-only> </client-only>
@ -63,6 +63,10 @@ export default {
margin-top: $space-x-small; margin-top: $space-x-small;
} }
&.--read {
opacity: 0.5;
}
.user-teaser { .user-teaser {
margin-bottom: $space-x-small; margin-bottom: $space-x-small;
} }

View File

@ -73,7 +73,7 @@ describe('NotificationList.vue', () => {
describe('click on a notification', () => { describe('click on a notification', () => {
beforeEach(() => { beforeEach(() => {
wrapper.find('.notification-mention-post').trigger('click') wrapper.find('.notification > .link').trigger('click')
}) })
it("emits 'markAsRead' with the id of the notification source", () => { it("emits 'markAsRead' with the id of the notification source", () => {

View File

@ -1,68 +1,44 @@
<template> <template>
<ds-card <nuxt-link
:lang="post.language" class="post-teaser"
:image="post.image | proxyApiUrl" :to="{ name: 'post-id-slug', params: { id: post.id, slug: post.slug } }"
:class="{
'post-card': true,
'disabled-content': post.disabled,
'--pinned': isPinned,
'--blur-image': post.imageBlurred,
}"
> >
<!-- Post Link Target --> <base-card
<nuxt-link :lang="post.language"
class="post-link" :class="{
:to="{ name: 'post-id-slug', params: { id: post.id, slug: post.slug } }" 'post-card': true,
'disabled-content': post.disabled,
'--pinned': isPinned,
'--blur-image': post.imageBlurred,
}"
> >
{{ post.title }} <div class="card-image">
</nuxt-link> <img :src="post.image | proxyApiUrl" class="image" />
<ds-space margin-bottom="small" /> </div>
<!-- Username, Image & Date of Post -->
<div class="user-wrapper">
<client-only> <client-only>
<user-teaser :user="post.author" :date-time="post.createdAt" /> <user-teaser :user="post.author" :date-time="post.createdAt" />
</client-only> </client-only>
<hc-ribbon v-if="isPinned" class="ribbon--pinned" :text="$t('post.pinned')" /> <h2 class="card-heading hyphentate-text">{{ post.title }}</h2>
<hc-ribbon v-else :text="$t('post.name')" /> <!-- TODO: replace editor content with tiptap render view -->
</div> <!-- eslint-disable vue/no-v-html -->
<ds-space margin-bottom="small" /> <div class="content hyphenate-text" v-html="excerpt" />
<!-- Post Title --> <!-- eslint-enable vue/no-v-html -->
<ds-heading tag="h3" class="hyphenate-text post-title">{{ post.title }}</ds-heading> <footer class="footer">
<ds-space margin-bottom="small" /> <div class="categories">
<!-- Post Content Excerpt --> <hc-category
<!-- eslint-disable vue/no-v-html --> v-for="category in post.categories"
<!-- TODO: replace editor content with tiptap render view --> :key="category.id"
<div class="hc-editor-content hyphenate-text" v-html="excerpt" /> v-tooltip="{
<!-- eslint-enable vue/no-v-html --> content: $t(`contribution.category.name.${category.slug}`),
<!-- Footer o the Post --> placement: 'bottom-start',
<template slot="footer"> delay: { show: 500 },
<div style="display: inline-block; opacity: .5;"> }"
<!-- Categories --> :icon="category.icon"
<hc-category />
v-for="category in post.categories" </div>
:key="category.id" <counter-icon icon="bullhorn" :count="post.shoutedCount" />
v-tooltip="{ <counter-icon icon="comments" :count="post.commentsCount" />
content: $t(`contribution.category.name.${category.slug}`), <client-only>
placement: 'bottom-start',
delay: { show: 500 },
}"
:icon="category.icon"
/>
</div>
<client-only>
<div style="display: inline-block; float: right">
<!-- Shouts Count -->
<span :style="{ opacity: post.shoutedCount ? 1 : 0.5 }">
<base-icon name="bullhorn" />
<small>{{ post.shoutedCount }}</small>
</span>
&nbsp;
<!-- Comments Count -->
<span :style="{ opacity: post.commentsCount ? 1 : 0.5 }">
<base-icon name="comments" />
<small>{{ post.commentsCount }}</small>
</span>
<!-- Menu -->
<content-menu <content-menu
resource-type="contribution" resource-type="contribution"
:resource="post" :resource="post"
@ -71,10 +47,14 @@
@pinPost="pinPost" @pinPost="pinPost"
@unpinPost="unpinPost" @unpinPost="unpinPost"
/> />
</div> </client-only>
</client-only> </footer>
</template> </base-card>
</ds-card> <hc-ribbon
:class="{ '--pinned': isPinned }"
:text="isPinned ? $t('post.pinned') : $t('post.name')"
/>
</nuxt-link>
</template> </template>
<script> <script>
@ -82,7 +62,7 @@ import UserTeaser from '~/components/UserTeaser/UserTeaser'
import ContentMenu from '~/components/ContentMenu/ContentMenu' import ContentMenu from '~/components/ContentMenu/ContentMenu'
import HcCategory from '~/components/Category' import HcCategory from '~/components/Category'
import HcRibbon from '~/components/Ribbon' import HcRibbon from '~/components/Ribbon'
// import { randomBytes } from 'crypto' import CounterIcon from '~/components/_new/generic/CounterIcon/CounterIcon'
import { mapGetters } from 'vuex' import { mapGetters } from 'vuex'
import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers' import { postMenuModalsData, deletePostMutation } from '~/components/utils/PostHelpers'
@ -93,6 +73,7 @@ export default {
HcCategory, HcCategory,
HcRibbon, HcRibbon,
ContentMenu, ContentMenu,
CounterIcon,
}, },
props: { props: {
post: { post: {
@ -157,63 +138,75 @@ export default {
} }
</script> </script>
<style lang="scss"> <style lang="scss">
.post-card { .post-teaser,
justify-content: space-between; .post-teaser:hover,
.post-teaser:active {
position: relative; position: relative;
z-index: 1; display: block;
cursor: pointer; height: 100%;
color: $text-color-base;
&.--pinned { .user-teaser {
border: 1px solid $color-warning; margin-bottom: $space-small;
} }
&.--blur-image > .ds-card-image img { > .base-card {
filter: blur(22px); display: flex;
} flex-direction: column;
> .ds-card-image img {
width: 100%;
max-height: 2000px;
object-fit: contain;
}
> .ds-card-content {
flex-grow: 0;
}
/* workaround to avoid jumping layout when footer is rendered */
> .ds-card-footer {
height: 75px;
}
.post-title {
margin-top: $space-large;
}
/* workaround to avoid jumping layout when user-teaser is rendered */
.user-wrapper {
height: 36px;
position: relative;
z-index: $z-index-post-card-link;
}
.content-menu {
position: relative;
z-index: $z-index-post-card-link;
display: inline-block;
margin-left: $space-xx-small;
margin-right: -$space-x-small;
}
.post-link {
margin: 15px;
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%; height: 100%;
text-indent: -999999px;
&.--pinned {
border: 1px solid $color-warning;
}
&.--blur-image > .card-image > .image {
filter: blur(22px);
}
> .card-image {
overflow: hidden;
> .image {
width: 100%;
object-fit: contain;
}
}
> .content {
flex-grow: 1;
margin-bottom: $space-small;
}
> .footer {
display: flex;
justify-content: space-between;
align-items: center;
> .categories {
flex-grow: 1;
}
> .counter-icon {
display: block;
margin-right: $space-small;
opacity: 0.5;
}
> .content-menu {
position: relative;
z-index: $z-index-post-card-link;
}
.ds-tag {
margin: 0;
}
}
}
> .ribbon {
position: absolute;
top: 50%;
right: -7px;
} }
} }
</style> </style>