mirror of
https://akkoma.dev/lamp/akkoma-fe.git
synced 2026-06-04 22:30:04 -04:00
Compare commits
403 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c3fcbbd918 | |||
| 0ac34b3014 | |||
| 06cde8ad06 | |||
| 434f9cdd7e | |||
| 35cde98d2c | |||
| 49aa10e1c0 | |||
| 09fe160e8b | |||
| 59db4582b0 | |||
| 44e687653c | |||
| 20b755d57e | |||
| a7a69d08a7 | |||
| 2e7529cf50 | |||
| 6fefa5a9c5 | |||
| cef6ecb916 | |||
| acc08932cd | |||
| 74caf42ed7 | |||
| 34d18ac0c4 | |||
| dd9e18fd34 | |||
| 59aaade7fc | |||
| 5faca01261 | |||
| e14b9ddc02 | |||
| 3d013630ae | |||
| 589ab6510c | |||
| e8b8c3cc49 | |||
| 2f60c6a821 | |||
| 5ddfc787ed | |||
| 226ec1c5be | |||
| 3983ea79cd | |||
| 20997d6cfc | |||
| d5f191db38 | |||
| d0b1a68f86 | |||
| a89710452a | |||
| 663362db56 | |||
| a7f055a875 | |||
| 67f3532ac9 | |||
| ee1cf36d52 | |||
| 7834ff52b1 | |||
| 47770ed715 | |||
| e720d4dd8a | |||
| aa240f935f | |||
| 265bb2cd41 | |||
| 23a5c601a7 | |||
| b4580d086f | |||
| a636e53404 | |||
| 2f8d4c7406 | |||
| 3d25946bbf | |||
| c3b267f2b9 | |||
| 44bddf6cd2 | |||
| 7e11093fcd | |||
| cba48476ad | |||
| 033b7eaeb9 | |||
| 6acf812101 | |||
| 376d431681 | |||
| 0dc6937bf8 | |||
| a848462f19 | |||
| cccdda3a7b | |||
| e85fa160c7 | |||
| 586c538aa0 | |||
| 21e2b3ce0e | |||
| 11081c2870 | |||
| 4c845a1a99 | |||
| 0a3f40eebb | |||
| 63317a2fdf | |||
| 0ffb7b67ed | |||
| 1a836c8527 | |||
| 7f3fd9ca21 | |||
| c7018057f1 | |||
| 398aac6558 | |||
| 01275fbac0 | |||
| 4859e63a89 | |||
| b2a96417cf | |||
| da807a12fb | |||
| 8b7c367b04 | |||
| 13ff99881b | |||
| 1506b97e35 | |||
| 647d75f27c | |||
| 213c5637d4 | |||
| 6f3acb3c1b | |||
| 7d4c7e3b3f | |||
| 78f8147aa6 | |||
| 982c799b6f | |||
| 66f3e72b54 | |||
| 8958f386be | |||
| de66267a07 | |||
| 6e4a0d408c | |||
| 2576b75059 | |||
| 11963de288 | |||
| 79e4df99dc | |||
| 58a92c1b7d | |||
| 286527b489 | |||
| bc9cd4170d | |||
| c4fb123d07 | |||
| 3b6a30ec9f | |||
| 238e9dcd35 | |||
| c3e5fd5fa1 | |||
| 05e5bb6404 | |||
| 836fc4d205 | |||
| c8240a48d5 | |||
| d39e918cd3 | |||
| da47d9a43d | |||
| 0c2b425682 | |||
| ffd673d4a5 | |||
| 6df5459ec9 | |||
| c5477e489b | |||
| cdd632f04c | |||
| e9c5e06f50 | |||
| a9cbf3eafe | |||
| ac43a8145b | |||
| 21eac51029 | |||
| 600ff9a67b | |||
| a5def5cf56 | |||
| 24f7cbf3c9 | |||
| 916d4e0496 | |||
| 1036395dfc | |||
| 58528605c8 | |||
| 9a074fbdfa | |||
| e8fb0f313e | |||
| 67a0d83568 | |||
| 7c295e1e0f | |||
| a02b769c8f | |||
| 7b6f68ebcd | |||
| 9cf487497e | |||
| eb2975b64d | |||
| 272ba8f7a9 | |||
| 28ebb8b0ae | |||
| 27a537d307 | |||
| daa9f211a6 | |||
| 60a8a89f5b | |||
| 0358284ebf | |||
| 11c7355749 | |||
| f614da2abb | |||
| 831cf9eafb | |||
| e14917e28d | |||
| 02ab803725 | |||
| 9bf80cc7be | |||
| 62dcf34e0d | |||
| 8011556c28 | |||
| dcba920f92 | |||
| b76a68e622 | |||
| 36e56354e4 | |||
| 9656c9b969 | |||
| 320418d524 | |||
| 8f55cb151c | |||
| 4f0c43bd84 | |||
| fe78ed78fd | |||
| 8c82bb61f1 | |||
| 38e5eec122 | |||
| f52bca04c9 | |||
| 0ee0551a47 | |||
| 65dbf7b85d | |||
| 728726cf17 | |||
| cdb9b4aea2 | |||
| 5ab96ae0d2 | |||
| 1a89ec5d8a | |||
| 83db5f0916 | |||
| 4f69c41fa5 | |||
| 8729c66374 | |||
| 6670668a7c | |||
| c1de7b60e1 | |||
| bdee1277b1 | |||
| 12991f915f | |||
| 2053b3396a | |||
| e98c19c725 | |||
| 3681d6bbd1 | |||
| e3b02de6fb | |||
| fa6cfc8238 | |||
| 2509bfc5e6 | |||
| d50798e8ce | |||
| b5dca9bbe2 | |||
| 3987020216 | |||
| 271f9e539a | |||
| a2dff27737 | |||
| 467efc4639 | |||
| 646ff273ee | |||
| 2b6b5ff227 | |||
| cf796d8f5c | |||
| 762204f3be | |||
| d1f51d946b | |||
| 837df4f5a5 | |||
| 76809e9d24 | |||
| 1847315353 | |||
| 07b31a7d9c | |||
| 9780e1fc11 | |||
| 21f624609f | |||
| 3e7d1fbf23 | |||
| ef6e2087ae | |||
| bc23266d70 | |||
| 4b0308ad1f | |||
| 9d45db959f | |||
| 9bfc3c275c | |||
| 34d8893f1c | |||
| a36922ae1b | |||
| 3df84ccd5b | |||
| 243383852b | |||
| 2312f6c15a | |||
| f01dce99df | |||
| a39866308c | |||
| 00cb8d9dce | |||
| 19bde84f6d | |||
| 481c71517e | |||
| 8d9bf3efc8 | |||
| 93af7ee36a | |||
| 3359d4ddf6 | |||
| a2f1ad93f5 | |||
| 10399c193a | |||
| 466fc84e82 | |||
| 0cf06cb9ec | |||
| 81bac9f8ac | |||
| 5cb41c7175 | |||
| c197756767 | |||
| 34c65e3bcf | |||
| 6a469963b0 | |||
| e8cebb568b | |||
| 22546ea813 | |||
| 5077549c73 | |||
| 32ed09bae5 | |||
| 6d9c79fb6d | |||
| 39c4672175 | |||
| 4451ac9f7c | |||
| bdb994d450 | |||
| 51e6f5e255 | |||
| 415119cda9 | |||
| 99e12091b7 | |||
| 83bc74de0a | |||
| 674c302350 | |||
| 45e08f83aa | |||
| 3b037218b2 | |||
| 506cf0902e | |||
| bfeb8ed14b | |||
| ffd0bbbf16 | |||
| ff93f43468 | |||
| 56927c5a09 | |||
| c74ee1153d | |||
| ccf357c206 | |||
| 99c1fb0068 | |||
| dc90db91fd | |||
| 0c3f62642b | |||
| 6b7f82174c | |||
| a8d3ce4671 | |||
| 95b911d7a0 | |||
| f1066c393f | |||
| 215e3753e1 | |||
| 426441b51c | |||
| fc4a17aa8c | |||
| f30450be12 | |||
| 17abcda2aa | |||
| 0f8587463c | |||
| 3d8af7256b | |||
| 60598f9bda | |||
| 800964ea6b | |||
| 06d05b7b82 | |||
| ac45e410d3 | |||
| 4667137fff | |||
| 037185a463 | |||
| 33e3ada7da | |||
| 00c762474f | |||
| ee0748bff5 | |||
| 2bbb01e751 | |||
| 2ac23d8318 | |||
| 3dcbc2c294 | |||
| 0f2841a98a | |||
| 8a260f4102 | |||
| c20c418e6d | |||
| fdcd4828ed | |||
| 6923d5f983 | |||
| 35773e2339 | |||
| 291d9929f8 | |||
| a3f6476ae1 | |||
| be2e6f39aa | |||
| 6111affc61 | |||
| 4f54b0123a | |||
| a5b961ed31 | |||
| ed5c1c0a4c | |||
| 061a500e0a | |||
| 78b052b6fc | |||
| 66ad886e33 | |||
| c823800a67 | |||
| d9b4c87dda | |||
| 60121775f2 | |||
| 8fbf91f3e8 | |||
| e713e17e9d | |||
| a4a0695c57 | |||
| 9657a5a098 | |||
| 55b0b81252 | |||
| ae3ded9185 | |||
| 8140501e37 | |||
| 71b0ef8f1b | |||
| 0dc0c816ea | |||
| 2478b5a306 | |||
| a464135cbd | |||
| 3f452a5462 | |||
| 431e9369c2 | |||
| c789db82df | |||
| 171462b246 | |||
| 0cccb39710 | |||
| a7b2c5cdad | |||
| a6c93c5eab | |||
| badbd27e27 | |||
| 1116b2cd32 | |||
| 9cb83648e3 | |||
| 42c747a342 | |||
| 2427757184 | |||
| 5d95376bef | |||
| 46320090e3 | |||
| fa01030641 | |||
| f4b18df644 | |||
| 15ea735006 | |||
| 0d53af786b | |||
| b537032e6d | |||
| 4dde9c4d52 | |||
| fdfb8810c1 | |||
| c655699935 | |||
| 10e2648142 | |||
| 655d985a82 | |||
| 133294dc2a | |||
| 397622078f | |||
| f1b36f3b1a | |||
| c4b098be0e | |||
| cf3ad0632a | |||
| 848b77acaa | |||
| bd1564765c | |||
| c17a0523d5 | |||
| e0d08490a4 | |||
| 2506b2629a | |||
| e98e285f50 | |||
| 767db567ad | |||
| a4e76067db | |||
| 8f118c01a4 | |||
| 00b93c0947 | |||
| 95ad9efff3 | |||
| aec6dc7858 | |||
| 6fbd6ee9ea | |||
| 83319904c7 | |||
| a68899b4a9 | |||
| 4ac2bc1c44 | |||
| 32f77cfbd7 | |||
| e6e3b752d6 | |||
| 276ef31145 | |||
| 5dfcf2acac | |||
| 1172feaa72 | |||
| aea172a6f7 | |||
| bee77ffdb2 | |||
| ebe3b38a90 | |||
| 2137d6395a | |||
| e771fd8f13 | |||
| 1d178b7341 | |||
| 04af772c1e | |||
| a6e495e413 | |||
| 38c32c7f7a | |||
| 8b775f94a9 | |||
| 7b99d98c55 | |||
| 14ce0c1c07 | |||
| 11f7b818b4 | |||
| f5186e1a33 | |||
| 838cbd8715 | |||
| 4922a8ded9 | |||
| 45180d4069 | |||
| 0089d1e8d1 | |||
| 9684bf6e94 | |||
| 4001c075d4 | |||
| b1ab09b348 | |||
| 419df9d446 | |||
| 1cd222d85c | |||
| 1495db084a | |||
| 0f386ccbc7 | |||
| d770bab1b0 | |||
| cd784396e7 | |||
| b66b4124f4 | |||
| 5c47aeeccf | |||
| d905a6cb70 | |||
| dd3c8631bf | |||
| 49f7c84e3f | |||
| fa2884a805 | |||
| 6cdf347ed1 | |||
| fb5d3d3292 | |||
| 3e1c828ba9 | |||
| a7567ce6d0 | |||
| 476154d0ee | |||
| 563377b59c | |||
| b536c6e3c5 | |||
| 41dbdc2b28 | |||
| 1d2ba946b6 | |||
| d150dae5d1 | |||
| e6ca489d30 | |||
| c1c207788a | |||
| fb80dbbc77 | |||
| 553155fc49 | |||
| 8e87e3d88b | |||
| 3963f240d5 | |||
| 9ff48b88bf | |||
| 3220e72eb9 | |||
| def1bd0676 | |||
| 9f96b592d4 | |||
| 82f17961d1 | |||
| 56c1d65384 | |||
| 0206b2bcc5 | |||
| 19fd1d4a1e | |||
| 1fa046126e | |||
| 350eb489c2 | |||
| e695506c51 | |||
| a664fde02f | |||
| 29ff0be92c | |||
| a463959a36 |
@@ -4,6 +4,72 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
|
||||
## [2.3.0] - 2021-03-01
|
||||
### Fixed
|
||||
- Button to remove uploaded media in post status form is now properly placed and sized.
|
||||
- Fixed shoutbox not working in mobile layout
|
||||
- Fixed missing highlighted border in expanded conversations again
|
||||
- Fixed some UI jumpiness when opening images particularly in chat view
|
||||
- Fixed chat unread badge looking weird
|
||||
- Fixed punycode names not working properly
|
||||
|
||||
### Changed
|
||||
- Display 'people voted' instead of 'votes' for multi-choice polls
|
||||
- Optimized chat to not get horrible performance after keeping the same chat open for a long time
|
||||
- When opening emoji picker or react picker, it automatically focuses the search field
|
||||
- Language picker now uses native language names
|
||||
|
||||
### Added
|
||||
- Added reason field for registration when approval is required
|
||||
- Group staff members by role in the About page
|
||||
|
||||
|
||||
## [2.2.3] - 2021-01-18
|
||||
### Added
|
||||
- Added Report button to status ellipsis menu for easier reporting
|
||||
|
||||
### Fixed
|
||||
- Follows/Followers tabs on user profiles now display the content properly.
|
||||
- Handle punycode in screen names
|
||||
|
||||
### Changed
|
||||
- Don't filter own posts when they hit your wordfilter
|
||||
|
||||
|
||||
## [2.2.2] - 2020-12-22
|
||||
### Added
|
||||
- Mouseover titles for emojis in reaction picker
|
||||
- Support to input emoji into the search box in reaction picker
|
||||
- Added some missing unicode emoji
|
||||
- Added the upload limit to the Features panel in the About page
|
||||
- Support for solid color wallpaper, instance doesn't have to define a wallpaper anymore
|
||||
|
||||
### Fixed
|
||||
- Fixed the occasional bug where screen would scroll 1px when typing into a reply form
|
||||
- Fixed timeline errors locking timelines
|
||||
- Fixed missing highlighted border in expanded conversations
|
||||
- Fixed custom emoji not working in profile field names
|
||||
- Fixed pinned statuses not appearing in user profiles
|
||||
- Fixed some elements not being keyboard navigation friendly
|
||||
- Fixed error handling when updating various profile images
|
||||
- Fixed your latest chat messages disappearing when closing chat view and opening it again during the same session
|
||||
- Fixed custom emoji not showing in poll options before voting
|
||||
- Fixed link color not applied to instance name in topbar
|
||||
|
||||
### Changed
|
||||
- Errors when fetching are now shown with popup errors instead of "Error fetching updates" in panel headers
|
||||
- Made reply/fav/repeat etc buttons easier to hit
|
||||
- Adjusted timeline menu clickable area to match the visible button
|
||||
- Moved external source link from status heading to the ellipsis menu
|
||||
- Disabled horizontal textarea resize
|
||||
- Wallpaper is now top-aligned, horizontally centered.
|
||||
|
||||
|
||||
## [2.2.1] - 2020-11-11
|
||||
### Fixed
|
||||
- Fixed regression in react popup alignment and overflowing
|
||||
|
||||
|
||||
## [2.2.0] - 2020-11-06
|
||||
### Added
|
||||
- New option to optimize timeline rendering to make the site more responsive (enabled by default)
|
||||
@@ -11,6 +77,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- Import/export a muted users
|
||||
- Proper handling of deletes when using websocket streaming
|
||||
- Added optimistic chat message sending, so you can start writing next message before the previous one has been sent
|
||||
- Added a small red badge to the favicon when there's unread notifications
|
||||
- Added the NSFW alert to link previews
|
||||
|
||||
### Fixed
|
||||
- Fixed clicking NSFW hider through status popover
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
|
||||
<title>Pleroma</title>
|
||||
<!--server-generated-meta-->
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
</head>
|
||||
|
||||
+3
-2
@@ -31,6 +31,7 @@
|
||||
"parse-link-header": "^1.0.1",
|
||||
"phoenix": "^1.3.0",
|
||||
"portal-vue": "^2.1.4",
|
||||
"punycode.js": "^2.1.0",
|
||||
"v-click-outside": "^2.1.1",
|
||||
"vue": "^2.6.11",
|
||||
"vue-chat-scroll": "^1.2.1",
|
||||
@@ -55,7 +56,7 @@
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"chai": "^3.5.0",
|
||||
"chalk": "^1.1.3",
|
||||
"chromedriver": "^2.21.2",
|
||||
"chromedriver": "^87.0.1",
|
||||
"connect-history-api-fallback": "^1.1.0",
|
||||
"cross-spawn": "^4.0.2",
|
||||
"css-loader": "^0.28.0",
|
||||
@@ -102,7 +103,7 @@
|
||||
"selenium-server": "2.53.1",
|
||||
"semver": "^5.3.0",
|
||||
"serviceworker-webpack-plugin": "^1.0.0",
|
||||
"shelljs": "^0.7.4",
|
||||
"shelljs": "^0.8.4",
|
||||
"sinon": "^2.1.0",
|
||||
"sinon-chai": "^2.8.0",
|
||||
"stylelint": "^13.6.1",
|
||||
|
||||
+13
-10
@@ -15,6 +15,7 @@ import UserReportingModal from './components/user_reporting_modal/user_reporting
|
||||
import PostStatusModal from './components/post_status_modal/post_status_modal.vue'
|
||||
import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue'
|
||||
import { windowWidth, windowHeight } from './services/window_utils/window_utils'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
@@ -50,17 +51,18 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
currentUser () { return this.$store.state.users.currentUser },
|
||||
background () {
|
||||
return this.currentUser.background_image || this.$store.state.instance.background
|
||||
userBackground () { return this.currentUser.background_image },
|
||||
instanceBackground () {
|
||||
return this.mergedConfig.hideInstanceWallpaper
|
||||
? null
|
||||
: this.$store.state.instance.background
|
||||
},
|
||||
background () { return this.userBackground || this.instanceBackground },
|
||||
bgStyle () {
|
||||
return {
|
||||
'background-image': `url(${this.background})`
|
||||
}
|
||||
},
|
||||
bgAppStyle () {
|
||||
return {
|
||||
'--body-background-image': `url(${this.background})`
|
||||
if (this.background) {
|
||||
return {
|
||||
'--body-background-image': `url(${this.background})`
|
||||
}
|
||||
}
|
||||
},
|
||||
chat () { return this.$store.state.chat.channel.state === 'joined' },
|
||||
@@ -77,7 +79,8 @@ export default {
|
||||
return {
|
||||
'order': this.$store.state.instance.sidebarRight ? 99 : 0
|
||||
}
|
||||
}
|
||||
},
|
||||
...mapGetters(['mergedConfig'])
|
||||
},
|
||||
methods: {
|
||||
updateMobileState () {
|
||||
|
||||
+68
-18
@@ -14,7 +14,9 @@
|
||||
right: -20px;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 50%;
|
||||
background-color: var(--wallpaper);
|
||||
background-image: var(--body-background-image);
|
||||
background-position: 50% 50px;
|
||||
}
|
||||
|
||||
i[class^='icon-'] {
|
||||
@@ -33,6 +35,7 @@ h4 {
|
||||
max-width: 980px;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
.underlay {
|
||||
background-color: rgba(0,0,0,0.15);
|
||||
background-color: var(--underlay, rgba(0,0,0,0.15));
|
||||
@@ -69,7 +72,7 @@ a {
|
||||
color: var(--link, $fallback--link);
|
||||
}
|
||||
|
||||
button {
|
||||
.button-default {
|
||||
user-select: none;
|
||||
color: $fallback--text;
|
||||
color: var(--btnText, $fallback--text);
|
||||
@@ -85,7 +88,8 @@ button {
|
||||
font-family: sans-serif;
|
||||
font-family: var(--interfaceFont, sans-serif);
|
||||
|
||||
i[class*=icon-], .svg-inline--fa {
|
||||
i[class*=icon-],
|
||||
.svg-inline--fa {
|
||||
color: $fallback--text;
|
||||
color: var(--btnText, $fallback--text);
|
||||
}
|
||||
@@ -107,7 +111,8 @@ button {
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnPressed, $fallback--fg);
|
||||
|
||||
svg, i {
|
||||
svg,
|
||||
i {
|
||||
color: $fallback--text;
|
||||
color: var(--btnPressedText, $fallback--text);
|
||||
}
|
||||
@@ -120,7 +125,8 @@ button {
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnDisabled, $fallback--fg);
|
||||
|
||||
svg, i {
|
||||
svg,
|
||||
i {
|
||||
color: $fallback--text;
|
||||
color: var(--btnDisabledText, $fallback--text);
|
||||
}
|
||||
@@ -134,7 +140,8 @@ button {
|
||||
box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
box-shadow: var(--buttonPressedShadow);
|
||||
|
||||
svg, i {
|
||||
svg,
|
||||
i {
|
||||
color: $fallback--text;
|
||||
color: var(--btnToggledText, $fallback--text);
|
||||
}
|
||||
@@ -149,6 +156,37 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
.button-unstyled {
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
display: inline;
|
||||
text-align: initial;
|
||||
font-size: 100%;
|
||||
font-family: inherit;
|
||||
padding: 0;
|
||||
line-height: unset;
|
||||
cursor: pointer;
|
||||
box-sizing: content-box;
|
||||
color: inherit;
|
||||
|
||||
&.-link {
|
||||
color: $fallback--link;
|
||||
color: var(--link, $fallback--link);
|
||||
}
|
||||
|
||||
&.-fullwidth {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.-hover-highlight {
|
||||
&:hover svg {
|
||||
color: $fallback--lightText;
|
||||
color: var(--lightText, $fallback--lightText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input, textarea, .select, .input {
|
||||
|
||||
&.unstyled {
|
||||
@@ -303,6 +341,10 @@ input, textarea, .select, .input {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
&.resize-height {
|
||||
resize: vertical;
|
||||
}
|
||||
}
|
||||
|
||||
option {
|
||||
@@ -442,6 +484,7 @@ main-router {
|
||||
color: $fallback--faint;
|
||||
color: var(--panelFaint, $fallback--faint);
|
||||
}
|
||||
|
||||
.faint-link {
|
||||
color: $fallback--faint;
|
||||
color: var(--faintLink, $fallback--faint);
|
||||
@@ -453,11 +496,8 @@ main-router {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
button, .alert {
|
||||
.button-default,
|
||||
.alert {
|
||||
// height: 100%;
|
||||
line-height: 21px;
|
||||
min-height: 0;
|
||||
@@ -468,8 +508,11 @@ main-router {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
button {
|
||||
&, i[class*=icon-] {
|
||||
.button-default {
|
||||
flex-shrink: 0;
|
||||
|
||||
&,
|
||||
i[class*=icon-] {
|
||||
color: $fallback--text;
|
||||
color: var(--btnPanelText, $fallback--text);
|
||||
}
|
||||
@@ -492,7 +535,8 @@ main-router {
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
a,
|
||||
.-link {
|
||||
color: $fallback--link;
|
||||
color: var(--panelLink, $fallback--link)
|
||||
}
|
||||
@@ -507,15 +551,15 @@ 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 {
|
||||
a,
|
||||
.-link {
|
||||
color: $fallback--link;
|
||||
color: var(--panelLink, $fallback--link)
|
||||
color: var(--panelLink, $fallback--link);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -542,6 +586,7 @@ nav {
|
||||
color: var(--faint, $fallback--faint);
|
||||
box-shadow: 0px 0px 4px rgba(0,0,0,.6);
|
||||
box-shadow: var(--topBarShadow);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
@@ -797,7 +842,7 @@ nav {
|
||||
}
|
||||
}
|
||||
|
||||
.btn.btn-default {
|
||||
.btn.button-default {
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
@@ -834,6 +879,11 @@ nav {
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
|
||||
// Get rid of scrollbar on body as scrolling happens on different element
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Ensures the fixed position of the mobile browser bars on scroll up / down events.
|
||||
// Prevents the mobile browser bars from overlapping or hiding the message posting form.
|
||||
@media all and (max-width: 800px) {
|
||||
|
||||
+1
-2
@@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div
|
||||
id="app"
|
||||
:style="bgAppStyle"
|
||||
:style="bgStyle"
|
||||
>
|
||||
<div
|
||||
id="app_bg_wrapper"
|
||||
class="app-bg-wrapper"
|
||||
:style="bgStyle"
|
||||
/>
|
||||
<MobileNav v-if="isMobileLayout" />
|
||||
<DesktopNav v-else />
|
||||
|
||||
@@ -7,6 +7,7 @@ import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
||||
import { applyTheme } from '../services/style_setter/style_setter.js'
|
||||
import FaviconService from '../services/favicon_service/favicon_service.js'
|
||||
|
||||
let staticInitialResults = null
|
||||
|
||||
@@ -50,6 +51,7 @@ const getInstanceConfig = async ({ store }) => {
|
||||
const vapidPublicKey = data.pleroma.vapid_public_key
|
||||
|
||||
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
|
||||
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
|
||||
|
||||
if (vapidPublicKey) {
|
||||
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
|
||||
@@ -326,6 +328,8 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
||||
const width = windowWidth()
|
||||
store.dispatch('setMobileLayout', width <= 800)
|
||||
|
||||
FaviconService.initFaviconService()
|
||||
|
||||
const overrides = window.___pleromafe_dev_overrides || {}
|
||||
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
|
||||
store.dispatch('setInstanceOption', { name: 'server', value: server })
|
||||
|
||||
@@ -35,7 +35,7 @@ const AccountActions = {
|
||||
this.$store.dispatch('unblockUser', this.user.id)
|
||||
},
|
||||
reportUser () {
|
||||
this.$store.dispatch('openUserReportingModal', this.user.id)
|
||||
this.$store.dispatch('openUserReportingModal', { userId: this.user.id })
|
||||
},
|
||||
openChat () {
|
||||
this.$router.push({
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
:bound-to="{ x: 'container' }"
|
||||
remove-padding
|
||||
>
|
||||
<div
|
||||
slot="content"
|
||||
@@ -13,14 +14,14 @@
|
||||
<template v-if="relationship.following">
|
||||
<button
|
||||
v-if="relationship.showing_reblogs"
|
||||
class="btn btn-default dropdown-item"
|
||||
class="btn button-default dropdown-item"
|
||||
@click="hideRepeats"
|
||||
>
|
||||
{{ $t('user_card.hide_repeats') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="!relationship.showing_reblogs"
|
||||
class="btn btn-default dropdown-item"
|
||||
class="btn button-default dropdown-item"
|
||||
@click="showRepeats"
|
||||
>
|
||||
{{ $t('user_card.show_repeats') }}
|
||||
@@ -32,27 +33,27 @@
|
||||
</template>
|
||||
<button
|
||||
v-if="relationship.blocking"
|
||||
class="btn btn-default btn-block dropdown-item"
|
||||
class="btn button-default btn-block dropdown-item"
|
||||
@click="unblockUser"
|
||||
>
|
||||
{{ $t('user_card.unblock') }}
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-default btn-block dropdown-item"
|
||||
class="btn button-default btn-block dropdown-item"
|
||||
@click="blockUser"
|
||||
>
|
||||
{{ $t('user_card.block') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default btn-block dropdown-item"
|
||||
class="btn button-default btn-block dropdown-item"
|
||||
@click="reportUser"
|
||||
>
|
||||
{{ $t('user_card.report') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="pleromaChatMessagesAvailable"
|
||||
class="btn btn-default btn-block dropdown-item"
|
||||
class="btn button-default btn-block dropdown-item"
|
||||
@click="openChat"
|
||||
>
|
||||
{{ $t('user_card.message') }}
|
||||
@@ -61,7 +62,7 @@
|
||||
</div>
|
||||
<div
|
||||
slot="trigger"
|
||||
class="btn btn-default ellipsis-button"
|
||||
class="ellipsis-button"
|
||||
>
|
||||
<FAIcon
|
||||
class="icon"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
{{ $t('general.error_retry') }}
|
||||
</p>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="retry"
|
||||
>
|
||||
{{ $t('general.retry') }}
|
||||
|
||||
@@ -8,14 +8,18 @@ import {
|
||||
faFile,
|
||||
faMusic,
|
||||
faImage,
|
||||
faVideo
|
||||
faVideo,
|
||||
faPlayCircle,
|
||||
faTimes
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faFile,
|
||||
faMusic,
|
||||
faImage,
|
||||
faVideo
|
||||
faVideo,
|
||||
faPlayCircle,
|
||||
faTimes
|
||||
)
|
||||
|
||||
const Attachment = {
|
||||
|
||||
@@ -42,15 +42,13 @@
|
||||
icon="play-circle"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
<button
|
||||
v-if="nsfw && hideNsfwLocal && !hidden"
|
||||
class="hider"
|
||||
class="button-unstyled hider"
|
||||
@click.prevent="toggleHidden"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
@click.prevent="toggleHidden"
|
||||
>Hide</a>
|
||||
</div>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
|
||||
<a
|
||||
v-if="type === 'image' && (!hidden || preloadImage)"
|
||||
@@ -234,15 +232,23 @@
|
||||
.hider {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
white-space: nowrap;
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
background: rgba(230,230,230,0.6);
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
z-index: 4;
|
||||
line-height: 1;
|
||||
border-radius: $fallback--tooltipRadius;
|
||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
||||
text-align: center;
|
||||
width: 2em;
|
||||
height: 2em;
|
||||
font-size: 1.25em;
|
||||
// TODO: theming? hard to theme with unknown background image color
|
||||
background: rgba(230, 230, 230, 0.7);
|
||||
.svg-inline--fa {
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
&:hover .svg-inline--fa {
|
||||
color: rgba(0, 0, 0, 0.9);
|
||||
}
|
||||
}
|
||||
|
||||
video {
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
class="basic-user-card-screen-name"
|
||||
:to="userProfileLink(user)"
|
||||
>
|
||||
@{{ user.screen_name }}
|
||||
@{{ user.screen_name_ui }}
|
||||
</router-link>
|
||||
</div>
|
||||
<slot />
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="block-card-content-container">
|
||||
<button
|
||||
v-if="blocked"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="progress"
|
||||
@click="unblockUser"
|
||||
>
|
||||
@@ -16,7 +16,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="progress"
|
||||
@click="blockUser"
|
||||
>
|
||||
|
||||
@@ -73,7 +73,7 @@ const Chat = {
|
||||
},
|
||||
formPlaceholder () {
|
||||
if (this.recipient) {
|
||||
return this.$t('chats.message_user', { nickname: this.recipient.screen_name })
|
||||
return this.$t('chats.message_user', { nickname: this.recipient.screen_name_ui })
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
@@ -234,6 +234,13 @@ const Chat = {
|
||||
const scrollable = this.$refs.scrollable
|
||||
return scrollable && scrollable.scrollTop <= 0
|
||||
},
|
||||
cullOlderCheck () {
|
||||
window.setTimeout(() => {
|
||||
if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) {
|
||||
this.$store.dispatch('cullOlderMessages', this.currentChatMessageService.chatId)
|
||||
}
|
||||
}, 5000)
|
||||
},
|
||||
handleScroll: _.throttle(function () {
|
||||
if (!this.currentChat) { return }
|
||||
|
||||
@@ -241,6 +248,7 @@ const Chat = {
|
||||
this.fetchChat({ maxId: this.currentChatMessageService.minId })
|
||||
} else if (this.bottomedOut(JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET)) {
|
||||
this.jumpToBottomButtonVisible = false
|
||||
this.cullOlderCheck()
|
||||
if (this.newMessageCount > 0) {
|
||||
// Use a delay before marking as read to prevent situation where new messages
|
||||
// arrive just as you're leaving the view and messages that you didn't actually
|
||||
|
||||
@@ -98,10 +98,10 @@
|
||||
.unread-message-count {
|
||||
font-size: 0.8em;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
border-radius: 100%;
|
||||
margin-top: -1rem;
|
||||
padding: 0;
|
||||
padding: 0.1em;
|
||||
border-radius: 50px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.chat-loading-error {
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
<span class="title">
|
||||
{{ $t("chats.chats") }}
|
||||
</span>
|
||||
<button @click="newChat">
|
||||
<button
|
||||
class="button-default"
|
||||
@click="newChat"
|
||||
>
|
||||
{{ $t("chats.new") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -31,9 +31,6 @@
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
}
|
||||
|
||||
border-radius: $fallback--chatMessageRadius;
|
||||
border-radius: var(--chatMessageRadius, $fallback--chatMessageRadius);
|
||||
}
|
||||
|
||||
.popover {
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<div slot="content">
|
||||
<div class="dropdown-menu">
|
||||
<button
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click="deleteMessage"
|
||||
>
|
||||
<FAIcon icon="times" /> {{ $t("chats.delete") }}
|
||||
@@ -62,7 +62,7 @@
|
||||
</div>
|
||||
<button
|
||||
slot="trigger"
|
||||
class="menu-icon"
|
||||
class="button-default menu-icon"
|
||||
:title="$t('chats.more')"
|
||||
>
|
||||
<FAIcon icon="ellipsis-h" />
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import localeService from 'src/services/locale/locale.service.js'
|
||||
|
||||
export default {
|
||||
name: 'Timeago',
|
||||
props: ['date'],
|
||||
@@ -16,7 +18,7 @@ export default {
|
||||
if (this.date.getTime() === today.getTime()) {
|
||||
return this.$t('display_date.today')
|
||||
} else {
|
||||
return this.date.toLocaleDateString('en', { day: 'numeric', month: 'long' })
|
||||
return this.date.toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale), { day: 'numeric', month: 'long' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export default Vue.component('chat-title', {
|
||||
],
|
||||
computed: {
|
||||
title () {
|
||||
return this.user ? this.user.screen_name : ''
|
||||
return this.user ? this.user.screen_name_ui : ''
|
||||
},
|
||||
htmlTitle () {
|
||||
return this.user ? this.user.name_html : ''
|
||||
|
||||
@@ -10,12 +10,13 @@
|
||||
class="panel-heading conversation-heading"
|
||||
>
|
||||
<span class="title"> {{ $t('timeline.conversation') }} </span>
|
||||
<span v-if="collapsable">
|
||||
<a
|
||||
href="#"
|
||||
@click.prevent="toggleExpanded"
|
||||
>{{ $t('timeline.collapse') }}</a>
|
||||
</span>
|
||||
<button
|
||||
v-if="collapsable"
|
||||
class="button-unstyled -link"
|
||||
@click.prevent="toggleExpanded"
|
||||
>
|
||||
{{ $t('timeline.collapse') }}
|
||||
</button>
|
||||
</div>
|
||||
<status
|
||||
v-for="status in conversation"
|
||||
@@ -49,7 +50,6 @@
|
||||
|
||||
.Conversation {
|
||||
.conversation-status {
|
||||
border-left: none;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-color: var(--border, $fallback--border);
|
||||
@@ -57,13 +57,6 @@
|
||||
}
|
||||
|
||||
&.-expanded {
|
||||
.conversation-status {
|
||||
border-color: $fallback--border;
|
||||
border-color: var(--border, $fallback--border);
|
||||
border-left-color: $fallback--cRed;
|
||||
border-left-color: var(--cRed, $fallback--cRed);
|
||||
}
|
||||
|
||||
.conversation-status:last-child {
|
||||
border-bottom: none;
|
||||
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
|
||||
a {
|
||||
color: var(--topBarLink, $fallback--link);
|
||||
}
|
||||
|
||||
.inner-nav {
|
||||
display: grid;
|
||||
grid-template-rows: 50px;
|
||||
@@ -21,7 +25,7 @@
|
||||
grid-template-areas: "logo sitename actions";
|
||||
}
|
||||
|
||||
button {
|
||||
.button-default {
|
||||
&, svg {
|
||||
color: $fallback--text;
|
||||
color: var(--btnTopBarText, $fallback--text);
|
||||
@@ -80,12 +84,13 @@
|
||||
.nav-icon {
|
||||
margin-left: 0.2em;
|
||||
width: 2em;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
a, a svg {
|
||||
color: $fallback--link;
|
||||
color: var(--topBarLink, $fallback--link);
|
||||
.svg-inline--fa {
|
||||
color: $fallback--link;
|
||||
color: var(--topBarLink, $fallback--link);
|
||||
}
|
||||
}
|
||||
|
||||
.sitename {
|
||||
|
||||
@@ -36,9 +36,8 @@
|
||||
@toggled="onSearchBarToggled"
|
||||
@click.stop.native
|
||||
/>
|
||||
<a
|
||||
href="#"
|
||||
class="nav-icon"
|
||||
<button
|
||||
class="button-unstyled nav-icon"
|
||||
@click.stop="openSettingsModal"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -47,29 +46,32 @@
|
||||
icon="cog"
|
||||
:title="$t('nav.preferences')"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
<a
|
||||
v-if="currentUser && currentUser.role === 'admin'"
|
||||
href="/pleroma/admin/#/login-pleroma"
|
||||
class="nav-icon"
|
||||
target="_blank"
|
||||
><FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="tachometer-alt"
|
||||
:title="$t('nav.administration')"
|
||||
/></a>
|
||||
<a
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="tachometer-alt"
|
||||
:title="$t('nav.administration')"
|
||||
/>
|
||||
</a>
|
||||
<button
|
||||
v-if="currentUser"
|
||||
href="#"
|
||||
class="nav-icon"
|
||||
class="button-unstyled nav-icon"
|
||||
@click.prevent="logout"
|
||||
><FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="sign-out-alt"
|
||||
:title="$t('login.logout')"
|
||||
/></a>
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="sign-out-alt"
|
||||
:title="$t('login.logout')"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ProgressButton
|
||||
v-if="muted"
|
||||
:click="unmuteDomain"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('domain_mute_card.unmute') }}
|
||||
<template slot="progress">
|
||||
@@ -16,7 +16,7 @@
|
||||
<ProgressButton
|
||||
v-else
|
||||
:click="muteDomain"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('domain_mute_card.mute') }}
|
||||
<template slot="progress">
|
||||
|
||||
@@ -114,7 +114,8 @@ const EmojiInput = {
|
||||
showPicker: false,
|
||||
temporarilyHideSuggestions: false,
|
||||
keepOpen: false,
|
||||
disableClickOutside: false
|
||||
disableClickOutside: false,
|
||||
suggestions: []
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -124,21 +125,6 @@ const EmojiInput = {
|
||||
padEmoji () {
|
||||
return this.$store.getters.mergedConfig.padEmoji
|
||||
},
|
||||
suggestions () {
|
||||
const firstchar = this.textAtCaret.charAt(0)
|
||||
if (this.textAtCaret === firstchar) { return [] }
|
||||
const matchedSuggestions = this.suggest(this.textAtCaret)
|
||||
if (matchedSuggestions.length <= 0) {
|
||||
return []
|
||||
}
|
||||
return take(matchedSuggestions, 5)
|
||||
.map(({ imageUrl, ...rest }, index) => ({
|
||||
...rest,
|
||||
// eslint-disable-next-line camelcase
|
||||
img: imageUrl || '',
|
||||
highlighted: index === this.highlighted
|
||||
}))
|
||||
},
|
||||
showSuggestions () {
|
||||
return this.focused &&
|
||||
this.suggestions &&
|
||||
@@ -188,14 +174,38 @@ const EmojiInput = {
|
||||
watch: {
|
||||
showSuggestions: function (newValue) {
|
||||
this.$emit('shown', newValue)
|
||||
},
|
||||
textAtCaret: async function (newWord) {
|
||||
const firstchar = newWord.charAt(0)
|
||||
this.suggestions = []
|
||||
if (newWord === firstchar) return
|
||||
const matchedSuggestions = await this.suggest(newWord)
|
||||
// Async: cancel if textAtCaret has changed during wait
|
||||
if (this.textAtCaret !== newWord) return
|
||||
if (matchedSuggestions.length <= 0) return
|
||||
this.suggestions = take(matchedSuggestions, 5)
|
||||
.map(({ imageUrl, ...rest }) => ({
|
||||
...rest,
|
||||
img: imageUrl || ''
|
||||
}))
|
||||
},
|
||||
suggestions (newValue) {
|
||||
this.$nextTick(this.resize)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
focusPickerInput () {
|
||||
const pickerEl = this.$refs.picker.$el
|
||||
if (!pickerEl) return
|
||||
const pickerInput = pickerEl.querySelector('input')
|
||||
if (pickerInput) pickerInput.focus()
|
||||
},
|
||||
triggerShowPicker () {
|
||||
this.showPicker = true
|
||||
this.$refs.picker.startEmojiLoad()
|
||||
this.$nextTick(() => {
|
||||
this.scrollIntoView()
|
||||
this.focusPickerInput()
|
||||
})
|
||||
// This temporarily disables "click outside" handler
|
||||
// since external trigger also means click originates
|
||||
@@ -211,6 +221,7 @@ const EmojiInput = {
|
||||
if (this.showPicker) {
|
||||
this.scrollIntoView()
|
||||
this.$refs.picker.startEmojiLoad()
|
||||
this.$nextTick(this.focusPickerInput)
|
||||
}
|
||||
},
|
||||
replace (replacement) {
|
||||
|
||||
@@ -6,13 +6,14 @@
|
||||
>
|
||||
<slot />
|
||||
<template v-if="enableEmojiPicker">
|
||||
<div
|
||||
<button
|
||||
v-if="!hideEmojiButton"
|
||||
class="emoji-picker-icon"
|
||||
class="button-unstyled emoji-picker-icon"
|
||||
type="button"
|
||||
@click.prevent="togglePicker"
|
||||
>
|
||||
<FAIcon :icon="['far', 'smile-beam']" />
|
||||
</div>
|
||||
</button>
|
||||
<EmojiPicker
|
||||
v-if="enableEmojiPicker"
|
||||
ref="picker"
|
||||
@@ -37,7 +38,7 @@
|
||||
v-for="(suggestion, index) in suggestions"
|
||||
:key="index"
|
||||
class="autocomplete-item"
|
||||
:class="{ highlighted: suggestion.highlighted }"
|
||||
:class="{ highlighted: index === highlighted }"
|
||||
@click.stop.prevent="onClick($event, suggestion)"
|
||||
>
|
||||
<span class="image">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { debounce } from 'lodash'
|
||||
/**
|
||||
* suggest - generates a suggestor function to be used by emoji-input
|
||||
* data: object providing source information for specific types of suggestions:
|
||||
@@ -11,19 +10,19 @@ import { debounce } from 'lodash'
|
||||
* doesn't support user linking you can just provide only emoji.
|
||||
*/
|
||||
|
||||
const debounceUserSearch = debounce((data, input) => {
|
||||
data.updateUsersList(input)
|
||||
}, 500)
|
||||
|
||||
export default data => input => {
|
||||
const firstChar = input[0]
|
||||
if (firstChar === ':' && data.emoji) {
|
||||
return suggestEmoji(data.emoji)(input)
|
||||
export default data => {
|
||||
const emojiCurry = suggestEmoji(data.emoji)
|
||||
const usersCurry = data.store && suggestUsers(data.store)
|
||||
return input => {
|
||||
const firstChar = input[0]
|
||||
if (firstChar === ':' && data.emoji) {
|
||||
return emojiCurry(input)
|
||||
}
|
||||
if (firstChar === '@' && usersCurry) {
|
||||
return usersCurry(input)
|
||||
}
|
||||
return []
|
||||
}
|
||||
if (firstChar === '@' && data.users) {
|
||||
return suggestUsers(data)(input)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export const suggestEmoji = emojis => input => {
|
||||
@@ -57,50 +56,75 @@ export const suggestEmoji = emojis => input => {
|
||||
})
|
||||
}
|
||||
|
||||
export const suggestUsers = data => input => {
|
||||
const noPrefix = input.toLowerCase().substr(1)
|
||||
const users = data.users
|
||||
export const suggestUsers = ({ dispatch, state }) => {
|
||||
// Keep some persistent values in closure, most importantly for the
|
||||
// custom debounce to work. Lodash debounce does not return a promise.
|
||||
let suggestions = []
|
||||
let previousQuery = ''
|
||||
let timeout = null
|
||||
let cancelUserSearch = null
|
||||
|
||||
const newUsers = users.filter(
|
||||
user =>
|
||||
user.screen_name.toLowerCase().startsWith(noPrefix) ||
|
||||
user.name.toLowerCase().startsWith(noPrefix)
|
||||
|
||||
/* taking only 20 results so that sorting is a bit cheaper, we display
|
||||
* only 5 anyway. could be inaccurate, but we ideally we should query
|
||||
* backend anyway
|
||||
*/
|
||||
).slice(0, 20).sort((a, b) => {
|
||||
let aScore = 0
|
||||
let bScore = 0
|
||||
|
||||
// Matches on screen name (i.e. user@instance) makes a priority
|
||||
aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
|
||||
bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
|
||||
|
||||
// Matches on name takes second priority
|
||||
aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
|
||||
bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
|
||||
|
||||
const diff = (bScore - aScore) * 10
|
||||
|
||||
// Then sort alphabetically
|
||||
const nameAlphabetically = a.name > b.name ? 1 : -1
|
||||
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
|
||||
|
||||
return diff + nameAlphabetically + screenNameAlphabetically
|
||||
/* eslint-disable camelcase */
|
||||
}).map(({ screen_name, name, profile_image_url_original }) => ({
|
||||
displayText: screen_name,
|
||||
detailText: name,
|
||||
imageUrl: profile_image_url_original,
|
||||
replacement: '@' + screen_name + ' '
|
||||
}))
|
||||
|
||||
// BE search users to get more comprehensive results
|
||||
if (data.updateUsersList) {
|
||||
debounceUserSearch(data, noPrefix)
|
||||
const userSearch = (query) => dispatch('searchUsers', { query })
|
||||
const debounceUserSearch = (query) => {
|
||||
cancelUserSearch && cancelUserSearch()
|
||||
return new Promise((resolve, reject) => {
|
||||
timeout = setTimeout(() => {
|
||||
userSearch(query).then(resolve).catch(reject)
|
||||
}, 300)
|
||||
cancelUserSearch = () => {
|
||||
clearTimeout(timeout)
|
||||
resolve([])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return async input => {
|
||||
const noPrefix = input.toLowerCase().substr(1)
|
||||
if (previousQuery === noPrefix) return suggestions
|
||||
|
||||
suggestions = []
|
||||
previousQuery = noPrefix
|
||||
// Fetch more and wait, don't fetch if there's the 2nd @ because
|
||||
// the backend user search can't deal with it.
|
||||
// Reference semantics make it so that we get the updated data after
|
||||
// the await.
|
||||
if (!noPrefix.includes('@')) {
|
||||
await debounceUserSearch(noPrefix)
|
||||
}
|
||||
|
||||
const newSuggestions = state.users.users.filter(
|
||||
user =>
|
||||
user.screen_name.toLowerCase().startsWith(noPrefix) ||
|
||||
user.name.toLowerCase().startsWith(noPrefix)
|
||||
).slice(0, 20).sort((a, b) => {
|
||||
let aScore = 0
|
||||
let bScore = 0
|
||||
|
||||
// Matches on screen name (i.e. user@instance) makes a priority
|
||||
aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
|
||||
bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
|
||||
|
||||
// Matches on name takes second priority
|
||||
aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
|
||||
bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
|
||||
|
||||
const diff = (bScore - aScore) * 10
|
||||
|
||||
// Then sort alphabetically
|
||||
const nameAlphabetically = a.name > b.name ? 1 : -1
|
||||
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
|
||||
|
||||
return diff + nameAlphabetically + screenNameAlphabetically
|
||||
/* eslint-disable camelcase */
|
||||
}).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
|
||||
displayText: screen_name_ui,
|
||||
detailText: name,
|
||||
imageUrl: profile_image_url_original,
|
||||
replacement: '@' + screen_name + ' '
|
||||
}))
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
suggestions = newSuggestions || []
|
||||
return suggestions
|
||||
}
|
||||
return newUsers
|
||||
/* eslint-enable camelcase */
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
:users="accountsForEmoji[reaction.name]"
|
||||
>
|
||||
<button
|
||||
class="emoji-reaction btn btn-default"
|
||||
class="emoji-reaction btn button-default"
|
||||
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
|
||||
@click="emojiOnClick(reaction.name, $event)"
|
||||
@mouseenter="fetchEmojiReactionsByIfMissing()"
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<div class="import-export-container">
|
||||
<slot name="before" />
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="exportData"
|
||||
>
|
||||
{{ exportLabel }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="importData"
|
||||
>
|
||||
{{ importLabel }}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
</div>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="process"
|
||||
>
|
||||
{{ exportButtonLabel }}
|
||||
|
||||
@@ -5,10 +5,12 @@ import {
|
||||
faBookmark,
|
||||
faEyeSlash,
|
||||
faThumbtack,
|
||||
faShareAlt
|
||||
faShareAlt,
|
||||
faExternalLinkAlt
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import {
|
||||
faBookmark as faBookmarkReg
|
||||
faBookmark as faBookmarkReg,
|
||||
faFlag
|
||||
} from '@fortawesome/free-regular-svg-icons'
|
||||
|
||||
library.add(
|
||||
@@ -17,7 +19,9 @@ library.add(
|
||||
faBookmarkReg,
|
||||
faEyeSlash,
|
||||
faThumbtack,
|
||||
faShareAlt
|
||||
faShareAlt,
|
||||
faExternalLinkAlt,
|
||||
faFlag
|
||||
)
|
||||
|
||||
const ExtraButtons = {
|
||||
@@ -64,6 +68,9 @@ const ExtraButtons = {
|
||||
this.$store.dispatch('unbookmark', { id: this.status.id })
|
||||
.then(() => this.$emit('onSuccess'))
|
||||
.catch(err => this.$emit('onError', err.error.error))
|
||||
},
|
||||
reportStatus () {
|
||||
this.$store.dispatch('openUserReportingModal', { userId: this.status.user.id, statusIds: [this.status.id] })
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<Popover
|
||||
class="ExtraButtons"
|
||||
trigger="click"
|
||||
placement="top"
|
||||
class="extra-button-popover"
|
||||
:offset="{ y: 5 }"
|
||||
:bound-to="{ x: 'container' }"
|
||||
remove-padding
|
||||
>
|
||||
<div
|
||||
slot="content"
|
||||
@@ -12,7 +14,7 @@
|
||||
<div class="dropdown-menu">
|
||||
<button
|
||||
v-if="canMute && !status.thread_muted"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="muteConversation"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -22,7 +24,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="canMute && status.thread_muted"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="unmuteConversation"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -32,7 +34,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="!status.pinned && canPin"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="pinStatus"
|
||||
@click="close"
|
||||
>
|
||||
@@ -43,7 +45,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="status.pinned && canPin"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="unpinStatus"
|
||||
@click="close"
|
||||
>
|
||||
@@ -54,7 +56,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="!status.bookmarked"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="bookmarkStatus"
|
||||
@click="close"
|
||||
>
|
||||
@@ -65,7 +67,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="status.bookmarked"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="unbookmarkStatus"
|
||||
@click="close"
|
||||
>
|
||||
@@ -76,7 +78,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="canDelete"
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="deleteStatus"
|
||||
@click="close"
|
||||
>
|
||||
@@ -86,7 +88,7 @@
|
||||
/><span>{{ $t("status.delete") }}</span>
|
||||
</button>
|
||||
<button
|
||||
class="dropdown-item dropdown-item-icon"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="copyLink"
|
||||
@click="close"
|
||||
>
|
||||
@@ -95,11 +97,36 @@
|
||||
icon="share-alt"
|
||||
/><span>{{ $t("status.copy_link") }}</span>
|
||||
</button>
|
||||
<a
|
||||
v-if="!status.is_local"
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
title="Source"
|
||||
:href="status.external_url"
|
||||
target="_blank"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
icon="external-link-alt"
|
||||
/><span>{{ $t("status.external_source") }}</span>
|
||||
</a>
|
||||
<button
|
||||
class="button-default dropdown-item dropdown-item-icon"
|
||||
@click.prevent="reportStatus"
|
||||
@click="close"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
:icon="['far', 'flag']"
|
||||
/><span>{{ $t("user_card.report") }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="trigger">
|
||||
<span
|
||||
slot="trigger"
|
||||
class="popover-trigger"
|
||||
>
|
||||
<FAIcon
|
||||
class="ExtraButtons fa-scale-110 fa-old-padding"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="ellipsis-h"
|
||||
/>
|
||||
</span>
|
||||
@@ -112,13 +139,20 @@
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.ExtraButtons {
|
||||
cursor: pointer;
|
||||
position: static;
|
||||
/* override of popover internal stuff */
|
||||
.popover-trigger-button {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
.extra-button-popover.open & {
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
.popover-trigger {
|
||||
position: static;
|
||||
padding: 10px;
|
||||
margin: -10px;
|
||||
|
||||
&:hover .svg-inline--fa {
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,11 +31,6 @@ const FavoriteButton = {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
classes () {
|
||||
return {
|
||||
'-favorited': this.status.favorited
|
||||
}
|
||||
},
|
||||
...mapGetters(['mergedConfig'])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
<template>
|
||||
<div v-if="loggedIn">
|
||||
<FAIcon
|
||||
:class="classes"
|
||||
class="FavoriteButton fa-scale-110 fa-old-padding -interactive"
|
||||
<div class="FavoriteButton">
|
||||
<button
|
||||
v-if="loggedIn"
|
||||
class="button-unstyled interactive"
|
||||
:class="status.favorited && '-favorited'"
|
||||
:title="$t('tool_tip.favorite')"
|
||||
:icon="[status.favorited ? 'fas' : 'far', 'star']"
|
||||
:spin="animated"
|
||||
@click.prevent="favorite()"
|
||||
/>
|
||||
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<FAIcon
|
||||
:class="classes"
|
||||
class="FavoriteButton fa-scale-110 fa-old-padding"
|
||||
:title="$t('tool_tip.favorite')"
|
||||
:icon="['far', 'star']"
|
||||
/>
|
||||
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
:icon="[status.favorited ? 'fas' : 'far', 'star']"
|
||||
:spin="animated"
|
||||
/>
|
||||
</button>
|
||||
<span v-else>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
:title="$t('tool_tip.favorite')"
|
||||
:icon="['far', 'star']"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
v-if="!mergedConfig.hidePostStats && status.fave_num > 0"
|
||||
class="action-counter"
|
||||
>
|
||||
{{ status.fave_num }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -27,19 +35,28 @@
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.FavoriteButton {
|
||||
&.-interactive {
|
||||
cursor: pointer;
|
||||
animation-duration: 0.6s;
|
||||
display: flex;
|
||||
|
||||
&:hover {
|
||||
> :first-child {
|
||||
padding: 10px;
|
||||
margin: -10px -8px -10px -10px;
|
||||
}
|
||||
|
||||
.action-counter {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.interactive {
|
||||
.svg-inline--fa {
|
||||
animation-duration: 0.6s;
|
||||
}
|
||||
|
||||
&:hover .svg-inline--fa,
|
||||
&.-favorited .svg-inline--fa {
|
||||
color: $fallback--cOrange;
|
||||
color: var(--cOrange, $fallback--cOrange);
|
||||
}
|
||||
}
|
||||
|
||||
&.-favorited {
|
||||
color: $fallback--cOrange;
|
||||
color: var(--cOrange, $fallback--cOrange);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
||||
|
||||
const FeaturesPanel = {
|
||||
computed: {
|
||||
chat: function () { return this.$store.state.instance.chatAvailable },
|
||||
@@ -6,7 +8,8 @@ const FeaturesPanel = {
|
||||
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
|
||||
mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable },
|
||||
minimalScopesMode: function () { return this.$store.state.instance.minimalScopesMode },
|
||||
textlimit: function () { return this.$store.state.instance.textlimit }
|
||||
textlimit: function () { return this.$store.state.instance.textlimit },
|
||||
uploadlimit: function () { return fileSizeFormatService.fileSizeFormat(this.$store.state.instance.uploadlimit) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
</li>
|
||||
<li>{{ $t('features_panel.scope_options') }}</li>
|
||||
<li>{{ $t('features_panel.text_limit') }} = {{ textlimit }}</li>
|
||||
<li>{{ $t('features_panel.upload_limit') }} = {{ uploadlimit.num }} {{ $t('upload.file_size_units.' + uploadlimit.unit) }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<button
|
||||
class="btn btn-default follow-button"
|
||||
class="btn button-default follow-button"
|
||||
:class="{ toggled: isPressed }"
|
||||
:disabled="inProgress"
|
||||
:title="title"
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
<basic-user-card :user="user">
|
||||
<div class="follow-request-card-content-container">
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="approveUser"
|
||||
>
|
||||
{{ $t('user_card.approve') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="denyUser"
|
||||
>
|
||||
{{ $t('user_card.deny') }}
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
<div class="notice-message">
|
||||
{{ $t(notice.messageKey, notice.messageArgs) }}
|
||||
</div>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="times"
|
||||
<button
|
||||
class="button-unstyled close-notice"
|
||||
@click="closeNotice(notice)"
|
||||
/>
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="times"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -54,7 +58,7 @@
|
||||
.global-error {
|
||||
background-color: var(--alertPopupError, $fallback--cRed);
|
||||
color: var(--alertPopupErrorText, $fallback--text);
|
||||
i {
|
||||
.svg-inline--fa {
|
||||
color: var(--alertPopupErrorText, $fallback--text);
|
||||
}
|
||||
}
|
||||
@@ -62,7 +66,7 @@
|
||||
.global-warning {
|
||||
background-color: var(--alertPopupWarning, $fallback--cOrange);
|
||||
color: var(--alertPopupWarningText, $fallback--text);
|
||||
i {
|
||||
.svg-inline--fa {
|
||||
color: var(--alertPopupWarningText, $fallback--text);
|
||||
}
|
||||
}
|
||||
@@ -70,9 +74,16 @@
|
||||
.global-info {
|
||||
background-color: var(--alertPopupNeutral, $fallback--fg);
|
||||
color: var(--alertPopupNeutralText, $fallback--text);
|
||||
i {
|
||||
.svg-inline--fa {
|
||||
color: var(--alertPopupNeutralText, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
.close-notice {
|
||||
padding-right: 0.2em;
|
||||
.svg-inline--fa:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -2,12 +2,10 @@ import Cropper from 'cropperjs'
|
||||
import 'cropperjs/dist/cropper.css'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faTimes,
|
||||
faCircleNotch
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faTimes,
|
||||
faCircleNotch
|
||||
)
|
||||
|
||||
@@ -53,8 +51,7 @@ const ImageCropper = {
|
||||
cropper: undefined,
|
||||
dataUrl: undefined,
|
||||
filename: undefined,
|
||||
submitting: false,
|
||||
submitError: null
|
||||
submitting: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -66,9 +63,6 @@ const ImageCropper = {
|
||||
},
|
||||
cancelText () {
|
||||
return this.cancelButtonLabel || this.$t('image_cropper.cancel')
|
||||
},
|
||||
submitErrorMsg () {
|
||||
return this.submitError && this.submitError instanceof Error ? this.submitError.toString() : this.submitError
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -82,12 +76,8 @@ const ImageCropper = {
|
||||
},
|
||||
submit (cropping = true) {
|
||||
this.submitting = true
|
||||
this.avatarUploadError = null
|
||||
this.submitHandler(cropping && this.cropper, this.file)
|
||||
.then(() => this.destroy())
|
||||
.catch((err) => {
|
||||
this.submitError = err
|
||||
})
|
||||
.finally(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
@@ -113,9 +103,6 @@ const ImageCropper = {
|
||||
reader.readAsDataURL(this.file)
|
||||
this.$emit('changed', this.file, reader)
|
||||
}
|
||||
},
|
||||
clearError () {
|
||||
this.submitError = null
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -11,21 +11,21 @@
|
||||
</div>
|
||||
<div class="image-cropper-buttons-wrapper">
|
||||
<button
|
||||
class="btn"
|
||||
class="button-default btn"
|
||||
type="button"
|
||||
:disabled="submitting"
|
||||
@click="submit()"
|
||||
v-text="saveText"
|
||||
/>
|
||||
<button
|
||||
class="btn"
|
||||
class="button-default btn"
|
||||
type="button"
|
||||
:disabled="submitting"
|
||||
@click="destroy"
|
||||
v-text="cancelText"
|
||||
/>
|
||||
<button
|
||||
class="btn"
|
||||
class="button-default btn"
|
||||
type="button"
|
||||
:disabled="submitting"
|
||||
@click="submit(false)"
|
||||
@@ -37,17 +37,6 @@
|
||||
icon="circle-notch"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="submitError"
|
||||
class="alert error"
|
||||
>
|
||||
{{ submitErrorMsg }}
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="times"
|
||||
@click="clearError"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
ref="input"
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
/>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="submit"
|
||||
>
|
||||
{{ submitButtonLabel }}
|
||||
|
||||
@@ -12,11 +12,11 @@
|
||||
v-model="language"
|
||||
>
|
||||
<option
|
||||
v-for="(langCode, i) in languageCodes"
|
||||
:key="langCode"
|
||||
:value="langCode"
|
||||
v-for="lang in languages"
|
||||
:key="lang.code"
|
||||
:value="lang.code"
|
||||
>
|
||||
{{ languageNames[i] }}
|
||||
{{ lang.name }}
|
||||
</option>
|
||||
</select>
|
||||
<FAIcon
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
<script>
|
||||
import languagesObject from '../../i18n/messages'
|
||||
import localeService from '../../services/locale/locale.service.js'
|
||||
import ISO6391 from 'iso-639-1'
|
||||
import _ from 'lodash'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
@@ -42,12 +43,8 @@ library.add(
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
languageCodes () {
|
||||
return languagesObject.languages
|
||||
},
|
||||
|
||||
languageNames () {
|
||||
return _.map(this.languageCodes, this.getLanguageName)
|
||||
languages () {
|
||||
return _.map(languagesObject.languages, (code) => ({ code: code, name: this.getLanguageName(code) })).sort((a, b) => a.name.localeCompare(b.name))
|
||||
},
|
||||
|
||||
language: {
|
||||
@@ -61,11 +58,13 @@ export default {
|
||||
methods: {
|
||||
getLanguageName (code) {
|
||||
const specialLanguageNames = {
|
||||
'ja': 'Japanese (日本語)',
|
||||
'ja_easy': 'Japanese (やさしいにほんご)',
|
||||
'zh': 'Chinese (简体中文)'
|
||||
'ja_easy': 'やさしいにほんご',
|
||||
'zh': '简体中文',
|
||||
'zh_Hant': '繁體中文'
|
||||
}
|
||||
return specialLanguageNames[code] || ISO6391.getName(code)
|
||||
const languageName = specialLanguageNames[code] || ISO6391.getNativeName(code)
|
||||
const browserLocale = localeService.internalToBrowserLocale(code)
|
||||
return languageName.charAt(0).toLocaleUpperCase(browserLocale) + languageName.slice(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
const LinkPreview = {
|
||||
name: 'LinkPreview',
|
||||
props: [
|
||||
@@ -15,11 +17,20 @@ const LinkPreview = {
|
||||
// Currently BE shoudn't give cards if tagged NSFW, this is a bit paranoid
|
||||
// as it makes sure to hide the image if somehow NSFW tagged preview can
|
||||
// exist.
|
||||
return this.card.image && !this.nsfw && this.size !== 'hide'
|
||||
return this.card.image && !this.censored && this.size !== 'hide'
|
||||
},
|
||||
censored () {
|
||||
return this.nsfw && this.hideNsfwConfig
|
||||
},
|
||||
useDescription () {
|
||||
return this.card.description && /\S/.test(this.card.description)
|
||||
}
|
||||
},
|
||||
hideNsfwConfig () {
|
||||
return this.mergedConfig.hideNsfw
|
||||
},
|
||||
...mapGetters([
|
||||
'mergedConfig'
|
||||
])
|
||||
},
|
||||
created () {
|
||||
if (this.useImage) {
|
||||
|
||||
@@ -9,12 +9,17 @@
|
||||
<div
|
||||
v-if="useImage && imageLoaded"
|
||||
class="card-image"
|
||||
:class="{ 'small-image': size === 'small' }"
|
||||
>
|
||||
<img :src="card.image">
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span class="card-host faint">{{ card.provider_name }}</span>
|
||||
<span class="card-host faint">
|
||||
<span
|
||||
v-if="censored"
|
||||
class="nsfw-alert alert warning"
|
||||
>{{ $t('status.nsfw') }}</span>
|
||||
{{ card.provider_name }}
|
||||
</span>
|
||||
<h4 class="card-title">{{ card.title }}</h4>
|
||||
<p
|
||||
v-if="useDescription"
|
||||
@@ -50,10 +55,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.small-image {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
max-height: 100%;
|
||||
margin: 0.5em;
|
||||
@@ -76,6 +77,10 @@
|
||||
max-height: calc(1.2em * 3 - 1px);
|
||||
}
|
||||
|
||||
.nsfw-alert {
|
||||
margin: 2em 0;
|
||||
}
|
||||
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
border-style: solid;
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<button
|
||||
:disabled="loggingIn"
|
||||
type="submit"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('login.login') }}
|
||||
</button>
|
||||
|
||||
@@ -73,11 +73,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes media-fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-image {
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
box-shadow: 0px 5px 15px 0 rgba(0, 0, 0, 0.5);
|
||||
image-orientation: from-image; // NOTE: only FF supports this
|
||||
animation: 0.1s cubic-bezier(0.7, 0, 1, 0.6) media-fadein;
|
||||
}
|
||||
|
||||
.modal-view-button-arrow {
|
||||
|
||||
@@ -1,33 +1,29 @@
|
||||
<template>
|
||||
<div
|
||||
<label
|
||||
class="media-upload"
|
||||
:class="{ disabled: disabled }"
|
||||
:title="$t('tool_tip.media_upload')"
|
||||
>
|
||||
<label
|
||||
class="label"
|
||||
:title="$t('tool_tip.media_upload')"
|
||||
<FAIcon
|
||||
v-if="uploading"
|
||||
class="progress-icon"
|
||||
icon="circle-notch"
|
||||
spin
|
||||
/>
|
||||
<FAIcon
|
||||
v-if="!uploading"
|
||||
class="new-icon"
|
||||
icon="upload"
|
||||
/>
|
||||
<input
|
||||
v-if="uploadReady"
|
||||
:disabled="disabled"
|
||||
type="file"
|
||||
style="position: fixed; top: -100em"
|
||||
multiple="true"
|
||||
@change="change"
|
||||
>
|
||||
<FAIcon
|
||||
v-if="uploading"
|
||||
class="progress-icon"
|
||||
icon="circle-notch"
|
||||
spin
|
||||
/>
|
||||
<FAIcon
|
||||
v-if="!uploading"
|
||||
class="new-icon"
|
||||
icon="upload"
|
||||
/>
|
||||
<input
|
||||
v-if="uploadReady"
|
||||
:disabled="disabled"
|
||||
type="file"
|
||||
style="position: fixed; top: -100em"
|
||||
multiple="true"
|
||||
@change="change"
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script src="./media_upload.js" ></script>
|
||||
@@ -36,12 +32,6 @@
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.media-upload {
|
||||
.label {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.new-icon {
|
||||
cursor: pointer;
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,23 +23,25 @@
|
||||
<div class="form-group">
|
||||
<div class="login-bottom">
|
||||
<div>
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link"
|
||||
type="button"
|
||||
@click.prevent="requireTOTP"
|
||||
>
|
||||
{{ $t('login.enter_two_factor_code') }}
|
||||
</a>
|
||||
</button>
|
||||
<br>
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link"
|
||||
type="button"
|
||||
@click.prevent="abortMFA"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('general.verify') }}
|
||||
</button>
|
||||
|
||||
@@ -25,23 +25,25 @@
|
||||
<div class="form-group">
|
||||
<div class="login-bottom">
|
||||
<div>
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link"
|
||||
type="button"
|
||||
@click.prevent="requireRecovery"
|
||||
>
|
||||
{{ $t('login.enter_recovery_code') }}
|
||||
</a>
|
||||
</button>
|
||||
<br>
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link"
|
||||
type="button"
|
||||
@click.prevent="abortMFA"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('general.verify') }}
|
||||
</button>
|
||||
|
||||
@@ -9,9 +9,8 @@
|
||||
@click="scrollToTop()"
|
||||
>
|
||||
<div class="item">
|
||||
<a
|
||||
href="#"
|
||||
class="mobile-nav-button"
|
||||
<button
|
||||
class="button-unstyled mobile-nav-button"
|
||||
@click.stop.prevent="toggleMobileSidebar()"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -22,7 +21,7 @@
|
||||
v-if="unreadChatCount"
|
||||
class="alert-dot"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
<router-link
|
||||
v-if="!hideSitename"
|
||||
class="site-name"
|
||||
@@ -33,10 +32,9 @@
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="item right">
|
||||
<a
|
||||
<button
|
||||
v-if="currentUser"
|
||||
class="mobile-nav-button"
|
||||
href="#"
|
||||
class="button-unstyled mobile-nav-button"
|
||||
@click.stop.prevent="openMobileNotifications()"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -47,7 +45,7 @@
|
||||
v-if="unseenNotificationsCount"
|
||||
class="alert-dot"
|
||||
/>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</nav>
|
||||
<div
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div v-if="isLoggedIn">
|
||||
<button
|
||||
class="new-status-button"
|
||||
class="button-default new-status-button"
|
||||
:class="{ 'hidden': isHidden }"
|
||||
@click="openPostForm"
|
||||
>
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
<div class="dropdown-menu">
|
||||
<span v-if="user.is_local">
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleRight("admin")"
|
||||
>
|
||||
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
|
||||
</button>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleRight("moderator")"
|
||||
>
|
||||
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
|
||||
@@ -29,13 +29,13 @@
|
||||
/>
|
||||
</span>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleActivationStatus()"
|
||||
>
|
||||
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
|
||||
</button>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="deleteUserDialog(true)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.delete_account') }}
|
||||
@@ -47,7 +47,7 @@
|
||||
/>
|
||||
<span v-if="hasTagPolicy">
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.FORCE_NSFW)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.force_nsfw') }}
|
||||
@@ -57,7 +57,7 @@
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.STRIP_MEDIA)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.strip_media') }}
|
||||
@@ -67,7 +67,7 @@
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.FORCE_UNLISTED)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.force_unlisted') }}
|
||||
@@ -77,7 +77,7 @@
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.SANDBOX)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.sandbox') }}
|
||||
@@ -88,7 +88,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="user.is_local"
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
|
||||
@@ -99,7 +99,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="user.is_local"
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.disable_any_subscription') }}
|
||||
@@ -110,7 +110,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-if="user.is_local"
|
||||
class="dropdown-item"
|
||||
class="button-default dropdown-item"
|
||||
@click="toggleTag(tags.QUARANTINE)"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.quarantine') }}
|
||||
@@ -124,7 +124,7 @@
|
||||
</div>
|
||||
<button
|
||||
slot="trigger"
|
||||
class="btn btn-default btn-block"
|
||||
class="btn button-default btn-block"
|
||||
:class="{ toggled }"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.moderation') }}
|
||||
@@ -141,13 +141,13 @@
|
||||
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
|
||||
<template slot="footer">
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="deleteUserDialog(false)"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default danger"
|
||||
class="btn button-default danger"
|
||||
@click="deleteUser()"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.delete_user') }}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="mute-card-content-container">
|
||||
<button
|
||||
v-if="muted"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="progress"
|
||||
@click="unmuteUser"
|
||||
>
|
||||
@@ -16,7 +16,7 @@
|
||||
</button>
|
||||
<button
|
||||
v-else
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="progress"
|
||||
@click="muteUser"
|
||||
>
|
||||
|
||||
@@ -11,17 +11,18 @@
|
||||
>
|
||||
<small>
|
||||
<router-link :to="userProfileLink">
|
||||
{{ notification.from_profile.screen_name }}
|
||||
{{ notification.from_profile.screen_name_ui }}
|
||||
</router-link>
|
||||
</small>
|
||||
<a
|
||||
href="#"
|
||||
class="unmute"
|
||||
<button
|
||||
class="button-unstyled unmute"
|
||||
@click.prevent="toggleMute"
|
||||
><FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="eye-slash"
|
||||
/></a>
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="eye-slash"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
@@ -53,14 +54,14 @@
|
||||
<bdi
|
||||
v-if="!!notification.from_profile.name_html"
|
||||
class="username"
|
||||
:title="'@'+notification.from_profile.screen_name"
|
||||
:title="'@'+notification.from_profile.screen_name_ui"
|
||||
v-html="notification.from_profile.name_html"
|
||||
/>
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
<span
|
||||
v-else
|
||||
class="username"
|
||||
:title="'@'+notification.from_profile.screen_name"
|
||||
:title="'@'+notification.from_profile.screen_name_ui"
|
||||
>{{ notification.from_profile.name }}</span>
|
||||
<span v-if="notification.type === 'like'">
|
||||
<FAIcon
|
||||
@@ -132,14 +133,16 @@
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<a
|
||||
<button
|
||||
v-if="needMute"
|
||||
href="#"
|
||||
class="button-unstyled"
|
||||
@click.prevent="toggleMute"
|
||||
><FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="eye-slash"
|
||||
/></a>
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="eye-slash"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
<div
|
||||
v-if="notification.type === 'follow' || notification.type === 'follow_request'"
|
||||
@@ -149,7 +152,7 @@
|
||||
:to="userProfileLink"
|
||||
class="follow-name"
|
||||
>
|
||||
@{{ notification.from_profile.screen_name }}
|
||||
@{{ notification.from_profile.screen_name_ui }}
|
||||
</router-link>
|
||||
<div
|
||||
v-if="notification.type === 'follow_request'"
|
||||
@@ -174,7 +177,7 @@
|
||||
class="move-text"
|
||||
>
|
||||
<router-link :to="targetUserProfileLink">
|
||||
@{{ notification.target.screen_name }}
|
||||
@{{ notification.target.screen_name_ui }}
|
||||
</router-link>
|
||||
</div>
|
||||
<template v-else>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
filteredNotificationsFromStore,
|
||||
unseenNotificationsFromStore
|
||||
} from '../../services/notification_utils/notification_utils.js'
|
||||
import FaviconService from '../../services/favicon_service/favicon_service.js'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
@@ -75,8 +76,10 @@ const Notifications = {
|
||||
watch: {
|
||||
unseenCountTitle (count) {
|
||||
if (count > 0) {
|
||||
FaviconService.drawFaviconBadge()
|
||||
this.$store.dispatch('setPageTitle', `(${count})`)
|
||||
} else {
|
||||
FaviconService.clearFaviconBadge()
|
||||
this.$store.dispatch('setPageTitle', '')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,9 @@
|
||||
class="badge badge-notification unseen-count"
|
||||
>{{ unseenCount }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-if="error"
|
||||
class="loadmore-error alert error"
|
||||
@click.prevent
|
||||
>
|
||||
{{ $t('timeline.error_fetching') }}
|
||||
</div>
|
||||
<button
|
||||
v-if="unseenCount"
|
||||
class="read-button"
|
||||
class="button-default read-button"
|
||||
@click.prevent="markAsSeen"
|
||||
>
|
||||
{{ $t('notifications.read') }}
|
||||
@@ -48,15 +41,15 @@
|
||||
>
|
||||
{{ $t('notifications.no_more_notifications') }}
|
||||
</div>
|
||||
<a
|
||||
<button
|
||||
v-else-if="!loading"
|
||||
href="#"
|
||||
class="button-unstyled -link -fullwidth"
|
||||
@click.prevent="fetchOlderNotifications()"
|
||||
>
|
||||
<div class="new-status-notification text-center panel-footer">
|
||||
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
|
||||
</div>
|
||||
</a>
|
||||
</button>
|
||||
<div
|
||||
v-else
|
||||
class="new-status-notification text-center panel-footer"
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<button
|
||||
:disabled="isPending"
|
||||
type="submit"
|
||||
class="btn btn-default btn-block"
|
||||
class="btn button-default btn-block"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
</button>
|
||||
|
||||
@@ -42,14 +42,15 @@
|
||||
:value="index"
|
||||
>
|
||||
<label class="option-vote">
|
||||
<div>{{ option.title }}</div>
|
||||
<!-- eslint-disable-next-line vue/no-v-html -->
|
||||
<div v-html="option.title_html" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer faint">
|
||||
<button
|
||||
v-if="!showResults"
|
||||
class="btn btn-default poll-vote-button"
|
||||
class="btn button-default poll-vote-button"
|
||||
type="button"
|
||||
:disabled="isDisabled"
|
||||
@click="vote"
|
||||
@@ -57,7 +58,12 @@
|
||||
{{ $t('polls.vote') }}
|
||||
</button>
|
||||
<div class="total">
|
||||
{{ totalVotesCount }} {{ $t("polls.votes") }} ·
|
||||
<template v-if="typeof poll.voters_count === 'number'">
|
||||
{{ $tc("polls.people_voted_count", poll.voters_count, { count: poll.voters_count }) }} ·
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ $tc("polls.votes_count", poll.votes_count, { count: poll.votes_count }) }} ·
|
||||
</template>
|
||||
</div>
|
||||
<i18n :path="expired ? 'polls.expired' : 'polls.expires_in'">
|
||||
<Timeago
|
||||
|
||||
@@ -21,20 +21,17 @@
|
||||
@keydown.enter.stop.prevent="nextOption(index)"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
<button
|
||||
v-if="options.length > 2"
|
||||
class="icon-container"
|
||||
class="delete-option button-unstyled -hover-highlight"
|
||||
@click="deleteOption(index)"
|
||||
>
|
||||
<FAIcon
|
||||
icon="times"
|
||||
class="delete"
|
||||
@click="deleteOption(index)"
|
||||
/>
|
||||
</div>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
</div>
|
||||
<a
|
||||
<button
|
||||
v-if="options.length < maxOptions"
|
||||
class="add-option faint"
|
||||
class="add-option faint button-unstyled -hover-highlight"
|
||||
@click="addOption"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -43,7 +40,7 @@
|
||||
/>
|
||||
|
||||
{{ $t("polls.add_option") }}
|
||||
</a>
|
||||
</button>
|
||||
<div class="poll-type-expiry">
|
||||
<div
|
||||
class="poll-type"
|
||||
@@ -116,7 +113,6 @@
|
||||
align-self: flex-start;
|
||||
padding-top: 0.25em;
|
||||
padding-left: 0.1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.poll-option {
|
||||
@@ -135,19 +131,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
.delete-option {
|
||||
// Hack: Move the icon over the input box
|
||||
width: 1.5em;
|
||||
margin-left: -1.5em;
|
||||
z-index: 1;
|
||||
|
||||
.delete {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.poll-type-expiry {
|
||||
@@ -163,6 +151,7 @@
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
background-color: transparent;
|
||||
padding-right: 0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ const Popover = {
|
||||
// Replaces the classes you may want for the popover container.
|
||||
// Use 'popover-default' in addition to get the default popover
|
||||
// styles with your custom class.
|
||||
popoverClass: String
|
||||
popoverClass: String,
|
||||
// If true, subtract padding when calculating position for the popover,
|
||||
// use it when popover offset looks to be different on top vs bottom.
|
||||
removePadding: Boolean
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -96,9 +99,15 @@ const Popover = {
|
||||
if (origin.y + content.offsetHeight > yBounds.max) usingTop = true
|
||||
if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
|
||||
|
||||
let vPadding = 0
|
||||
if (this.removePadding && usingTop) {
|
||||
const anchorStyle = getComputedStyle(anchorEl)
|
||||
vPadding = parseFloat(anchorStyle.paddingTop) + parseFloat(anchorStyle.paddingBottom)
|
||||
}
|
||||
|
||||
const yOffset = (this.offset && this.offset.y) || 0
|
||||
const translateY = usingTop
|
||||
? -anchorEl.offsetHeight - yOffset - content.offsetHeight
|
||||
? -anchorEl.offsetHeight + vPadding - yOffset - content.offsetHeight
|
||||
: yOffset
|
||||
|
||||
const xOffset = (this.offset && this.offset.x) || 0
|
||||
@@ -112,9 +121,12 @@ const Popover = {
|
||||
}
|
||||
},
|
||||
showPopover () {
|
||||
if (this.hidden) this.$emit('show')
|
||||
const wasHidden = this.hidden
|
||||
this.hidden = false
|
||||
this.$nextTick(this.updateStyles)
|
||||
this.$nextTick(() => {
|
||||
if (wasHidden) this.$emit('show')
|
||||
this.updateStyles()
|
||||
})
|
||||
},
|
||||
hidePopover () {
|
||||
if (!this.hidden) this.$emit('close')
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
@mouseenter="onMouseenter"
|
||||
@mouseleave="onMouseleave"
|
||||
>
|
||||
<div
|
||||
<button
|
||||
ref="trigger"
|
||||
class="button-unstyled -fullwidth popover-trigger-button"
|
||||
type="button"
|
||||
@click="onClick"
|
||||
>
|
||||
<slot name="trigger" />
|
||||
</div>
|
||||
</button>
|
||||
<div
|
||||
v-if="!hidden"
|
||||
ref="content"
|
||||
@@ -30,6 +32,10 @@
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.popover-trigger-button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.popover {
|
||||
z-index: 8;
|
||||
position: absolute;
|
||||
@@ -90,6 +96,7 @@
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
--btnText: var(--popoverText, $fallback--text);
|
||||
|
||||
|
||||
@@ -159,8 +159,7 @@ const PostStatusForm = {
|
||||
...this.$store.state.instance.emoji,
|
||||
...this.$store.state.instance.customEmoji
|
||||
],
|
||||
users: this.$store.state.users.users,
|
||||
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
|
||||
store: this.$store
|
||||
})
|
||||
},
|
||||
emojiSuggestor () {
|
||||
@@ -531,7 +530,7 @@ const PostStatusForm = {
|
||||
!(isFormBiggerThanScroller &&
|
||||
this.$refs.textarea.selectionStart !== this.$refs.textarea.value.length)
|
||||
const totalDelta = shouldScrollToBottom ? bottomChangeDelta : 0
|
||||
const targetScroll = currentScroll + totalDelta
|
||||
const targetScroll = Math.round(currentScroll + totalDelta)
|
||||
|
||||
if (scrollerRef === window) {
|
||||
scrollerRef.scroll(0, targetScroll)
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
tag="p"
|
||||
class="visibility-notice"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link"
|
||||
@click="openProfileTab"
|
||||
>
|
||||
{{ $t('post_status.account_not_locked_warning_link') }}
|
||||
</a>
|
||||
</button>
|
||||
</i18n>
|
||||
<p
|
||||
v-if="!hideScopeNotice && newStatus.visibility === 'public'"
|
||||
@@ -243,38 +243,34 @@
|
||||
@upload-failed="uploadFailed"
|
||||
@all-uploaded="finishedUploadingFiles"
|
||||
/>
|
||||
<div
|
||||
class="emoji-icon"
|
||||
<button
|
||||
class="emoji-icon button-unstyled"
|
||||
:title="$t('emoji.add_emoji')"
|
||||
@click="showEmojiPicker"
|
||||
>
|
||||
<div
|
||||
:title="$t('emoji.add_emoji')"
|
||||
class="btn btn-default"
|
||||
@click="showEmojiPicker"
|
||||
>
|
||||
<FAIcon icon="smile-beam" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
<FAIcon icon="smile-beam" />
|
||||
</button>
|
||||
<button
|
||||
v-if="pollsAvailable"
|
||||
class="poll-icon"
|
||||
class="poll-icon button-unstyled"
|
||||
:class="{ selected: pollFormVisible }"
|
||||
:title="$t('polls.add_poll')"
|
||||
@click="togglePollForm"
|
||||
>
|
||||
<FAIcon icon="poll-h" />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
v-if="posting"
|
||||
disabled
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('post_status.posting') }}
|
||||
</button>
|
||||
<button
|
||||
v-else-if="isOverLengthLimit"
|
||||
disabled
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
</button>
|
||||
@@ -282,7 +278,7 @@
|
||||
<button
|
||||
v-else
|
||||
:disabled="uploadingFiles || disableSubmit"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@touchstart.stop.prevent="postStatus($event, newStatus)"
|
||||
@click.stop.prevent="postStatus($event, newStatus)"
|
||||
>
|
||||
@@ -306,11 +302,12 @@
|
||||
:key="file.url"
|
||||
class="media-upload-wrapper"
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="times"
|
||||
<button
|
||||
class="button-unstyled hider"
|
||||
@click="removeMediaFile(file)"
|
||||
/>
|
||||
>
|
||||
<FAIcon icon="times" />
|
||||
</button>
|
||||
<attachment
|
||||
:attachment="file"
|
||||
:set-media="() => $store.dispatch('setMedia', newStatus.files)"
|
||||
@@ -520,26 +517,11 @@
|
||||
}
|
||||
|
||||
.attachments .media-upload-wrapper {
|
||||
padding: 0 0.5em;
|
||||
position: relative;
|
||||
|
||||
.attachment {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.fa-scale-110 fa-old-padding {
|
||||
position: absolute;
|
||||
margin: 10px;
|
||||
margin: .75em;
|
||||
padding: .5em;
|
||||
background: rgba(230,230,230,0.6);
|
||||
z-index: 2;
|
||||
color: black;
|
||||
border-radius: $fallback--attachmentRadius;
|
||||
border-radius: var(--attachmentRadius, $fallback--attachmentRadius);
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,31 @@ const ReactButton = {
|
||||
this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
|
||||
}
|
||||
close()
|
||||
},
|
||||
focusInput () {
|
||||
this.$nextTick(() => {
|
||||
const input = this.$el.querySelector('input')
|
||||
if (input) input.focus()
|
||||
})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
commonEmojis () {
|
||||
return ['👍', '😠', '👀', '😂', '🔥']
|
||||
return [
|
||||
{ displayText: 'thumbsup', replacement: '👍' },
|
||||
{ displayText: 'angry', replacement: '😠' },
|
||||
{ displayText: 'eyes', replacement: '👀' },
|
||||
{ displayText: 'joy', replacement: '😂' },
|
||||
{ displayText: 'fire', replacement: '🔥' }
|
||||
]
|
||||
},
|
||||
emojis () {
|
||||
if (this.filterWord !== '') {
|
||||
const filterWordLowercase = this.filterWord.toLowerCase()
|
||||
let orderedEmojiList = []
|
||||
for (const emoji of this.$store.state.instance.emoji) {
|
||||
if (emoji.replacement === this.filterWord) return [emoji]
|
||||
|
||||
const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase)
|
||||
if (indexOfFilterWord > -1) {
|
||||
if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) {
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<template>
|
||||
<Popover
|
||||
trigger="click"
|
||||
class="ReactButton"
|
||||
placement="top"
|
||||
:offset="{ y: 5 }"
|
||||
class="react-button-popover"
|
||||
:bound-to="{ x: 'container' }"
|
||||
remove-padding
|
||||
@show="focusInput"
|
||||
>
|
||||
<div
|
||||
slot="content"
|
||||
@@ -19,17 +22,19 @@
|
||||
<div class="reaction-picker">
|
||||
<span
|
||||
v-for="emoji in commonEmojis"
|
||||
:key="emoji"
|
||||
:key="emoji.replacement"
|
||||
class="emoji-button"
|
||||
@click="addReaction($event, emoji, close)"
|
||||
:title="emoji.displayText"
|
||||
@click="addReaction($event, emoji.replacement, close)"
|
||||
>
|
||||
{{ emoji }}
|
||||
{{ emoji.replacement }}
|
||||
</span>
|
||||
<div class="reaction-picker-divider" />
|
||||
<span
|
||||
v-for="(emoji, key) in emojis"
|
||||
:key="key"
|
||||
class="emoji-button"
|
||||
:title="emoji.displayText"
|
||||
@click="addReaction($event, emoji.replacement, close)"
|
||||
>
|
||||
{{ emoji.replacement }}
|
||||
@@ -37,12 +42,16 @@
|
||||
<div class="reaction-bottom-fader" />
|
||||
</div>
|
||||
</div>
|
||||
<FAIcon
|
||||
<span
|
||||
slot="trigger"
|
||||
class="fa-scale-110 fa-old-padding add-reaction-button"
|
||||
:icon="['far', 'smile-beam']"
|
||||
class="popover-trigger"
|
||||
:title="$t('tool_tip.add_reaction')"
|
||||
/>
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
:icon="['far', 'smile-beam']"
|
||||
/>
|
||||
</span>
|
||||
</Popover>
|
||||
</template>
|
||||
|
||||
@@ -51,62 +60,72 @@
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.reaction-picker-filter {
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
input {
|
||||
flex: 1;
|
||||
.ReactButton {
|
||||
.reaction-picker-filter {
|
||||
padding: 0.5em;
|
||||
display: flex;
|
||||
|
||||
input {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reaction-picker-divider {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
margin: 0.5em;
|
||||
background-color: var(--border, $fallback--border);
|
||||
}
|
||||
.reaction-picker-divider {
|
||||
height: 1px;
|
||||
width: 100%;
|
||||
margin: 0.5em;
|
||||
background-color: var(--border, $fallback--border);
|
||||
}
|
||||
|
||||
.reaction-picker {
|
||||
width: 10em;
|
||||
height: 9em;
|
||||
font-size: 1.5em;
|
||||
overflow-y: scroll;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
align-content: flex-start;
|
||||
user-select: none;
|
||||
.reaction-picker {
|
||||
width: 10em;
|
||||
height: 9em;
|
||||
font-size: 1.5em;
|
||||
overflow-y: scroll;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
align-content: flex-start;
|
||||
user-select: none;
|
||||
|
||||
mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
|
||||
linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
|
||||
linear-gradient(to top, white, white);
|
||||
transition: mask-size 150ms;
|
||||
mask-size: 100% 20px, 100% 20px, auto;
|
||||
// Autoprefixed seem to ignore this one, and also syntax is different
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
|
||||
linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
|
||||
linear-gradient(to top, white, white);
|
||||
transition: mask-size 150ms;
|
||||
mask-size: 100% 20px, 100% 20px, auto;
|
||||
|
||||
.emoji-button {
|
||||
cursor: pointer;
|
||||
/* Autoprefixed seem to ignore this one, and also syntax is different */
|
||||
-webkit-mask-composite: xor;
|
||||
mask-composite: exclude;
|
||||
|
||||
flex-basis: 20%;
|
||||
line-height: 1.5em;
|
||||
align-content: center;
|
||||
.emoji-button {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.25);
|
||||
flex-basis: 20%;
|
||||
line-height: 1.5em;
|
||||
align-content: center;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* override of popover internal stuff */
|
||||
.popover-trigger-button {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.popover-trigger {
|
||||
padding: 10px;
|
||||
margin: -10px;
|
||||
|
||||
&:hover .svg-inline--fa {
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add-reaction-button {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -10,7 +10,8 @@ const registration = {
|
||||
fullname: '',
|
||||
username: '',
|
||||
password: '',
|
||||
confirm: ''
|
||||
confirm: '',
|
||||
reason: ''
|
||||
},
|
||||
captcha: {}
|
||||
}),
|
||||
@@ -24,7 +25,8 @@ const registration = {
|
||||
confirm: {
|
||||
required,
|
||||
sameAsPassword: sameAs('password')
|
||||
}
|
||||
},
|
||||
reason: { required: requiredIf(() => this.accountApprovalRequired) }
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -38,7 +40,10 @@ const registration = {
|
||||
computed: {
|
||||
token () { return this.$route.params.token },
|
||||
bioPlaceholder () {
|
||||
return this.$t('registration.bio_placeholder').replace(/\s*\n\s*/g, ' \n')
|
||||
return this.replaceNewlines(this.$t('registration.bio_placeholder'))
|
||||
},
|
||||
reasonPlaceholder () {
|
||||
return this.replaceNewlines(this.$t('registration.reason_placeholder'))
|
||||
},
|
||||
...mapState({
|
||||
registrationOpen: (state) => state.instance.registrationOpen,
|
||||
@@ -46,7 +51,8 @@ const registration = {
|
||||
isPending: (state) => state.users.signUpPending,
|
||||
serverValidationErrors: (state) => state.users.signUpErrors,
|
||||
termsOfService: (state) => state.instance.tos,
|
||||
accountActivationRequired: (state) => state.instance.accountActivationRequired
|
||||
accountActivationRequired: (state) => state.instance.accountActivationRequired,
|
||||
accountApprovalRequired: (state) => state.instance.accountApprovalRequired
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
@@ -73,6 +79,9 @@ const registration = {
|
||||
},
|
||||
setCaptcha () {
|
||||
this.getCaptcha().then(cpt => { this.captcha = cpt })
|
||||
},
|
||||
replaceNewlines (str) {
|
||||
return str.replace(/\s*\n\s*/g, ' \n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,6 +162,23 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="accountApprovalRequired"
|
||||
class="form-group"
|
||||
>
|
||||
<label
|
||||
class="form--label"
|
||||
for="reason"
|
||||
>{{ $t('registration.reason') }}</label>
|
||||
<textarea
|
||||
id="reason"
|
||||
v-model="user.reason"
|
||||
:disabled="isPending"
|
||||
class="form-control"
|
||||
:placeholder="reasonPlaceholder"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="captcha.type != 'none'"
|
||||
id="captcha-group"
|
||||
@@ -211,7 +228,7 @@
|
||||
<button
|
||||
:disabled="isPending"
|
||||
type="submit"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
</button>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
>
|
||||
<button
|
||||
click="submit"
|
||||
class="remote-button"
|
||||
class="button-default remote-button"
|
||||
>
|
||||
{{ $t('user_card.remote_follow') }}
|
||||
</button>
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
<template>
|
||||
<div>
|
||||
<FAIcon
|
||||
<div class="ReplyButton">
|
||||
<button
|
||||
v-if="loggedIn"
|
||||
class="ReplyButton fa-scale-110 fa-old-padding -interactive"
|
||||
icon="reply"
|
||||
:title="$t('tool_tip.reply')"
|
||||
class="button-unstyled interactive"
|
||||
:class="{'-active': replying}"
|
||||
@click.prevent="$emit('toggle')"
|
||||
/>
|
||||
<FAIcon
|
||||
v-else
|
||||
icon="reply"
|
||||
class="ReplyButton fa-scale-110 fa-old-padding"
|
||||
:title="$t('tool_tip.reply')"
|
||||
/>
|
||||
<span v-if="status.replies_count > 0">
|
||||
@click.prevent="$emit('toggle')"
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="reply"
|
||||
/>
|
||||
</button>
|
||||
<span v-else>
|
||||
<FAIcon
|
||||
icon="reply"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
:title="$t('tool_tip.reply')"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
v-if="status.replies_count > 0"
|
||||
class="action-counter"
|
||||
>
|
||||
{{ status.replies_count }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -26,14 +34,25 @@
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.ReplyButton {
|
||||
&.-interactive {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
&:hover,
|
||||
&.-active {
|
||||
> :first-child {
|
||||
padding: 10px;
|
||||
margin: -10px -8px -10px -10px;
|
||||
}
|
||||
|
||||
.action-counter {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.interactive {
|
||||
&:hover .svg-inline--fa,
|
||||
&.-active .svg-inline--fa {
|
||||
color: $fallback--cBlue;
|
||||
color: var(--cBlue, $fallback--cBlue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -24,11 +24,6 @@ const RetweetButton = {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
classes () {
|
||||
return {
|
||||
'-repeated': this.status.repeated
|
||||
}
|
||||
},
|
||||
mergedConfig () {
|
||||
return this.$store.getters.mergedConfig
|
||||
}
|
||||
|
||||
@@ -1,33 +1,38 @@
|
||||
<template>
|
||||
<div v-if="loggedIn">
|
||||
<template v-if="visibility !== 'private' && visibility !== 'direct'">
|
||||
<div class="RetweetButton">
|
||||
<button
|
||||
v-if="visibility !== 'private' && visibility !== 'direct' && loggedIn"
|
||||
class="button-unstyled interactive"
|
||||
:class="status.repeated && '-repeated'"
|
||||
:title="$t('tool_tip.repeat')"
|
||||
@click.prevent="retweet()"
|
||||
>
|
||||
<FAIcon
|
||||
:class="classes"
|
||||
class="RetweetButton fa-scale-110 fa-old-padding -interactive"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="retweet"
|
||||
:spin="animated"
|
||||
:title="$t('tool_tip.repeat')"
|
||||
@click.prevent="retweet()"
|
||||
/>
|
||||
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
|
||||
</template>
|
||||
<template v-else>
|
||||
</button>
|
||||
<span v-else-if="loggedIn">
|
||||
<FAIcon
|
||||
:class="classes"
|
||||
class="RetweetButton fa-scale-110 fa-old-padding"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="lock"
|
||||
:title="$t('timeline.no_retweet_hint')"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<div v-else-if="!loggedIn">
|
||||
<FAIcon
|
||||
:class="classes"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="retweet"
|
||||
:title="$t('tool_tip.repeat')"
|
||||
/>
|
||||
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
|
||||
</span>
|
||||
<span v-else>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="retweet"
|
||||
:title="$t('tool_tip.repeat')"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
|
||||
class="no-event"
|
||||
>
|
||||
{{ status.repeat_num }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -37,19 +42,28 @@
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.RetweetButton {
|
||||
&.-interactive {
|
||||
cursor: pointer;
|
||||
animation-duration: 0.6s;
|
||||
display: flex;
|
||||
|
||||
&:hover {
|
||||
> :first-child {
|
||||
padding: 10px;
|
||||
margin: -10px -8px -10px -10px;
|
||||
}
|
||||
|
||||
.action-counter {
|
||||
pointer-events: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.interactive {
|
||||
.svg-inline--fa {
|
||||
animation-duration: 0.6s;
|
||||
}
|
||||
|
||||
&:hover .svg-inline--fa,
|
||||
&.-repeated .svg-inline--fa {
|
||||
color: $fallback--cGreen;
|
||||
color: var(--cGreen, $fallback--cGreen);
|
||||
}
|
||||
}
|
||||
|
||||
&.-repeated {
|
||||
color: $fallback--cGreen;
|
||||
color: var(--cGreen, $fallback--cGreen);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -3,54 +3,58 @@
|
||||
v-if="!showNothing"
|
||||
class="ScopeSelector"
|
||||
>
|
||||
<span
|
||||
<button
|
||||
v-if="showDirect"
|
||||
class="scope"
|
||||
class="button-unstyled scope"
|
||||
:class="css.direct"
|
||||
:title="$t('post_status.scope.direct')"
|
||||
type="button"
|
||||
@click="changeVis('direct')"
|
||||
>
|
||||
<FAIcon
|
||||
icon="envelope"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
</button>
|
||||
<button
|
||||
v-if="showPrivate"
|
||||
class="scope"
|
||||
class="button-unstyled scope"
|
||||
:class="css.private"
|
||||
:title="$t('post_status.scope.private')"
|
||||
type="button"
|
||||
@click="changeVis('private')"
|
||||
>
|
||||
<FAIcon
|
||||
icon="lock"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
</button>
|
||||
<button
|
||||
v-if="showUnlisted"
|
||||
class="scope"
|
||||
class="button-unstyled scope"
|
||||
:class="css.unlisted"
|
||||
:title="$t('post_status.scope.unlisted')"
|
||||
type="button"
|
||||
@click="changeVis('unlisted')"
|
||||
>
|
||||
<FAIcon
|
||||
icon="lock-open"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
</button>
|
||||
<button
|
||||
v-if="showPublic"
|
||||
class="scope"
|
||||
class="button-unstyled scope"
|
||||
:class="css.public"
|
||||
:title="$t('post_status.scope.public')"
|
||||
type="button"
|
||||
@click="changeVis('public')"
|
||||
>
|
||||
<FAIcon
|
||||
icon="globe"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
@keyup.enter="newQuery(searchTerm)"
|
||||
>
|
||||
<button
|
||||
class="btn search-button"
|
||||
class="btn button-default search-button"
|
||||
type="submit"
|
||||
@click="newQuery(searchTerm)"
|
||||
>
|
||||
<FAIcon icon="search" />
|
||||
|
||||
@@ -3,17 +3,19 @@
|
||||
class="SearchBar"
|
||||
:class="{ '-expanded': !hidden }"
|
||||
>
|
||||
<a
|
||||
<button
|
||||
v-if="hidden"
|
||||
href="#"
|
||||
class="nav-icon"
|
||||
class="button-unstyled nav-icon"
|
||||
:title="$t('nav.search')"
|
||||
><FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="search"
|
||||
type="button"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
/></a>
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="search"
|
||||
/>
|
||||
</button>
|
||||
<template v-else>
|
||||
<input
|
||||
id="search-bar-input"
|
||||
@@ -25,7 +27,8 @@
|
||||
@keyup.enter="find(searchTerm)"
|
||||
>
|
||||
<button
|
||||
class="btn search-button"
|
||||
class="button-default search-button"
|
||||
type="submit"
|
||||
@click="find(searchTerm)"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -33,14 +36,17 @@
|
||||
icon="search"
|
||||
/>
|
||||
</button>
|
||||
<span>
|
||||
<button
|
||||
class="button-unstyled cancel-search"
|
||||
type="button"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
>
|
||||
<FAIcon
|
||||
fixed-width
|
||||
icon="times"
|
||||
class="cancel-icon fa-scale-110 fa-old-padding"
|
||||
@click.prevent.stop="toggleHidden"
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
@@ -69,8 +75,11 @@
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.cancel-search {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.cancel-icon {
|
||||
cursor: pointer;
|
||||
color: $fallback--text;
|
||||
color: var(--btnTopBarText, $fallback--text);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<label
|
||||
class="BooleanSetting"
|
||||
>
|
||||
<Checkbox
|
||||
:checked="state"
|
||||
:disabled="disabled"
|
||||
@change="update"
|
||||
>
|
||||
<span
|
||||
v-if="!!$slots.default"
|
||||
class="label"
|
||||
>
|
||||
<slot />
|
||||
</span>
|
||||
<ModifiedIndicator :changed="isChanged" />
|
||||
</Checkbox>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { get, set } from 'lodash'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import ModifiedIndicator from './modified_indicator.vue'
|
||||
export default {
|
||||
components: {
|
||||
Checkbox,
|
||||
ModifiedIndicator
|
||||
},
|
||||
props: [
|
||||
'path',
|
||||
'disabled'
|
||||
],
|
||||
computed: {
|
||||
pathDefault () {
|
||||
const [firstSegment, ...rest] = this.path.split('.')
|
||||
return [firstSegment + 'DefaultValue', ...rest].join('.')
|
||||
},
|
||||
state () {
|
||||
return get(this.$parent, this.path)
|
||||
},
|
||||
isChanged () {
|
||||
return get(this.$parent, this.path) !== get(this.$parent, this.pathDefault)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update (e) {
|
||||
set(this.$parent, this.path, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.BooleanSetting {
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<span
|
||||
v-if="changed"
|
||||
class="ModifiedIndicator"
|
||||
>
|
||||
<Popover
|
||||
trigger="hover"
|
||||
>
|
||||
<span slot="trigger">
|
||||
|
||||
<FAIcon
|
||||
icon="wrench"
|
||||
/>
|
||||
</span>
|
||||
<div
|
||||
slot="content"
|
||||
class="modified-tooltip"
|
||||
>
|
||||
{{ $t('settings.setting_changed') }}
|
||||
</div>
|
||||
</Popover>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faWrench } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faWrench
|
||||
)
|
||||
|
||||
export default {
|
||||
components: { Popover },
|
||||
props: ['changed']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.ModifiedIndicator {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
.modified-tooltip {
|
||||
margin: 0.5em 1em;
|
||||
min-width: 10em;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,29 +1,15 @@
|
||||
import {
|
||||
instanceDefaultProperties,
|
||||
multiChoiceProperties,
|
||||
defaultState as configDefaultState
|
||||
} from 'src/modules/config.js'
|
||||
import { defaultState as configDefaultState } from 'src/modules/config.js'
|
||||
|
||||
const SharedComputedObject = () => ({
|
||||
user () {
|
||||
return this.$store.state.users.currentUser
|
||||
},
|
||||
// Getting localized values for instance-default properties
|
||||
...instanceDefaultProperties
|
||||
.filter(key => multiChoiceProperties.includes(key))
|
||||
// Getting values for default properties
|
||||
...Object.keys(configDefaultState)
|
||||
.map(key => [
|
||||
key + 'DefaultValue',
|
||||
function () {
|
||||
return this.$store.getters.instanceDefaultConfig[key]
|
||||
}
|
||||
])
|
||||
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
|
||||
...instanceDefaultProperties
|
||||
.filter(key => !multiChoiceProperties.includes(key))
|
||||
.map(key => [
|
||||
key + 'LocalizedValue',
|
||||
function () {
|
||||
return this.$t('settings.values.' + this.$store.getters.instanceDefaultConfig[key])
|
||||
return this.$store.getters.defaultConfig[key]
|
||||
}
|
||||
])
|
||||
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
|
||||
|
||||
@@ -30,13 +30,13 @@
|
||||
</template>
|
||||
</transition>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="peekModal"
|
||||
>
|
||||
{{ $t('general.peek') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="closeModal"
|
||||
>
|
||||
{{ $t('general.close') }}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { filter, trim } from 'lodash'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
@@ -18,7 +18,7 @@ const FilteringTab = {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Checkbox
|
||||
BooleanSetting
|
||||
},
|
||||
computed: {
|
||||
...SharedComputedObject(),
|
||||
|
||||
@@ -5,34 +5,34 @@
|
||||
<span class="label">{{ $t('settings.notification_visibility') }}</span>
|
||||
<ul class="option-list">
|
||||
<li>
|
||||
<Checkbox v-model="notificationVisibility.likes">
|
||||
<BooleanSetting path="notificationVisibility.likes">
|
||||
{{ $t('settings.notification_visibility_likes') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="notificationVisibility.repeats">
|
||||
<BooleanSetting path="notificationVisibility.repeats">
|
||||
{{ $t('settings.notification_visibility_repeats') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="notificationVisibility.follows">
|
||||
<BooleanSetting path="notificationVisibility.follows">
|
||||
{{ $t('settings.notification_visibility_follows') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="notificationVisibility.mentions">
|
||||
<BooleanSetting path="notificationVisibility.mentions">
|
||||
{{ $t('settings.notification_visibility_mentions') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="notificationVisibility.moves">
|
||||
<BooleanSetting path="notificationVisibility.moves">
|
||||
{{ $t('settings.notification_visibility_moves') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="notificationVisibility.emojiReactions">
|
||||
<BooleanSetting path="notificationVisibility.emojiReactions">
|
||||
{{ $t('settings.notification_visibility_emoji_reactions') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -60,14 +60,14 @@
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<Checkbox v-model="hidePostStats">
|
||||
{{ $t('settings.hide_post_stats') }} {{ $t('settings.instance_default', { value: hidePostStatsLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="hidePostStats">
|
||||
{{ $t('settings.hide_post_stats') }}
|
||||
</BooleanSetting>
|
||||
</div>
|
||||
<div>
|
||||
<Checkbox v-model="hideUserStats">
|
||||
{{ $t('settings.hide_user_stats') }} {{ $t('settings.instance_default', { value: hideUserStatsLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="hideUserStats">
|
||||
{{ $t('settings.hide_user_stats') }}
|
||||
</BooleanSetting>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
@@ -76,12 +76,13 @@
|
||||
<textarea
|
||||
id="muteWords"
|
||||
v-model="muteWordsString"
|
||||
class="resize-height"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Checkbox v-model="hideFilteredStatuses">
|
||||
{{ $t('settings.hide_filtered_statuses') }} {{ $t('settings.instance_default', { value: hideFilteredStatusesLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="hideFilteredStatuses">
|
||||
{{ $t('settings.hide_filtered_statuses') }}
|
||||
</BooleanSetting>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
||||
|
||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||
@@ -26,7 +26,7 @@ const GeneralTab = {
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Checkbox,
|
||||
BooleanSetting,
|
||||
InterfaceLanguageSwitcher
|
||||
},
|
||||
computed: {
|
||||
@@ -34,6 +34,10 @@ const GeneralTab = {
|
||||
return this.$store.state.instance.postFormats || []
|
||||
},
|
||||
instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel },
|
||||
instanceWallpaperUsed () {
|
||||
return this.$store.state.instance.background &&
|
||||
!this.$store.state.users.currentUser.background_image
|
||||
},
|
||||
...SharedComputedObject()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,14 @@
|
||||
<interface-language-switcher />
|
||||
</li>
|
||||
<li v-if="instanceSpecificPanelPresent">
|
||||
<Checkbox v-model="hideISP">
|
||||
<BooleanSetting path="hideISP">
|
||||
{{ $t('settings.hide_isp') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li v-if="instanceWallpaperUsed">
|
||||
<BooleanSetting path="hideInstanceWallpaper">
|
||||
{{ $t('settings.hide_wallpaper') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -17,51 +22,51 @@
|
||||
<h2>{{ $t('nav.timeline') }}</h2>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<Checkbox v-model="hideMutedPosts">
|
||||
{{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="hideMutedPosts">
|
||||
{{ $t('settings.hide_muted_posts') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="collapseMessageWithSubject">
|
||||
{{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="collapseMessageWithSubject">
|
||||
{{ $t('settings.collapse_subject') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="streaming">
|
||||
<BooleanSetting path="streaming">
|
||||
{{ $t('settings.streaming') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
<ul
|
||||
class="setting-list suboptions"
|
||||
:class="[{disabled: !streaming}]"
|
||||
>
|
||||
<li>
|
||||
<Checkbox
|
||||
v-model="pauseOnUnfocused"
|
||||
<BooleanSetting
|
||||
path="pauseOnUnfocused"
|
||||
:disabled="!streaming"
|
||||
>
|
||||
{{ $t('settings.pause_on_unfocused') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="useStreamingApi">
|
||||
<BooleanSetting path="useStreamingApi">
|
||||
{{ $t('settings.useStreamingApi') }}
|
||||
<br>
|
||||
<small>
|
||||
{{ $t('settings.useStreamingApiWarning') }}
|
||||
</small>
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="emojiReactionsOnTimeline">
|
||||
<BooleanSetting path="emojiReactionsOnTimeline">
|
||||
{{ $t('settings.emoji_reactions_on_timeline') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="virtualScrolling">
|
||||
<BooleanSetting path="virtualScrolling">
|
||||
{{ $t('settings.virtual_scrolling') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -70,14 +75,14 @@
|
||||
<h2>{{ $t('settings.composing') }}</h2>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<Checkbox v-model="scopeCopy">
|
||||
{{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="scopeCopy">
|
||||
{{ $t('settings.scope_copy') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="alwaysShowSubjectInput">
|
||||
{{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="alwaysShowSubjectInput">
|
||||
{{ $t('settings.subject_input_always_show') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
@@ -138,19 +143,19 @@
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="minimalScopesMode">
|
||||
{{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="minimalScopesMode">
|
||||
{{ $t('settings.minimal_scopes_mode') }} {{ minimalScopesModeDefaultValue }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="autohideFloatingPostButton">
|
||||
<BooleanSetting path="autohideFloatingPostButton">
|
||||
{{ $t('settings.autohide_floating_post_button') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="padEmoji">
|
||||
<BooleanSetting path="padEmoji">
|
||||
{{ $t('settings.pad_emoji') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -159,14 +164,14 @@
|
||||
<h2>{{ $t('settings.attachments') }}</h2>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<Checkbox v-model="hideAttachments">
|
||||
<BooleanSetting path="hideAttachments">
|
||||
{{ $t('settings.hide_attachments_in_tl') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="hideAttachmentsInConv">
|
||||
<BooleanSetting path="hideAttachmentsInConv">
|
||||
{{ $t('settings.hide_attachments_in_convo') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<label for="maxThumbnails">
|
||||
@@ -174,7 +179,7 @@
|
||||
</label>
|
||||
<input
|
||||
id="maxThumbnails"
|
||||
v-model.number="maxThumbnails"
|
||||
path.number="maxThumbnails"
|
||||
class="number-input"
|
||||
type="number"
|
||||
min="0"
|
||||
@@ -182,48 +187,48 @@
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="hideNsfw">
|
||||
<BooleanSetting path="hideNsfw">
|
||||
{{ $t('settings.nsfw_clickthrough') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<ul class="setting-list suboptions">
|
||||
<li>
|
||||
<Checkbox
|
||||
v-model="preloadImage"
|
||||
<BooleanSetting
|
||||
path="preloadImage"
|
||||
:disabled="!hideNsfw"
|
||||
>
|
||||
{{ $t('settings.preload_images') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox
|
||||
v-model="useOneClickNsfw"
|
||||
<BooleanSetting
|
||||
path="useOneClickNsfw"
|
||||
:disabled="!hideNsfw"
|
||||
>
|
||||
{{ $t('settings.use_one_click_nsfw') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
<li>
|
||||
<Checkbox v-model="stopGifs">
|
||||
<BooleanSetting path="stopGifs">
|
||||
{{ $t('settings.stop_gifs') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="loopVideo">
|
||||
<BooleanSetting path="loopVideo">
|
||||
{{ $t('settings.loop_video') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
<ul
|
||||
class="setting-list suboptions"
|
||||
:class="[{disabled: !streaming}]"
|
||||
>
|
||||
<li>
|
||||
<Checkbox
|
||||
v-model="loopVideoSilentOnly"
|
||||
<BooleanSetting
|
||||
path="loopVideoSilentOnly"
|
||||
:disabled="!loopVideo || !loopSilentAvailable"
|
||||
>
|
||||
{{ $t('settings.loop_video_silent_only') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
<div
|
||||
v-if="!loopSilentAvailable"
|
||||
class="unavailable"
|
||||
@@ -234,14 +239,14 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="playVideosInModal">
|
||||
<BooleanSetting path="playVideosInModal">
|
||||
{{ $t('settings.play_videos_in_modal') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<Checkbox v-model="useContainFit">
|
||||
<BooleanSetting path="useContainFit">
|
||||
{{ $t('settings.use_contain_fit') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -250,9 +255,9 @@
|
||||
<h2>{{ $t('settings.notifications') }}</h2>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<Checkbox v-model="webPushNotifications">
|
||||
<BooleanSetting path="webPushNotifications">
|
||||
{{ $t('settings.enable_web_push_notifications') }}
|
||||
</Checkbox>
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -261,9 +266,9 @@
|
||||
<h2>{{ $t('settings.fun') }}</h2>
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<Checkbox v-model="greentext">
|
||||
{{ $t('settings.greentext') }} {{ $t('settings.instance_default', { value: greentextLocalizedValue }) }}
|
||||
</Checkbox>
|
||||
<BooleanSetting path="greentext">
|
||||
{{ $t('settings.greentext') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="bulk-actions">
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default bulk-action-button"
|
||||
class="btn button-default bulk-action-button"
|
||||
:click="() => blockUsers(selected)"
|
||||
>
|
||||
{{ $t('user_card.block') }}
|
||||
@@ -37,7 +37,7 @@
|
||||
</ProgressButton>
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:click="() => unblockUsers(selected)"
|
||||
>
|
||||
{{ $t('user_card.unblock') }}
|
||||
@@ -85,7 +85,7 @@
|
||||
<div class="bulk-actions">
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:click="() => muteUsers(selected)"
|
||||
>
|
||||
{{ $t('user_card.mute') }}
|
||||
@@ -95,7 +95,7 @@
|
||||
</ProgressButton>
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:click="() => unmuteUsers(selected)"
|
||||
>
|
||||
{{ $t('user_card.unmute') }}
|
||||
@@ -141,7 +141,7 @@
|
||||
<div class="bulk-actions">
|
||||
<ProgressButton
|
||||
v-if="selected.length > 0"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:click="() => unmuteDomains(selected)"
|
||||
>
|
||||
{{ $t('domain_mute_card.unmute') }}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<p>{{ $t('settings.notification_mutes') }}</p>
|
||||
<p>{{ $t('settings.notification_blocks') }}</p>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="updateNotificationSettings"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
|
||||
@@ -45,9 +45,7 @@ const ProfileTab = {
|
||||
banner: null,
|
||||
bannerPreview: null,
|
||||
background: null,
|
||||
backgroundPreview: null,
|
||||
bannerUploadError: null,
|
||||
backgroundUploadError: null
|
||||
backgroundPreview: null
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@@ -68,8 +66,7 @@ const ProfileTab = {
|
||||
...this.$store.state.instance.emoji,
|
||||
...this.$store.state.instance.customEmoji
|
||||
],
|
||||
users: this.$store.state.users.users,
|
||||
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
|
||||
store: this.$store
|
||||
})
|
||||
},
|
||||
emojiSuggestor () {
|
||||
@@ -79,10 +76,7 @@ const ProfileTab = {
|
||||
] })
|
||||
},
|
||||
userSuggestor () {
|
||||
return suggestor({
|
||||
users: this.$store.state.users.users,
|
||||
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
|
||||
})
|
||||
return suggestor({ store: this.$store })
|
||||
},
|
||||
fieldsLimits () {
|
||||
return this.$store.state.instance.fieldsLimits
|
||||
@@ -166,18 +160,18 @@ const ProfileTab = {
|
||||
if (file.size > this.$store.state.instance[slot + 'limit']) {
|
||||
const filesize = fileSizeFormatService.fileSizeFormat(file.size)
|
||||
const allowedsize = fileSizeFormatService.fileSizeFormat(this.$store.state.instance[slot + 'limit'])
|
||||
this[slot + 'UploadError'] = [
|
||||
this.$t('upload.error.base'),
|
||||
this.$t(
|
||||
'upload.error.file_too_big',
|
||||
{
|
||||
this.$store.dispatch('pushGlobalNotice', {
|
||||
messageKey: 'upload.error.message',
|
||||
messageArgs: [
|
||||
this.$t('upload.error.file_too_big', {
|
||||
filesize: filesize.num,
|
||||
filesizeunit: filesize.unit,
|
||||
allowedsize: allowedsize.num,
|
||||
allowedsizeunit: allowedsize.unit
|
||||
}
|
||||
)
|
||||
].join(' ')
|
||||
})
|
||||
],
|
||||
level: 'error'
|
||||
})
|
||||
return
|
||||
}
|
||||
// eslint-disable-next-line no-undef
|
||||
@@ -217,8 +211,9 @@ const ProfileTab = {
|
||||
that.$store.commit('setCurrentUser', user)
|
||||
resolve()
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(new Error(that.$t('upload.error.base') + ' ' + err.message))
|
||||
.catch((error) => {
|
||||
that.displayUploadError(error)
|
||||
reject(error)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -239,24 +234,27 @@ const ProfileTab = {
|
||||
this.$store.commit('setCurrentUser', user)
|
||||
this.bannerPreview = null
|
||||
})
|
||||
.catch((err) => {
|
||||
this.bannerUploadError = this.$t('upload.error.base') + ' ' + err.message
|
||||
})
|
||||
.then(() => { this.bannerUploading = false })
|
||||
.catch(this.displayUploadError)
|
||||
.finally(() => { this.bannerUploading = false })
|
||||
},
|
||||
submitBackground (background) {
|
||||
if (!this.backgroundPreview && background !== '') { return }
|
||||
|
||||
this.backgroundUploading = true
|
||||
this.$store.state.api.backendInteractor.updateProfileImages({ background }).then((data) => {
|
||||
if (!data.error) {
|
||||
this.$store.state.api.backendInteractor.updateProfileImages({ background })
|
||||
.then((data) => {
|
||||
this.$store.commit('addNewUsers', [data])
|
||||
this.$store.commit('setCurrentUser', data)
|
||||
this.backgroundPreview = null
|
||||
} else {
|
||||
this.backgroundUploadError = this.$t('upload.error.base') + data.error
|
||||
}
|
||||
this.backgroundUploading = false
|
||||
})
|
||||
.catch(this.displayUploadError)
|
||||
.finally(() => { this.backgroundUploading = false })
|
||||
},
|
||||
displayUploadError (error) {
|
||||
this.$store.dispatch('pushGlobalNotice', {
|
||||
messageKey: 'upload.error.message',
|
||||
messageArgs: [error.message],
|
||||
level: 'error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,16 +111,17 @@
|
||||
.profile-fields {
|
||||
display: flex;
|
||||
|
||||
&>.emoji-input {
|
||||
& > .emoji-input {
|
||||
flex: 1 1 auto;
|
||||
margin: 0 .2em .5em;
|
||||
margin: 0 0.2em 0.5em;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
&>.icon-container {
|
||||
.delete-field {
|
||||
width: 20px;
|
||||
align-self: center;
|
||||
margin: 0 .2em .5em;
|
||||
margin: 0 0.2em 0.5em;
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<input
|
||||
id="username"
|
||||
v-model="newName"
|
||||
classname="name-changer"
|
||||
class="name-changer"
|
||||
>
|
||||
</EmojiInput>
|
||||
<p>{{ $t('settings.bio') }}</p>
|
||||
@@ -22,7 +22,7 @@
|
||||
>
|
||||
<textarea
|
||||
v-model="newBio"
|
||||
classname="bio"
|
||||
class="bio resize-height"
|
||||
/>
|
||||
</EmojiInput>
|
||||
<p>
|
||||
@@ -124,24 +124,24 @@
|
||||
:placeholder="$t('settings.profile_fields.value')"
|
||||
>
|
||||
</EmojiInput>
|
||||
<div
|
||||
class="icon-container"
|
||||
<button
|
||||
class="delete-field button-unstyled -hover-highlight"
|
||||
@click="deleteField(i)"
|
||||
>
|
||||
<FAIcon
|
||||
v-show="newFields.length > 1"
|
||||
icon="times"
|
||||
@click="deleteField(i)"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<a
|
||||
<button
|
||||
v-if="newFields.length < maxFields"
|
||||
class="add-field faint"
|
||||
class="add-field faint button-unstyled -hover-highlight"
|
||||
@click="addField"
|
||||
>
|
||||
<FAIcon icon="plus" />
|
||||
{{ $t("settings.profile_fields.add_field") }}
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
<Checkbox v-model="bot">
|
||||
@@ -150,7 +150,7 @@
|
||||
</p>
|
||||
<button
|
||||
:disabled="newName && newName.length === 0"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="updateProfile"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
@@ -179,7 +179,7 @@
|
||||
<button
|
||||
v-show="pickAvatarBtnVisible"
|
||||
id="pick-avatar"
|
||||
class="btn"
|
||||
class="button-default btn"
|
||||
type="button"
|
||||
>
|
||||
{{ $t('settings.upload_a_photo') }}
|
||||
@@ -224,22 +224,11 @@
|
||||
/>
|
||||
<button
|
||||
v-else-if="bannerPreview"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="submitBanner(banner)"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
</button>
|
||||
<div
|
||||
v-if="bannerUploadError"
|
||||
class="alert error"
|
||||
>
|
||||
Error: {{ bannerUploadError }}
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="times"
|
||||
@click="clearUploadError('banner')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<h2>{{ $t('settings.profile_background') }}</h2>
|
||||
@@ -274,23 +263,11 @@
|
||||
/>
|
||||
<button
|
||||
v-else-if="backgroundPreview"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="submitBackground(background)"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
</button>
|
||||
<div
|
||||
v-if="backgroundUploadError"
|
||||
class="alert error"
|
||||
>
|
||||
Error: {{ backgroundUploadError }}
|
||||
<FAIcon
|
||||
size="lg"
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="times"
|
||||
@click="clearUploadError('background')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
<div>
|
||||
<slot />
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="disabled"
|
||||
@click="confirm"
|
||||
>
|
||||
{{ $t('general.confirm') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="disabled"
|
||||
@click="cancel"
|
||||
>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/>
|
||||
<button
|
||||
v-if="!confirmNewBackupCodes"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="getBackupCodes"
|
||||
>
|
||||
{{ $t('settings.mfa.generate_new_recovery_codes') }}
|
||||
@@ -61,7 +61,7 @@
|
||||
|
||||
<button
|
||||
v-if="canSetupOTP"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="cancelSetup"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
<button
|
||||
v-if="canSetupOTP"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="setupOTP"
|
||||
>
|
||||
{{ $t('settings.mfa.setup_otp') }}
|
||||
@@ -108,13 +108,13 @@
|
||||
>
|
||||
<div class="confirm-otp-actions">
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="doConfirmOTP"
|
||||
>
|
||||
{{ $t('settings.mfa.confirm_and_enable') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="cancelSetup"
|
||||
>
|
||||
{{ $t('general.cancel') }}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<strong>{{ $t('settings.mfa.otp') }}</strong>
|
||||
<button
|
||||
v-if="!isActivated"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="doActivate"
|
||||
>
|
||||
{{ $t('general.enable') }}
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<button
|
||||
v-if="isActivated"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="deactivate"
|
||||
@click="doDeactivate"
|
||||
>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import Mfa from './mfa.vue'
|
||||
import localeService from 'src/services/locale/locale.service.js'
|
||||
|
||||
const SecurityTab = {
|
||||
data () {
|
||||
@@ -37,7 +38,7 @@ const SecurityTab = {
|
||||
return {
|
||||
id: oauthToken.id,
|
||||
appName: oauthToken.app_name,
|
||||
validUntil: new Date(oauthToken.valid_until).toLocaleDateString()
|
||||
validUntil: new Date(oauthToken.valid_until).toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="changeEmail"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
@@ -57,7 +57,7 @@
|
||||
>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="changePassword"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
@@ -92,7 +92,7 @@
|
||||
<td>{{ oauthToken.validUntil }}</td>
|
||||
<td class="actions">
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="revokeToken(oauthToken.id)"
|
||||
>
|
||||
{{ $t('settings.revoke_token') }}
|
||||
@@ -116,7 +116,7 @@
|
||||
type="password"
|
||||
>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="deleteAccount"
|
||||
>
|
||||
{{ $t('settings.delete_account') }}
|
||||
@@ -130,7 +130,7 @@
|
||||
</p>
|
||||
<button
|
||||
v-if="!deletingAccount"
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
@click="confirmDelete"
|
||||
>
|
||||
{{ $t('general.submit') }}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<span class="alert error">
|
||||
{{ $t('settings.style.preview.error') }}
|
||||
</span>
|
||||
<button class="btn">
|
||||
<button class="btn button-default">
|
||||
{{ $t('settings.style.preview.button') }}
|
||||
</button>
|
||||
</div>
|
||||
@@ -102,7 +102,7 @@
|
||||
>
|
||||
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
|
||||
</span>
|
||||
<button class="btn">
|
||||
<button class="btn button-default">
|
||||
{{ $t('settings.style.preview.button') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -165,7 +165,8 @@
|
||||
border-color: var(--border, $fallback--border);
|
||||
margin: 1em 0;
|
||||
padding: 1em;
|
||||
background: var(--body-background-image);
|
||||
background-color: var(--wallpaper);
|
||||
background-image: var(--body-background-image);
|
||||
background-size: cover;
|
||||
background-position: 50% 50%;
|
||||
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
<div class="buttons">
|
||||
<template v-if="themeWarning.type === 'snapshot_source_mismatch'">
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="forceLoad"
|
||||
>
|
||||
{{ $t('settings.style.switcher.use_source') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="forceSnapshot"
|
||||
>
|
||||
{{ $t('settings.style.switcher.use_snapshot') }}
|
||||
@@ -26,7 +26,7 @@
|
||||
</template>
|
||||
<template v-else-if="themeWarning.noActionsPossible">
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="dismissWarning"
|
||||
>
|
||||
{{ $t('general.dismiss') }}
|
||||
@@ -34,13 +34,13 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="forceLoad"
|
||||
>
|
||||
{{ $t('settings.style.switcher.load_theme') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="dismissWarning"
|
||||
>
|
||||
{{ $t('settings.style.switcher.keep_as_is') }}
|
||||
@@ -131,13 +131,13 @@
|
||||
<p>{{ $t('settings.theme_help') }}</p>
|
||||
<div class="tab-header-buttons">
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearOpacity"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_opacity') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearV1"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_all') }}
|
||||
@@ -238,13 +238,13 @@
|
||||
<div class="tab-header">
|
||||
<p>{{ $t('settings.theme_help') }}</p>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearOpacity"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_opacity') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearV1"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_all') }}
|
||||
@@ -616,6 +616,15 @@
|
||||
:disabled="underlayOpacityLocal === 'transparent'"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.wallpaper') }}</h4>
|
||||
<ColorInput
|
||||
v-model="wallpaperColorLocal"
|
||||
name="wallpaper"
|
||||
:label="$t('settings.style.advanced_colors.wallpaper')"
|
||||
:fallback="previewTheme.colors.wallpaper"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.poll') }}</h4>
|
||||
<ColorInput
|
||||
@@ -806,7 +815,7 @@
|
||||
<div class="tab-header">
|
||||
<p>{{ $t('settings.radii_help') }}</p>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearRoundness"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_all') }}
|
||||
@@ -936,7 +945,7 @@
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearShadows"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_all') }}
|
||||
@@ -980,7 +989,7 @@
|
||||
<div class="tab-header">
|
||||
<p>{{ $t('settings.style.fonts.help') }}</p>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearFonts"
|
||||
>
|
||||
{{ $t('settings.style.switcher.clear_all') }}
|
||||
@@ -1017,14 +1026,14 @@
|
||||
|
||||
<div class="apply-container">
|
||||
<button
|
||||
class="btn submit"
|
||||
class="btn button-default submit"
|
||||
:disabled="!themeValid"
|
||||
@click="setCustomTheme"
|
||||
>
|
||||
{{ $t('general.apply') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
class="btn button-default"
|
||||
@click="clearAll"
|
||||
>
|
||||
{{ $t('settings.style.switcher.reset') }}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="!ready || !present"
|
||||
@click="del"
|
||||
>
|
||||
@@ -94,7 +94,7 @@
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="!moveUpValid"
|
||||
@click="moveUp"
|
||||
>
|
||||
@@ -104,7 +104,7 @@
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="!moveDnValid"
|
||||
@click="moveDn"
|
||||
>
|
||||
@@ -114,7 +114,7 @@
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-default"
|
||||
class="btn button-default"
|
||||
:disabled="usingFallback"
|
||||
@click="add"
|
||||
>
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
v-if="chat"
|
||||
@click="toggleDrawer"
|
||||
>
|
||||
<router-link :to="{ name: 'chat' }">
|
||||
<router-link :to="{ name: 'chat-panel' }">
|
||||
<FAIcon
|
||||
fixed-width
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
@@ -144,8 +144,8 @@
|
||||
</router-link>
|
||||
</li>
|
||||
<li @click="toggleDrawer">
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link -fullwidth"
|
||||
@click="openSettingsModal"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -153,7 +153,7 @@
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="cog"
|
||||
/> {{ $t("settings.settings") }}
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'about'}">
|
||||
@@ -183,8 +183,8 @@
|
||||
v-if="currentUser"
|
||||
@click="toggleDrawer"
|
||||
>
|
||||
<a
|
||||
href="#"
|
||||
<button
|
||||
class="button-unstyled -link -fullwidth"
|
||||
@click="doLogout"
|
||||
>
|
||||
<FAIcon
|
||||
@@ -192,7 +192,7 @@
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="sign-out-alt"
|
||||
/> {{ $t("login.logout") }}
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -331,7 +331,7 @@
|
||||
.side-drawer li {
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
a, button {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
height: 3em;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user