refactored attachments and gallery. All attachments now are in gallery.

This commit is contained in:
Henry Jameson 2021-06-17 16:29:46 +03:00
parent 9c4957268d
commit e654fead23
10 changed files with 296 additions and 365 deletions

View file

@ -1,15 +1,17 @@
import Attachment from '../attachment/attachment.vue'
import { chunk, last, dropRight, sumBy } from 'lodash'
import { sumBy } from 'lodash'
const Gallery = {
props: [
'attachments',
'nsfw',
'setMedia'
'setMedia',
'size'
],
data () {
return {
sizes: {}
sizes: {},
hidingLong: true
}
},
components: { Attachment },
@ -18,26 +20,54 @@ const Gallery = {
if (!this.attachments) {
return []
}
const rows = chunk(this.attachments, 3)
if (last(rows).length === 1 && rows.length > 1) {
// if 1 attachment on last row -> add it to the previous row instead
const lastAttachment = last(rows)[0]
const allButLastRow = dropRight(rows)
last(allButLastRow).push(lastAttachment)
return allButLastRow
console.log(this.size)
if (this.size === 'hide') {
return this.attachments.map(item => ({ minimal: true, items: [item] }))
}
const rows = this.attachments.reduce((acc, attachment, i) => {
if (attachment.mimetype.includes('audio')) {
return [...acc, { audio: true, items: [attachment] }, { items: [] }]
}
const maxPerRow = 3
const attachmentsRemaining = this.attachments.length - i - 1
const currentRow = acc[acc.length - 1].items
if (
currentRow.length <= maxPerRow ||
attachmentsRemaining === 1
) {
currentRow.push(attachment)
}
if (currentRow.length === maxPerRow && attachmentsRemaining > 1) {
return [...acc, { items: [] }]
} else {
return acc
}
}, [{ items: [] }]).filter(_ => _.items.length > 0)
return rows
},
useContainFit () {
return this.$store.getters.mergedConfig.useContainFit
attachmentsDimensionalScore () {
return this.rows.reduce((acc, row) => {
return acc + (row.audio ? 0.25 : (1 / (row.items.length + 0.6)))
}, 0)
},
tooManyAttachments () {
if (this.size === 'hide') {
return this.attachments.length > 8
} else {
return this.attachmentsDimensionalScore > 1
}
}
},
methods: {
onNaturalSizeLoad (id, size) {
this.$set(this.sizes, id, size)
},
rowStyle (itemsPerRow) {
return { 'padding-bottom': `${(100 / (itemsPerRow + 0.6))}%` }
rowStyle (row) {
if (row.audio) {
return { 'padding-bottom': '25%' } // fixed reduced height for audio
} else if (!row.minimal) {
return { 'padding-bottom': `${(100 / (row.items.length + 0.6))}%` }
}
},
itemStyle (id, row) {
const total = sumBy(row, item => this.getAspectRatio(item.id))
@ -46,6 +76,13 @@ const Gallery = {
getAspectRatio (id) {
const size = this.sizes[id]
return size ? size.width / size.height : 1
},
toggleHidingLong (event) {
this.hidingLong = event
},
openGallery () {
this.setMedia()
this.$store.dispatch('setCurrent', this.attachments[0])
}
}
}

View file

@ -1,26 +1,74 @@
<template>
<div
class="Gallery"
ref="galleryContainer"
style="width: 100%;"
:class="{ '-long': tooManyAttachments && hidingLong }"
>
<div class="gallery-rows">
<div
v-for="(row, index) in rows"
:key="index"
class="gallery-row"
:style="rowStyle(row)"
:class="{ '-audio': row.audio, '-minimal': row.minimal }"
>
<div class="gallery-row-inner">
<attachment
v-for="attachment in row.items"
class="gallery-item"
:key="attachment.id"
:set-media="setMedia"
:nsfw="nsfw"
:attachment="attachment"
:allow-play="false"
:size="size"
:natural-size-load="onNaturalSizeLoad.bind(null, attachment.id)"
:style="itemStyle(attachment.id, row.items)"
/>
</div>
</div>
</div>
<div
v-for="(row, index) in rows"
:key="index"
class="gallery-row"
:style="rowStyle(row.length)"
:class="{ 'contain-fit': useContainFit, 'cover-fit': !useContainFit }"
v-if="tooManyAttachments"
class="many-attachments"
>
<div class="gallery-row-inner">
<attachment
v-for="attachment in row"
:key="attachment.id"
:set-media="setMedia"
:nsfw="nsfw"
:attachment="attachment"
:allow-play="false"
:natural-size-load="onNaturalSizeLoad.bind(null, attachment.id)"
:style="itemStyle(attachment.id, row)"
/>
<div class="many-attachments-text">
{{ $t("status.many_attachments", { number: attachments.length })}}
</div>
<div class="many-attachments-buttons">
<span
v-if="!hidingLong"
class="many-attachments-button"
>
<button
class="button-unstyled -link"
@click="toggleHidingLong(true)"
>
{{ $t("status.collapse_attachments") }}
</button>
</span>
<span
v-if="hidingLong"
class="many-attachments-button"
>
<button
class="button-unstyled -link"
@click="toggleHidingLong(false)"
>
{{ $t("status.show_all_attachments") }}
</button>
</span>
<span
class="many-attachments-button"
v-if="hidingLong"
>
<button
class="button-unstyled -link"
@click="openGallery"
>
{{ $t("status.open_gallery") }}
</button>
</span>
</div>
</div>
</div>
@ -31,12 +79,64 @@
<style lang="scss">
@import '../../_variables.scss';
.gallery-row {
position: relative;
height: 0;
width: 100%;
flex-grow: 1;
margin-top: 0.5em;
.Gallery {
.gallery-rows {
display: flex;
flex-direction: column;
}
.gallery-row {
position: relative;
height: 0;
width: 100%;
flex-grow: 1;
margin-top: 0.5em;
}
&.-long {
.gallery-rows {
max-height: 25em;
overflow: hidden;
mask:
linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat,
linear-gradient(to top, white, white);
/* Autoprefixed seem to ignore this one, and also syntax is different */
-webkit-mask-composite: xor;
mask-composite: exclude;
}
}
.many-attachments-text {
text-align: center;
line-height: 2;
}
.many-attachments-buttons {
display: flex;
}
.many-attachments-button {
display: flex;
flex: 1;
justify-content: center;
line-height: 2;
button {
padding: 0 2em;
}
}
.gallery-row {
&.-minimal {
height: auto;
.gallery-row-inner {
position: relative;
}
}
}
.gallery-row-inner {
position: absolute;
@ -50,7 +150,7 @@
align-content: stretch;
}
.gallery-row-inner .attachment {
.gallery-item {
margin: 0 0.5em 0 0;
flex-grow: 1;
height: 100%;
@ -61,32 +161,5 @@
margin: 0;
}
}
.image-attachment {
width: 100%;
height: 100%;
}
.video-container {
height: 100%;
}
&.contain-fit {
img,
video,
canvas {
object-fit: contain;
height: 100%;
}
}
&.cover-fit {
img,
video,
canvas {
object-fit: cover;
}
}
}
</style>