forked from AkkomaGang/akkoma-fe
gallery in post status form!
This commit is contained in:
parent
90345f158f
commit
f15599e6e5
6 changed files with 231 additions and 196 deletions
|
@ -13,7 +13,9 @@ import {
|
|||
faPlayCircle,
|
||||
faTimes,
|
||||
faStop,
|
||||
faSearchPlus
|
||||
faSearchPlus,
|
||||
faTrashAlt,
|
||||
faPencilAlt
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
|
@ -24,19 +26,25 @@ library.add(
|
|||
faPlayCircle,
|
||||
faTimes,
|
||||
faStop,
|
||||
faSearchPlus
|
||||
faSearchPlus,
|
||||
faTrashAlt,
|
||||
faPencilAlt
|
||||
)
|
||||
|
||||
const Attachment = {
|
||||
props: [
|
||||
'attachment',
|
||||
'description',
|
||||
'hideDescription',
|
||||
'nsfw',
|
||||
'size',
|
||||
'setMedia',
|
||||
'naturalSizeLoad'
|
||||
'remove',
|
||||
'edit'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
localDescription: this.description || this.attachment.description,
|
||||
nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage,
|
||||
hideNsfwLocal: this.$store.getters.mergedConfig.hideNsfw,
|
||||
preloadImage: this.$store.getters.mergedConfig.preloadImage,
|
||||
|
@ -93,9 +101,6 @@ const Attachment = {
|
|||
isEmpty () {
|
||||
return (this.type === 'html' && !this.attachment.oembed) || this.type === 'unknown'
|
||||
},
|
||||
isSmall () {
|
||||
return this.size === 'small'
|
||||
},
|
||||
useModal () {
|
||||
const modalTypes = this.size === 'hide' ? ['image', 'video', 'audio']
|
||||
: this.mergedConfig.playVideosInModal
|
||||
|
@ -105,6 +110,11 @@ const Attachment = {
|
|||
},
|
||||
...mapGetters(['mergedConfig'])
|
||||
},
|
||||
watch: {
|
||||
localDescription (newVal) {
|
||||
this.onEdit(newVal)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
linkClicked ({ target }) {
|
||||
if (target.tagName === 'A') {
|
||||
|
@ -121,6 +131,12 @@ const Attachment = {
|
|||
this.$emit('setMedia')
|
||||
this.$store.dispatch('setCurrentMedia', this.attachment)
|
||||
},
|
||||
onEdit (event) {
|
||||
console.log('ONEDIT', event)
|
||||
this.edit && this.edit(this.attachment, event)
|
||||
},
|
||||
onRemove () {
|
||||
this.remove && this.remove(this.attachment)
|
||||
},
|
||||
stopFlash () {
|
||||
this.$refs.flash.closePlayer()
|
||||
|
@ -154,7 +170,7 @@ const Attachment = {
|
|||
onImageLoad (image) {
|
||||
const width = image.naturalWidth
|
||||
const height = image.naturalHeight
|
||||
this.naturalSizeLoad && this.naturalSizeLoad({ width, height })
|
||||
this.$emit('naturalSizeLoad', { id: this.attachment.id, width, height })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,151 +12,180 @@
|
|||
:href="attachment.url"
|
||||
:alt="attachment.description"
|
||||
:title="attachment.description"
|
||||
@click.prevent=""
|
||||
>
|
||||
<FAIcon :icon="placeholderIconClass" />
|
||||
<b>{{ nsfw ? "NSFW / " : "" }}</b>{{ placeholderName }}
|
||||
</a>
|
||||
</button>
|
||||
<div
|
||||
v-else
|
||||
v-show="!isEmpty"
|
||||
class="Attachment"
|
||||
:class="classNames"
|
||||
v-else
|
||||
>
|
||||
<a
|
||||
v-if="hidden"
|
||||
class="image-container"
|
||||
:href="attachment.url"
|
||||
:alt="attachment.description"
|
||||
:title="attachment.description"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
>
|
||||
<img
|
||||
:key="nsfwImage"
|
||||
class="nsfw"
|
||||
:src="nsfwImage"
|
||||
>
|
||||
<FAIcon
|
||||
v-if="type === 'video'"
|
||||
class="play-icon"
|
||||
icon="play-circle"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
class="attachment-buttons"
|
||||
v-if="!hidden"
|
||||
>
|
||||
<button
|
||||
v-if="type === 'flash' && flashLoaded"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="stopFlash"
|
||||
>
|
||||
<FAIcon icon="stop" />
|
||||
</button>
|
||||
<button
|
||||
v-if="!useModal"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="openModalForce"
|
||||
>
|
||||
<FAIcon icon="search-plus" />
|
||||
</button>
|
||||
<button
|
||||
v-if="nsfw && hideNsfwLocal"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="toggleHidden"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<a
|
||||
v-if="type === 'image' && (!hidden || preloadImage)"
|
||||
class="image-container"
|
||||
:class="{'-hidden': hidden && preloadImage }"
|
||||
:href="attachment.url"
|
||||
target="_blank"
|
||||
@click.stop.prevent="openModal"
|
||||
class="attachment-wrapper"
|
||||
v-show="!isEmpty"
|
||||
>
|
||||
<StillImage
|
||||
class="image"
|
||||
:referrerpolicy="referrerpolicy"
|
||||
:mimetype="attachment.mimetype"
|
||||
:src="attachment.large_thumb_url || attachment.url"
|
||||
:image-load-handler="onImageLoad"
|
||||
:alt="attachment.description"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-if="type === 'video' && !hidden"
|
||||
class="video-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<VideoAttachment
|
||||
class="video"
|
||||
:attachment="attachment"
|
||||
:controls="!useModal"
|
||||
@play="$emit('play')"
|
||||
@pause="$emit('pause')"
|
||||
/>
|
||||
<FAIcon
|
||||
v-if="useModal"
|
||||
class="play-icon"
|
||||
icon="play-circle"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-if="type === 'audio' && !hidden"
|
||||
class="audio-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<audio
|
||||
v-if="type === 'audio'"
|
||||
:src="attachment.url"
|
||||
<a
|
||||
v-if="hidden"
|
||||
class="image-container"
|
||||
:href="attachment.url"
|
||||
:alt="attachment.description"
|
||||
:title="attachment.description"
|
||||
controls
|
||||
@play="$emit('play')"
|
||||
@pause="$emit('pause')"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div
|
||||
v-if="type === 'html' && attachment.oembed"
|
||||
class="oembed-container"
|
||||
@click.prevent="linkClicked"
|
||||
>
|
||||
<div
|
||||
v-if="attachment.thumb_url"
|
||||
class="image"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
>
|
||||
<img :src="attachment.thumb_url">
|
||||
<img
|
||||
:key="nsfwImage"
|
||||
class="nsfw"
|
||||
:src="nsfwImage"
|
||||
>
|
||||
<FAIcon
|
||||
v-if="type === 'video'"
|
||||
class="play-icon"
|
||||
icon="play-circle"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
class="attachment-buttons"
|
||||
v-if="!hidden"
|
||||
>
|
||||
<button
|
||||
v-if="type === 'flash' && flashLoaded"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="stopFlash"
|
||||
>
|
||||
<FAIcon icon="stop" />
|
||||
</button>
|
||||
<button
|
||||
v-if="!useModal"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="openModalForce"
|
||||
>
|
||||
<FAIcon icon="search-plus" />
|
||||
</button>
|
||||
<button
|
||||
v-if="nsfw && hideNsfwLocal"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="toggleHidden"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
<button
|
||||
v-if="remove"
|
||||
class="button-unstyled attachment-button"
|
||||
@click.prevent="onRemove"
|
||||
>
|
||||
<FAIcon icon="trash-alt" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="text">
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<h1><a :href="attachment.url">{{ attachment.oembed.title }}</a></h1>
|
||||
<div v-html="attachment.oembed.oembedHTML" />
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
v-if="type === 'flash' && !hidden"
|
||||
class="flash-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
<a
|
||||
v-if="type === 'image' && (!hidden || preloadImage)"
|
||||
class="image-container"
|
||||
:class="{'-hidden': hidden && preloadImage }"
|
||||
:href="attachment.url"
|
||||
target="_blank"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<StillImage
|
||||
class="image"
|
||||
:referrerpolicy="referrerpolicy"
|
||||
:mimetype="attachment.mimetype"
|
||||
:src="attachment.large_thumb_url || attachment.url"
|
||||
:image-load-handler="onImageLoad"
|
||||
:alt="attachment.description"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-if="type === 'video' && !hidden"
|
||||
class="video-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<VideoAttachment
|
||||
class="video"
|
||||
:attachment="attachment"
|
||||
:controls="!useModal"
|
||||
@play="$emit('play')"
|
||||
@pause="$emit('pause')"
|
||||
/>
|
||||
<FAIcon
|
||||
v-if="useModal"
|
||||
class="play-icon"
|
||||
icon="play-circle"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
v-if="type === 'audio' && !hidden"
|
||||
class="audio-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<audio
|
||||
v-if="type === 'audio'"
|
||||
:src="attachment.url"
|
||||
:alt="attachment.description"
|
||||
:title="attachment.description"
|
||||
controls
|
||||
@play="$emit('play')"
|
||||
@pause="$emit('pause')"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div
|
||||
v-if="type === 'html' && attachment.oembed"
|
||||
class="oembed-container"
|
||||
@click.prevent="linkClicked"
|
||||
>
|
||||
<div
|
||||
v-if="attachment.thumb_url"
|
||||
class="image"
|
||||
>
|
||||
<img :src="attachment.thumb_url">
|
||||
</div>
|
||||
<div class="text">
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<h1><a :href="attachment.url">{{ attachment.oembed.title }}</a></h1>
|
||||
<div v-html="attachment.oembed.oembedHTML" />
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
v-if="type === 'flash' && !hidden"
|
||||
class="flash-container"
|
||||
:href="attachment.url"
|
||||
@click.stop.prevent="openModal"
|
||||
>
|
||||
<Flash
|
||||
class="flash"
|
||||
ref="flash"
|
||||
:src="attachment.large_thumb_url || attachment.url"
|
||||
@playerOpened="setFlashLoaded(true)"
|
||||
@playerClosed="setFlashLoaded(false)"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
v-if="size !== 'hide' && !hideDescription && (edit || localDescription)"
|
||||
class="description-container"
|
||||
:class="{ '-static': !edit }"
|
||||
>
|
||||
<Flash
|
||||
class="flash"
|
||||
ref="flash"
|
||||
:src="attachment.large_thumb_url || attachment.url"
|
||||
@playerOpened="setFlashLoaded(true)"
|
||||
@playerClosed="setFlashLoaded(false)"
|
||||
/>
|
||||
</a>
|
||||
<input
|
||||
v-if="edit"
|
||||
v-model="localDescription"
|
||||
type="text"
|
||||
class="description-field"
|
||||
:placeholder="$t('post_status.media_description')"
|
||||
@keydown.enter.prevent=""
|
||||
>
|
||||
<p v-else>
|
||||
{{ localDescription }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -4,9 +4,15 @@ import { sumBy } from 'lodash'
|
|||
const Gallery = {
|
||||
props: [
|
||||
'attachments',
|
||||
'limitRows',
|
||||
'descriptions',
|
||||
'nsfw',
|
||||
'setMedia',
|
||||
'size'
|
||||
'size',
|
||||
'editable',
|
||||
'removeAttachment',
|
||||
'editAttachment',
|
||||
'maxPerRow'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
|
@ -20,24 +26,19 @@ const Gallery = {
|
|||
if (!this.attachments) {
|
||||
return []
|
||||
}
|
||||
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 (this.size === 'small' && acc.length === 2) return acc
|
||||
if (attachment.mimetype.includes('audio')) {
|
||||
return [...acc, { audio: true, items: [attachment] }, { items: [] }]
|
||||
}
|
||||
const maxPerRow = 3
|
||||
const attachmentsRemaining = this.attachments.length - i - 1
|
||||
const maxPerRow = this.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) {
|
||||
currentRow.push(attachment)
|
||||
if (currentRow.length >= maxPerRow && attachmentsRemaining > maxPerRow) {
|
||||
return [...acc, { items: [] }]
|
||||
} else {
|
||||
return acc
|
||||
|
@ -51,7 +52,9 @@ const Gallery = {
|
|||
}, 0)
|
||||
},
|
||||
tooManyAttachments () {
|
||||
if (this.size === 'hide') {
|
||||
if (this.editable || this.size === 'small') {
|
||||
return false
|
||||
} else if (this.size === 'hide') {
|
||||
return this.attachments.length > 8
|
||||
} else {
|
||||
return this.attachmentsDimensionalScore > 1
|
||||
|
@ -59,8 +62,8 @@ const Gallery = {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
onNaturalSizeLoad (id, size) {
|
||||
this.$set(this.sizes, id, size)
|
||||
onNaturalSizeLoad ({ id, width, height }) {
|
||||
this.$set(this.sizes, id, { width, height })
|
||||
},
|
||||
rowStyle (row) {
|
||||
if (row.audio) {
|
||||
|
@ -81,8 +84,11 @@ const Gallery = {
|
|||
this.hidingLong = event
|
||||
},
|
||||
openGallery () {
|
||||
this.setMedia()
|
||||
this.$store.dispatch('setCurrent', this.attachments[0])
|
||||
this.$store.dispatch('setMedia', this.attachments)
|
||||
this.$store.dispatch('setCurrentMedia', this.attachments[0])
|
||||
},
|
||||
onMedia () {
|
||||
this.$store.dispatch('setMedia', this.attachments)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,18 @@
|
|||
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)"
|
||||
:editable="editable"
|
||||
:remove="removeAttachment"
|
||||
:edit="editAttachment"
|
||||
:description="descriptions && descriptions[attachment.id]"
|
||||
:hideDescription="tooManyAttachments && hidingLong"
|
||||
:style="itemStyle(attachment.id, row.items)"
|
||||
@setMedia="onMedia"
|
||||
@naturalSizeLoad="onNaturalSizeLoad"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,6 +4,7 @@ import ScopeSelector from '../scope_selector/scope_selector.vue'
|
|||
import EmojiInput from '../emoji_input/emoji_input.vue'
|
||||
import PollForm from '../poll/poll_form.vue'
|
||||
import Attachment from '../attachment/attachment.vue'
|
||||
import Gallery from 'src/components/gallery/gallery.vue'
|
||||
import StatusContent from '../status_content/status_content.vue'
|
||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
|
||||
|
@ -85,7 +86,8 @@ const PostStatusForm = {
|
|||
Checkbox,
|
||||
Select,
|
||||
Attachment,
|
||||
StatusContent
|
||||
StatusContent,
|
||||
Gallery
|
||||
},
|
||||
mounted () {
|
||||
this.updateIdempotencyKey()
|
||||
|
@ -388,6 +390,10 @@ const PostStatusForm = {
|
|||
this.newStatus.files.splice(index, 1)
|
||||
this.$emit('resize')
|
||||
},
|
||||
editAttachment (fileInfo, newText) {
|
||||
console.log(fileInfo, newText)
|
||||
this.newStatus.mediaDescriptions[fileInfo.id] = newText
|
||||
},
|
||||
uploadFailed (errString, templateArgs) {
|
||||
templateArgs = templateArgs || {}
|
||||
this.error = this.$t('upload.error.base') + ' ' + this.$t('upload.error.' + errString, templateArgs)
|
||||
|
|
|
@ -287,32 +287,21 @@
|
|||
@click="clearError"
|
||||
/>
|
||||
</div>
|
||||
<div class="attachments">
|
||||
<div
|
||||
v-for="file in newStatus.files"
|
||||
:key="file.url"
|
||||
class="media-upload-wrapper"
|
||||
>
|
||||
<button
|
||||
class="button-unstyled hider"
|
||||
@click="removeMediaFile(file)"
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
<attachment
|
||||
:attachment="file"
|
||||
:set-media="() => $store.dispatch('setMedia', newStatus.files)"
|
||||
size="small"
|
||||
allow-play="false"
|
||||
/>
|
||||
<input
|
||||
v-model="newStatus.mediaDescriptions[file.id]"
|
||||
type="text"
|
||||
:placeholder="$t('post_status.media_description')"
|
||||
@keydown.enter.prevent=""
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<gallery
|
||||
v-if="newStatus.files && newStatus.files.length > 0"
|
||||
class="attachments"
|
||||
:maxPerRow="1"
|
||||
:nsfw="false"
|
||||
:attachments="newStatus.files"
|
||||
:descriptions="newStatus.mediaDescriptions"
|
||||
:set-media="() => $store.dispatch('setMedia', newStatus.files)"
|
||||
:editable="true"
|
||||
:editAttachment="editAttachment"
|
||||
:removeAttachment="removeMediaFile"
|
||||
size="small"
|
||||
@play="$emit('mediaplay', attachment.id)"
|
||||
@pause="$emit('mediapause', attachment.id)"
|
||||
/>
|
||||
<div
|
||||
v-if="newStatus.files.length > 0 && !disableSensitivityCheckbox"
|
||||
class="upload_settings"
|
||||
|
@ -507,15 +496,6 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.attachments .media-upload-wrapper {
|
||||
position: relative;
|
||||
|
||||
.attachment {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -616,11 +596,4 @@
|
|||
border: 2px dashed var(--text, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: unify with attachment.vue (otherwise the uploaded images are not minified unless a status with an attachment was displayed before)
|
||||
img.media-upload, .media-upload-container > video {
|
||||
line-height: 0;
|
||||
max-height: 200px;
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
Loading…
Reference in a new issue