Merge branch 'stillGifs' into 'develop'
Still gifs See merge request pleroma/pleroma-fe!193
This commit is contained in:
commit
e4b2fdf124
14 changed files with 184 additions and 17 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import StillImage from '../still-image/still-image.vue'
|
||||||
import nsfwImage from '../../assets/nsfw.png'
|
import nsfwImage from '../../assets/nsfw.png'
|
||||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||||
|
|
||||||
|
@ -16,6 +17,9 @@ const Attachment = {
|
||||||
img: document.createElement('img')
|
img: document.createElement('img')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
StillImage
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
type () {
|
type () {
|
||||||
return fileTypeService.fileType(this.attachment.mimetype)
|
return fileTypeService.fileType(this.attachment.mimetype)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank">
|
<a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank">
|
||||||
<img class="base03-border" referrerpolicy="no-referrer" :src="attachment.large_thumb_url || attachment.url"/>
|
<StillImage class="base03-border" referrerpolicy="no-referrer" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<video class="base03" v-if="type === 'video' && !hidden" :src="attachment.url" controls loop></video>
|
<video class="base03" v-if="type === 'video' && !hidden" :src="attachment.url" controls loop></video>
|
||||||
|
@ -126,6 +126,11 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
.still-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Status from '../status/status.vue'
|
import Status from '../status/status.vue'
|
||||||
|
import StillImage from '../still-image/still-image.vue'
|
||||||
|
|
||||||
import { sortBy, take, filter } from 'lodash'
|
import { sortBy, take, filter } from 'lodash'
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ const Notifications = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
Status
|
Status, StillImage
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
unseenCount (count) {
|
unseenCount (count) {
|
||||||
|
|
|
@ -88,10 +88,26 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
padding-top: 0.3em;
|
margin-top: 0.3em;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: 0;
|
||||||
|
|
||||||
|
&.animated::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .animated.avatar {
|
||||||
|
canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
|
@ -104,6 +120,10 @@
|
||||||
max-height: 12em;
|
max-height: 12em;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
//text-overflow: ellipsis;
|
//text-overflow: ellipsis;
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification-gradient {
|
.notification-gradient {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div v-for="notification in visibleNotifications" :key="notification" class="notification" :class='{"unseen": !notification.seen}'>
|
<div v-for="notification in visibleNotifications" :key="notification" class="notification" :class='{"unseen": !notification.seen}'>
|
||||||
<div>
|
<div>
|
||||||
<a :href="notification.action.user.statusnet_profile_url" target="_blank">
|
<a :href="notification.action.user.statusnet_profile_url" target="_blank">
|
||||||
<img class='avatar' :src="notification.action.user.profile_image_url_original">
|
<StillImage class='avatar' :src="notification.action.user.profile_image_url_original"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class='text' style="width: 100%;">
|
<div class='text' style="width: 100%;">
|
||||||
|
|
|
@ -10,7 +10,8 @@ const settings = {
|
||||||
muteWordsString: this.$store.state.config.muteWords.join('\n'),
|
muteWordsString: this.$store.state.config.muteWords.join('\n'),
|
||||||
autoLoadLocal: this.$store.state.config.autoLoad,
|
autoLoadLocal: this.$store.state.config.autoLoad,
|
||||||
streamingLocal: this.$store.state.config.streaming,
|
streamingLocal: this.$store.state.config.streaming,
|
||||||
hoverPreviewLocal: this.$store.state.config.hoverPreview
|
hoverPreviewLocal: this.$store.state.config.hoverPreview,
|
||||||
|
stopGifs: this.$store.state.config.stopGifs
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -43,6 +44,9 @@ const settings = {
|
||||||
muteWordsString (value) {
|
muteWordsString (value) {
|
||||||
value = filter(value.split('\n'), (word) => trim(word).length > 0)
|
value = filter(value.split('\n'), (word) => trim(word).length > 0)
|
||||||
this.$store.dispatch('setOption', { name: 'muteWords', value })
|
this.$store.dispatch('setOption', { name: 'muteWords', value })
|
||||||
|
},
|
||||||
|
stopGifs (value) {
|
||||||
|
this.$store.dispatch('setOption', { name: 'stopGifs', value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@
|
||||||
<label for="hideNsfw">{{$t('settings.nsfw_clickthrough')}}</label>
|
<label for="hideNsfw">{{$t('settings.nsfw_clickthrough')}}</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="autoLoad" v-model="autoLoadLocal">
|
<input type="checkbox" id="autoload" v-model="autoloadlocal">
|
||||||
<label for="autoLoad">{{$t('settings.autoload')}}</label>
|
<label for="autoload">{{$t('settings.autoload')}}</label>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<input type="checkbox" id="streaming" v-model="streamingLocal">
|
<input type="checkbox" id="streaming" v-model="streamingLocal">
|
||||||
|
@ -40,6 +40,10 @@
|
||||||
<input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal">
|
<input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal">
|
||||||
<label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label>
|
<label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" id="stopGifs" v-model="stopGifs">
|
||||||
|
<label for="stopGifs">{{$t('settings.stop_gifs')}}</label>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,6 +4,7 @@ import RetweetButton from '../retweet_button/retweet_button.vue'
|
||||||
import DeleteButton from '../delete_button/delete_button.vue'
|
import DeleteButton from '../delete_button/delete_button.vue'
|
||||||
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||||
|
import StillImage from '../still-image/still-image.vue'
|
||||||
import { filter, find } from 'lodash'
|
import { filter, find } from 'lodash'
|
||||||
|
|
||||||
const Status = {
|
const Status = {
|
||||||
|
@ -76,7 +77,8 @@ const Status = {
|
||||||
RetweetButton,
|
RetweetButton,
|
||||||
DeleteButton,
|
DeleteButton,
|
||||||
PostStatusForm,
|
PostStatusForm,
|
||||||
UserCardContent
|
UserCardContent,
|
||||||
|
StillImage
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
linkClicked ({target}) {
|
linkClicked ({target}) {
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
<div class="media status container">
|
<div class="media status container">
|
||||||
<div class="media-left">
|
<div class="media-left">
|
||||||
<a :href="status.user.statusnet_profile_url">
|
<a :href="status.user.statusnet_profile_url">
|
||||||
<img @click.prevent="toggleUserExpanded" :class="{retweeted: retweet}" class='avatar' :src="status.user.profile_image_url_original">
|
<StillImage @click.native.prevent="toggleUserExpanded" :class="{retweeted: retweet}" class='avatar' :src="status.user.profile_image_url_original"/>
|
||||||
<img v-if="retweet" class='avatar-retweeter' :src="statusoid.user.profile_image_url_original"></img>
|
<StillImage v-if="retweet" class='avatar avatar-retweeter' :src="statusoid.user.profile_image_url_original"/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
|
@ -84,7 +84,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-preview base00-background base03-border" v-if="showPreview && preview">
|
<div class="status-preview base00-background base03-border" v-if="showPreview && preview">
|
||||||
<img class="avatar" :src="preview.user.profile_image_url_original">
|
<StillImage class="avatar" :src="preview.user.profile_image_url_original"/>
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<h4>
|
<h4>
|
||||||
{{ preview.user.name }}
|
{{ preview.user.name }}
|
||||||
|
@ -146,6 +146,7 @@
|
||||||
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
|
box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
margin-left: 1em;
|
margin-left: 1em;
|
||||||
|
z-index: 50;
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
@ -264,9 +265,8 @@
|
||||||
|
|
||||||
.media-left {
|
.media-left {
|
||||||
margin: 0.2em 0.3em 0 0;
|
margin: 0.2em 0.3em 0 0;
|
||||||
img {
|
.avatar {
|
||||||
float: right;
|
float: right;
|
||||||
border-radius: 5px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,6 +330,17 @@
|
||||||
.status .avatar {
|
.status .avatar {
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.animated::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&.retweeted {
|
&.retweeted {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
|
@ -339,7 +350,16 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status img.avatar-retweeter {
|
.status:hover .animated.avatar {
|
||||||
|
canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.status .avatar-retweeter {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
@ -413,7 +433,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.status img.avatar-retweeter {
|
.status .avatar-retweeter {
|
||||||
width: 22px;
|
width: 22px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
26
src/components/still-image/still-image.js
Normal file
26
src/components/still-image/still-image.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const StillImage = {
|
||||||
|
props: [
|
||||||
|
'src',
|
||||||
|
'referrerpolicy',
|
||||||
|
'mimetype'
|
||||||
|
],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
stopGifs: this.$store.state.config.stopGifs
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
animated () {
|
||||||
|
return this.stopGifs && (this.mimetype === 'image/gif' || this.src.endsWith('.gif'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onLoad () {
|
||||||
|
const canvas = this.$refs.canvas
|
||||||
|
if (!canvas) return
|
||||||
|
canvas.getContext('2d').drawImage(this.$refs.src, 1, 1, canvas.width, canvas.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StillImage
|
62
src/components/still-image/still-image.vue
Normal file
62
src/components/still-image/still-image.vue
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<div class='still-image' :class='{ animated: animated }' >
|
||||||
|
<canvas ref="canvas" v-if="animated"></canvas>
|
||||||
|
<img ref="src" :src="src" :referrerpolicy="referrerpolicy" v-on:load="onLoad"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./still-image.js"></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
.still-image {
|
||||||
|
position: relative;
|
||||||
|
line-height: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:hover canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
&.animated {
|
||||||
|
&:hover::before,
|
||||||
|
img {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover img {
|
||||||
|
visibility: visible
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: 'gif';
|
||||||
|
position: absolute;
|
||||||
|
line-height: 10px;
|
||||||
|
font-size: 10px;
|
||||||
|
top: 5px;
|
||||||
|
left: 5px;
|
||||||
|
background: rgba(127,127,127,.5);
|
||||||
|
color: #FFF;
|
||||||
|
display: block;
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 3px;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,3 +1,4 @@
|
||||||
|
import StillImage from '../still-image/still-image.vue'
|
||||||
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -35,6 +36,9 @@ export default {
|
||||||
return Math.round(this.user.statuses_count / days)
|
return Math.round(this.user.statuses_count / days)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
StillImage
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
followUser () {
|
followUser () {
|
||||||
const store = this.$store
|
const store = this.$store
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
<div class='container'>
|
<div class='container'>
|
||||||
<router-link :to="{ name: 'user-profile', params: { id: user.id } }">
|
<router-link :to="{ name: 'user-profile', params: { id: user.id } }">
|
||||||
<img :src="user.profile_image_url_original">
|
<StillImage class="avatar" :src="user.profile_image_url_original"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
<span class="glyphicon glyphicon-user"></span>
|
<span class="glyphicon glyphicon-user"></span>
|
||||||
<div class="name-and-screen-name">
|
<div class="name-and-screen-name">
|
||||||
|
@ -135,13 +135,26 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
.avatar {
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
flex: 1 0 100%;
|
flex: 1 0 100%;
|
||||||
width: 56px;
|
width: 56px;
|
||||||
height: 56px;
|
height: 56px;
|
||||||
box-shadow: 0px 1px 8px rgba(0,0,0,0.75);
|
box-shadow: 0px 1px 8px rgba(0,0,0,0.75);
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
|
||||||
|
&.animated::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .animated.avatar {
|
||||||
|
canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0);
|
text-shadow: 0px 1px 1.5px rgba(0, 0, 0, 1.0);
|
||||||
|
|
|
@ -249,6 +249,7 @@ const en = {
|
||||||
hide_attachments_in_tl: 'Hide attachments in timeline',
|
hide_attachments_in_tl: 'Hide attachments in timeline',
|
||||||
hide_attachments_in_convo: 'Hide attachments in conversations',
|
hide_attachments_in_convo: 'Hide attachments in conversations',
|
||||||
nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding',
|
nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding',
|
||||||
|
stop_gifs: 'Play-on-hover GIFs',
|
||||||
autoload: 'Enable automatic loading when scrolled to the bottom',
|
autoload: 'Enable automatic loading when scrolled to the bottom',
|
||||||
streaming: 'Enable automatic streaming of new posts when scrolled to the top',
|
streaming: 'Enable automatic streaming of new posts when scrolled to the top',
|
||||||
reply_link_preview: 'Enable reply-link preview on mouse hover',
|
reply_link_preview: 'Enable reply-link preview on mouse hover',
|
||||||
|
@ -1103,6 +1104,7 @@ const ru = {
|
||||||
attachments: 'Вложения',
|
attachments: 'Вложения',
|
||||||
hide_attachments_in_tl: 'Прятать вложения в ленте',
|
hide_attachments_in_tl: 'Прятать вложения в ленте',
|
||||||
hide_attachments_in_convo: 'Прятать вложения в разговорах',
|
hide_attachments_in_convo: 'Прятать вложения в разговорах',
|
||||||
|
stop_gifs: 'Проигрывать GIF анимации только при наведении',
|
||||||
nsfw_clickthrough: 'Включить скрытие NSFW вложений',
|
nsfw_clickthrough: 'Включить скрытие NSFW вложений',
|
||||||
autoload: 'Включить автоматическую загрузку при прокрутке вниз',
|
autoload: 'Включить автоматическую загрузку при прокрутке вниз',
|
||||||
streaming: 'Включить автоматическую загрузку новых сообщений при прокрутке вверх',
|
streaming: 'Включить автоматическую загрузку новых сообщений при прокрутке вверх',
|
||||||
|
|
Loading…
Reference in a new issue