Skip to content

Commit

Permalink
feat(comp:comment): add comment component (#822)
Browse files Browse the repository at this point in the history
fix #358
  • Loading branch information
thinkingOfBetty committed Mar 25, 2022
1 parent e367009 commit e3f1e98
Show file tree
Hide file tree
Showing 24 changed files with 757 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Comment render work 1`] = `
"<div class=\\"ix-comment\\">
<div class=\\"ix-comment-inner\\">
<!---->
<div class=\\"ix-comment-content\\">
<div class=\\"ix-comment-content-author\\">
<!---->
<!---->
</div>
<div class=\\"ix-comment-content-detail\\">comment content</div>
<!---->
</div>
</div>
<!---->
</div>"
`;
129 changes: 129 additions & 0 deletions packages/components/comment/__tests__/comment.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import { MountingOptions, mount } from '@vue/test-utils'
import { h } from 'vue'

import { renderWork } from '@tests'

import { IxAvatar } from '@idux/components/avatar'
import { IxIcon } from '@idux/components/icon'

import Comment from '../src/Comment'
import { CommentProps } from '../src/types'

describe('Comment', () => {
const CommentMount = (options?: MountingOptions<Partial<CommentProps>>) => mount(Comment, { ...options })

renderWork<CommentProps>(Comment, {
props: {
content: 'comment content',
},
})
const authorText = 'Han Solo'

test('author work', async () => {
const wrapper = CommentMount({ props: { author: authorText } })

expect(wrapper.find('.ix-comment-content-author-name').text()).toBe(authorText)
})

test('author slot work', async () => {
const wrapper = CommentMount({ slots: { author: () => authorText } })

expect(wrapper.find('.ix-comment-content-author-name').text()).toBe(authorText)
})

const avatarSrc = '/images/avatar/0.png'

test('avatar string work', async () => {
const wrapper = CommentMount({ props: { avatar: avatarSrc } })

expect(wrapper.find('.ix-comment-avatar').exists()).toBe(true)
expect(wrapper.find('img').element.src).toContain(avatarSrc)
})

const squareShape = 'square'
const circleShape = 'circle'

test('avatar object work', async () => {
const wrapper = CommentMount({
props: {
avatar: { src: avatarSrc, shape: squareShape },
},
})

expect(wrapper.find('.ix-avatar-square').exists()).toBe(true)
expect(wrapper.find('img').element.src).toContain(avatarSrc)

await wrapper.setProps({ avatar: { src: avatarSrc, shape: circleShape } })
expect(wrapper.find('.ix-avatar-circle').exists()).toBe(true)
expect(wrapper.find('.ix-avatar-square').exists()).toBe(false)
})

test('avatar slot work', async () => {
const wrapper = CommentMount({
slots: { avatar: () => [h(IxAvatar, { src: avatarSrc })] },
})

expect(wrapper.find('img').element.src).toContain(avatarSrc)
})

const commentContent = 'this is comment text !'

test('content work', async () => {
const wrapper = CommentMount({
props: { content: commentContent },
})

expect(wrapper.find('.ix-comment-content-detail').text()).toBe(commentContent)
})

test('content slot work', async () => {
const wrapper = CommentMount({
slots: { content: () => [h('p', commentContent)] },
})

expect(wrapper.find('p').text()).toContain(commentContent)
})

const datetime1 = '2022/3/24'
const datetime2 = '2022/3/25'

test('datetime work', async () => {
const wrapper = CommentMount({
props: { datetime: datetime1 },
})

expect(wrapper.find('.ix-comment-content-author-time').text()).toBe(datetime1)

await wrapper.setProps({ datetime: datetime2 })
expect(wrapper.find('.ix-comment-content-author-time').text()).toBe(datetime2)
})

test('default slot work', async () => {
const wrapper = CommentMount({
slots: {
default: () => [
h(Comment, {
content: commentContent,
}),
],
},
})

expect(wrapper.find('.ix-comment-nested').text()).toContain(commentContent)
})

test('actions slot work', async () => {
const wrapper = CommentMount({
slots: {
actions: () => [
h(IxIcon, {
name: 'like',
}),
],
},
})

const action = wrapper.find('.ix-icon-like')
expect(action.exists()).toBe(true)
})
})
14 changes: 14 additions & 0 deletions packages/components/comment/demo/Basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 0
title:
zh: 基本评论
en: Basic comment
---

## zh

一个基本的评论组件,带有作者、头像、时间和操作。

## en

A basic comment with author, avatar, time and actions.
75 changes: 75 additions & 0 deletions packages/components/comment/demo/Basic.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<IxComment :datetime="datetime">
<template #author>
<a>Han Solo</a>
</template>
<template #avatar>
<IxAvatar src="/images/avatar/0.png" />
</template>
<template #content>
<p>
We supply a series of design principles, practical patterns and high quality design resources (Sketch and
Axure), to help people create their product prototypes beautifully and efficiently.
</p>
</template>
<template #actions>
<IxTooltip title="Like">
<span @click="handleLike">
<IxIcon :name="likeIconName" />
<span className="comment-action">{{ likes }}</span>
</span>
</IxTooltip>
<IxTooltip title="disLike">
<span @click="handleDislike">
<IxIcon :name="dislikeIconName" />
<span className="comment-action">{{ dislikes }}</span>
</span>
</IxTooltip>
<span key="comment-basic-reply-to">Reply to</span>
</template>
<slot></slot>
</IxComment>
</template>

<script lang="ts">
import { computed, defineComponent, ref } from 'vue'
import { format } from 'date-fns'
export default defineComponent({
setup() {
const datetime = ref(format(new Date(), 'yyyy-MM-dd HH:mm'))
const likes = ref(0)
const dislikes = ref(0)
const action = ref('')
const likeStatus = 'liked'
const dislikedStatus = 'disliked'
const likeIconName = computed(() => (action.value === likeStatus ? 'like-filled' : 'like'))
const dislikeIconName = computed(() => (action.value === dislikedStatus ? 'dislike-filled' : 'dislike'))
const setAction = (status: string) => {
action.value = status
}
const setLikes = (value: number) => {
likes.value = value
}
const setDislikes = (value: number) => {
dislikes.value = value
}
const handleLike = () => {
setAction(likeStatus)
setLikes(1)
setDislikes(0)
}
const handleDislike = () => {
setAction('disliked')
setLikes(0)
setDislikes(1)
}
return { datetime, likes, dislikes, action, likeIconName, dislikeIconName, handleLike, handleDislike }
},
})
</script>
14 changes: 14 additions & 0 deletions packages/components/comment/demo/Editor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 3
title:
zh: 回复框
en: Reply Editor
---

## zh-CN

评论编辑器组件提供了相同样式的封装以支持自定义评论编辑器。

## en-US

Comment can be used as an editor, so the user can customize the contents of the component.
67 changes: 67 additions & 0 deletions packages/components/comment/demo/Editor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<template>
<IxList :header="`${listData.length} replies`">
<li v-for="item in listData" :key="item.id">
<IxComment :author="item.author" :avatar="item.avatar" :datetime="item.datetime">
<template #content>
<p>{{ item.content }}</p>
</template>
</IxComment>
</li>
</IxList>
<IxComment>
<template #avatar>
<IxAvatar src="/images/avatar/0.png" />
</template>
<template #content>
<IxForm>
<IxFormItem>
<IxTextarea v-model:value="commentValue" placeholder="Basic usage"></IxTextarea>
</IxFormItem>
<IxFormItem>
<IxButton mode="primary" :loading="submitting" @click="handleSubmit">submit</IxButton>
</IxFormItem>
</IxForm>
</template>
</IxComment>
</template>

<script lang="ts">
import { defineComponent, reactive, ref } from 'vue'
import { format } from 'date-fns'
interface listDataNode {
author: string
avatar: string
content: string
datetime: string
}
export default defineComponent({
setup() {
const submitting = ref(false)
const commentValue = ref('')
const listData: listDataNode[] = reactive([])
const handleSubmit = () => {
if (!commentValue.value) {
return
}
submitting.value = true
setTimeout(() => {
listData.push({
author: 'Han Solo',
avatar: '/images/avatar/0.png',
content: commentValue.value,
datetime: format(new Date(), 'yyyy-MM-dd HH:mm'),
})
commentValue.value = ''
submitting.value = false
}, 1000)
}
return { submitting, commentValue, listData, handleSubmit }
},
})
</script>
14 changes: 14 additions & 0 deletions packages/components/comment/demo/List.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 1
title:
zh: 配合 List 组件
en: Usage with list
---

## zh-CN

配合 List 组件展现评论列表。

## en-US

Displaying a series of comments using the `antd` List Component.
53 changes: 53 additions & 0 deletions packages/components/comment/demo/List.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<IxList :header="`${listData.length} replies`">
<li v-for="item in listData" :key="item.id">
<IxComment :author="item.author" :avatar="item.avatar">
<template #content>
<p>{{ item.content }}</p>
</template>
<template #actions>
<span key="comment-basic-reply-to">Reply to</span>
</template>
<template #datetime>
<p>
<IxTooltip :title="item.datetime">
<span>{{ item.datetime }}</span>
</IxTooltip>
</p>
</template>
</IxComment>
</li>
</IxList>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import { format } from 'date-fns'
export default defineComponent({
setup() {
const datetime = format(new Date(), 'yyyy-MM-dd HH:mm')
const listData = [
{
author: 'Han Solo',
avatar: '/images/avatar/0.png',
content: `We supply a series of design principles, practical patterns and high quality design
resources (Sketch and Axure), to help people create their product prototypes beautifully and
efficiently.`,
datetime: datetime,
},
{
author: 'Han Solo',
avatar: '/images/avatar/0.png',
content: `We supply a series of design principles, practical patterns and high quality design
resources (Sketch and Axure), to help people create their product prototypes beautifully and
efficiently.`,
datetime: datetime,
},
]
return { listData }
},
})
</script>
Loading

0 comments on commit e3f1e98

Please sign in to comment.