Commit d365791d authored by Sebastien Chopin's avatar Sebastien Chopin

Create distinct view for each category

parent c9313029
...@@ -19,147 +19,135 @@ ...@@ -19,147 +19,135 @@
</template> </template>
<script> <script>
import { watchList } from '../../api' import { watchList } from '../api'
import Item from '../../components/Item.vue' import Item from './Item.vue'
const camelize = str => str.charAt(0).toUpperCase() + str.slice(1) export default {
const TYPES = ['top', 'new', 'show', 'ask', 'job'] name: 'item-list',
components: {
export default { Item
name: 'item-list', },
validate({params: {type, page = 0}}) { props: {
return TYPES.includes(type) && /^[0-9]+$/.test(page) type: String
}, },
components: { data() {
Item return {
}, transition: 'slide-right',
head() { displayedPage: Number(this.$route.params.page) || 1,
return { displayedItems: this.$store.getters.activeItems
title: camelize(this.$route.params.type) }
} },
}, computed: {
data() { page() {
return { return Number(this.$route.params.page) || 1
transition: 'slide-right',
displayedPage: Number(this.$route.params.page) || 1,
displayedItems: this.$store.getters.activeItems,
type: this.$route.params.type
}
},
fetch({store, params}) {
return store.dispatch('FETCH_LIST_DATA', {type: params.type})
}, },
computed: { maxPage() {
page() { const {itemsPerPage, lists} = this.$store.state
return Number(this.$route.params.page) || 1 return Math.ceil(lists[this.type].length / itemsPerPage)
},
maxPage() {
const {itemsPerPage, lists} = this.$store.state
return Math.ceil(lists[this.type].length / itemsPerPage)
},
hasMore() {
return this.page < this.maxPage
}
}, },
hasMore() {
return this.page < this.maxPage
}
},
beforeMount() { beforeMount() {
if (this.$root._isMounted) { if (this.$root._isMounted) {
this.loadItems(this.page) this.loadItems(this.page)
} }
// watch the current list for realtime updates // watch the current list for realtime updates
this.unwatchList = watchList(this.type, ids => { this.unwatchList = watchList(this.type, ids => {
this.$store.commit('SET_LIST', {type: this.type, ids}) this.$store.commit('SET_LIST', {type: this.type, ids})
this.$store.dispatch('ENSURE_ACTIVE_ITEMS').then(() => { this.$store.dispatch('ENSURE_ACTIVE_ITEMS').then(() => {
this.displayedItems = this.$store.getters.activeItems this.displayedItems = this.$store.getters.activeItems
})
}) })
}, })
},
beforeDestroy() {
this.unwatchList()
},
watch: { beforeDestroy() {
page(to, from) { this.unwatchList()
this.loadItems(to, from) },
}
},
methods: { watch: {
loadItems(to = this.page, from = -1) { page(to, from) {
this.$nuxt.$loading.start() this.loadItems(to, from)
this.$store.dispatch('FETCH_LIST_DATA', { }
type: this.type },
}).then(() => {
if (this.page < 0 || this.page > this.maxPage) { methods: {
this.$router.replace(`/${this.type}/1`) loadItems(to = this.page, from = -1) {
return this.$nuxt.$loading.start()
} this.$store.dispatch('FETCH_LIST_DATA', {
this.transition = from === -1 type: this.type
? null }).then(() => {
: to > from ? 'slide-left' : 'slide-right' if (this.page < 0 || this.page > this.maxPage) {
this.displayedPage = to this.$router.replace(`/${this.type}/1`)
this.displayedItems = this.$store.getters.activeItems return
this.$nuxt.$loading.finish() }
}) this.transition = from === -1
} ? null
: to > from ? 'slide-left' : 'slide-right'
this.displayedPage = to
this.displayedItems = this.$store.getters.activeItems
this.$nuxt.$loading.finish()
})
} }
} }
}
</script> </script>
<style lang="stylus"> <style lang="stylus">
.news-view .news-view
padding-top 45px padding-top 45px
.news-list-nav, .news-list .news-list-nav, .news-list
background-color #fff background-color #fff
border-radius 2px border-radius 2px
.news-list-nav .news-list-nav
padding 15px 30px padding 15px 30px
position fixed position fixed
text-align center text-align center
top 55px top 55px
left 0 left 0
right 0 right 0
z-index 998 z-index 998
box-shadow 0 1px 2px rgba(0, 0, 0, .1) box-shadow 0 1px 2px rgba(0, 0, 0, .1)
a a
margin 0 1em margin 0 1em
.disabled .disabled
color #ccc color #ccc
.news-list
position absolute
margin 30px 0
width 100%
transition all .5s cubic-bezier(.55, 0, .1, 1)
ul
list-style-type none
padding 0
margin 0
.slide-left-enter, .slide-right-leave-to
opacity 0
transform translate(30px, 0)
.slide-left-leave-to, .slide-right-enter
opacity 0
transform translate(-30px, 0)
.item-move, .item-enter-active, .item-leave-active
transition all .5s cubic-bezier(.55, 0, .1, 1)
.item-enter
opacity 0
transform translate(30px, 0)
.item-leave-active
position absolute
opacity 0
transform translate(30px, 0)
@media (max-width 600px)
.news-list .news-list
position absolute margin 10px 0
margin 30px 0
width 100%
transition all .5s cubic-bezier(.55, 0, .1, 1)
ul
list-style-type none
padding 0
margin 0
.slide-left-enter, .slide-right-leave-to
opacity 0
transform translate(30px, 0)
.slide-left-leave-to, .slide-right-enter
opacity 0
transform translate(-30px, 0)
.item-move, .item-enter-active, .item-leave-active
transition all .5s cubic-bezier(.55, 0, .1, 1)
.item-enter
opacity 0
transform translate(30px, 0)
.item-leave-active
position absolute
opacity 0
transform translate(30px, 0)
@media (max-width 600px)
.news-list
margin 10px 0
</style> </style>
import ItemList from './ItemList.vue'
const camelize = str => str.charAt(0).toUpperCase() + str.slice(1)
// This is a factory function for dynamically creating root-level list views,
// since they share most of the logic except for the type of items to display.
// They are essentially higher order components wrapping ItemList.vue.
export default function createListView (type) {
return {
name: `${type}-stories-view`,
fetch ({ store }) {
return store.dispatch('FETCH_LIST_DATA', { type })
},
head: {
title: camelize(type),
},
render (h) {
return h(ItemList, { props: { type }})
}
}
}
<script>
import createListView from '~components/createListView'
export default createListView('ask')
</script>
<script>
import createListView from '~components/createListView'
export default createListView('job')
</script>
<script>
import createListView from '~components/createListView'
export default createListView('new')
</script>
<script>
import createListView from '~components/createListView'
export default createListView('show')
</script>
<script>
import createListView from '~components/createListView'
export default createListView('top')
</script>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment