diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 8a2a3826..cd72e571 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -1,3 +1,4 @@ +import StillImage from '../still-image/still-image.vue' import nsfwImage from '../../assets/nsfw.png' import fileTypeService from '../../services/file_type/file_type.service.js' @@ -16,6 +17,9 @@ const Attachment = { img: document.createElement('img') } }, + components: { + StillImage + }, computed: { type () { return fileTypeService.fileType(this.attachment.mimetype) diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index d6a51ffd..a1b35d91 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -8,7 +8,7 @@ - + @@ -126,6 +126,11 @@ display: flex; flex: 1; + .still-image { + width: 100%; + height: 100%; + } + img { object-fit: contain; width: 100%; diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 5f0d7f26..e9b83bf0 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -1,4 +1,5 @@ import Status from '../status/status.vue' +import StillImage from '../still-image/still-image.vue' import { sortBy, take, filter } from 'lodash' @@ -31,7 +32,7 @@ const Notifications = { } }, components: { - Status + Status, StillImage }, watch: { unseenCount (count) { diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 241f10b4..3c500b36 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -88,10 +88,26 @@ } .avatar { - padding-top: 0.3em; + margin-top: 0.3em; width: 32px; height: 32px; border-radius: 50%; + overflow: hidden; + line-height: 0; + + &.animated::before { + display: none; + } + + } + + &:hover .animated.avatar { + canvas { + display: none; + } + img { + visibility: visible; + } } &:last-child { @@ -104,6 +120,10 @@ max-height: 12em; overflow-y: hidden; //text-overflow: ellipsis; + + img { + object-fit: contain; + } } .notification-gradient { diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index b341fcef..8e6f12b2 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -10,7 +10,7 @@
- +
diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index b88937bb..a26111d6 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -10,7 +10,8 @@ const settings = { muteWordsString: this.$store.state.config.muteWords.join('\n'), autoLoadLocal: this.$store.state.config.autoLoad, 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: { @@ -43,6 +44,9 @@ const settings = { muteWordsString (value) { value = filter(value.split('\n'), (word) => trim(word).length > 0) this.$store.dispatch('setOption', { name: 'muteWords', value }) + }, + stopGifs (value) { + this.$store.dispatch('setOption', { name: 'stopGifs', value }) } } } diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 8fdd09de..5aa7596a 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -29,8 +29,8 @@
  • - - + +
  • @@ -40,6 +40,10 @@
  • +
  • + + +
  • diff --git a/src/components/status/status.js b/src/components/status/status.js index 12f3bb25..7397e80c 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -4,6 +4,7 @@ import RetweetButton from '../retweet_button/retweet_button.vue' import DeleteButton from '../delete_button/delete_button.vue' import PostStatusForm from '../post_status_form/post_status_form.vue' import UserCardContent from '../user_card_content/user_card_content.vue' +import StillImage from '../still-image/still-image.vue' import { filter, find } from 'lodash' const Status = { @@ -76,7 +77,8 @@ const Status = { RetweetButton, DeleteButton, PostStatusForm, - UserCardContent + UserCardContent, + StillImage }, methods: { linkClicked ({target}) { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 28272b0b..d451b67c 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -34,8 +34,8 @@
    - - + +
    @@ -84,7 +84,7 @@
    - +

    {{ preview.user.name }} @@ -146,6 +146,7 @@ box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5); margin-top: 0.5em; margin-left: 1em; + z-index: 50; .avatar { flex-shrink: 0; @@ -264,9 +265,8 @@ .media-left { margin: 0.2em 0.3em 0 0; - img { + .avatar { float: right; - border-radius: 5px; } } @@ -330,6 +330,17 @@ .status .avatar { width: 48px; height: 48px; + border-radius: 5px; + overflow: hidden; + + img { + width: 100%; + height: 100%; + } + + &.animated::before { + display: none; + } &.retweeted { 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; height: 24px; position: absolute; @@ -413,7 +433,7 @@ } } - .status img.avatar-retweeter { + .status .avatar-retweeter { width: 22px; height: 22px; position: absolute; diff --git a/src/components/still-image/still-image.js b/src/components/still-image/still-image.js new file mode 100644 index 00000000..0839aca5 --- /dev/null +++ b/src/components/still-image/still-image.js @@ -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 diff --git a/src/components/still-image/still-image.vue b/src/components/still-image/still-image.vue new file mode 100644 index 00000000..5695c554 --- /dev/null +++ b/src/components/still-image/still-image.vue @@ -0,0 +1,62 @@ + + + + + diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 32d62ebb..8c9ccda1 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -1,3 +1,4 @@ +import StillImage from '../still-image/still-image.vue' import { hex2rgb } from '../../services/color_convert/color_convert.js' export default { @@ -35,6 +36,9 @@ export default { return Math.round(this.user.statuses_count / days) } }, + components: { + StillImage + }, methods: { followUser () { const store = this.$store diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index ef000c94..71a879df 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -7,7 +7,7 @@
    - +
    @@ -135,13 +135,26 @@ overflow: hidden; } - img { + .avatar { border-radius: 5px; flex: 1 0 100%; width: 56px; height: 56px; box-shadow: 0px 1px 8px rgba(0,0,0,0.75); 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); diff --git a/src/i18n/messages.js b/src/i18n/messages.js index 2a465794..abf64607 100644 --- a/src/i18n/messages.js +++ b/src/i18n/messages.js @@ -249,6 +249,7 @@ const en = { hide_attachments_in_tl: 'Hide attachments in timeline', hide_attachments_in_convo: 'Hide attachments in conversations', nsfw_clickthrough: 'Enable clickthrough NSFW attachment hiding', + stop_gifs: 'Play-on-hover GIFs', autoload: 'Enable automatic loading when scrolled to the bottom', streaming: 'Enable automatic streaming of new posts when scrolled to the top', reply_link_preview: 'Enable reply-link preview on mouse hover', @@ -1103,6 +1104,7 @@ const ru = { attachments: 'Вложения', hide_attachments_in_tl: 'Прятать вложения в ленте', hide_attachments_in_convo: 'Прятать вложения в разговорах', + stop_gifs: 'Проигрывать GIF анимации только при наведении', nsfw_clickthrough: 'Включить скрытие NSFW вложений', autoload: 'Включить автоматическую загрузку при прокрутке вниз', streaming: 'Включить автоматическую загрузку новых сообщений при прокрутке вверх',