-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
Copy pathItemView.vue
135 lines (119 loc) · 2.96 KB
/
ItemView.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<template>
<div class="item-view" v-if="item">
<template v-if="item">
<div class="item-view-header">
<a :href="item.url" target="_blank">
<h1>{{ item.title }}</h1>
</a>
<span v-if="item.url" class="host">
({{ item.url | host }})
</span>
<p class="meta">
{{ item.score }} points
| by <router-link :to="'/user/' + item.by">{{ item.by }}</router-link>
{{ item.time | timeAgo }} ago
</p>
</div>
<div class="item-view-comments">
<p class="item-view-comments-header">
{{ item.kids ? item.descendants + ' comments' : 'No comments yet.' }}
<spinner :show="loading"></spinner>
</p>
<ul v-if="!loading" class="comment-children">
<comment v-for="id in item.kids" :key="id" :id="id"></comment>
</ul>
</div>
</template>
</div>
</template>
<script>
import Spinner from '../components/Spinner.vue'
import Comment from '../components/Comment.vue'
export default {
name: 'item-view',
components: { Spinner, Comment },
data: () => ({
loading: true
}),
computed: {
item () {
return this.$store.state.items[this.$route.params.id]
}
},
// We only fetch the item itself before entering the view, because
// it might take a long time to load threads with hundreds of comments
// due to how the HN Firebase API works.
asyncData ({ store, route: { params: { id }}}) {
return store.dispatch('FETCH_ITEMS', { ids: [id] })
},
title () {
return this.item.title
},
// Fetch comments when mounted on the client
beforeMount () {
this.fetchComments()
},
// refetch comments if item changed
watch: {
item: function () {
!this.loading && this.fetchComments();
}
},
methods: {
fetchComments () {
if (!this.item || !this.item.kids) {
return
}
this.loading = true
fetchComments(this.$store, this.item).then(() => {
this.loading = false
})
}
}
}
// recursively fetch all descendent comments
function fetchComments (store, item) {
if (item && item.kids) {
return store.dispatch('FETCH_ITEMS', {
ids: item.kids
}).then(() => Promise.all(item.kids.map(id => {
return fetchComments(store, store.state.items[id])
})))
}
}
</script>
<style lang="stylus">
.item-view-header
background-color #fff
padding 1.8em 2em 1em
box-shadow 0 1px 2px rgba(0,0,0,.1)
h1
display inline
font-size 1.5em
margin 0
margin-right .5em
.host, .meta, .meta a
color #828282
.meta a
text-decoration underline
.item-view-comments
background-color #fff
margin-top 10px
padding 0 2em .5em
.item-view-comments-header
margin 0
font-size 1.1em
padding 1em 0
position relative
.spinner
display inline-block
margin -15px 0
.comment-children
list-style-type none
padding 0
margin 0
@media (max-width 600px)
.item-view-header
h1
font-size 1.25em
</style>