From ca0b73060556367b5a7ec0d771b9ca14ba958870 Mon Sep 17 00:00:00 2001 From: eris Date: Sun, 14 Aug 2022 23:24:59 +0000 Subject: [PATCH 01/50] Redo desktop nav, add options for site name and favicon (#83) Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/83 Co-authored-by: eris Co-committed-by: eris --- src/components/desktop_nav/desktop_nav.js | 31 ++++- src/components/desktop_nav/desktop_nav.scss | 42 ++++-- src/components/desktop_nav/desktop_nav.vue | 125 +++++++++++++++--- src/components/mobile_nav/mobile_nav.js | 7 +- src/components/mobile_nav/mobile_nav.vue | 2 +- src/components/nav_panel/nav_panel.js | 4 +- src/components/nav_panel/nav_panel.vue | 2 +- .../settings_modal/settings_modal.js | 8 ++ .../settings_modal/settings_modal.scss | 6 + .../settings_modal/settings_modal.vue | 14 ++ .../settings_modal/tabs/general_tab.vue | 32 +++++ src/components/side_drawer/side_drawer.js | 4 +- src/components/side_drawer/side_drawer.vue | 2 +- src/i18n/en.json | 4 + src/modules/config.js | 4 + src/modules/instance.js | 5 +- 16 files changed, 251 insertions(+), 41 deletions(-) diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js index e048f53d..3307b5d5 100644 --- a/src/components/desktop_nav/desktop_nav.js +++ b/src/components/desktop_nav/desktop_nav.js @@ -5,12 +5,16 @@ import { faSignOutAlt, faHome, faComments, - faBell, faUserPlus, faBullhorn, faSearch, faTachometerAlt, faCog, + faGlobe, + faBolt, + faUsers, + faCommentMedical, + faBookmark, faInfoCircle } from '@fortawesome/free-solid-svg-icons' @@ -19,12 +23,16 @@ library.add( faSignOutAlt, faHome, faComments, - faBell, faUserPlus, faBullhorn, faSearch, faTachometerAlt, faCog, + faGlobe, + faBolt, + faUsers, + faCommentMedical, + faBookmark, faInfoCircle ) @@ -65,7 +73,22 @@ export default { }) }, logo () { return this.$store.state.instance.logo }, + mergedConfig () { + return this.$store.getters.mergedConfig + }, sitename () { return this.$store.state.instance.name }, + showNavShortcuts () { + return this.mergedConfig.showNavShortcuts + }, + showWiderShortcuts () { + return this.mergedConfig.showWiderShortcuts + }, + hideSiteFavicon () { + return this.mergedConfig.hideSiteFavicon + }, + hideSiteName () { + return this.mergedConfig.hideSiteName + }, hideSitename () { return this.$store.state.instance.hideSitename }, logoLeft () { return this.$store.state.instance.logoLeft }, currentUser () { return this.$store.state.users.currentUser }, @@ -75,10 +98,6 @@ export default { scrollToTop () { window.scrollTo(0, 0) }, - logout () { - this.$router.replace('/main/public') - this.$store.dispatch('logout') - }, onSearchBarToggled (hidden) { this.searchBarHidden = hidden }, diff --git a/src/components/desktop_nav/desktop_nav.scss b/src/components/desktop_nav/desktop_nav.scss index 7fd2b26f..4d8c40e3 100644 --- a/src/components/desktop_nav/desktop_nav.scss +++ b/src/components/desktop_nav/desktop_nav.scss @@ -15,16 +15,16 @@ display: grid; grid-template-rows: var(--navbar-height); grid-template-columns: 2fr auto 2fr; - grid-template-areas: "sitename logo actions"; + grid-template-areas: "nav-left logo actions"; box-sizing: border-box; padding: 0 1.2em; margin: auto; - max-width: 980px; + max-width: 1110px; } &.-logoLeft .inner-nav { grid-template-columns: auto 2fr 2fr; - grid-template-areas: "logo sitename actions"; + grid-template-areas: "logo nav-left actions"; } .button-default { @@ -84,14 +84,21 @@ } .nav-icon { - margin-left: 1em; + margin-left: 0.2em; width: 2em; height: 100%; - font-size: 130%; text-align: center; - &-logout { - margin-left: 2em; + &.router-link-active { + font-size: 1.2em; + margin-top: 0.05em; + + .svg-inline--fa { + font-weight: bolder; + color: $fallback--text; + color: var(--selectedMenuText, $fallback--text); + --lightText: var(--selectedMenuLightText, $fallback--lightText); + } } .svg-inline--fa { @@ -100,8 +107,25 @@ } } - .sitename { - grid-area: sitename; + .-wide { + .nav-icon { + margin-left: 0.7em; + } + } + + .left { + padding-left: 5px; + display: flex; + } + + .nav-left-wrapper { + grid-area: nav-left; + + .favicon { + height: 28px; + vertical-align: middle; + padding-right: 5px; + } } .actions { diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue index fe9af544..32b90749 100644 --- a/src/components/desktop_nav/desktop_nav.vue +++ b/src/components/desktop_nav/desktop_nav.vue @@ -5,16 +5,79 @@ :class="{ '-logoLeft': logoLeft }" @click="scrollToTop()" > -
-
+
+
diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js index 713fd37b..7a356921 100644 --- a/src/components/mobile_nav/mobile_nav.js +++ b/src/components/mobile_nav/mobile_nav.js @@ -41,7 +41,12 @@ const MobileNav = { unseenNotificationsCount () { return this.unseenNotifications.length }, - hideSitename () { return this.$store.state.instance.hideSitename }, + mergedConfig () { + return this.$store.getters.mergedConfig + }, + hideSiteName () { + return this.mergedConfig.hideSiteName + }, sitename () { return this.$store.state.instance.name } }, methods: { diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue index 3583ab3c..308c8d57 100644 --- a/src/components/mobile_nav/mobile_nav.vue +++ b/src/components/mobile_nav/mobile_nav.vue @@ -22,7 +22,7 @@ /> {{ $t("nav.interactions") }} diff --git a/src/components/settings_modal/settings_modal.js b/src/components/settings_modal/settings_modal.js index 0a72dca1..b1bb4eab 100644 --- a/src/components/settings_modal/settings_modal.js +++ b/src/components/settings_modal/settings_modal.js @@ -14,6 +14,7 @@ import { faTimes, faFileUpload, faFileDownload, + faSignOutAlt, faChevronDown } from '@fortawesome/free-solid-svg-icons' import { @@ -28,6 +29,7 @@ library.add( faWindowMinimize, faFileUpload, faFileDownload, + faSignOutAlt, faChevronDown ) @@ -66,6 +68,11 @@ const SettingsModal = { closeModal () { this.$store.dispatch('closeSettingsModal') }, + logout () { + this.$router.replace('/main/public') + this.$store.dispatch('closeSettingsModal') + this.$store.dispatch('logout') + }, peekModal () { this.$store.dispatch('togglePeekSettingsModal') }, @@ -150,6 +157,7 @@ const SettingsModal = { } }, computed: { + currentUser () { return this.$store.state.users.currentUser }, currentSaveStateNotice () { return this.$store.state.interface.settings.currentSaveStateNotice }, diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss index 13cb0e65..70b63360 100644 --- a/src/components/settings_modal/settings_modal.scss +++ b/src/components/settings_modal/settings_modal.scss @@ -71,5 +71,11 @@ display: flex; flex-grow: 1; } + + .logout-button { + position: absolute; + right: 20px; + padding-right: 10px; + } } } diff --git a/src/components/settings_modal/settings_modal.vue b/src/components/settings_modal/settings_modal.vue index d3bed061..03c9978e 100644 --- a/src/components/settings_modal/settings_modal.vue +++ b/src/components/settings_modal/settings_modal.vue @@ -111,6 +111,20 @@ id="unscrolled-content" class="extra-content" /> +
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index b2d06eef..2c6ff5cd 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -25,6 +25,38 @@ {{ $t('settings.hide_wallpaper') }} +
  • + + {{ $t('settings.hide_site_favicon') }} + +
  • +
  • + + {{ $t('settings.hide_site_name') }} + +
  • +
  • + + {{ $t('settings.show_nav_shortcuts') }} + +
  • +
  • + + {{ $t('settings.show_wider_shortcuts') }} + +
  • {{ $t('settings.stop_gifs') }} diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js index 9bfee6bd..1c8d5865 100644 --- a/src/components/side_drawer/side_drawer.js +++ b/src/components/side_drawer/side_drawer.js @@ -8,7 +8,7 @@ import { faSignOutAlt, faHome, faComments, - faBell, + faBolt, faUserPlus, faBullhorn, faSearch, @@ -23,7 +23,7 @@ library.add( faSignOutAlt, faHome, faComments, - faBell, + faBolt, faUserPlus, faBullhorn, faSearch, diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue index 4bbc43bb..6d78fa85 100644 --- a/src/components/side_drawer/side_drawer.vue +++ b/src/components/side_drawer/side_drawer.vue @@ -74,7 +74,7 @@ {{ $t("nav.interactions") }}
  • diff --git a/src/i18n/en.json b/src/i18n/en.json index 308575f4..853f5917 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -461,6 +461,8 @@ "hide_muted_threads": "Hide muted threads", "hide_post_stats": "Hide post statistics (e.g. the number of favorites)", "hide_shoutbox": "Hide instance shoutbox", + "hide_site_favicon": "Hide instance favicon in top panel", + "hide_site_name": "Hide instance name in top panel", "hide_threads_with_blocked_users": "Hide threads mentioning blocked users", "hide_user_stats": "Hide user statistics (e.g. the number of followers)", "hide_wallpaper": "Hide instance wallpaper", @@ -613,7 +615,9 @@ "settings": "Settings", "show_admin_badge": "Show \"Admin\" badge in my profile", "show_moderator_badge": "Show \"Moderator\" badge in my profile", + "show_nav_shortcuts": "Show extra navigation shortcuts in top panel", "show_scrollbars": "Show side column's scrollbars", + "show_wider_shortcuts": "Show wider gap between top panel shortcuts", "show_yous": "Show (You)s", "stop_gifs": "Pause animated images until you hover on them", "streaming": "Automatically show new posts when scrolled to the top", diff --git a/src/modules/config.js b/src/modules/config.js index 2f12e153..501d5dfe 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -36,6 +36,10 @@ export const defaultState = { muteBotStatuses: undefined, // instance default collapseMessageWithSubject: undefined, // instance default padEmoji: true, + showNavShortcuts: undefined, // instance default + showWiderShortcuts: undefined, // instance default + hideSiteFavicon: undefined, // instance default + hideSiteName: undefined, // instance default hideAttachments: false, hideAttachmentsInConv: false, maxThumbnails: 16, diff --git a/src/modules/instance.js b/src/modules/instance.js index cb6250ef..faa8692a 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -34,7 +34,8 @@ const defaultState = { hideWordFilteredPosts: false, hidePostStats: false, hideBotIndication: false, - hideSitename: false, + hideSiteFavicon: false, + hideSiteName: false, hideUserStats: false, muteBotStatuses: false, loginMethod: 'password', @@ -50,6 +51,8 @@ const defaultState = { scopeCopy: true, showFeaturesPanel: true, showInstanceSpecificPanel: false, + showNavShortcuts: true, + showWiderShortcuts: true, sidebarRight: false, subjectLineBehavior: 'email', theme: 'pleroma-dark', -- 2.34.1 From 64fdde52f6d20f5615a34b114b638851a84ae918 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Wed, 17 Aug 2022 08:41:36 +0000 Subject: [PATCH 02/50] timeline panel nav (#131) Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/131 --- package.json | 2 +- src/components/desktop_nav/desktop_nav.vue | 23 ++-- .../moderation_tools/moderation_tools.vue | 5 +- .../settings_modal/tabs/general_tab.vue | 8 ++ src/components/timeline/timeline.js | 5 + src/components/timeline/timeline.vue | 6 +- .../timeline_menu_content.js | 30 +++++ .../timeline_menu_content.vue | 114 ++++++++++++++++++ .../timeline_menu_tabs/timeline_menu_tabs.js | 61 ++++++++++ .../timeline_menu_tabs/timeline_menu_tabs.vue | 96 +++++++++++++++ src/components/user_card/user_card.js | 1 + src/components/user_card/user_card.vue | 2 +- src/i18n/en.json | 1 + src/modules/config.js | 1 + yarn.lock | 15 ++- 15 files changed, 349 insertions(+), 21 deletions(-) create mode 100644 src/components/timeline_menu_tabs/timeline_menu_content.js create mode 100644 src/components/timeline_menu_tabs/timeline_menu_content.vue create mode 100644 src/components/timeline_menu_tabs/timeline_menu_tabs.js create mode 100644 src/components/timeline_menu_tabs/timeline_menu_tabs.vue diff --git a/package.json b/package.json index 1445f12c..dcde025a 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@babel/runtime": "7.17.8", "@chenfengyuan/vue-qrcode": "2.0.0", "@fortawesome/fontawesome-svg-core": "1.3.0", - "@fortawesome/free-regular-svg-icons": "5.15.4", + "@fortawesome/free-regular-svg-icons": "^6.1.2", "@fortawesome/free-solid-svg-icons": "5.15.4", "@fortawesome/vue-fontawesome": "3.0.1", "@kazvmoe-infra/pinch-zoom-element": "1.2.0", diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue index 32b90749..25b4fe8e 100644 --- a/src/components/desktop_nav/desktop_nav.vue +++ b/src/components/desktop_nav/desktop_nav.vue @@ -54,17 +54,6 @@ :title="$t('nav.public_tl')" /> - - - + + + @@ -167,6 +167,7 @@ .moderation-tools-popover { height: 100%; + z-index: 999; .trigger { display: flex !important; height: 100%; diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 2c6ff5cd..4f5a5bc7 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -49,6 +49,14 @@ {{ $t('settings.show_nav_shortcuts') }} +
  • + + {{ $t('settings.show_panel_nav_shortcuts') }} + +
  • - + +
    diff --git a/src/i18n/en.json b/src/i18n/en.json index 853f5917..84e4a185 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -616,6 +616,7 @@ "show_admin_badge": "Show \"Admin\" badge in my profile", "show_moderator_badge": "Show \"Moderator\" badge in my profile", "show_nav_shortcuts": "Show extra navigation shortcuts in top panel", + "show_panel_nav_shortcuts": "Show timeline navigation shortcuts at the top of the panel", "show_scrollbars": "Show side column's scrollbars", "show_wider_shortcuts": "Show wider gap between top panel shortcuts", "show_yous": "Show (You)s", diff --git a/src/modules/config.js b/src/modules/config.js index 501d5dfe..5b60520b 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -37,6 +37,7 @@ export const defaultState = { collapseMessageWithSubject: undefined, // instance default padEmoji: true, showNavShortcuts: undefined, // instance default + showPanelNavShortcuts: undefined, // instance default showWiderShortcuts: undefined, // instance default hideSiteFavicon: undefined, // instance default hideSiteName: undefined, // instance default diff --git a/yarn.lock b/yarn.lock index a761ad0d..5961b770 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1085,6 +1085,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@fortawesome/fontawesome-common-types@6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz#c1095b1bbabf19f37f9ff0719db38d92a410bcfe" + integrity sha512-wBaAPGz1Awxg05e0PBRkDRuTsy4B3dpBm+zreTTyd9TH4uUM27cAL4xWyWR0rLJCrRwzVsQ4hF3FvM6rqydKPA== + "@fortawesome/fontawesome-common-types@^0.2.36": version "0.2.36" resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903" @@ -1102,12 +1107,12 @@ dependencies: "@fortawesome/fontawesome-common-types" "^0.3.0" -"@fortawesome/free-regular-svg-icons@5.15.4": - version "5.15.4" - resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz#b97edab436954333bbeac09cfc40c6a951081a02" - integrity sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw== +"@fortawesome/free-regular-svg-icons@^6.1.2": + version "6.1.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.2.tgz#9f04009098addcc11d0d185126f058ed042c3099" + integrity sha512-xR4hA+tAwsaTHGfb+25H1gVU/aJ0Rzu+xIUfnyrhaL13yNQ7TWiI2RvzniAaB+VGHDU2a+Pk96Ve+pkN3/+TTQ== dependencies: - "@fortawesome/fontawesome-common-types" "^0.2.36" + "@fortawesome/fontawesome-common-types" "6.1.2" "@fortawesome/free-solid-svg-icons@5.15.4": version "5.15.4" -- 2.34.1 From e61228b0310c46e641cd3429ccb5348e954dbf6e Mon Sep 17 00:00:00 2001 From: floatingghost Date: Wed, 17 Aug 2022 09:34:50 +0000 Subject: [PATCH 03/50] use akkoma-specific source for MFM unless asked not to (#132) Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/132 --- src/boot/after_store.js | 6 ++++++ src/components/rich_content/rich_content.jsx | 15 +++++++++++++-- src/components/status_body/status_body.vue | 1 + src/modules/users.js | 2 +- .../entity_normalizer.service.js | 1 + 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/boot/after_store.js b/src/boot/after_store.js index c0a4cff9..b1f1ee02 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -124,6 +124,11 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => { copyInstanceOption('hideBotIndication') copyInstanceOption('hideUserStats') copyInstanceOption('hideFilteredStatuses') + copyInstanceOption('hideSiteName') + copyInstanceOption('hideSiteFavicon') + copyInstanceOption('showWiderShortcuts') + copyInstanceOption('showNavShortcuts') + copyInstanceOption('showPanelNavShortcuts') copyInstanceOption('logo') store.dispatch('setInstanceOption', { @@ -154,6 +159,7 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => { copyInstanceOption('alwaysShowSubjectInput') copyInstanceOption('showFeaturesPanel') copyInstanceOption('hideSitename') + copyInstanceOption('renderMisskeyMarkdown') copyInstanceOption('sidebarRight') return store.dispatch('setTheme', config['theme']) diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index 0d4127b6..e384b745 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -10,6 +10,11 @@ import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue' import './rich_content.scss' +const selectContent = (html, sourceContent, mfm) => { + if (!mfm) return html + return sourceContent === '' ? html : sourceContent +} + /** * RichContent, The Über-powered component for rendering Post HTML. * @@ -66,6 +71,11 @@ export default { required: false, type: Boolean, default: false + }, + sourceContent: { + required: false, + type: String, + default: '' } }, // NEVER EVER TOUCH DATA INSIDE RENDER @@ -74,7 +84,8 @@ export default { const greentext = this.mfm ? false : this.greentext // Pre-process HTML - const { newHtml: html } = preProcessPerLine(this.html, greentext) + const useContent = selectContent(this.html, this.sourceContent, this.mfm) + const { newHtml: html } = preProcessPerLine(useContent, greentext) let currentMentions = null // Current chain of mentions, we group all mentions together // This is used to recover spacing removed when parsing mentions let lastSpacing = '' @@ -169,7 +180,7 @@ export default { } // Processor to use with html_tree_converter - const processItem = (item, index, array, what) => { + const processItem = (item, index, array) => { // Handle text nodes - just add emoji if (typeof item === 'string') { const emptyText = item.trim() === '' diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue index 321f3c4b..5a5f3e5e 100644 --- a/src/components/status_body/status_body.vue +++ b/src/components/status_body/status_body.vue @@ -52,6 +52,7 @@ :emoji="status.emojis" :handle-links="true" :mfm="renderMisskeyMarkdown && (status.media_type === 'text/x.misskeymarkdown')" + :sourceContent="status.source_content" :greentext="mergedConfig.greentext" :attentions="status.attentions" @parseReady="onParseReady" diff --git a/src/modules/users.js b/src/modules/users.js index 02a9e361..5daf3862 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -589,7 +589,7 @@ const users = { const response = data.error // Authentication failed commit('endLogin') - if (response.status === 401) { + if (response.status === 401 || response.status === 403) { reject(new Error('Wrong username or password')) } else { reject(new Error('An error occurred, please try again')) diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index b66191bf..29032a65 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -282,6 +282,7 @@ export const parseStatus = (data) => { const { akkoma } = data if (akkoma && akkoma.source) { output.media_type = akkoma.source.mediaType + output.source_content = akkoma.source.content } } -- 2.34.1 From 2d85ee6a0831ed1c3d5f1a0e2934718f4ef4a111 Mon Sep 17 00:00:00 2001 From: floatingghost Date: Thu, 18 Aug 2022 03:14:38 +0000 Subject: [PATCH 04/50] use-server-side-mfm (#133) Reviewed-on: https://akkoma.dev/AkkomaGang/pleroma-fe/pulls/133 --- src/components/rich_content/rich_content.jsx | 15 ++------------- src/components/status_body/status_body.vue | 1 - src/components/status_content/status_content.js | 3 +++ src/components/status_content/status_content.vue | 9 +++++++-- src/modules/users.js | 2 +- .../entity_normalizer.service.js | 1 - 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/components/rich_content/rich_content.jsx b/src/components/rich_content/rich_content.jsx index e384b745..0d4127b6 100644 --- a/src/components/rich_content/rich_content.jsx +++ b/src/components/rich_content/rich_content.jsx @@ -10,11 +10,6 @@ import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue' import './rich_content.scss' -const selectContent = (html, sourceContent, mfm) => { - if (!mfm) return html - return sourceContent === '' ? html : sourceContent -} - /** * RichContent, The Über-powered component for rendering Post HTML. * @@ -71,11 +66,6 @@ export default { required: false, type: Boolean, default: false - }, - sourceContent: { - required: false, - type: String, - default: '' } }, // NEVER EVER TOUCH DATA INSIDE RENDER @@ -84,8 +74,7 @@ export default { const greentext = this.mfm ? false : this.greentext // Pre-process HTML - const useContent = selectContent(this.html, this.sourceContent, this.mfm) - const { newHtml: html } = preProcessPerLine(useContent, greentext) + const { newHtml: html } = preProcessPerLine(this.html, greentext) let currentMentions = null // Current chain of mentions, we group all mentions together // This is used to recover spacing removed when parsing mentions let lastSpacing = '' @@ -180,7 +169,7 @@ export default { } // Processor to use with html_tree_converter - const processItem = (item, index, array) => { + const processItem = (item, index, array, what) => { // Handle text nodes - just add emoji if (typeof item === 'string') { const emptyText = item.trim() === '' diff --git a/src/components/status_body/status_body.vue b/src/components/status_body/status_body.vue index 5a5f3e5e..321f3c4b 100644 --- a/src/components/status_body/status_body.vue +++ b/src/components/status_body/status_body.vue @@ -52,7 +52,6 @@ :emoji="status.emojis" :handle-links="true" :mfm="renderMisskeyMarkdown && (status.media_type === 'text/x.misskeymarkdown')" - :sourceContent="status.source_content" :greentext="mergedConfig.greentext" :attentions="status.attentions" @parseReady="onParseReady" diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js index 96fb99b2..81e40b0b 100644 --- a/src/components/status_content/status_content.js +++ b/src/components/status_content/status_content.js @@ -103,6 +103,9 @@ const StatusContent = { renderMfmOnHover () { return this.mergedConfig.renderMfmOnHover }, + renderMisskeyMarkdown () { + return this.mergedConfig.renderMisskeyMarkdown + }, ...mapGetters(['mergedConfig']), ...mapState({ currentUser: state => state.users.currentUser diff --git a/src/components/status_content/status_content.vue b/src/components/status_content/status_content.vue index 3a99c779..b8735f2c 100644 --- a/src/components/status_content/status_content.vue +++ b/src/components/status_content/status_content.vue @@ -1,7 +1,7 @@ diff --git a/src/components/confirm_modal/confirm_modal.js b/src/components/confirm_modal/confirm_modal.js new file mode 100644 index 00000000..96ddc118 --- /dev/null +++ b/src/components/confirm_modal/confirm_modal.js @@ -0,0 +1,37 @@ +import DialogModal from '../dialog_modal/dialog_modal.vue' + +/** + * This component emits the following events: + * cancelled, emitted when the action should not be performed; + * accepted, emitted when the action should be performed; + * + * The caller should close this dialog after receiving any of the two events. + */ +const ConfirmModal = { + components: { + DialogModal + }, + props: { + title: { + type: String + }, + cancelText: { + type: String + }, + confirmText: { + type: String + } + }, + computed: { + }, + methods: { + onCancel () { + this.$emit('cancelled') + }, + onAccept () { + this.$emit('accepted') + } + } +} + +export default ConfirmModal diff --git a/src/components/confirm_modal/confirm_modal.vue b/src/components/confirm_modal/confirm_modal.vue new file mode 100644 index 00000000..5783c794 --- /dev/null +++ b/src/components/confirm_modal/confirm_modal.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js index 3307b5d5..9ba5abc4 100644 --- a/src/components/desktop_nav/desktop_nav.js +++ b/src/components/desktop_nav/desktop_nav.js @@ -1,4 +1,5 @@ import SearchBar from 'components/search_bar/search_bar.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faSignInAlt, @@ -38,7 +39,8 @@ library.add( export default { components: { - SearchBar + SearchBar, + ConfirmModal }, data: () => ({ searchBarHidden: true, @@ -48,7 +50,8 @@ export default { window.CSS.supports('-moz-mask-size', 'contain') || window.CSS.supports('-ms-mask-size', 'contain') || window.CSS.supports('-o-mask-size', 'contain') - ) + ), + showingConfirmLogout: false }), computed: { enableMask () { return this.supportsMask && this.$store.state.instance.logoMask }, @@ -92,7 +95,10 @@ export default { hideSitename () { return this.$store.state.instance.hideSitename }, logoLeft () { return this.$store.state.instance.logoLeft }, currentUser () { return this.$store.state.users.currentUser }, - privateMode () { return this.$store.state.instance.private } + privateMode () { return this.$store.state.instance.private }, + shouldConfirmLogout () { + return this.$store.getters.mergedConfig.modalOnLogout + } }, methods: { scrollToTop () { diff --git a/src/components/desktop_nav/desktop_nav.vue b/src/components/desktop_nav/desktop_nav.vue index 25b4fe8e..32e3c73f 100644 --- a/src/components/desktop_nav/desktop_nav.vue +++ b/src/components/desktop_nav/desktop_nav.vue @@ -167,6 +167,18 @@ + + + {{ $t('login.logout_confirm') }} + + diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue index 06b270c3..1a42b0e5 100644 --- a/src/components/dialog_modal/dialog_modal.vue +++ b/src/components/dialog_modal/dialog_modal.vue @@ -39,7 +39,7 @@ right: 0; top: 0; background: rgba(27,31,35,.5); - z-index: 99; + z-index: 2000; } } @@ -51,7 +51,7 @@ margin: 15vh auto; position: fixed; transform: translateX(-50%); - z-index: 999; + z-index: 2001; cursor: default; display: block; background-color: $fallback--bg; diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js index dd45b6b9..f7045110 100644 --- a/src/components/extra_buttons/extra_buttons.js +++ b/src/components/extra_buttons/extra_buttons.js @@ -1,4 +1,5 @@ import Popover from '../popover/popover.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faEllipsisH, @@ -25,15 +26,35 @@ library.add( ) const ExtraButtons = { - props: [ 'status' ], - components: { Popover }, + props: ['status'], + components: { + Popover, + ConfirmModal + }, + data () { + return { + expanded: false, + showingDeleteDialog: false + } + }, methods: { deleteStatus () { - const confirmed = window.confirm(this.$t('status.delete_confirm')) - if (confirmed) { - this.$store.dispatch('deleteStatus', { id: this.status.id }) + if (this.shouldConfirmDelete) { + this.showDeleteStatusConfirmDialog() + } else { + this.doDeleteStatus() } }, + doDeleteStatus () { + this.$store.dispatch('deleteStatus', { id: this.status.id }) + this.hideDeleteStatusConfirmDialog() + }, + showDeleteStatusConfirmDialog () { + this.showingDeleteDialog = true + }, + hideDeleteStatusConfirmDialog () { + this.showingDeleteDialog = false + }, pinStatus () { this.$store.dispatch('pinStatus', this.status.id) .then(() => this.$emit('onSuccess')) @@ -91,6 +112,9 @@ const ExtraButtons = { }, statusLink () { return `${this.$store.state.instance.server}${this.$router.resolve({ name: 'conversation', params: { id: this.status.id } }).href}` + }, + shouldConfirmDelete () { + return this.$store.getters.mergedConfig.modalOnDelete } } } diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue index a3c3c767..2b574bbd 100644 --- a/src/components/extra_buttons/extra_buttons.vue +++ b/src/components/extra_buttons/extra_buttons.vue @@ -125,6 +125,18 @@ icon="ellipsis-h" /> + + + {{ $t('status.delete_confirm') }} + + diff --git a/src/components/follow_button/follow_button.js b/src/components/follow_button/follow_button.js index 3edbcb86..443aa9bc 100644 --- a/src/components/follow_button/follow_button.js +++ b/src/components/follow_button/follow_button.js @@ -1,12 +1,20 @@ +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' export default { props: ['relationship', 'user', 'labelFollowing', 'buttonClass'], + components: { + ConfirmModal + }, data () { return { - inProgress: false + inProgress: false, + showingConfirmUnfollow: false } }, computed: { + shouldConfirmUnfollow () { + return this.$store.getters.mergedConfig.modalOnUnfollow + }, isPressed () { return this.inProgress || this.relationship.following }, @@ -35,6 +43,12 @@ export default { } }, methods: { + showConfirmUnfollow () { + this.showingConfirmUnfollow = true + }, + hideConfirmUnfollow () { + this.showingConfirmUnfollow = false + }, onClick () { this.relationship.following || this.relationship.requested ? this.unfollow() : this.follow() }, @@ -45,12 +59,21 @@ export default { }) }, unfollow () { + if (this.shouldConfirmUnfollow) { + this.showConfirmUnfollow() + } else { + this.doUnfollow() + } + }, + doUnfollow () { const store = this.$store this.inProgress = true requestUnfollow(this.relationship.id, store).then(() => { this.inProgress = false store.commit('removeStatus', { timeline: 'friends', userId: this.relationship.id }) }) + + this.hideConfirmUnfollow() } } } diff --git a/src/components/follow_button/follow_button.vue b/src/components/follow_button/follow_button.vue index 965d5256..e421c15b 100644 --- a/src/components/follow_button/follow_button.vue +++ b/src/components/follow_button/follow_button.vue @@ -7,6 +7,27 @@ @click="onClick" > {{ label }} + + + + + + + diff --git a/src/components/follow_request_card/follow_request_card.js b/src/components/follow_request_card/follow_request_card.js index cbd75311..b0873bb1 100644 --- a/src/components/follow_request_card/follow_request_card.js +++ b/src/components/follow_request_card/follow_request_card.js @@ -1,10 +1,18 @@ import BasicUserCard from '../basic_user_card/basic_user_card.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js' const FollowRequestCard = { props: ['user'], components: { - BasicUserCard + BasicUserCard, + ConfirmModal + }, + data () { + return { + showingApproveConfirmDialog: false, + showingDenyConfirmDialog: false + } }, methods: { findFollowRequestNotificationId () { @@ -13,7 +21,26 @@ const FollowRequestCard = { ) return notif && notif.id }, + showApproveConfirmDialog () { + this.showingApproveConfirmDialog = true + }, + hideApproveConfirmDialog () { + this.showingApproveConfirmDialog = false + }, + showDenyConfirmDialog () { + this.showingDenyConfirmDialog = true + }, + hideDenyConfirmDialog () { + this.showingDenyConfirmDialog = false + }, approveUser () { + if (this.shouldConfirmApprove) { + this.showApproveConfirmDialog() + } else { + this.doApprove() + } + }, + doApprove () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) @@ -25,14 +52,34 @@ const FollowRequestCard = { notification.type = 'follow' } }) + this.hideApproveConfirmDialog() }, denyUser () { + if (this.shouldConfirmDeny) { + this.showDenyConfirmDialog() + } else { + this.doDeny() + } + }, + doDeny () { const notifId = this.findFollowRequestNotificationId() this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { this.$store.dispatch('dismissNotificationLocal', { id: notifId }) this.$store.dispatch('removeFollowRequest', this.user) }) + this.hideDenyConfirmDialog() + } + }, + computed: { + mergedConfig () { + return this.$store.getters.mergedConfig + }, + shouldConfirmApprove () { + return this.mergedConfig.modalOnApproveFollow + }, + shouldConfirmDeny () { + return this.mergedConfig.modalOnDenyFollow } } } diff --git a/src/components/follow_request_card/follow_request_card.vue b/src/components/follow_request_card/follow_request_card.vue index 1b12ba4b..835471e7 100644 --- a/src/components/follow_request_card/follow_request_card.vue +++ b/src/components/follow_request_card/follow_request_card.vue @@ -14,6 +14,28 @@ {{ $t('user_card.deny') }} + + + {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }} + + + {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }} + + diff --git a/src/components/mobile_nav/mobile_nav.js b/src/components/mobile_nav/mobile_nav.js index 7a356921..bba520d4 100644 --- a/src/components/mobile_nav/mobile_nav.js +++ b/src/components/mobile_nav/mobile_nav.js @@ -1,7 +1,9 @@ import SideDrawer from '../side_drawer/side_drawer.vue' import Notifications from '../notifications/notifications.vue' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils' import GestureService from '../../services/gesture_service/gesture_service' +import { mapGetters } from 'vuex' import { library } from '@fortawesome/fontawesome-svg-core' import { faTimes, @@ -18,11 +20,13 @@ library.add( const MobileNav = { components: { SideDrawer, - Notifications + Notifications, + ConfirmModal }, data: () => ({ notificationsCloseGesture: undefined, - notificationsOpen: false + notificationsOpen: false, + showingConfirmLogout: false }), created () { this.notificationsCloseGesture = GestureService.swipeGesture( @@ -47,7 +51,11 @@ const MobileNav = { hideSiteName () { return this.mergedConfig.hideSiteName }, - sitename () { return this.$store.state.instance.name } + sitename () { return this.$store.state.instance.name }, + shouldConfirmLogout () { + return this.$store.getters.mergedConfig.modalOnLogout + }, + ...mapGetters(['unreadChatCount']) }, methods: { toggleMobileSidebar () { @@ -73,9 +81,23 @@ const MobileNav = { scrollToTop () { window.scrollTo(0, 0) }, + showConfirmLogout () { + this.showingConfirmLogout = true + }, + hideConfirmLogout () { + this.showingConfirmLogout = false + }, logout () { + if (!this.shouldConfirmLogout) { + this.doLogout() + } else { + this.showConfirmLogout() + } + }, + doLogout () { this.$router.replace('/main/public') this.$store.dispatch('logout') + this.hideConfirmLogout() }, markNotificationsAsSeen () { // this.$refs.notifications.markAsSeen() diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue index 308c8d57..e6a8e694 100644 --- a/src/components/mobile_nav/mobile_nav.vue +++ b/src/components/mobile_nav/mobile_nav.vue @@ -76,6 +76,18 @@ ref="sideDrawer" :logout="logout" /> + + + {{ $t('login.logout_confirm') }} + + @@ -206,6 +218,14 @@ } } } + .confirm-modal.dark-overlay { + &::before { + z-index: 3000; + } + .dialog-modal.panel { + z-index: 3001; + } + } } diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index 398bb7a9..af612ccb 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -5,6 +5,7 @@ import UserAvatar from '../user_avatar/user_avatar.vue' import UserCard from '../user_card/user_card.vue' import Timeago from '../timeago/timeago.vue' import RichContent from 'src/components/rich_content/rich_content.jsx' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { isStatusNotification } from '../../services/notification_utils/notification_utils.js' import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' @@ -36,7 +37,9 @@ const Notification = { return { userExpanded: false, betterShadow: this.$store.state.interface.browserSupport.cssFilter, - unmuted: false + unmuted: false, + showingApproveConfirmDialog: false, + showingDenyConfirmDialog: false } }, props: [ 'notification' ], @@ -46,7 +49,8 @@ const Notification = { UserCard, Timeago, Status, - RichContent + RichContent, + ConfirmModal }, methods: { toggleUserExpanded () { @@ -61,7 +65,26 @@ const Notification = { toggleMute () { this.unmuted = !this.unmuted }, + showApproveConfirmDialog () { + this.showingApproveConfirmDialog = true + }, + hideApproveConfirmDialog () { + this.showingApproveConfirmDialog = false + }, + showDenyConfirmDialog () { + this.showingDenyConfirmDialog = true + }, + hideDenyConfirmDialog () { + this.showingDenyConfirmDialog = false + }, approveUser () { + if (this.shouldConfirmApprove) { + this.showApproveConfirmDialog() + } else { + this.doApprove() + } + }, + doApprove () { this.$store.state.api.backendInteractor.approveUser({ id: this.user.id }) this.$store.dispatch('removeFollowRequest', this.user) this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id }) @@ -71,13 +94,22 @@ const Notification = { notification.type = 'follow' } }) + this.hideApproveConfirmDialog() }, denyUser () { + if (this.shouldConfirmDeny) { + this.showDenyConfirmDialog() + } else { + this.doDeny() + } + }, + doDeny () { this.$store.state.api.backendInteractor.denyUser({ id: this.user.id }) .then(() => { this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id }) this.$store.dispatch('removeFollowRequest', this.user) }) + this.hideDenyConfirmDialog() } }, computed: { @@ -107,6 +139,15 @@ const Notification = { isStatusNotification () { return isStatusNotification(this.notification.type) }, + mergedConfig () { + return this.$store.getters.mergedConfig + }, + shouldConfirmApprove () { + return this.mergedConfig.modalOnApproveFollow + }, + shouldConfirmDeny () { + return this.mergedConfig.modalOnDenyFollow + }, ...mapState({ currentUser: state => state.users.currentUser }) diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 72e31a0c..76101865 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -231,6 +231,28 @@ + + + {{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }} + + + {{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }} + + diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js index 4f71af0a..9dc4d091 100644 --- a/src/components/retweet_button/retweet_button.js +++ b/src/components/retweet_button/retweet_button.js @@ -1,3 +1,4 @@ +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { faRetweet } from '@fortawesome/free-solid-svg-icons' @@ -5,13 +6,24 @@ library.add(faRetweet) const RetweetButton = { props: ['status', 'loggedIn', 'visibility'], + components: { + ConfirmModal + }, data () { return { - animated: false + animated: false, + showingConfirmDialog: false } }, methods: { retweet () { + if (!this.status.repeated && this.shouldConfirmRepeat) { + this.showConfirmDialog() + } else { + this.doRetweet() + } + }, + doRetweet () { if (!this.status.repeated) { this.$store.dispatch('retweet', { id: this.status.id }) } else { @@ -21,6 +33,13 @@ const RetweetButton = { setTimeout(() => { this.animated = false }, 500) + this.hideConfirmDialog() + }, + showConfirmDialog () { + this.showingConfirmDialog = true + }, + hideConfirmDialog () { + this.showingConfirmDialog = false } }, computed: { @@ -29,6 +48,9 @@ const RetweetButton = { }, mergedConfig () { return this.$store.getters.mergedConfig + }, + shouldConfirmRepeat () { + return this.mergedConfig.modalOnRepeat } } } diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue index e8a77e10..6bb7a283 100644 --- a/src/components/retweet_button/retweet_button.vue +++ b/src/components/retweet_button/retweet_button.vue @@ -33,6 +33,18 @@ > {{ status.repeat_num }} + + + {{ $t('status.repeat_confirm') }} + + diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 4f5a5bc7..1e696d1a 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -172,6 +172,77 @@ {{ $t('settings.autohide_floating_post_button') }}
  • +
  • +

    {{ $t('settings.columns') }}

    +
  • +
  • + + {{ $t('settings.disable_sticky_headers') }} + +
  • +
  • + + {{ $t('settings.show_scrollbars') }} + +
  • +
  • + + {{ $t('settings.right_sidebar') }} + +
  • +
  • + + {{ $t('settings.third_column_mode') }} + +
  • +
  • +

    {{ $t('settings.confirmation_dialogs') }}

    +
  • +
  • + {{ $t('settings.confirm_dialogs') }} +
      +
    • + + {{ $t('settings.confirm_dialogs_repeat') }} + +
    • +
    • + + {{ $t('settings.confirm_dialogs_unfollow') }} + +
    • +
    • + + {{ $t('settings.confirm_dialogs_block') }} + +
    • +
    • + + {{ $t('settings.confirm_dialogs_mute') }} + +
    • +
    • + + {{ $t('settings.confirm_dialogs_delete') }} + +
    • +
    • + + {{ $t('settings.confirm_dialogs_approve_follow') }} + +
    • +
    • + + {{ $t('settings.confirm_dialogs_deny_follow') }} + +
    • +
    +
  • diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index ef898f96..97e619a2 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -6,6 +6,7 @@ import ModerationTools from '../moderation_tools/moderation_tools.vue' import AccountActions from '../account_actions/account_actions.vue' import Select from '../select/select.vue' import RichContent from 'src/components/rich_content/rich_content.jsx' +import ConfirmModal from '../confirm_modal/confirm_modal.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' import { mapGetters } from 'vuex' import { library } from '@fortawesome/fontawesome-svg-core' @@ -32,7 +33,8 @@ export default { data () { return { followRequestInProgress: false, - betterShadow: this.$store.state.interface.browserSupport.cssFilter + betterShadow: this.$store.state.interface.browserSupport.cssFilter, + showingConfirmMute: false } }, created () { @@ -113,6 +115,9 @@ export default { hideFollowersCount () { return this.isOtherUser && this.user.hide_followers_count }, + shouldConfirmMute () { + return this.mergedConfig.modalOnMute + }, ...mapGetters(['mergedConfig']) }, components: { @@ -123,14 +128,29 @@ export default { ProgressButton, FollowButton, Select, - RichContent + RichContent, + ConfirmModal }, methods: { refetchRelationship () { return this.$store.dispatch('fetchUserRelationship', this.user.id) }, + showConfirmMute () { + this.showingConfirmMute = true + }, + hideConfirmMute () { + this.showingConfirmMute = false + }, muteUser () { + if (!this.shouldConfirmMute) { + this.doMuteUser() + } else { + this.showConfirmMute() + } + }, + doMuteUser () { this.$store.dispatch('muteUser', this.user.id) + this.hideConfirmMute() }, unmuteUser () { this.$store.dispatch('unmuteUser', this.user.id) diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index 0f776e55..c04250aa 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -295,6 +295,27 @@ :handle-links="true" />
    + + + + + + + diff --git a/src/i18n/en.json b/src/i18n/en.json index 84e4a185..7d845ca4 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -394,7 +394,17 @@ "chatMessageRadius": "Chat message", "checkboxRadius": "Checkboxes", "collapse_subject": "Collapse posts with subjects", + "columns": "Columns", "composing": "Composing", + "confirmation_dialogs": "Confirmation options", + "confirm_dialogs": "Require confirmation for:", + "confirm_dialogs_repeat": "Repeating a post", + "confirm_dialogs_unfollow": "Unfollowing someone", + "confirm_dialogs_block": "Blocking someone", + "confirm_dialogs_mute": "Muting someone", + "confirm_dialogs_delete": "Deleting a post", + "confirm_dialogs_approve_follow": "Accepting a follow request", + "confirm_dialogs_deny_follow": "Rejecting a follow request", "confirm_new_password": "Confirm new password", "conversation_display": "Conversation display style", "conversation_display_linear": "Linear-style", @@ -819,6 +829,9 @@ "copy_link": "Copy link to post", "delete": "Delete post", "delete_confirm": "Do you really want to delete this post?", + "delete_confirm_title": "Confirm deletion", + "delete_confirm_accept_button": "Yes, delete it", + "delete_confirm_cancel_button": "No, keep it", "expand": "Expand", "external_source": "External source", "favorites": "Favorites", @@ -840,6 +853,10 @@ "replies_list": "Replies:", "replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):", "reply_to": "Reply to", + "repeat_confirm": "Do you really want to repeat this post?", + "repeat_confirm_title": "Confirm repeat", + "repeat_confirm_accept_button": "Yes, repeat it", + "repeat_confirm_cancel_button": "No, don't repeat", "show_all_attachments": "Show all attachments", "show_all_conversation": "Show full conversation ({numStatus} other post) | Show full conversation ({numStatus} other posts)", "show_all_conversation_with_icon": "{icon} {text}", @@ -948,12 +965,24 @@ "strip_media": "Remove media from posts" }, "approve": "Approve", + "approve_confirm_title": "Approve follow request", + "approve_confirm": "Are you sure you want to let this user follow you?", + "approve_confirm_accept_button": "Yes, accept", + "approve_confirm_cancel_button": "No, cancel", "block": "Block", + "block_confirm": "Are you sure you want to block {user}?", + "block_confirm_title": "Block user", + "block_confirm_cancel_button": "No, don't block", + "block_confirm_accept_button": "Yes, block", "block_progress": "Blocking…", "blocked": "Blocked!", "bot": "Bot", "deactivated": "Deactivated", "deny": "Deny", + "deny_confirm_title": "Deny follow request", + "deny_confirm": "Are you sure you want to deny this user's follow request?", + "deny_confirm_accept_button": "Yes, deny", + "deny_confirm_cancel_button": "No, cancel", "domain_muted": "Unblock domain", "edit_profile": "Edit profile", "favorites": "Favorites", @@ -979,6 +1008,10 @@ "mention": "Mention", "message": "Message", "mute": "Mute", + "mute_confirm": "Are you sure you want to mute {user}?", + "mute_confirm_title": "Mute user", + "mute_confirm_cancel_button": "No, don't mute", + "mute_confirm_accept_button": "Yes, mute", "mute_domain": "Block domain", "mute_progress": "Muting…", "muted": "Muted", @@ -991,6 +1024,10 @@ "subscribe": "Subscribe", "unblock": "Unblock", "unblock_progress": "Unblocking…", + "unfollow_confirm": "Are you sure you want to unfollow {user}?", + "unfollow_confirm_title": "Unfollow user", + "unfollow_confirm_cancel_button": "No, don't unfollow", + "unfollow_confirm_accept_button": "Yes, unfollow", "unmute": "Unmute", "unmute_progress": "Unmuting…", "unsubscribe": "Unsubscribe" diff --git a/src/modules/config.js b/src/modules/config.js index 5b60520b..f97e5a8f 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -81,6 +81,14 @@ export const defaultState = { minimalScopesMode: undefined, // instance default // This hides statuses filtered via a word filter hideFilteredStatuses: undefined, // instance default + modalOnRepeat: undefined, // instance default + modalOnUnfollow: undefined, // instance default + modalOnBlock: undefined, // instance default + modalOnMute: undefined, // instance default + modalOnDelete: undefined, // instance default + modalOnLogout: undefined, // instance default + modalOnApproveFollow: undefined, // instance default + modalOnDenyFollow: undefined, // instance default playVideosInModal: false, useOneClickNsfw: false, useContainFit: true, diff --git a/src/modules/instance.js b/src/modules/instance.js index faa8692a..f9118e16 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -38,6 +38,14 @@ const defaultState = { hideSiteName: false, hideUserStats: false, muteBotStatuses: false, + modalOnRepeat: false, + modalOnUnfollow: false, + modalOnBlock: true, + modalOnMute: false, + modalOnDelete: true, + modalOnLogout: true, + modalOnApproveFollow: false, + modalOnDenyFollow: false, loginMethod: 'password', logo: '/static/logo.svg', logoMargin: '.2em', -- 2.34.1 From b1460a990944c2f2588b038024576225e97c196c Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 26 Aug 2022 12:44:30 +0000 Subject: [PATCH 15/50] Translated using Weblate (Japanese (ja_PEDANTIC)) Currently translated at 86.1% (773 of 897 strings) Translated using Weblate (Japanese (ja_PEDANTIC)) Currently translated at 86.0% (740 of 860 strings) Co-authored-by: Weblate Co-authored-by: Weblate Admin Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ja_PEDANTIC/ Translation: Pleroma fe/pleroma-fe --- src/i18n/ja_pedantic.json | 41 ++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/i18n/ja_pedantic.json b/src/i18n/ja_pedantic.json index f9149743..1858ed92 100644 --- a/src/i18n/ja_pedantic.json +++ b/src/i18n/ja_pedantic.json @@ -23,8 +23,9 @@ "media_nsfw_desc": "このインスタンスでは、以下のインスタンスからの投稿に対して、メディアを閲覧注意に設定します:", "media_removal": "メディア除去", "media_removal_desc": "このインスタンスでは、以下のインスタンスからの投稿に対して、メディアを除去します:", + "not_applicable": "なし", "quarantine": "検疫", - "quarantine_desc": "このインスタンスでは、以下のインスタンスに対して公開投稿のみを送信します:", + "quarantine_desc": "このインスタンスでは、以下のインスタンスに投稿を送信しません", "reason": "理由", "reject": "拒否", "reject_desc": "このインスタンスでは、以下のインスタンスからのメッセージを受け付けません:", @@ -36,15 +37,19 @@ "announcements": { "all_day_prompt": "一日中", "cancel_edit_action": "キャンセル", + "close_error": "閉じる", "delete_action": "削除", "edit_action": "更新", "end_time_display": "{time}に終わる", "end_time_prompt": "終了時間 ", "mark_as_read_action": "読んだ", "page_header": "お知らせ", + "post_action": "投稿", "post_error": "エラーが発生しました: {error}", + "post_form_header": "お知らせ作成", "post_placeholder": "コンテンツ", "published_time_display": "{time}に告知されました", + "start_time_display": "{time}で始まる", "start_time_prompt": "開始時間 ", "title": "お知らせ" }, @@ -158,7 +163,9 @@ "moves": "ユーザーの引っ越し" }, "lists": { + "create": "作成", "delete": "削除", + "following_only": "フォローしているユーザーのみ", "lists": "リスト", "new": "リスト作成", "save": "OK", @@ -178,12 +185,14 @@ "login": "ログイン", "logout": "ログアウト", "password": "パスワード", - "placeholder": "例: lain", + "placeholder": "例: user", "recovery_code": "リカバリーコード", "register": "登録", "username": "ユーザー名" }, "media_modal": { + "counter": "{current} / {total}", + "hide": "閉じる", "next": "次", "previous": "前" }, @@ -215,18 +224,19 @@ "who_to_follow": "おすすめユーザー" }, "notifications": { - "broken_favorite": "ステータスが見つかりません。探しています…", + "broken_favorite": "投稿が見つかりません。探しています…", "error": "通知の取得に失敗しました: {0}", - "favorited_you": "あなたのステータスがお気に入りされました", + "favorited_you": "あなたの投稿がいいねされました", "follow_request": "あなたをフォローしたいです", "followed_you": "フォローされました", "load_older": "古い通知をみる", "migrated_to": "インスタンスを引っ越しました", "no_more_notifications": "通知はありません", "notifications": "通知", + "poll_ended": "投票終了", "reacted_with": "{0} でリアクションしました", "read": "読んだ!", - "repeated_you": "あなたのステータスがリピートされました" + "repeated_you": "あなたの投稿がリピートされました" }, "password_reset": { "check_email": "パスワードをリセットするためのリンクが記載されたメールが届いているか確認してください。", @@ -264,7 +274,8 @@ "text/bbcode": "BBCode", "text/html": "HTML", "text/markdown": "Markdown", - "text/plain": "プレーンテキスト" + "text/plain": "プレーンテキスト", + "text/x.misskeymarkdown": "MFM" }, "content_warning": "説明 (省略可)", "default": "羽田空港に着きました。", @@ -273,6 +284,7 @@ "empty_status_error": "投稿内容を入力してください", "media_description": "メディアの説明", "media_description_error": "メディアのアップロードに失敗しました。もう一度お試しください", + "media_not_sensitive_warning": "注意: 説明が付けていますがNSFW警告が付けていません", "new_status": "投稿する", "post": "投稿", "posting": "投稿", @@ -372,8 +384,21 @@ "chatMessageRadius": "チャットメッセージ", "checkboxRadius": "チェックボックス", "collapse_subject": "説明のある投稿をたたむ", + "columns": "カラム", "composing": "投稿", + "confirm_dialogs": "選択しているアクションは確認必要があります", + "confirm_dialogs_approve_follow": "フォローリクエストを受け入れること", + "confirm_dialogs_block": "ユーザーをブロックすること", + "confirm_dialogs_delete": "投稿を削除すること", + "confirm_dialogs_deny_follow": "フォローリクエストを断ること", + "confirm_dialogs_mute": "ユーザーをミュートすること", + "confirm_dialogs_repeat": "投稿をリピートすること", + "confirm_dialogs_unfollow": "フォローをやめること", "confirm_new_password": "新しいパスワードの確認", + "confirmation_dialogs": "確認設定", + "conversation_display": "スレッドの表示モード", + "conversation_display_linear": "リニアー", + "conversation_display_tree": "ツリー", "current_avatar": "現在のアバター", "current_password": "現在のパスワード", "data_import_export_tab": "インポートとエクスポート", @@ -385,6 +410,8 @@ "disable_sticky_headers": "ヘッダーを追従させない", "discoverable": "検索などのサービスでこのアカウントを見つけることを許可する", "domain_mutes": "ドメイン", + "download_backup": "ダウンロード", + "email_language": "メールの表示言語", "emoji_reactions_on_timeline": "絵文字リアクションをタイムラインに表示", "enable_web_push_notifications": "ウェブプッシュ通知を許可する", "enter_current_password_to_confirm": "あなたのアイデンティティを証明するため、現在のパスワードを入力してください", @@ -436,7 +463,7 @@ "instance_default": "(デフォルト: {value})", "instance_default_simple": "(デフォルト)", "interface": "インターフェース", - "interfaceLanguage": "インターフェースの言語", + "interfaceLanguage": "表示言語", "invalid_theme_imported": "このファイルはPleromaのテーマではありません。テーマは変更されませんでした。", "limited_availability": "あなたのブラウザではできません", "links": "リンク", -- 2.34.1 From b39143413c8515a19b44225025412a919b205a10 Mon Sep 17 00:00:00 2001 From: Weblate Date: Fri, 26 Aug 2022 12:44:30 +0000 Subject: [PATCH 16/50] Translated using Weblate (Catalan) Currently translated at 100.0% (860 of 860 strings) Co-authored-by: Weblate Co-authored-by: sola Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ca/ Translation: Pleroma fe/pleroma-fe --- src/i18n/ca.json | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/i18n/ca.json b/src/i18n/ca.json index af4a5b2d..8fb864c8 100644 --- a/src/i18n/ca.json +++ b/src/i18n/ca.json @@ -400,7 +400,7 @@ "conversation_display_linear": "Estil linear", "conversation_display_tree": "Estil d'arbre", "conversation_other_replies_button": "Mostra el botó \"altres respostes\"", - "conversation_other_replies_button_below": "Apunts a sota", + "conversation_other_replies_button_below": "Apunts de sota", "conversation_other_replies_button_inside": "Apunts interiors", "current_avatar": "El teu avatar actual", "current_mascot": "La teva mascota actual", @@ -461,6 +461,8 @@ "hide_muted_threads": "Amaga fils silenciats", "hide_post_stats": "Amaga les estadístiques dels apunts (p. ex. el número de favorits)", "hide_shoutbox": "Amaga la casella de gàbia de grills", + "hide_site_favicon": "Amaga el favicon de l'instància en el panell superior", + "hide_site_name": "Amaga el nom de l'instància en el panell superior", "hide_threads_with_blocked_users": "Amaga els fils mencionant usuaris bloquejats", "hide_user_stats": "Amaga les estadístiques de l'usuari (p. ex. el número de seguidors)", "hide_wallpaper": "Amagar el fons de l'instància", @@ -546,13 +548,13 @@ "notification_setting_hide_notification_contents": "Amagar el remitent i els continguts de les notificacions push", "notification_setting_privacy": "Privacitat", "notification_visibility": "Tipus de notificacions a mostrar", - "notification_visibility_emoji_reactions": "reacciona", - "notification_visibility_follows": "em segueix", - "notification_visibility_likes": "m'afavoreix", - "notification_visibility_mentions": "em menciona", - "notification_visibility_moves": "es mou", + "notification_visibility_emoji_reactions": "reaccionen", + "notification_visibility_follows": "em segueixen", + "notification_visibility_likes": "m'afavoreixen", + "notification_visibility_mentions": "em mencionen", + "notification_visibility_moves": "usuari es mou", "notification_visibility_polls": "finalitza una enquesta que he votat", - "notification_visibility_repeats": "em repeteix", + "notification_visibility_repeats": "em repeteixen", "notifications": "Notificacions", "nsfw_clickthrough": "Amaga els Mèdia sensibles/NSFW", "oauth_tokens": "Codis OAuth", @@ -613,7 +615,10 @@ "settings": "Configuració", "show_admin_badge": "Mostra l'insígnia \"Administrador\" en el meu perfil", "show_moderator_badge": "Mostra l'insígnia \"Moderador\" en el meu perfil", + "show_nav_shortcuts": "Mostra els accessos directes addicionals en el panell superior", + "show_panel_nav_shortcuts": "Mostra els accessos directes de navegació de la línia de temps en el panell superior", "show_scrollbars": "Mostra les barres de desplaçament de la columna lateral", + "show_wider_shortcuts": "Mostra més separats els accessos directes del panell superior", "show_yous": "Mostra (Tu)s", "stop_gifs": "Pausa les imatges animades fins que hi passis el cursor per sobre", "streaming": "Mostra automàticament els nous apunts quan et desplacis a la part superior", -- 2.34.1 From e67d94f73d273a6584635514fd368f87971ac254 Mon Sep 17 00:00:00 2001 From: eris Date: Sun, 28 Aug 2022 09:27:48 +0000 Subject: [PATCH 17/50] Fix MRF transparency panel showing without transparency --- .../mrf_transparency_panel/mrf_transparency_panel.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.vue b/src/components/mrf_transparency_panel/mrf_transparency_panel.vue index 1787fa07..b05bd298 100644 --- a/src/components/mrf_transparency_panel/mrf_transparency_panel.vue +++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.vue @@ -1,6 +1,6 @@