@kiva/kv-components 3.52.1 → 3.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/package.json +2 -2
- package/tests/fixtures/mockFeedActivityData.js +80 -0
- package/tests/unit/specs/components/KvCommentsHeartButton.spec.js +32 -0
- package/tests/unit/specs/components/KvCommentsList.spec.js +39 -0
- package/tests/unit/specs/components/KvCommentsListItem.spec.js +43 -0
- package/vue/KvButton.vue +5 -5
- package/vue/KvCommentsContainer.vue +20 -0
- package/vue/KvCommentsHeartButton.vue +74 -0
- package/vue/KvCommentsList.vue +38 -0
- package/vue/KvCommentsListItem.vue +133 -0
- package/vue/stories/KvCommentsContainer.stories.js +2 -1
- package/vue/stories/KvCommentsHeartButton.stories.js +25 -0
- package/vue/stories/KvCommentsList.stories.js +24 -0
- package/vue/stories/KvCommentsListItem.stories.js +24 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,36 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [3.54.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.53.0...@kiva/kv-components@3.54.0) (2024-02-28)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* kvcommentsheartbutton added for comments stuff ([#346](https://github.com/kiva/kv-ui-elements/issues/346)) ([57303da](https://github.com/kiva/kv-ui-elements/commit/57303daec80222c199556b296d720462265e53ac))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [3.53.0](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.52.1...@kiva/kv-components@3.53.0) (2024-02-26)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* indentation in item component ([30aee02](https://github.com/kiva/kv-ui-elements/commit/30aee02d3c2e58c7c98fe6a58689a9824f56ef60))
|
|
23
|
+
* optional chaining for comment object ([bac9ba1](https://github.com/kiva/kv-ui-elements/commit/bac9ba199970966564bfab7d6a2e64bb92fea286))
|
|
24
|
+
* revert profile image and small fixes ([fc8cf74](https://github.com/kiva/kv-ui-elements/commit/fc8cf7440fb355fbfee0e8acfb2a849dd6513a11))
|
|
25
|
+
* using more accurate data for components ([043f1c2](https://github.com/kiva/kv-ui-elements/commit/043f1c2d47a5d22157785b9d972246823572e4fd))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* provisional comment list and item components ([642745c](https://github.com/kiva/kv-ui-elements/commit/642745ce1359e5cc9e3d98d122f26728b3dffda0))
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
6
36
|
## [3.52.1](https://github.com/kiva/kv-ui-elements/compare/@kiva/kv-components@3.52.0...@kiva/kv-components@3.52.1) (2024-02-01)
|
|
7
37
|
|
|
8
38
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kiva/kv-components",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.54.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
"optional": true
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "b29d4c7e40f229ac09c7f68c377741af7d068158"
|
|
79
79
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const comments = {
|
|
2
|
+
duration: '6.42ms',
|
|
3
|
+
results: [
|
|
4
|
+
{
|
|
5
|
+
actor: {
|
|
6
|
+
created_at: '2024-02-01T19:48:26.890734Z',
|
|
7
|
+
updated_at: '2024-02-01T19:48:26.890734Z',
|
|
8
|
+
id: '123',
|
|
9
|
+
data: {},
|
|
10
|
+
},
|
|
11
|
+
foreign_id: 'CHALLENGE#test-challenge-id',
|
|
12
|
+
id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
|
|
13
|
+
latest_reactions: {
|
|
14
|
+
comment: [
|
|
15
|
+
{
|
|
16
|
+
created_at: '2024-02-01T20:12:31.398932Z',
|
|
17
|
+
updated_at: '2024-02-01T20:12:31.398932Z',
|
|
18
|
+
id: 'dade3812-6aa0-4c32-90ea-2366dab178a1',
|
|
19
|
+
user_id: '1de650a5-b12f-4d20-b46c-6e15b0722141',
|
|
20
|
+
kind: 'comment',
|
|
21
|
+
activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
|
|
22
|
+
data: {
|
|
23
|
+
text: 'another guest comment',
|
|
24
|
+
},
|
|
25
|
+
parent: '',
|
|
26
|
+
latest_children: {},
|
|
27
|
+
children_counts: {},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
created_at: '2024-02-01T20:11:23.931133Z',
|
|
31
|
+
updated_at: '2024-02-01T20:11:23.931133Z',
|
|
32
|
+
id: '3de615bb-0d48-4a69-9004-141ee26985eb',
|
|
33
|
+
user_id: '1de650a5-b12f-4d20-b46c-6e15b0722141',
|
|
34
|
+
kind: 'comment',
|
|
35
|
+
activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
|
|
36
|
+
data: {
|
|
37
|
+
text: 'test as visitor',
|
|
38
|
+
},
|
|
39
|
+
parent: '',
|
|
40
|
+
latest_children: {},
|
|
41
|
+
children_counts: {},
|
|
42
|
+
is_liked: true,
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
created_at: '2024-02-01T20:06:46.651764Z',
|
|
46
|
+
updated_at: '2024-02-01T20:06:46.651764Z',
|
|
47
|
+
id: 'e1db4420-159e-4ba2-aab9-704d1cc56dae',
|
|
48
|
+
user_id: '123',
|
|
49
|
+
user: {
|
|
50
|
+
created_at: '2024-02-01T19:48:26.890734Z',
|
|
51
|
+
updated_at: '2024-02-01T19:48:26.890734Z',
|
|
52
|
+
id: '123',
|
|
53
|
+
data: {},
|
|
54
|
+
},
|
|
55
|
+
kind: 'comment',
|
|
56
|
+
activity_id: 'efb2dbfe-c12a-11ee-9fbc-065afce7d41d',
|
|
57
|
+
data: {
|
|
58
|
+
text: 'asd',
|
|
59
|
+
},
|
|
60
|
+
parent: '',
|
|
61
|
+
latest_children: {},
|
|
62
|
+
children_counts: {},
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
latest_reactions_extra: {
|
|
67
|
+
comment: {
|
|
68
|
+
next: '',
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
object: 'test-challenge-id',
|
|
72
|
+
origin: null,
|
|
73
|
+
target: '',
|
|
74
|
+
time: '2024-02-01T17:54:24.932762',
|
|
75
|
+
verb: 'CHALLENGE',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export default comments;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { render } from '@testing-library/vue';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import KvCommentsHeartButton from '../../../../vue/KvCommentsHeartButton.vue';
|
|
4
|
+
|
|
5
|
+
const CLICK_EVENT = 'click';
|
|
6
|
+
|
|
7
|
+
describe('KvCommentsListItem', () => {
|
|
8
|
+
it('should render defaults', () => {
|
|
9
|
+
const { getByRole } = render(KvCommentsHeartButton);
|
|
10
|
+
const likeButton = getByRole('button', { name: 'Like' });
|
|
11
|
+
|
|
12
|
+
expect(likeButton).toBeDefined();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should emit true value when clicked as not liked', async () => {
|
|
16
|
+
const { getByRole, emitted } = render(KvCommentsHeartButton);
|
|
17
|
+
const likeButton = getByRole('button', { name: 'Like' });
|
|
18
|
+
|
|
19
|
+
await userEvent.click(likeButton);
|
|
20
|
+
|
|
21
|
+
expect(emitted()[CLICK_EVENT]).toEqual([[true]]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should emit false value when clicked as liked', async () => {
|
|
25
|
+
const { getByRole, emitted } = render(KvCommentsHeartButton, { props: { isLiked: true } });
|
|
26
|
+
const likeButton = getByRole('button', { name: 'Like' });
|
|
27
|
+
|
|
28
|
+
await userEvent.click(likeButton);
|
|
29
|
+
|
|
30
|
+
expect(emitted()[CLICK_EVENT]).toEqual([[false]]);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { render } from '@testing-library/vue';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import ListComponent from '../../../../vue/KvCommentsList.vue';
|
|
4
|
+
import activityFeed from '../../../fixtures/mockFeedActivityData';
|
|
5
|
+
import { LIKE_COMMENT_EVENT, REPLY_COMMENT_EVENT } from '../../../../vue/KvCommentsListItem.vue';
|
|
6
|
+
|
|
7
|
+
const renderList = (props = {}) => {
|
|
8
|
+
return render(ListComponent, { props });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const comments = activityFeed.results[0].latest_reactions;
|
|
12
|
+
|
|
13
|
+
describe('KvCommentsList', () => {
|
|
14
|
+
it('should render comments component', async () => {
|
|
15
|
+
const { container } = renderList({ comments });
|
|
16
|
+
|
|
17
|
+
const { id } = comments.comment[0];
|
|
18
|
+
expect(container.querySelectorAll(`#${id}`).length).toBe(1);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should emit comment events', async () => {
|
|
22
|
+
const { getAllByRole, emitted } = renderList({ comments });
|
|
23
|
+
const replyButton = getAllByRole('button', { name: 'Reply' })[0];
|
|
24
|
+
const likeButton = getAllByRole('button', { name: 'Like' })[0];
|
|
25
|
+
const firstComment = comments.comment[0];
|
|
26
|
+
|
|
27
|
+
const TEST_OBJ = {
|
|
28
|
+
userId: firstComment.user_id,
|
|
29
|
+
id: firstComment.id,
|
|
30
|
+
isChild: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
await userEvent.click(replyButton);
|
|
34
|
+
expect(emitted()[REPLY_COMMENT_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: REPLY_COMMENT_EVENT }]]);
|
|
35
|
+
|
|
36
|
+
await userEvent.click(likeButton);
|
|
37
|
+
expect(emitted()[LIKE_COMMENT_EVENT]).toEqual([[{ ...TEST_OBJ, reaction: LIKE_COMMENT_EVENT, value: true }]]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { render } from '@testing-library/vue';
|
|
2
|
+
import userEvent from '@testing-library/user-event';
|
|
3
|
+
import KvCommentsListItem from '../../../../vue/KvCommentsListItem.vue';
|
|
4
|
+
import activityFeed from '../../../fixtures/mockFeedActivityData';
|
|
5
|
+
|
|
6
|
+
const comment = activityFeed.results[0].latest_reactions.comment[0];
|
|
7
|
+
|
|
8
|
+
const handleClick = jest.fn();
|
|
9
|
+
|
|
10
|
+
const renderComment = (props = {}) => {
|
|
11
|
+
return render(KvCommentsListItem, { props });
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
describe('KvCommentsListItem', () => {
|
|
15
|
+
it('should render defaults', () => {
|
|
16
|
+
const { getByRole } = renderComment({ comment });
|
|
17
|
+
getByRole('button', { name: 'Reply' });
|
|
18
|
+
getByRole('button', { name: 'Like' });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should render comment text', () => {
|
|
22
|
+
const { getByText } = renderComment({ comment });
|
|
23
|
+
getByText(comment.data.text);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should handle like button click', async () => {
|
|
27
|
+
const { getByRole } = renderComment({ comment, handleClick });
|
|
28
|
+
const likeButton = getByRole('button', { name: 'Like' });
|
|
29
|
+
|
|
30
|
+
await userEvent.click(likeButton);
|
|
31
|
+
|
|
32
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should handle reply button click', async () => {
|
|
36
|
+
const { getByRole } = renderComment({ comment, handleClick });
|
|
37
|
+
const replyButton = getByRole('button', { name: 'Reply' });
|
|
38
|
+
|
|
39
|
+
await userEvent.click(replyButton);
|
|
40
|
+
|
|
41
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
42
|
+
});
|
|
43
|
+
});
|
package/vue/KvButton.vue
CHANGED
|
@@ -53,14 +53,14 @@ export default {
|
|
|
53
53
|
props: {
|
|
54
54
|
/**
|
|
55
55
|
* Use if linking to a Vue route
|
|
56
|
-
|
|
56
|
+
*/
|
|
57
57
|
to: {
|
|
58
58
|
type: [String, Object],
|
|
59
59
|
default: null,
|
|
60
60
|
},
|
|
61
61
|
/**
|
|
62
62
|
* Use if linking to an external link or old-stack page
|
|
63
|
-
|
|
63
|
+
*/
|
|
64
64
|
href: {
|
|
65
65
|
type: String,
|
|
66
66
|
default: null,
|
|
@@ -68,7 +68,7 @@ export default {
|
|
|
68
68
|
/**
|
|
69
69
|
* The behavior of the button when used in an HTML form.
|
|
70
70
|
* `button (default), submit, reset`
|
|
71
|
-
|
|
71
|
+
*/
|
|
72
72
|
type: {
|
|
73
73
|
type: String,
|
|
74
74
|
default: 'button',
|
|
@@ -79,7 +79,7 @@ export default {
|
|
|
79
79
|
/**
|
|
80
80
|
* Appearance of the button
|
|
81
81
|
* `primary (default), secondary, danger, link, ghost`
|
|
82
|
-
|
|
82
|
+
*/
|
|
83
83
|
variant: {
|
|
84
84
|
type: String,
|
|
85
85
|
default: 'primary',
|
|
@@ -90,7 +90,7 @@ export default {
|
|
|
90
90
|
/**
|
|
91
91
|
* State of the button
|
|
92
92
|
* `'' (default), active, disabled, loading`
|
|
93
|
-
|
|
93
|
+
*/
|
|
94
94
|
state: {
|
|
95
95
|
type: String,
|
|
96
96
|
default: '',
|
|
@@ -5,17 +5,26 @@
|
|
|
5
5
|
:user-display-name="userDisplayName"
|
|
6
6
|
@add-comment="comment"
|
|
7
7
|
/>
|
|
8
|
+
<kv-comments-list
|
|
9
|
+
v-if="comments"
|
|
10
|
+
:comments="comments"
|
|
11
|
+
@[REPLY_COMMENT_EVENT]="comment"
|
|
12
|
+
@[LIKE_COMMENT_EVENT]="comment"
|
|
13
|
+
/>
|
|
8
14
|
</div>
|
|
9
15
|
</template>
|
|
10
16
|
|
|
11
17
|
<script>
|
|
12
18
|
import KvCommentsAdd from './KvCommentsAdd.vue';
|
|
19
|
+
import KvCommentsList from './KvCommentsList.vue';
|
|
20
|
+
import { REPLY_COMMENT_EVENT, LIKE_COMMENT_EVENT } from './KvCommentsListItem.vue';
|
|
13
21
|
|
|
14
22
|
export const ADD_COMMENT_EVENT = 'add-comment';
|
|
15
23
|
|
|
16
24
|
export default {
|
|
17
25
|
components: {
|
|
18
26
|
KvCommentsAdd,
|
|
27
|
+
KvCommentsList,
|
|
19
28
|
},
|
|
20
29
|
props: {
|
|
21
30
|
/**
|
|
@@ -32,13 +41,24 @@ export default {
|
|
|
32
41
|
type: String,
|
|
33
42
|
default: '',
|
|
34
43
|
},
|
|
44
|
+
/**
|
|
45
|
+
* Activity comments
|
|
46
|
+
*/
|
|
47
|
+
comments: {
|
|
48
|
+
type: Object,
|
|
49
|
+
default: () => {},
|
|
50
|
+
},
|
|
35
51
|
},
|
|
36
52
|
setup(_props, { emit }) {
|
|
37
53
|
const comment = (commentValue) => {
|
|
38
54
|
emit(ADD_COMMENT_EVENT, commentValue);
|
|
55
|
+
emit(REPLY_COMMENT_EVENT, commentValue);
|
|
56
|
+
emit(LIKE_COMMENT_EVENT, commentValue);
|
|
39
57
|
};
|
|
40
58
|
return {
|
|
41
59
|
comment,
|
|
60
|
+
REPLY_COMMENT_EVENT,
|
|
61
|
+
LIKE_COMMENT_EVENT,
|
|
42
62
|
};
|
|
43
63
|
},
|
|
44
64
|
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
aria-label="Like"
|
|
4
|
+
@click="changeState"
|
|
5
|
+
>
|
|
6
|
+
<kv-material-icon
|
|
7
|
+
:icon="icon"
|
|
8
|
+
:class="classState"
|
|
9
|
+
/>
|
|
10
|
+
</button>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script>
|
|
14
|
+
import { computed, toRefs } from 'vue-demi';
|
|
15
|
+
import { mdiHeart, mdiHeartOutline } from '@mdi/js';
|
|
16
|
+
import KvMaterialIcon from './KvMaterialIcon.vue';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
name: 'KvCommentsHeartButton',
|
|
20
|
+
components: {
|
|
21
|
+
KvMaterialIcon,
|
|
22
|
+
},
|
|
23
|
+
props: {
|
|
24
|
+
/**
|
|
25
|
+
* Use if small icon is needed
|
|
26
|
+
*/
|
|
27
|
+
isSmall: {
|
|
28
|
+
type: Boolean,
|
|
29
|
+
default: false,
|
|
30
|
+
},
|
|
31
|
+
/**
|
|
32
|
+
* Use if icon is liked
|
|
33
|
+
*/
|
|
34
|
+
isLiked: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
emits: [
|
|
40
|
+
'click',
|
|
41
|
+
],
|
|
42
|
+
setup(props, { emit }) {
|
|
43
|
+
const {
|
|
44
|
+
isSmall,
|
|
45
|
+
isLiked,
|
|
46
|
+
} = toRefs(props);
|
|
47
|
+
|
|
48
|
+
const icon = computed(() => (isLiked.value ? mdiHeart : mdiHeartOutline));
|
|
49
|
+
|
|
50
|
+
const classState = computed(() => {
|
|
51
|
+
let className = isSmall.value ? 'tw-w-2.5 tw-h-2.5' : 'tw-w-3 tw-h-3';
|
|
52
|
+
className += isLiked.value ? ' filled' : '';
|
|
53
|
+
|
|
54
|
+
return className;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const changeState = () => {
|
|
58
|
+
emit('click', !isLiked.value);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
icon,
|
|
63
|
+
classState,
|
|
64
|
+
changeState,
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<style scoped>
|
|
71
|
+
.filled >>> svg {
|
|
72
|
+
fill: #F60059;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<KvCommentsListItem
|
|
4
|
+
v-for="comment in comments.comment"
|
|
5
|
+
:id="comment.id"
|
|
6
|
+
:key="comment.id"
|
|
7
|
+
:nest-level="1"
|
|
8
|
+
:comment="comment"
|
|
9
|
+
:is-liked="comment.is_liked"
|
|
10
|
+
:handle-click="handleClick"
|
|
11
|
+
/>
|
|
12
|
+
</div>
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<script>
|
|
16
|
+
|
|
17
|
+
import KvCommentsListItem, { REPLY_COMMENT_EVENT, LIKE_COMMENT_EVENT } from './KvCommentsListItem.vue';
|
|
18
|
+
|
|
19
|
+
export default {
|
|
20
|
+
components: { KvCommentsListItem },
|
|
21
|
+
props: {
|
|
22
|
+
/**
|
|
23
|
+
* Activity comments
|
|
24
|
+
*/
|
|
25
|
+
comments: {
|
|
26
|
+
type: Object,
|
|
27
|
+
default: () => {},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
methods: {
|
|
31
|
+
handleClick(payload) {
|
|
32
|
+
if ([REPLY_COMMENT_EVENT, LIKE_COMMENT_EVENT].includes(payload.reaction)) {
|
|
33
|
+
this.$emit(payload.reaction, { ...payload });
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
</script>
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<div
|
|
4
|
+
class="tw-flex tw-items-center tw-gap-1"
|
|
5
|
+
>
|
|
6
|
+
<img
|
|
7
|
+
v-if="profileImage"
|
|
8
|
+
class="
|
|
9
|
+
data-hj-suppress
|
|
10
|
+
tw-inline-block
|
|
11
|
+
tw-w-3.5
|
|
12
|
+
tw-h-3.5
|
|
13
|
+
tw-rounded-full
|
|
14
|
+
tw-overflow-hidden
|
|
15
|
+
tw-object-fill
|
|
16
|
+
"
|
|
17
|
+
:src="profileImage"
|
|
18
|
+
alt="picture"
|
|
19
|
+
>
|
|
20
|
+
<p>
|
|
21
|
+
{{ text }}
|
|
22
|
+
</p>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="tw-flex tw-items-center tw-gap-x-0.5">
|
|
25
|
+
<kv-comments-heart-button
|
|
26
|
+
:is-small="true"
|
|
27
|
+
:is-liked="isLiked"
|
|
28
|
+
@click="onClick(LIKE_COMMENT_EVENT, $event)"
|
|
29
|
+
/>
|
|
30
|
+
<kv-button
|
|
31
|
+
variant="ghost"
|
|
32
|
+
class="tw-font-medium"
|
|
33
|
+
@click="onClick(REPLY_COMMENT_EVENT)"
|
|
34
|
+
>
|
|
35
|
+
Reply
|
|
36
|
+
</kv-button>
|
|
37
|
+
</div>
|
|
38
|
+
<div
|
|
39
|
+
v-if="latestChildren"
|
|
40
|
+
class="tw-my-1"
|
|
41
|
+
>
|
|
42
|
+
<p
|
|
43
|
+
v-for="nested_comment in latestChildren"
|
|
44
|
+
:key="nested_comment.id"
|
|
45
|
+
class="tw-ml-3"
|
|
46
|
+
>
|
|
47
|
+
<kv-comments-list-item
|
|
48
|
+
:comment="nested_comment"
|
|
49
|
+
:is-liked="nested_comment.is_liked"
|
|
50
|
+
:nest-level="nestLevel + 1"
|
|
51
|
+
:handle-click="handleClick"
|
|
52
|
+
/>
|
|
53
|
+
</p>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<script>
|
|
59
|
+
import KvButton from './KvButton.vue';
|
|
60
|
+
import KvCommentsHeartButton from './KvCommentsHeartButton.vue';
|
|
61
|
+
|
|
62
|
+
export const REPLY_COMMENT_EVENT = 'reply-comment';
|
|
63
|
+
export const LIKE_COMMENT_EVENT = 'like-comment';
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
name: 'KvCommentsListItem',
|
|
67
|
+
components: {
|
|
68
|
+
KvButton,
|
|
69
|
+
KvCommentsHeartButton,
|
|
70
|
+
},
|
|
71
|
+
props: {
|
|
72
|
+
/**
|
|
73
|
+
* Activity comment
|
|
74
|
+
*/
|
|
75
|
+
comment: {
|
|
76
|
+
type: Object,
|
|
77
|
+
default: () => ({}),
|
|
78
|
+
},
|
|
79
|
+
/**
|
|
80
|
+
* The nest level of the comment
|
|
81
|
+
*/
|
|
82
|
+
nestLevel: {
|
|
83
|
+
type: Number,
|
|
84
|
+
default: 0,
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* Comment is liked by current user
|
|
88
|
+
*/
|
|
89
|
+
isLiked: {
|
|
90
|
+
type: Boolean,
|
|
91
|
+
default: false,
|
|
92
|
+
},
|
|
93
|
+
/**
|
|
94
|
+
* The function to call when a reaction is clicked
|
|
95
|
+
*/
|
|
96
|
+
handleClick: {
|
|
97
|
+
type: Function,
|
|
98
|
+
default: () => ({}),
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
setup(props) {
|
|
102
|
+
const onClick = (reaction, value) => {
|
|
103
|
+
props.handleClick({
|
|
104
|
+
reaction,
|
|
105
|
+
id: props.comment?.id ?? null,
|
|
106
|
+
userId: props.comment?.user_id ?? null,
|
|
107
|
+
isChild: true,
|
|
108
|
+
value,
|
|
109
|
+
});
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
onClick,
|
|
114
|
+
REPLY_COMMENT_EVENT,
|
|
115
|
+
LIKE_COMMENT_EVENT,
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
computed: {
|
|
119
|
+
text() {
|
|
120
|
+
return this.comment?.data?.text ?? '';
|
|
121
|
+
},
|
|
122
|
+
userId() {
|
|
123
|
+
return this.comment?.user_id ?? null;
|
|
124
|
+
},
|
|
125
|
+
latestChildren() {
|
|
126
|
+
return this.comment?.latest_children ?? null;
|
|
127
|
+
},
|
|
128
|
+
profileImage() {
|
|
129
|
+
return this.comment?.user_picture ?? '';
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
</script>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import KvCommentsContainer from '../KvCommentsContainer.vue';
|
|
2
|
+
import comments from '../../tests/fixtures/mockFeedActivityData';
|
|
2
3
|
|
|
3
4
|
export default {
|
|
4
5
|
title: 'KvCommentsContainer',
|
|
@@ -20,4 +21,4 @@ const story = (args) => {
|
|
|
20
21
|
return template;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
|
-
export const Default = story({});
|
|
24
|
+
export const Default = story({ comments });
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import KvCommentsHeartButton from '../KvCommentsHeartButton.vue';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
title: 'KvCommentsHeartButton',
|
|
5
|
+
component: KvCommentsHeartButton,
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const story = (args) => {
|
|
9
|
+
const template = (templateArgs, { argTypes }) => ({
|
|
10
|
+
props: Object.keys(argTypes),
|
|
11
|
+
components: { KvCommentsHeartButton },
|
|
12
|
+
setup() { return { args: templateArgs }; },
|
|
13
|
+
template: `
|
|
14
|
+
<KvCommentsHeartButton v-bind="args" />
|
|
15
|
+
`,
|
|
16
|
+
});
|
|
17
|
+
template.args = args;
|
|
18
|
+
return template;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const Default = story({});
|
|
22
|
+
|
|
23
|
+
export const IsSmall = story({ isSmall: true });
|
|
24
|
+
|
|
25
|
+
export const IsLiked = story({ isLiked: true });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import KvCommentsList from '../KvCommentsList.vue';
|
|
2
|
+
import activityFeed from '../../tests/fixtures/mockFeedActivityData';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'KvCommentsList',
|
|
6
|
+
component: KvCommentsList,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const story = (args) => {
|
|
10
|
+
const template = (templateArgs, { argTypes }) => ({
|
|
11
|
+
props: Object.keys(argTypes),
|
|
12
|
+
components: { KvCommentsList },
|
|
13
|
+
setup() { return { args: templateArgs }; },
|
|
14
|
+
template: `
|
|
15
|
+
<KvCommentsList v-bind="args" />
|
|
16
|
+
`,
|
|
17
|
+
});
|
|
18
|
+
template.args = args;
|
|
19
|
+
return template;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const comments = activityFeed.results[0].latest_reactions;
|
|
23
|
+
|
|
24
|
+
export const Default = story({ comments });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import KvCommentsListItem from '../KvCommentsListItem.vue';
|
|
2
|
+
import activityFeed from '../../tests/fixtures/mockFeedActivityData';
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
title: 'KvCommentsListItem',
|
|
6
|
+
component: KvCommentsListItem,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const story = (args) => {
|
|
10
|
+
const template = (templateArgs, { argTypes }) => ({
|
|
11
|
+
props: Object.keys(argTypes),
|
|
12
|
+
components: { KvCommentsListItem },
|
|
13
|
+
setup() { return { args: templateArgs }; },
|
|
14
|
+
template: `
|
|
15
|
+
<KvCommentsListItem v-bind="args" />
|
|
16
|
+
`,
|
|
17
|
+
});
|
|
18
|
+
template.args = args;
|
|
19
|
+
return template;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const comment = activityFeed.results[0].latest_reactions.comment[0];
|
|
23
|
+
|
|
24
|
+
export const Default = story({ comment });
|