diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index ea46ce6f..e07bb7a2 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -95,7 +95,8 @@ module.exports = { }, plugins: [ new ServiceWorkerWebpackPlugin({ - entry: path.join(__dirname, '..', 'src/sw.js') + entry: path.join(__dirname, '..', 'src/sw.js'), + filename: 'sw-pleroma.js' }) ] } diff --git a/src/App.js b/src/App.js index 85df9416..18bff2dd 100644 --- a/src/App.js +++ b/src/App.js @@ -6,6 +6,7 @@ import InstanceSpecificPanel from './components/instance_specific_panel/instance import FeaturesPanel from './components/features_panel/features_panel.vue' import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue' import ChatPanel from './components/chat_panel/chat_panel.vue' +import MediaModal from './components/media_modal/media_modal.vue' import SideDrawer from './components/side_drawer/side_drawer.vue' import { unseenNotificationsFromStore } from './services/notification_utils/notification_utils' @@ -20,6 +21,7 @@ export default { FeaturesPanel, WhoToFollowPanel, ChatPanel, + MediaModal, SideDrawer }, data: () => ({ @@ -79,7 +81,8 @@ export default { }, unseenNotificationsCount () { return this.unseenNotifications.length - } + }, + showFeaturesPanel () { return this.$store.state.config.showFeaturesPanel } }, methods: { scrollToTop () { diff --git a/src/App.scss b/src/App.scss index ed06bbbc..d3721b32 100644 --- a/src/App.scss +++ b/src/App.scss @@ -425,6 +425,12 @@ main-router { border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius; border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius); + + .faint { + color: $fallback--faint; + color: var(--panelFaint, $fallback--faint); + } + a { color: $fallback--link; color: var(--panelLink, $fallback--link) @@ -499,7 +505,7 @@ nav { } .main { - flex-basis: 60%; + flex-basis: 50%; flex-grow: 1; flex-shrink: 1; } @@ -533,7 +539,7 @@ nav { } } -@media all and (min-width: 960px) { +@media all and (min-width: 800px) { body { overflow-y: scroll; } @@ -617,7 +623,7 @@ nav { color: $fallback--faint; color: var(--faint, $fallback--faint); } -@media all and (min-width: 959px) { +@media all and (min-width: 800px) { .logo { opacity: 1 !important; } @@ -654,7 +660,34 @@ nav { border-radius: var(--inputRadius, $fallback--inputRadius); } -@media all and (max-width: 959px) { +@keyframes shakeError { + 0% { + transform: translateX(0); + } + 15% { + transform: translateX(0.375rem); + } + 30% { + transform: translateX(-0.375rem); + } + 45% { + transform: translateX(0.375rem); + } + 60% { + transform: translateX(-0.375rem); + } + 75% { + transform: translateX(0.375rem); + } + 90% { + transform: translateX(-0.375rem); + } + 100% { + transform: translateX(0); + } +} + +@media all and (max-width: 800px) { .mobile-hidden { display: none; } diff --git a/src/App.vue b/src/App.vue index feadb009..082c6cb6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -29,7 +29,7 @@ - + @@ -41,6 +41,7 @@ + diff --git a/src/assets/nsfw.png b/src/assets/nsfw.png index 42749033..d2513776 100644 Binary files a/src/assets/nsfw.png and b/src/assets/nsfw.png differ diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 50500582..5693dcc6 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -89,6 +89,8 @@ const afterStoreSetup = ({ store, i18n }) => { if ((config.chatDisabled)) { store.dispatch('disableChat') + } else { + store.dispatch('initializeSocket') } const router = new VueRouter({ diff --git a/src/boot/routes.js b/src/boot/routes.js index 9dba532a..cfbcb1fe 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -39,7 +39,7 @@ export default (store) => { { name: 'dms', path: '/users/:username/dms', component: DMs }, { name: 'settings', path: '/settings', component: Settings }, { name: 'registration', path: '/registration', component: Registration }, - { name: 'registration', path: '/registration/:token', component: Registration }, + { name: 'registration-token', path: '/registration/:token', component: Registration }, { name: 'friend-requests', path: '/friend-requests', component: FollowRequests }, { name: 'user-settings', path: '/user-settings', component: UserSettings }, { name: 'notifications', path: '/:username/notifications', component: Notifications }, diff --git a/src/components/about/about.js b/src/components/about/about.js index b4433b4e..b1ce3c7d 100644 --- a/src/components/about/about.js +++ b/src/components/about/about.js @@ -7,6 +7,9 @@ const About = { InstanceSpecificPanel, FeaturesPanel, TermsOfServicePanel + }, + computed: { + showFeaturesPanel () { return this.$store.state.config.showFeaturesPanel } } } diff --git a/src/components/about/about.vue b/src/components/about/about.vue index bf87e0b8..13dec87c 100644 --- a/src/components/about/about.vue +++ b/src/components/about/about.vue @@ -1,7 +1,7 @@ diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js index 9212b74b..3b7f08dc 100644 --- a/src/components/attachment/attachment.js +++ b/src/components/attachment/attachment.js @@ -1,4 +1,5 @@ import StillImage from '../still-image/still-image.vue' +import VideoAttachment from '../video_attachment/video_attachment.vue' import nsfwImage from '../../assets/nsfw.png' import fileTypeService from '../../services/file_type/file_type.service.js' @@ -7,23 +8,29 @@ const Attachment = { 'attachment', 'nsfw', 'statusId', - 'size' + 'size', + 'allowPlay', + 'setMedia' ], data () { return { nsfwImage: this.$store.state.instance.nsfwCensorImage || nsfwImage, hideNsfwLocal: this.$store.state.config.hideNsfw, preloadImage: this.$store.state.config.preloadImage, - loopVideo: this.$store.state.config.loopVideo, - showHidden: false, loading: false, - img: fileTypeService.fileType(this.attachment.mimetype) === 'image' && document.createElement('img') + img: fileTypeService.fileType(this.attachment.mimetype) === 'image' && document.createElement('img'), + modalOpen: false, + showHidden: false } }, components: { - StillImage + StillImage, + VideoAttachment }, computed: { + usePlaceHolder () { + return this.size === 'hide' || this.type === 'unknown' + }, referrerpolicy () { return this.$store.state.instance.mediaProxyAvailable ? '' : 'no-referrer' }, @@ -40,7 +47,7 @@ const Attachment = { return this.size === 'small' }, fullwidth () { - return fileTypeService.fileType(this.attachment.mimetype) === 'html' + return this.type === 'html' || this.type === 'audio' } }, methods: { @@ -49,7 +56,24 @@ const Attachment = { window.open(target.href, '_blank') } }, - toggleHidden () { + openModal (event) { + const modalTypes = this.$store.state.config.playVideosInModal + ? ['image', 'video'] + : ['image'] + if (fileTypeService.fileMatchesSomeType(modalTypes, this.attachment) || + this.usePlaceHolder + ) { + event.stopPropagation() + event.preventDefault() + this.setMedia() + this.$store.dispatch('setCurrent', this.attachment) + } + }, + toggleHidden (event) { + if (this.$store.state.config.useOneClickNsfw && !this.showHidden) { + this.openModal(event) + return + } if (this.img && !this.preloadImage) { if (this.img.onload) { this.img.onload() @@ -64,23 +88,6 @@ const Attachment = { } else { this.showHidden = !this.showHidden } - }, - onVideoDataLoad (e) { - if (typeof e.srcElement.webkitAudioDecodedByteCount !== 'undefined') { - // non-zero if video has audio track - if (e.srcElement.webkitAudioDecodedByteCount > 0) { - this.loopVideo = this.loopVideo && !this.$store.state.config.loopVideoSilentOnly - } - } else if (typeof e.srcElement.mozHasAudio !== 'undefined') { - // true if video has audio track - if (e.srcElement.mozHasAudio) { - this.loopVideo = this.loopVideo && !this.$store.state.config.loopVideoSilentOnly - } - } else if (typeof e.srcElement.audioTracks !== 'undefined') { - if (e.srcElement.audioTracks.length > 0) { - this.loopVideo = this.loopVideo && !this.$store.state.config.loopVideoSilentOnly - } - } } } } diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue index d7f25953..7e972026 100644 --- a/src/components/attachment/attachment.vue +++ b/src/components/attachment/attachment.vue @@ -1,19 +1,44 @@ @@ -48,10 +55,6 @@ width: 10em; } - .error { - text-align: center; - } - .register { flex: 1 1; } @@ -64,4 +67,14 @@ justify-content: space-between; } } + +.login { + .error { + text-align: center; + + animation-name: shakeError; + animation-duration: 0.4s; + animation-timing-function: ease-in-out; + } +} diff --git a/src/components/media_modal/media_modal.js b/src/components/media_modal/media_modal.js new file mode 100644 index 00000000..14ae19d4 --- /dev/null +++ b/src/components/media_modal/media_modal.js @@ -0,0 +1,38 @@ +import StillImage from '../still-image/still-image.vue' +import VideoAttachment from '../video_attachment/video_attachment.vue' +import fileTypeService from '../../services/file_type/file_type.service.js' + +const MediaModal = { + components: { + StillImage, + VideoAttachment + }, + computed: { + showing () { + return this.$store.state.mediaViewer.activated + }, + currentIndex () { + return this.$store.state.mediaViewer.currentIndex + }, + currentMedia () { + return this.$store.state.mediaViewer.media[this.currentIndex] + }, + type () { + return this.currentMedia ? fileTypeService.fileType(this.currentMedia.mimetype) : null + } + }, + created () { + document.addEventListener('keyup', e => { + if (e.keyCode === 27 && this.showing) { // escape + this.hide() + } + }) + }, + methods: { + hide () { + this.$store.dispatch('closeMediaViewer') + } + } +} + +export default MediaModal diff --git a/src/components/media_modal/media_modal.vue b/src/components/media_modal/media_modal.vue new file mode 100644 index 00000000..796d4e40 --- /dev/null +++ b/src/components/media_modal/media_modal.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/src/components/media_upload/media_upload.js b/src/components/media_upload/media_upload.js index 42d900d3..1c874faa 100644 --- a/src/components/media_upload/media_upload.js +++ b/src/components/media_upload/media_upload.js @@ -3,19 +3,10 @@ import statusPosterService from '../../services/status_poster/status_poster.serv import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' const mediaUpload = { - mounted () { - const input = this.$el.querySelector('input') - - input.addEventListener('change', ({target}) => { - for (var i = 0; i < target.files.length; i++) { - let file = target.files[i] - this.uploadFile(file) - } - }) - }, data () { return { - uploading: false + uploading: false, + uploadReady: true } }, methods: { @@ -56,6 +47,18 @@ const mediaUpload = { } else { e.dataTransfer.dropEffect = 'none' } + }, + clearFile () { + this.uploadReady = false + this.$nextTick(() => { + this.uploadReady = true + }) + }, + change ({target}) { + for (var i = 0; i < target.files.length; i++) { + let file = target.files[i] + this.uploadFile(file) + } } }, props: [ diff --git a/src/components/media_upload/media_upload.vue b/src/components/media_upload/media_upload.vue index 768d3565..fcdc3471 100644 --- a/src/components/media_upload/media_upload.vue +++ b/src/components/media_upload/media_upload.vue @@ -3,7 +3,7 @@ diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index ad7c53f9..3aa0a793 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -44,6 +44,7 @@ .nav-panel .panel { overflow: hidden; + box-shadow: var(--panelShadow); } .nav-panel ul { list-style: none; diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index f95a329f..7d9807de 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -1,5 +1,5 @@ import Status from '../status/status.vue' -import StillImage from '../still-image/still-image.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import UserCardContent from '../user_card_content/user_card_content.vue' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' @@ -13,7 +13,7 @@ const Notification = { }, props: [ 'notification' ], components: { - Status, StillImage, UserCardContent + Status, UserAvatar, UserCardContent }, methods: { toggleUserExpanded () { diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index f91c90cc..a0a55cba 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -2,7 +2,7 @@
- +
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index ea32bbd0..5e95631a 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -13,6 +13,11 @@ const Notifications = { notificationsFetcher.startFetching({ store, credentials }) }, + data () { + return { + bottomedOut: false + } + }, computed: { notifications () { return notificationsFromStore(this.$store) @@ -28,6 +33,9 @@ const Notifications = { }, unseenCount () { return this.unseenNotifications.length + }, + loading () { + return this.$store.state.statuses.notifications.loading } }, components: { @@ -49,10 +57,16 @@ const Notifications = { fetchOlderNotifications () { const store = this.$store const credentials = store.state.users.currentUser.credentials + store.commit('setNotificationsLoading', { value: true }) notificationsFetcher.fetchAndUpdate({ store, credentials, older: true + }).then(notifs => { + store.commit('setNotificationsLoading', { value: false }) + if (notifs.length === 0) { + this.bottomedOut = true + } }) } } diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 5c4ca1b9..bc81d45c 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -36,26 +36,7 @@ border-color: $fallback--border; border-color: var(--border, $fallback--border); - .avatar-compact { - width: 32px; - height: 32px; - box-shadow: var(--avatarStatusShadow); - border-radius: $fallback--avatarAltRadius; - border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); - overflow: hidden; - line-height: 0; - - &.better-shadow { - box-shadow: var(--avatarStatusShadowInset); - filter: var(--avatarStatusShadowFilter) - } - - &.animated::before { - display: none; - } - } - - &:hover .animated.avatar-compact { + &:hover .animated.avatar { canvas { display: none; } diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 64f18720..6f162b62 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -18,10 +18,15 @@
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js index 8a4e2489..5e8c2252 100644 --- a/src/components/post_status_form/post_status_form.js +++ b/src/components/post_status_form/post_status_form.js @@ -16,7 +16,7 @@ const buildMentionsString = ({user, attentions}, currentUser) => { return `@${attention.screen_name}` }) - return mentions.join(' ') + ' ' + return mentions.length > 0 ? mentions.join(' ') + ' ' : '' } const PostStatusForm = { @@ -250,6 +250,7 @@ const PostStatusForm = { visibility: newStatus.visibility, contentType: newStatus.contentType } + this.$refs.mediaUpload.clearFile() this.$emit('posted') let el = this.$el.querySelector('textarea') el.style.height = 'auto' diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 398f1871..e09ad37f 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -64,7 +64,7 @@
- +

{{ charactersLeft }}

{{ charactersLeft }}

diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue index 25c1a9d0..f428ead3 100644 --- a/src/components/registration/registration.vue +++ b/src/components/registration/registration.vue @@ -147,24 +147,6 @@ $validations-cRed: #f04124; margin-bottom: 1em; } - @keyframes shakeError { - 0% { - transform: translateX(0); } - 15% { - transform: translateX(0.375rem); } - 30% { - transform: translateX(-0.375rem); } - 45% { - transform: translateX(0.375rem); } - 60% { - transform: translateX(-0.375rem); } - 75% { - transform: translateX(0.375rem); } - 90% { - transform: translateX(-0.375rem); } - 100% { - transform: translateX(0); } } - .form-group--error { animation-name: shakeError; animation-duration: .6s; @@ -215,7 +197,7 @@ $validations-cRed: #f04124; } } -@media all and (max-width: 959px) { +@media all and (max-width: 800px) { .registration-form .container { flex-direction: column-reverse; } diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index d45ec72d..8d138485 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -1,5 +1,5 @@ /* eslint-env browser */ -import TabSwitcher from '../tab_switcher/tab_switcher.jsx' +import TabSwitcher from '../tab_switcher/tab_switcher.js' import StyleSwitcher from '../style_switcher/style_switcher.vue' import InterfaceLanguageSwitcher from '../interface_language_switcher/interface_language_switcher.vue' import { filter, trim } from 'lodash' @@ -13,6 +13,7 @@ const settings = { hideAttachmentsLocal: user.hideAttachments, hideAttachmentsInConvLocal: user.hideAttachmentsInConv, hideNsfwLocal: user.hideNsfw, + useOneClickNsfw: user.useOneClickNsfw, hideISPLocal: user.hideISP, preloadImage: user.preloadImage, @@ -29,7 +30,6 @@ const settings = { notificationVisibilityLocal: user.notificationVisibility, replyVisibilityLocal: user.replyVisibility, loopVideoLocal: user.loopVideo, - loopVideoSilentOnlyLocal: user.loopVideoSilentOnly, muteWordsString: user.muteWords.join('\n'), autoLoadLocal: user.autoLoad, streamingLocal: user.streaming, @@ -58,13 +58,16 @@ const settings = { stopGifs: user.stopGifs, webPushNotificationsLocal: user.webPushNotifications, + loopVideoSilentOnlyLocal: user.loopVideosSilentOnly, loopSilentAvailable: // Firefox Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') || // Chrome-likes Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'webkitAudioDecodedByteCount') || // Future spec, still not supported in Nightly 63 as of 08/2018 - Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'audioTracks') + Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'audioTracks'), + playVideosInModal: user.playVideosInModal, + useContainFit: user.useContainFit } }, components: { @@ -96,6 +99,9 @@ const settings = { hideNsfwLocal (value) { this.$store.dispatch('setOption', { name: 'hideNsfw', value }) }, + useOneClickNsfw (value) { + this.$store.dispatch('setOption', { name: 'useOneClickNsfw', value }) + }, preloadImage (value) { this.$store.dispatch('setOption', { name: 'preloadImage', value }) }, @@ -157,6 +163,12 @@ const settings = { webPushNotificationsLocal (value) { this.$store.dispatch('setOption', { name: 'webPushNotifications', value }) if (value) this.$store.dispatch('registerPushNotifications') + }, + playVideosInModal (value) { + this.$store.dispatch('setOption', { name: 'playVideosInModal', value }) + }, + useContainFit (value) { + this.$store.dispatch('setOption', { name: 'useContainFit', value }) } } } diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 39125009..9953780f 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -123,6 +123,10 @@ +
  • + + +
  • @@ -141,6 +145,14 @@
  • +
  • + + +
  • +
  • + + +
  • diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js index 754a57e0..40ffa1dd 100644 --- a/src/components/side_drawer/side_drawer.js +++ b/src/components/side_drawer/side_drawer.js @@ -26,6 +26,12 @@ const SideDrawer = { }, suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled + }, + logo () { + return this.$store.state.instance.logo + }, + sitename () { + return this.$store.state.instance.name } }, methods: { diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue index fc90977b..a6c6f237 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -8,8 +8,11 @@ @touchmove="touchMove" >
    - - + +
    + + {{sitename}} +