fix(webapp): add responsive masonry layout and skeleton loading UI (#9282)

This commit is contained in:
Ulf Gebhardt 2026-02-21 12:01:59 +01:00 committed by GitHub
parent 64594a3235
commit e3a41cb828
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 352 additions and 119 deletions

View File

@ -1,9 +1,5 @@
<template>
<div
class="ds-grid"
:style="{ gridAutoRows: '20px', rowGap: '16px', columnGap: '16px' }"
:class="[itemsCalculating ? 'reset-grid-height' : '']"
>
<div class="ds-grid" :style="gridStyle" :class="[itemsCalculating ? 'reset-grid-height' : '']">
<slot></slot>
</div>
</template>
@ -13,16 +9,28 @@ export default {
data() {
return {
itemsCalculating: 0,
isMobile: false,
}
},
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)
},
beforeDestroy() {
this.$off('calculating-item-height', this.startCalculation)
this.$off('finished-calculating-item-height', this.endCalculation)
},
methods: {
startCalculation() {
this.itemsCalculating += 1
@ -30,6 +38,24 @@ export default {
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)
},
beforeDestroy() {
this.$off('calculating-item-height', this.startCalculation)
this.$off('finished-calculating-item-height', this.endCalculation)
window.removeEventListener('resize', this.checkMobile)
},
}
</script>
@ -37,6 +63,11 @@ export default {
<style lang="scss">
.ds-grid {
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
column-gap: 16px;
@media (max-width: 810px) {
column-gap: 8px;
}
}
.reset-grid-height {

View File

@ -7,38 +7,59 @@ describe('MasonryGridItem', () => {
let wrapper
describe('given an imageAspectRatio', () => {
it('sets the initial rowSpan to 13 when the ratio is higher than 1.3', () => {
it('sets the initial rowSpan to 114 when the ratio is higher than 1.3', () => {
const propsData = { imageAspectRatio: 2 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(13)
expect(wrapper.vm.rowSpan).toBe(114)
})
it('sets the initial rowSpan to 15 when the ratio is between 1.3 and 1', () => {
it('sets the initial rowSpan to 114 when the ratio is exactly 1.3', () => {
const propsData = { imageAspectRatio: 1.3 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(114)
})
it('sets the initial rowSpan to 132 when the ratio is between 1.3 and 1', () => {
const propsData = { imageAspectRatio: 1.1 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(15)
expect(wrapper.vm.rowSpan).toBe(132)
})
it('sets the initial rowSpan to 18 when the ratio is between 1 and 0.7', () => {
it('sets the initial rowSpan to 132 when the ratio is exactly 1', () => {
const propsData = { imageAspectRatio: 1.0 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(132)
})
it('sets the initial rowSpan to 159 when the ratio is between 1 and 0.7', () => {
const propsData = { imageAspectRatio: 0.8 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(159)
})
it('sets the initial rowSpan to 159 when the ratio is exactly 0.7', () => {
const propsData = { imageAspectRatio: 0.7 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(18)
expect(wrapper.vm.rowSpan).toBe(159)
})
it('sets the initial rowSpan to 25 when the ratio is lower than 0.7', () => {
it('sets the initial rowSpan to 222 when the ratio is lower than 0.7', () => {
const propsData = { imageAspectRatio: 0.3 }
wrapper = mount(MasonryGridItem, { localVue, propsData })
expect(wrapper.vm.rowSpan).toBe(25)
expect(wrapper.vm.rowSpan).toBe(222)
})
})
describe('given no aspect ratio', () => {
it('sets the initial rowSpan to 8 when not given an imageAspectRatio', () => {
it('sets the initial rowSpan to 69', () => {
wrapper = mount(MasonryGridItem, { localVue })
expect(wrapper.vm.rowSpan).toBe(8)
})
expect(wrapper.vm.rowSpan).toBe(69)
})
})
})

View File

@ -9,10 +9,10 @@ const landscapeRatio = 1.3
const squareRatio = 1
const portraitRatio = 0.7
const getRowSpan = (aspectRatio) => {
if (aspectRatio >= landscapeRatio) return 13
else if (aspectRatio >= squareRatio) return 15
else if (aspectRatio >= portraitRatio) return 18
else return 25
if (aspectRatio >= landscapeRatio) return 114
else if (aspectRatio >= squareRatio) return 132
else if (aspectRatio >= portraitRatio) return 159
else return 222
}
export default {
@ -24,7 +24,7 @@ export default {
},
data() {
return {
rowSpan: this.imageAspectRatio ? getRowSpan(this.imageAspectRatio) : 8,
rowSpan: this.imageAspectRatio ? getRowSpan(this.imageAspectRatio) : 69,
}
},
methods: {

View File

@ -12,7 +12,9 @@
: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>
</template>
<client-only>
<div class="post-user-row">
@ -23,6 +25,17 @@
:typ="post.postType[0]"
/>
</div>
<template #placeholder>
<div class="post-user-row">
<div class="user-teaser-placeholder">
<div class="placeholder-avatar" />
<div class="placeholder-text">
<div class="placeholder-line placeholder-line--name" />
<div class="placeholder-line placeholder-line--date" />
</div>
</div>
</div>
</template>
</client-only>
<h2 class="title hyphenate-text">{{ post.title }}</h2>
<client-only>
@ -133,6 +146,11 @@
<slot name="dateTime"></slot>
</span>
</div>
<template v-if="post.createdAt" #placeholder>
<div class="date-row">
<span class="placeholder-line placeholder-line--date-footer" />
</div>
</template>
</client-only>
</os-card>
</nuxt-link>
@ -189,16 +207,6 @@ export default {
default: false,
},
},
mounted() {
const { image } = this.post
if (!image) return
const width = this.$el.offsetWidth
const height = Math.min(width / image.aspectRatio, 2000)
const imageElement = this.$el.querySelector('.os-card__hero-image')
if (imageElement) {
imageElement.style.height = `${height}px`
}
},
computed: {
...mapGetters({
user: 'auth/user',
@ -289,6 +297,10 @@ export default {
height: 100%;
color: $text-color-base;
padding-top: 16px;
@media (max-width: 810px) {
padding-top: 8px;
}
}
.post-user-row {
@ -315,13 +327,24 @@ export default {
flex-direction: column;
overflow: visible;
height: 100%;
padding-bottom: $space-x-small;
> .os-card__hero-image {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
.image-placeholder {
width: 100%;
background-color: $color-neutral-80;
> .image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
}
&.--blur-image > .os-card__hero-image .image {
filter: blur($blur-radius);
}
@ -333,6 +356,8 @@ export default {
padding-bottom: 0 !important;
}
padding-bottom: $space-x-small !important;
.content {
flex-grow: 1;
margin-bottom: $space-small;
@ -368,10 +393,55 @@ export default {
margin-bottom: $space-small;
}
.user-teaser-placeholder {
display: flex;
align-items: center;
margin-bottom: $space-small;
.placeholder-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: currentColor;
opacity: 0.15;
flex-shrink: 0;
}
.placeholder-text {
display: flex;
flex-direction: column;
gap: 6px;
padding-left: 10px;
flex: 1;
}
.placeholder-line {
height: 10px;
border-radius: 5px;
background: currentColor;
opacity: 0.15;
&--name {
width: 120px;
}
&--date {
width: 80px;
}
}
}
.date-row {
display: flex;
justify-content: flex-end;
margin-top: $space-small;
> .placeholder-line--date-footer {
width: 100px;
height: 10px;
border-radius: 5px;
background: currentColor;
opacity: 0.15;
}
> .text {
overflow: hidden;
white-space: nowrap;

View File

@ -0,0 +1,127 @@
<template>
<div class="post-teaser-skeleton">
<div class="skeleton-image" />
<div class="skeleton-body">
<div class="skeleton-user">
<div class="skeleton-avatar" />
<div class="skeleton-user-text">
<div class="skeleton-line skeleton-line--short" />
<div class="skeleton-line skeleton-line--xshort" />
</div>
</div>
<div class="skeleton-title">
<div class="skeleton-line" />
<div class="skeleton-line skeleton-line--medium" />
</div>
<div class="skeleton-content">
<div class="skeleton-line" />
<div class="skeleton-line" />
<div class="skeleton-line skeleton-line--long" />
</div>
<div class="skeleton-footer">
<div class="skeleton-line skeleton-line--short" />
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PostTeaserSkeleton',
}
</script>
<style lang="scss">
@keyframes skeleton-pulse {
0% {
opacity: 0.15;
}
50% {
opacity: 0.3;
}
100% {
opacity: 0.15;
}
}
.post-teaser-skeleton {
background: #fff;
border-radius: $border-radius-base;
box-shadow: $box-shadow-base;
overflow: hidden;
height: 100%;
}
.skeleton-image {
width: 100%;
padding-bottom: 56%;
background: currentColor;
animation: skeleton-pulse 1.5s ease-in-out infinite;
}
.skeleton-body {
padding: 12px;
display: flex;
flex-direction: column;
gap: 12px;
}
.skeleton-user {
display: flex;
align-items: center;
gap: 8px;
}
.skeleton-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: currentColor;
flex-shrink: 0;
animation: skeleton-pulse 1.5s ease-in-out infinite;
}
.skeleton-user-text {
display: flex;
flex-direction: column;
gap: 6px;
flex: 1;
}
.skeleton-title {
display: flex;
flex-direction: column;
gap: 6px;
}
.skeleton-content {
display: flex;
flex-direction: column;
gap: 6px;
}
.skeleton-footer {
margin-top: 4px;
}
.skeleton-line {
height: 12px;
border-radius: 6px;
background: currentColor;
animation: skeleton-pulse 1.5s ease-in-out infinite;
width: 100%;
&--xshort {
width: 25%;
}
&--short {
width: 40%;
}
&--medium {
width: 65%;
}
&--long {
width: 85%;
}
}
</style>

View File

@ -35,6 +35,7 @@ export default {
},
computed: {
progressBarWidth() {
if (!this.goal) return 'width: 0%;'
return `width: ${(this.progress / this.goal) * 100}%;`
},
progressBarColorClass() {
@ -59,7 +60,6 @@ export default {
position: relative;
height: 100%;
flex: 1;
margin-right: $space-x-small;
}
.progress-bar__goal {
@ -108,7 +108,6 @@ export default {
.progress-bar__label {
position: relative;
float: right;
@media (max-width: 350px) {
font-size: $font-size-small;
@ -117,7 +116,7 @@ export default {
.progress-bar-button {
position: relative;
float: right;
margin-left: $space-x-small;
@media (max-width: 810px) {
display: none;

View File

@ -117,10 +117,6 @@ export default {
if (!(id && slug)) return ''
return { name: 'groups-id-slug', params: { slug, id } }
},
groupSlug() {
const { slug } = this.group || {}
return slug && `&${slug}`
},
groupName() {
const { name } = this.group || {}
return name || this.$t('profile.userAnonym')

View File

@ -66,10 +66,15 @@ export default {
padding-bottom: 8rem;
}
.desktop-footer {
@media (max-width: 810px) {
.desktop-footer {
display: none;
}
.ds-container {
padding-left: $space-x-small !important;
padding-right: $space-x-small !important;
}
}
.chat-modul {

View File

@ -224,8 +224,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
School For Citizens
@ -233,8 +232,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&school-for-citizens
@ -536,8 +534,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="chip"
>
<span
class="os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em]"
style="word-break: break-all;"
class="word-break-all os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em] word-break-all"
>
Our children shall receive education for life.
</span>
@ -990,7 +987,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -1148,8 +1145,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
School For Citizens
@ -1157,8 +1153,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&school-for-citizens
@ -1413,8 +1408,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="chip"
>
<span
class="os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em]"
style="word-break: break-all;"
class="word-break-all os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em] word-break-all"
>
Our children shall receive education for life.
</span>
@ -1498,7 +1492,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -1656,8 +1650,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
School For Citizens
@ -1665,8 +1658,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&school-for-citizens
@ -1940,8 +1932,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="chip"
>
<span
class="os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em]"
style="word-break: break-all;"
class="word-break-all os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em] word-break-all"
>
Our children shall receive education for life.
</span>
@ -2025,7 +2016,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -2278,8 +2269,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
School For Citizens
@ -2287,8 +2277,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&school-for-citizens
@ -2589,8 +2578,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
class="chip"
>
<span
class="os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em]"
style="word-break: break-all;"
class="word-break-all os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em] word-break-all"
>
Our children shall receive education for life.
</span>
@ -3043,7 +3031,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a close
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -3384,8 +3372,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
Yoga Practice
@ -3393,8 +3380,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&yoga-practice
@ -4081,7 +4067,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -4239,8 +4225,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
Yoga Practice
@ -4248,8 +4233,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&yoga-practice
@ -4882,7 +4866,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -5040,8 +5024,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
Yoga Practice
@ -5049,8 +5032,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&yoga-practice
@ -5702,7 +5684,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -5955,8 +5937,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
Yoga Practice
@ -5964,8 +5945,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&yoga-practice
@ -6651,7 +6631,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a curre
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -6992,8 +6972,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
Investigative Journalism
@ -7001,8 +6980,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&investigative-journalism
@ -7303,8 +7281,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
class="chip"
>
<span
class="os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em]"
style="word-break: break-all;"
class="word-break-all os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em] word-break-all"
>
Investigative journalists share ideas and insights and can collaborate.
</span>
@ -7774,7 +7751,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"
@ -8039,8 +8016,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
class="ds-my-small"
>
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all;"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
Investigative Journalism
@ -8048,8 +8024,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
</h3>
<p
class="ds-text ds-text-center ds-text-soft"
style="word-break: break-all;"
class="ds-text ds-text-center ds-text-soft word-break-all"
>
&investigative-journalism
@ -8349,8 +8324,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
class="chip"
>
<span
class="os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em]"
style="word-break: break-all;"
class="word-break-all os-badge inline-flex w-fit items-center gap-[0.25em] font-semibold text-[var(--color-default-contrast)] bg-[var(--color-default)] text-[0.75rem] py-[0.2em] px-[0.8em] rounded-[2em] word-break-all"
>
Investigative journalists share ideas and insights and can collaborate.
</span>
@ -8820,7 +8794,7 @@ exports[`GroupProfileSlug given a puplic group "yoga-practice" given a hidde
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
style="grid-row-end: span 4; grid-column: 1 / -1;"

View File

@ -30,13 +30,12 @@
<div class="ds-my-small">
<!-- group name -->
<h3
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin"
style="word-break: break-all"
class="ds-heading ds-heading-h3 ds-heading-align-center ds-heading-no-margin word-break-all"
>
{{ groupName }}
</h3>
<!-- group slug -->
<p class="ds-text ds-text-center ds-text-soft" style="word-break: break-all">
<p class="ds-text ds-text-center ds-text-soft word-break-all">
{{ `&${groupSlug}` }}
</p>
<!-- group location -->
@ -163,7 +162,7 @@
</p>
<div class="ds-my-xx-small"></div>
<div class="chip" align="center">
<os-badge style="word-break: break-all">{{ group.about }}</os-badge>
<os-badge class="word-break-all">{{ group.about }}</os-badge>
</div>
</div>
</template>
@ -710,6 +709,9 @@ export default {
margin-bottom: $space-small;
}
}
.word-break-all {
word-break: break-all;
}
.collaps-button {
align-self: flex-end;
}

View File

@ -110,8 +110,14 @@
!isMobile && posts.length <= 2 ? 'grid-column-helper' : '',
]"
>
<!-- skeleton placeholders while loading -->
<template v-if="$apollo.loading && posts.length === 0">
<masonry-grid-item v-for="n in 6" :key="'skeleton-' + n" :imageAspectRatio="1.5">
<post-teaser-skeleton />
</masonry-grid-item>
</template>
<!-- news feed -->
<template v-if="hasResults">
<template v-else-if="hasResults">
<masonry-grid-item
v-for="post in posts"
:key="post.id"
@ -160,6 +166,7 @@ import DonationInfo from '~/components/DonationInfo/DonationInfo.vue'
import HashtagsFilter from '~/components/HashtagsFilter/HashtagsFilter.vue'
import HcEmpty from '~/components/Empty/Empty'
import PostTeaser from '~/components/PostTeaser/PostTeaser.vue'
import PostTeaserSkeleton from '~/components/PostTeaser/PostTeaserSkeleton.vue'
import MasonryGrid from '~/components/MasonryGrid/MasonryGrid.vue'
import MasonryGridItem from '~/components/MasonryGrid/MasonryGridItem.vue'
import HeaderButton from '~/components/FilterMenu/HeaderButton'
@ -179,6 +186,7 @@ export default {
OsIcon,
OsSpinner,
PostTeaser,
PostTeaserSkeleton,
HcEmpty,
MasonryGrid,
MasonryGridItem,

View File

@ -445,7 +445,7 @@ exports[`ProfileSlug given an authenticated user given another profile user and
>
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
class="tab-navigation"
@ -1168,7 +1168,7 @@ exports[`ProfileSlug given an authenticated user given another profile user and
>
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
class="tab-navigation"
@ -1715,7 +1715,7 @@ exports[`ProfileSlug given an authenticated user given the logged in user as pro
>
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
class="tab-navigation"
@ -2341,7 +2341,7 @@ exports[`ProfileSlug given an authenticated user given the logged in user as pro
>
<div
class="ds-grid"
style="grid-auto-rows: 20px; row-gap: 16px; column-gap: 16px;"
style="grid-auto-rows: 2px; row-gap: 2px;"
>
<div
class="tab-navigation"