mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-13 07:46:06 +00:00
This fixes the lint errors and failing frontend tests. Also, when the user chooses another orderBy, the menu gets translated. The refactoring moves code and complexity into the vuex store where it can be tested separately.
224 lines
5.6 KiB
Vue
224 lines
5.6 KiB
Vue
<template>
|
|
<div>
|
|
<masonry-grid>
|
|
<ds-grid-item v-show="hashtag" :row-span="2" column-span="fullWidth">
|
|
<filter-menu :hashtag="hashtag" @clearSearch="clearSearch" />
|
|
</ds-grid-item>
|
|
<ds-grid-item :row-span="2" column-span="fullWidth">
|
|
<div class="sorting-dropdown">
|
|
<ds-select
|
|
v-model="selected"
|
|
:options="sortingOptions"
|
|
size="large"
|
|
:icon-right="sortingIcon"
|
|
></ds-select>
|
|
</div>
|
|
</ds-grid-item>
|
|
<template v-if="hasResults">
|
|
<masonry-grid-item v-for="post in posts" :key="post.id">
|
|
<hc-post-card
|
|
:post="post"
|
|
:width="{ base: '100%', xs: '100%', md: '50%', xl: '33%' }"
|
|
@removePostFromList="deletePost"
|
|
/>
|
|
</masonry-grid-item>
|
|
</template>
|
|
<template v-else>
|
|
<ds-grid-item :row-span="2" column-span="fullWidth">
|
|
<hc-empty icon="docs" />
|
|
<ds-text align="center">{{ $t('index.no-results') }}</ds-text>
|
|
<ds-text align="center">{{ $t('index.change-filter-settings') }}</ds-text>
|
|
</ds-grid-item>
|
|
</template>
|
|
</masonry-grid>
|
|
<client-only>
|
|
<ds-button
|
|
v-tooltip="{ content: $t('contribution.newPost'), placement: 'left', delay: { show: 500 } }"
|
|
:path="{ name: 'post-create' }"
|
|
class="post-add-button"
|
|
icon="plus"
|
|
size="x-large"
|
|
primary
|
|
/>
|
|
</client-only>
|
|
<div
|
|
v-if="hasMore"
|
|
v-infinite-scroll="showMoreContributions"
|
|
:infinite-scroll-disabled="$apollo.loading"
|
|
:infinite-scroll-distance="10"
|
|
:infinite-scroll-throttle-delay="800"
|
|
:infinite-scroll-immediate-check="true"
|
|
>
|
|
<hc-load-more :loading="$apollo.loading" @click="showMoreContributions" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import FilterMenu from '~/components/FilterMenu/FilterMenu.vue'
|
|
import HcEmpty from '~/components/Empty'
|
|
import HcPostCard from '~/components/PostCard'
|
|
import HcLoadMore from '~/components/LoadMore.vue'
|
|
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
|
|
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
|
|
import { mapGetters, mapMutations } from 'vuex'
|
|
import { filterPosts } from '~/graphql/PostQuery.js'
|
|
|
|
export default {
|
|
components: {
|
|
FilterMenu,
|
|
HcPostCard,
|
|
HcLoadMore,
|
|
HcEmpty,
|
|
MasonryGrid,
|
|
MasonryGridItem,
|
|
},
|
|
data() {
|
|
const { hashtag = null } = this.$route.query
|
|
return {
|
|
posts: [],
|
|
hasMore: true,
|
|
// Initialize your apollo data
|
|
offset: 0,
|
|
pageSize: 12,
|
|
hashtag,
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
postsFilter: 'posts/filter',
|
|
orderOptions: 'posts/orderOptions',
|
|
orderBy: 'posts/orderBy',
|
|
selectedOrder: 'posts/selectedOrder',
|
|
sortingIcon: 'posts/orderIcon',
|
|
}),
|
|
selected: {
|
|
get() {
|
|
return this.selectedOrder(this)
|
|
},
|
|
set({ value }) {
|
|
this.offset = 0
|
|
this.posts = []
|
|
this.selectOrder(value)
|
|
},
|
|
},
|
|
sortingOptions() {
|
|
return this.orderOptions(this)
|
|
},
|
|
finalFilters() {
|
|
let filter = this.postsFilter
|
|
if (this.hashtag) {
|
|
filter = {
|
|
...filter,
|
|
tags_some: { id: this.hashtag },
|
|
}
|
|
}
|
|
return filter
|
|
},
|
|
hasResults() {
|
|
return this.$apollo.loading || (this.posts && this.posts.length > 0)
|
|
},
|
|
},
|
|
methods: {
|
|
...mapMutations({
|
|
selectOrder: 'posts/SELECT_ORDER',
|
|
}),
|
|
clearSearch() {
|
|
this.$router.push({ path: '/' })
|
|
this.hashtag = null
|
|
},
|
|
href(post) {
|
|
return this.$router.resolve({
|
|
name: 'post-id-slug',
|
|
params: { id: post.id, slug: post.slug },
|
|
}).href
|
|
},
|
|
showMoreContributions() {
|
|
const { Post: PostQuery } = this.$apollo.queries
|
|
if (!PostQuery) return // seems this can be undefined on subpages
|
|
|
|
this.offset += this.pageSize
|
|
PostQuery.fetchMore({
|
|
variables: {
|
|
offset: this.offset,
|
|
filter: this.finalFilters,
|
|
first: this.pageSize,
|
|
orderBy: this.orderBy,
|
|
},
|
|
updateQuery: (previousResult, { fetchMoreResult }) => {
|
|
if (!fetchMoreResult || fetchMoreResult.Post.length < this.pageSize) {
|
|
this.hasMore = false
|
|
}
|
|
const result = Object.assign({}, previousResult, {
|
|
Post: [...previousResult.Post, ...fetchMoreResult.Post],
|
|
})
|
|
return result
|
|
},
|
|
})
|
|
},
|
|
deletePost(deletedPost) {
|
|
this.posts = this.posts.filter(post => {
|
|
return post.id !== deletedPost.id
|
|
})
|
|
},
|
|
},
|
|
apollo: {
|
|
Post: {
|
|
query() {
|
|
return filterPosts(this.$i18n)
|
|
},
|
|
variables() {
|
|
return {
|
|
filter: this.finalFilters,
|
|
first: this.pageSize,
|
|
orderBy: this.orderBy,
|
|
offset: 0,
|
|
}
|
|
},
|
|
update({ Post }) {
|
|
this.posts = Post
|
|
},
|
|
fetchPolicy: 'cache-and-network',
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.ds-card-image img {
|
|
max-height: 2000px;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.masonry-grid {
|
|
display: grid;
|
|
grid-gap: 10px;
|
|
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
grid-auto-rows: 20px;
|
|
}
|
|
|
|
.grid-item {
|
|
grid-row-end: span 2;
|
|
|
|
&--full-width {
|
|
grid-column: 1 / -1;
|
|
}
|
|
}
|
|
|
|
.post-add-button {
|
|
z-index: 100;
|
|
position: fixed;
|
|
bottom: -5px;
|
|
left: 98vw;
|
|
transform: translate(-120%, -120%);
|
|
box-shadow: $box-shadow-x-large;
|
|
}
|
|
|
|
.sorting-dropdown {
|
|
width: 250px;
|
|
position: relative;
|
|
float: right;
|
|
margin: 4px 0;
|
|
}
|
|
</style>
|