mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2026-03-01 12:44:37 +00:00
fix(webapp): optimize masonry grid rendering and add SSR compatibility (#9284)
This commit is contained in:
parent
e3a41cb828
commit
6b6e77c2a5
@ -7,6 +7,7 @@
|
||||
url('~@@/assets/fonts/gentium-basic/GentiumBasic.woff2') format('woff2'),
|
||||
url('~@@/assets/fonts/gentium-basic/GentiumBasic.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -18,4 +19,5 @@
|
||||
url('~@@/assets/fonts/gentium-basic/GentiumBasic-Italic.woff2') format('woff2'),
|
||||
url('~@@/assets/fonts/gentium-basic/GentiumBasic-Italic.woff') format('woff');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Webfont: Lato-BoldItalic */
|
||||
@ -16,6 +17,7 @@
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Webfont: Lato-Italic */
|
||||
@ -26,6 +28,7 @@
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
/* Webfont: Lato-Regular */
|
||||
@ -36,4 +39,5 @@
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@ -56,5 +56,6 @@ export default {
|
||||
margin-bottom: $space-x-small;
|
||||
margin-top: 16px;
|
||||
cursor: pointer;
|
||||
color: $text-color-base;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -45,6 +45,7 @@ export default {
|
||||
watch: {
|
||||
isPopoverOpen: {
|
||||
handler(isOpen) {
|
||||
if (typeof document === 'undefined') return
|
||||
if (isOpen) {
|
||||
document.body.classList.add('dropdown-open')
|
||||
} else {
|
||||
@ -58,7 +59,9 @@ export default {
|
||||
clearTimeout(mouseLeaveTimer)
|
||||
if (this.isPopoverOpen) {
|
||||
this.isPopoverOpen = false
|
||||
document.body.classList.remove('dropdown-open')
|
||||
if (typeof document !== 'undefined') {
|
||||
document.body.classList.remove('dropdown-open')
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
@ -4,6 +4,13 @@ import MasonryGrid from './MasonryGrid'
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const GridChild = {
|
||||
template: '<div>child</div>',
|
||||
data() {
|
||||
return { rowSpan: 0 }
|
||||
},
|
||||
}
|
||||
|
||||
describe('MasonryGrid', () => {
|
||||
let wrapper
|
||||
|
||||
@ -11,29 +18,66 @@ describe('MasonryGrid', () => {
|
||||
wrapper = mount(MasonryGrid, { localVue })
|
||||
})
|
||||
|
||||
it('adds the "reset-grid-height" class when itemsCalculating is more than 0', async () => {
|
||||
wrapper.setData({ itemsCalculating: 1 })
|
||||
it('adds the "reset-grid-height" class when measuring is true', async () => {
|
||||
wrapper.setData({ measuring: true })
|
||||
await Vue.nextTick()
|
||||
expect(wrapper.classes()).toContain('reset-grid-height')
|
||||
})
|
||||
|
||||
it('removes the "reset-grid-height" class when itemsCalculating is 0', async () => {
|
||||
wrapper.setData({ itemsCalculating: 0 })
|
||||
it('removes the "reset-grid-height" class when measuring is false', async () => {
|
||||
wrapper.setData({ measuring: false })
|
||||
await Vue.nextTick()
|
||||
expect(wrapper.classes()).not.toContain('reset-grid-height')
|
||||
})
|
||||
|
||||
it('adds 1 to itemsCalculating when "calculating-item-height" is emitted', async () => {
|
||||
wrapper.setData({ itemsCalculating: 0 })
|
||||
wrapper.vm.$emit('calculating-item-height')
|
||||
await Vue.nextTick()
|
||||
expect(wrapper.vm.itemsCalculating).toBe(1)
|
||||
it('sets inline grid styles', () => {
|
||||
expect(wrapper.element.style.gridAutoRows).toBe('2px')
|
||||
expect(wrapper.element.style.rowGap).toBe('2px')
|
||||
})
|
||||
|
||||
it('subtracts 1 from itemsCalculating when "finished-calculating-item-height" is emitted', async () => {
|
||||
wrapper.setData({ itemsCalculating: 2 })
|
||||
wrapper.vm.$emit('finished-calculating-item-height')
|
||||
it('calculates rowSpan for children via batchRecalculate', async () => {
|
||||
wrapper = mount(MasonryGrid, {
|
||||
localVue,
|
||||
slots: { default: GridChild },
|
||||
})
|
||||
|
||||
const child = wrapper.vm.$children[0]
|
||||
Object.defineProperty(child.$el, 'clientHeight', { value: 100, configurable: true })
|
||||
|
||||
await wrapper.vm.batchRecalculate()
|
||||
|
||||
// Math.ceil((100 + 2) / (2 + 2)) = Math.ceil(25.5) = 26
|
||||
expect(child.rowSpan).toBe(26)
|
||||
expect(wrapper.vm.measuring).toBe(false)
|
||||
})
|
||||
|
||||
it('recalculates when child count changes in updated()', async () => {
|
||||
const Parent = {
|
||||
template: '<MasonryGrid><GridChild v-for="n in count" :key="n" /></MasonryGrid>',
|
||||
components: { MasonryGrid, GridChild },
|
||||
data() {
|
||||
return { count: 1 }
|
||||
},
|
||||
}
|
||||
wrapper = mount(Parent, { localVue })
|
||||
await Vue.nextTick()
|
||||
expect(wrapper.vm.itemsCalculating).toBe(1)
|
||||
expect(wrapper.vm.$children[0].childCount).toBe(1)
|
||||
|
||||
wrapper.setData({ count: 2 })
|
||||
await Vue.nextTick()
|
||||
await Vue.nextTick()
|
||||
expect(wrapper.vm.$children[0].childCount).toBe(2)
|
||||
})
|
||||
|
||||
it('skips children without rowSpan', async () => {
|
||||
const NoRowSpan = { template: '<div>no rowSpan</div>' }
|
||||
wrapper = mount(MasonryGrid, {
|
||||
localVue,
|
||||
slots: { default: NoRowSpan },
|
||||
})
|
||||
|
||||
await wrapper.vm.batchRecalculate()
|
||||
|
||||
expect(wrapper.vm.measuring).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,61 +1,73 @@
|
||||
<template>
|
||||
<div class="ds-grid" :style="gridStyle" :class="[itemsCalculating ? 'reset-grid-height' : '']">
|
||||
<div
|
||||
class="ds-grid"
|
||||
:style="{ gridAutoRows: '2px', rowGap: '2px' }"
|
||||
:class="[measuring ? 'reset-grid-height' : '']"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const ROW_HEIGHT = 2
|
||||
const ROW_GAP = 2
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
itemsCalculating: 0,
|
||||
isMobile: false,
|
||||
measuring: false,
|
||||
childCount: 0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
gridStyle() {
|
||||
const size = this.isMobile ? '1px' : '2px'
|
||||
return { gridAutoRows: size, rowGap: size }
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
isMobile() {
|
||||
this.$nextTick(() => {
|
||||
this.$children.forEach((child) => {
|
||||
if (child.calculateItemHeight) child.calculateItemHeight()
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$on('calculating-item-height', this.startCalculation)
|
||||
this.$on('finished-calculating-item-height', this.endCalculation)
|
||||
},
|
||||
methods: {
|
||||
startCalculation() {
|
||||
this.itemsCalculating += 1
|
||||
},
|
||||
endCalculation() {
|
||||
this.itemsCalculating -= 1
|
||||
},
|
||||
checkMobile() {
|
||||
this.isMobile = window.innerWidth <= 810
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.checkMobile()
|
||||
// Children mount before parent — recalculate their spans with correct grid values
|
||||
this.$nextTick(() => {
|
||||
this.$children.forEach((child) => {
|
||||
if (child.calculateItemHeight) child.calculateItemHeight()
|
||||
})
|
||||
})
|
||||
window.addEventListener('resize', this.checkMobile)
|
||||
this.$nextTick(() => this.batchRecalculate())
|
||||
this._resizeTimer = null
|
||||
this._onResize = () => {
|
||||
clearTimeout(this._resizeTimer)
|
||||
this._resizeTimer = setTimeout(() => this.batchRecalculate(), 150)
|
||||
}
|
||||
window.addEventListener('resize', this._onResize)
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$off('calculating-item-height', this.startCalculation)
|
||||
this.$off('finished-calculating-item-height', this.endCalculation)
|
||||
window.removeEventListener('resize', this.checkMobile)
|
||||
clearTimeout(this._resizeTimer)
|
||||
window.removeEventListener('resize', this._onResize)
|
||||
},
|
||||
updated() {
|
||||
const count = this.$children.length
|
||||
if (count !== this.childCount) {
|
||||
this.batchRecalculate()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async batchRecalculate() {
|
||||
this._recalcId = (this._recalcId || 0) + 1
|
||||
const id = this._recalcId
|
||||
|
||||
this.childCount = this.$children.length
|
||||
// Switch to auto-height so items take their natural height
|
||||
this.measuring = true
|
||||
|
||||
await this.$nextTick()
|
||||
|
||||
// A newer call has started — let it handle the measurement
|
||||
if (id !== this._recalcId) return
|
||||
|
||||
// Read pass: measure all children in one go (single reflow)
|
||||
const measurements = this.$children.map((child) => ({
|
||||
child,
|
||||
height: child.$el.clientHeight,
|
||||
}))
|
||||
|
||||
// Write pass: set all rowSpans (no interleaved reads)
|
||||
measurements.forEach(({ child, height }) => {
|
||||
if (child.rowSpan !== undefined) {
|
||||
child.rowSpan = Math.ceil((height + ROW_GAP) / (ROW_HEIGHT + ROW_GAP))
|
||||
}
|
||||
})
|
||||
|
||||
// Switch back to fixed row grid
|
||||
this.measuring = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -27,24 +27,5 @@ export default {
|
||||
rowSpan: this.imageAspectRatio ? getRowSpan(this.imageAspectRatio) : 69,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
calculateItemHeight() {
|
||||
this.$parent.$emit('calculating-item-height')
|
||||
|
||||
this.$nextTick(() => {
|
||||
const gridStyle = this.$parent.$el.style
|
||||
const rowHeight = parseInt(gridStyle.gridAutoRows)
|
||||
const rowGapValue = gridStyle.rowGap || gridStyle.gridRowGap
|
||||
const rowGap = parseInt(rowGapValue)
|
||||
const itemHeight = this.$el.clientHeight
|
||||
|
||||
this.rowSpan = Math.ceil((itemHeight + rowGap) / (rowHeight + rowGap))
|
||||
this.$parent.$emit('finished-calculating-item-height')
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.calculateItemHeight()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -12,8 +12,17 @@
|
||||
:highlight="isPinned"
|
||||
>
|
||||
<template v-if="post.image" #heroImage>
|
||||
<div class="image-placeholder" :style="{ aspectRatio: post.image.aspectRatio }">
|
||||
<responsive-image :image="post.image" sizes="640px" class="image" />
|
||||
<div
|
||||
class="image-placeholder"
|
||||
:class="{ 'image-placeholder--loaded': imageLoaded }"
|
||||
:style="{ aspectRatio: post.image.aspectRatio }"
|
||||
>
|
||||
<responsive-image
|
||||
:image="post.image"
|
||||
sizes="640px"
|
||||
class="image"
|
||||
@loaded="imageLoaded = true"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<client-only>
|
||||
@ -207,6 +216,11 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
imageLoaded: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
user: 'auth/user',
|
||||
@ -303,6 +317,18 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes image-placeholder-pulse {
|
||||
0% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.post-user-row {
|
||||
position: relative;
|
||||
|
||||
@ -335,7 +361,12 @@ export default {
|
||||
|
||||
.image-placeholder {
|
||||
width: 100%;
|
||||
background-color: $color-neutral-80;
|
||||
background-color: $background-color-softer;
|
||||
animation: image-placeholder-pulse 1.5s ease-in-out infinite;
|
||||
|
||||
&--loaded {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
> .image {
|
||||
display: block;
|
||||
|
||||
@ -1,9 +1,20 @@
|
||||
<template>
|
||||
<img :src="image.url" :sizes="sizes" :srcset="srcset" />
|
||||
<img
|
||||
:src="image.url"
|
||||
:sizes="sizes"
|
||||
:srcset="srcset"
|
||||
:class="{ 'responsive-image--loaded': loaded }"
|
||||
class="responsive-image"
|
||||
loading="lazy"
|
||||
fetchpriority="low"
|
||||
@load="onLoad"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ResponsiveImage',
|
||||
emits: ['loaded'],
|
||||
props: {
|
||||
image: {
|
||||
type: Object,
|
||||
@ -14,11 +25,36 @@ export default {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loaded: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
srcset() {
|
||||
const { w320, w640, w1024 } = this.image
|
||||
return `${w320} 320w, ${w640} 640w, ${w1024} 1024w`
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.$el.complete && this.$el.naturalWidth > 0) this.onLoad()
|
||||
},
|
||||
methods: {
|
||||
onLoad() {
|
||||
this.loaded = true
|
||||
this.$emit('loaded')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.responsive-image {
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
|
||||
&--loaded {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -190,7 +190,9 @@ exports[`UserTeaser given an user user is disabled current user is a moderator r
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -321,7 +323,9 @@ exports[`UserTeaser given an user with linkToProfile, on desktop renders 1`] = `
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -411,7 +415,9 @@ exports[`UserTeaser given an user with linkToProfile, on desktop when hovering t
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -501,7 +507,9 @@ exports[`UserTeaser given an user with linkToProfile, on touch screen renders 1`
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -592,7 +600,9 @@ exports[`UserTeaser given an user with linkToProfile, on touch screen when click
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -687,7 +697,9 @@ exports[`UserTeaser given an user without linkToProfile, on desktop renders 1`]
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -777,7 +789,9 @@ exports[`UserTeaser given an user without linkToProfile, on desktop when hoverin
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -867,7 +881,9 @@ exports[`UserTeaser given an user without linkToProfile, on desktop when hoverin
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -957,7 +973,9 @@ exports[`UserTeaser given an user without linkToProfile, on touch screen renders
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -1048,7 +1066,9 @@ exports[`UserTeaser given an user without linkToProfile, on touch screen when cl
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
@ -1143,7 +1163,9 @@ exports[`UserTeaser given an user without linkToProfile, on touch screen when cl
|
||||
|
||||
<img
|
||||
alt="Tilda Swinton"
|
||||
class="image"
|
||||
class="responsive-image image"
|
||||
fetchpriority="low"
|
||||
loading="lazy"
|
||||
sizes="320px"
|
||||
src="/avatars/tilda-swinton"
|
||||
srcset="/avatars/tilda-swinton-w320 320w, /avatars/tilda-swinton-w640 640w, /avatars/tilda-swinton-w1024 1024w"
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
export const isTouchDevice = () =>
|
||||
'ontouchstart' in window || navigator.MaxTouchPoints > 0 || navigator.msMaxTouchPoints > 0
|
||||
typeof window !== 'undefined' &&
|
||||
('ontouchstart' in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0)
|
||||
|
||||
@ -52,7 +52,30 @@ export default (i18n) => {
|
||||
`
|
||||
}
|
||||
|
||||
export const filterPosts = (i18n) => {
|
||||
export const filterPosts = () => {
|
||||
return gql`
|
||||
${user}
|
||||
${post}
|
||||
${postCounts}
|
||||
${tagsCategoriesAndPinned}
|
||||
|
||||
query Post($filter: _PostFilter, $first: Int, $offset: Int, $orderBy: [_PostOrdering]) {
|
||||
Post(filter: $filter, first: $first, offset: $offset, orderBy: $orderBy) {
|
||||
postType
|
||||
eventStart
|
||||
eventEnd
|
||||
eventVenue
|
||||
eventLocationName
|
||||
eventIsOnline
|
||||
...post
|
||||
...postCounts
|
||||
...tagsCategoriesAndPinned
|
||||
}
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
export const filterMapPosts = (i18n) => {
|
||||
const lang = i18n.locale().toUpperCase()
|
||||
return gql`
|
||||
${user}
|
||||
|
||||
@ -239,6 +239,12 @@ export default {
|
||||
},
|
||||
|
||||
manifest,
|
||||
|
||||
render: {
|
||||
// Generate preload hints for critical JS/CSS/font assets
|
||||
resourceHints: true,
|
||||
},
|
||||
|
||||
/*
|
||||
** Build configuration
|
||||
*/
|
||||
|
||||
@ -344,7 +344,7 @@ export default {
|
||||
},
|
||||
Post: {
|
||||
query() {
|
||||
return filterPosts(this.$i18n)
|
||||
return filterPosts()
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
|
||||
@ -66,7 +66,7 @@ import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { profileUserQuery, mapUserQuery } from '~/graphql/User'
|
||||
import { groupQuery } from '~/graphql/groups'
|
||||
import { filterPosts } from '~/graphql/PostQuery.js'
|
||||
import { filterMapPosts } from '~/graphql/PostQuery.js'
|
||||
import mobile from '~/mixins/mobile'
|
||||
import Empty from '~/components/Empty/Empty'
|
||||
import MapStylesButtons from '~/components/Map/MapStylesButtons'
|
||||
@ -542,7 +542,7 @@ export default {
|
||||
},
|
||||
Post: {
|
||||
query() {
|
||||
return filterPosts(this.$i18n)
|
||||
return filterMapPosts(this.$i18n)
|
||||
},
|
||||
variables() {
|
||||
return {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user