Commit 61d8c288 authored by Evan You's avatar Evan You

refactor store naming + use stylus

parent c2559459
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
"css-loader": "^0.23.1", "css-loader": "^0.23.1",
"extract-text-webpack-plugin": "^2.0.0-beta.3", "extract-text-webpack-plugin": "^2.0.0-beta.3",
"file-loader": "^0.8.4", "file-loader": "^0.8.4",
"stylus": "^0.54.5",
"stylus-loader": "^2.1.2",
"vue-loader": "^9.2.2", "vue-loader": "^9.2.2",
"webpack": "^2.1.0-beta.20", "webpack": "^2.1.0-beta.20",
"webpack-dev-middleware": "^1.6.1", "webpack-dev-middleware": "^1.6.1",
......
...@@ -13,23 +13,22 @@ ...@@ -13,23 +13,22 @@
</div> </div>
</template> </template>
<style> <style lang="stylus">
body { body
font-family: Roboto, Helvetica, sans-serif; font-family Roboto, Helvetica, sans-serif
}
.logo { .logo
width: 30px; width 30px
}
.view { .view
transition: all .35s ease; transition all .35s ease
}
.view-enter, .view-leave-active { .view-enter, .view-leave-active
opacity: 0; opacity 0
}
a { a
color: #4fc08d; color #4fc08d
}
a.disabled { a.disabled
color: #999; color #999
}
</style> </style>
...@@ -10,41 +10,40 @@ export default { ...@@ -10,41 +10,40 @@ export default {
} }
</script> </script>
<style> <style lang="stylus">
.spinner { $offset = 126
opacity: 0; $duration = 1.4s
transition: opacity .3s ease;
animation: rotator 1.4s linear infinite;
animation-play-state: paused;
}
.spinner.show { .spinner
opacity: 1; opacity 0
animation-play-state: running; transition opacity .15s ease
} animation rotator $duration linear infinite
animation-play-state paused
@keyframes rotator { .spinner.show
0% { transform: scale(0.5) rotate(0deg); } opacity 1
100% { transform: scale(0.5) rotate(270deg); } animation-play-state running
}
.spinner .path { @keyframes rotator
stroke: #4fc08d; 0%
stroke-dasharray: 126; transform scale(0.5) rotate(0deg)
stroke-dashoffset: 0; 100%
transform-origin: center; transform scale(0.5) rotate(270deg)
animation: dash 1.4s ease-in-out infinite;
}
@keyframes dash { .spinner .path
0% { stroke-dashoffset: 126; } stroke #4fc08d
50% { stroke-dasharray $offset
stroke-dashoffset: 32; stroke-dashoffset 0
transform:rotate(135deg); transform-origin center
} animation dash 1.4s ease-in-out infinite
100% {
stroke-dashoffset: 126; @keyframes dash
transform:rotate(450deg); 0%
} stroke-dashoffset $offset
} 50%
stroke-dashoffset ($offset/2)
transform rotate(135deg)
100%
stroke-dashoffset $offset
transform rotate(450deg)
</style> </style>
...@@ -6,30 +6,30 @@ Vue.use(Vuex) ...@@ -6,30 +6,30 @@ Vue.use(Vuex)
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
storiesPerPage: 20, itemsPerPage: 20,
topStoryIds: [], activeItemIds: [],
items: {} items: {}
}, },
actions: { actions: {
FETCH_TOP_IDS: ({ commit }) => { FETCH_IDS: ({ commit }) => {
return fetchTopIds().then(ids => { return fetchTopIds().then(ids => {
commit('RECEIVE_TOP_IDS', { ids }) commit('SET_ACTIVE_IDS', { ids })
}) })
}, },
FETCH_NEWS: ({ commit, state }) => { FETCH_DISPLAYED_ITEMS: ({ commit, state }) => {
const ids = getDisplayedIds(state) const ids = getDisplayedIds(state)
return fetchItems(ids).then(items => { return fetchItems(ids).then(items => {
commit('RECEIVE_ITEMS', { items }) commit('SET_ITEMS', { items })
}) })
} }
}, },
mutations: { mutations: {
RECEIVE_TOP_IDS: (state, { ids }) => { SET_ACTIVE_IDS: (state, { ids }) => {
state.topStoryIds = ids state.activeItemIds = ids
}, },
RECEIVE_ITEMS: (state, { items }) => { SET_ITEMS: (state, { items }) => {
items.forEach(item => { items.forEach(item => {
Vue.set(state.items, item.id, item) Vue.set(state.items, item.id, item)
}) })
...@@ -37,7 +37,7 @@ const store = new Vuex.Store({ ...@@ -37,7 +37,7 @@ const store = new Vuex.Store({
}, },
getters: { getters: {
news: state => { displayedItems: state => {
const ids = getDisplayedIds(state) const ids = getDisplayedIds(state)
return ids.map(id => state.items[id]).filter(_ => _) return ids.map(id => state.items[id]).filter(_ => _)
} }
...@@ -47,17 +47,17 @@ const store = new Vuex.Store({ ...@@ -47,17 +47,17 @@ const store = new Vuex.Store({
// watch for realtime top IDs updates on the client // watch for realtime top IDs updates on the client
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
watchTopIds(ids => { watchTopIds(ids => {
store.commit('RECEIVE_TOP_IDS', { ids }) store.commit('SET_ACTIVE_IDS', { ids })
store.dispatch('FETCH_NEWS') store.dispatch('FETCH_DISPLAYED_ITEMS')
}) })
} }
function getDisplayedIds (state) { function getDisplayedIds (state) {
const page = Number(state.route.params.page) || 1 const page = Number(state.route.params.page) || 1
const { storiesPerPage, topStoryIds } = state const { itemsPerPage, activeItemIds } = state
const start = (page - 1) * storiesPerPage const start = (page - 1) * itemsPerPage
const end = page * storiesPerPage const end = page * itemsPerPage
return topStoryIds.slice(start, end) return activeItemIds.slice(start, end)
} }
export default store export default store
<template> <template>
<div> <div>
<h2>News <spinner :show="loading"></spinner></h2> <spinner :show="loading"></spinner>
<ul> <ul>
<li> <li>
<router-link v-if="page > 1" :to="'/news/' + (page - 1)">prev</router-link> <router-link v-if="page > 1" :to="'/news/' + (page - 1)">prev</router-link>
...@@ -28,8 +28,8 @@ import NewsItem from '../components/NewsItem.vue' ...@@ -28,8 +28,8 @@ import NewsItem from '../components/NewsItem.vue'
const fetchInitialData = store => { const fetchInitialData = store => {
return store return store
.dispatch(`FETCH_TOP_IDS`) .dispatch(`FETCH_IDS`)
.then(() => store.dispatch(`FETCH_NEWS`)) .then(() => store.dispatch(`FETCH_DISPLAYED_ITEMS`))
} }
export default { export default {
...@@ -43,7 +43,7 @@ export default { ...@@ -43,7 +43,7 @@ export default {
return { return {
loading: false, loading: false,
displayPage: this.$route.params.page, displayPage: this.$route.params.page,
displayItems: this.$store.getters.news, displayItems: this.$store.getters.displayedItems,
transition: 'slide-left' transition: 'slide-left'
} }
}, },
...@@ -52,8 +52,8 @@ export default { ...@@ -52,8 +52,8 @@ export default {
return Number(this.$route.params.page) return Number(this.$route.params.page)
}, },
maxPage () { maxPage () {
const { storiesPerPage, topStoryIds } = this.$store.state const { itemsPerPage, activeItemIds } = this.$store.state
return Math.floor(topStoryIds.length / storiesPerPage) return Math.floor(activeItemIds.length / itemsPerPage)
}, },
hasMore () { hasMore () {
return this.page < this.maxPage return this.page < this.maxPage
...@@ -68,12 +68,12 @@ export default { ...@@ -68,12 +68,12 @@ export default {
watch: { watch: {
'$route' (to, from) { '$route' (to, from) {
this.loading = true this.loading = true
this.$store.dispatch(`FETCH_NEWS`).then(() => { this.$store.dispatch(`FETCH_DISPLAYED_ITEMS`).then(() => {
const toPage = Number(to.params.page) const toPage = Number(to.params.page)
const fromPage = Number(from.params.page) const fromPage = Number(from.params.page)
this.transition = toPage > fromPage ? 'slide-left' : 'slide-right' this.transition = toPage > fromPage ? 'slide-left' : 'slide-right'
this.displayPage = toPage this.displayPage = toPage
this.displayItems = this.$store.getters.news.slice() this.displayItems = this.$store.getters.displayedItems
this.loading = false this.loading = false
}) })
} }
...@@ -81,29 +81,28 @@ export default { ...@@ -81,29 +81,28 @@ export default {
} }
</script> </script>
<style> <style lang="stylus">
.news-list { .news-list
position: absolute; position absolute
transition: all .5s cubic-bezier(.55,0,.1,1); transition all .5s cubic-bezier(.55,0,.1,1)
}
.slide-left-enter, .slide-right-leave-active { .slide-left-enter, .slide-right-leave-active
opacity: 0; opacity 0
transform: translate(30px, 0); transform translate(30px, 0)
}
.slide-left-leave-active, .slide-right-enter { .slide-left-leave-active, .slide-right-enter
opacity: 0; opacity 0
transform: translate(-30px, 0); transform translate(-30px, 0)
}
.item-move, .item-enter-active, .item-leave-active { .item-move, .item-enter-active, .item-leave-active
transition: all .5s cubic-bezier(.55,0,.1,1); transition all .5s cubic-bezier(.55,0,.1,1)
}
.item-enter { .item-enter
opacity: 0; opacity 0
transform: translate(30px, 0); transform translate(30px, 0)
}
.item-leave-active { .item-leave-active
position: absolute; position absolute
opacity: 0; opacity 0
transform: translate(30px, 0); transform translate(30px, 0)
}
</style> </style>
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