forked from AkkomaGang/akkoma-fe
Merge remote-tracking branch 'upstream/develop' into streaming
* upstream/develop: (51 commits) toggle_activation api is also deprecated use vuex action refactor toggleActivationStatus replace setActivationStatus api with new one use flex for stickers i18n/update-ja_easy Use a centralized fallback for missing values and use instance.federating instead of instance.federation.enabled Add fallback in case BE does not report federating status in nodeinfo The value we are looking for is federationPolicy.enabled, not federationPolicy.federating Logic should be to hide TWKN if not federating OR if instance is not public Finally trust eslint More lint More lint Lint mfa: removed unused code increase icon width a little bit in the nav panel add icons to nav panel Revert "Merge branch 'revert-96cab6d8' into 'develop'" Support "native" captcha Revert "Merge branch 'oauth-extra-scopes' into 'develop'" ...
This commit is contained in:
commit
b619477573
35 changed files with 1206 additions and 691 deletions
4
.babelrc
4
.babelrc
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"presets": ["es2015", "stage-2", "env"],
|
"presets": ["@babel/preset-env"],
|
||||||
"plugins": ["transform-runtime", "lodash", "transform-vue-jsx"],
|
"plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-transform-vue-jsx"],
|
||||||
"comments": false
|
"comments": false
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,6 +77,9 @@ Use custom image for NSFW'd images
|
||||||
### `showFeaturesPanel`
|
### `showFeaturesPanel`
|
||||||
Show panel showcasing instance features/settings to logged-out visitors
|
Show panel showcasing instance features/settings to logged-out visitors
|
||||||
|
|
||||||
|
### `hideSitename`
|
||||||
|
Hide instance name in header
|
||||||
|
|
||||||
## Indirect configuration
|
## Indirect configuration
|
||||||
Some features are configured depending on how backend is configured. In general the approach is "if backend allows it there's no need to hide it, if backend doesn't allow it there's no need to show it.
|
Some features are configured depending on how backend is configured. In general the approach is "if backend allows it there's no need to hide it, if backend doesn't allow it there's no need to show it.
|
||||||
|
|
||||||
|
@ -96,3 +99,6 @@ Setting this will change the warning text that is displayed for direct messages.
|
||||||
ATTENTION: If you actually want the behavior to change. You will need to set the appropriate option at the backend. See the backend documentation for information about that.
|
ATTENTION: If you actually want the behavior to change. You will need to set the appropriate option at the backend. See the backend documentation for information about that.
|
||||||
|
|
||||||
DO NOT activate this without checking the backend configuration first!
|
DO NOT activate this without checking the backend configuration first!
|
||||||
|
|
||||||
|
### Private Mode
|
||||||
|
If the `private` instance setting is enabled in the backend, features that are not accessible without authentication, such as the timelines and search will be disabled for unauthenticated users.
|
||||||
|
|
22
package.json
22
package.json
|
@ -15,9 +15,8 @@
|
||||||
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
|
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.7.6",
|
||||||
"@chenfengyuan/vue-qrcode": "^1.0.0",
|
"@chenfengyuan/vue-qrcode": "^1.0.0",
|
||||||
"babel-plugin-add-module-exports": "^0.2.1",
|
|
||||||
"babel-plugin-lodash": "^3.2.11",
|
|
||||||
"body-scroll-lock": "^2.6.4",
|
"body-scroll-lock": "^2.6.4",
|
||||||
"chromatism": "^3.0.0",
|
"chromatism": "^3.0.0",
|
||||||
"cropperjs": "^1.4.3",
|
"cropperjs": "^1.4.3",
|
||||||
|
@ -40,20 +39,17 @@
|
||||||
"whatwg-fetch": "^2.0.3"
|
"whatwg-fetch": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/polyfill": "^7.0.0",
|
"@babel/core": "^7.7.5",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.7.6",
|
||||||
|
"@babel/preset-env": "^7.7.6",
|
||||||
|
"@babel/register": "^7.7.4",
|
||||||
|
"@vue/babel-helper-vue-jsx-merge-props": "^1.0.0",
|
||||||
|
"@vue/babel-plugin-transform-vue-jsx": "^1.1.2",
|
||||||
"@vue/test-utils": "^1.0.0-beta.26",
|
"@vue/test-utils": "^1.0.0-beta.26",
|
||||||
"autoprefixer": "^6.4.0",
|
"autoprefixer": "^6.4.0",
|
||||||
"babel-core": "^6.0.0",
|
|
||||||
"babel-eslint": "^7.0.0",
|
"babel-eslint": "^7.0.0",
|
||||||
"babel-helper-vue-jsx-merge-props": "^2.0.3",
|
"babel-loader": "^8.0.6",
|
||||||
"babel-loader": "^7.0.0",
|
"babel-plugin-lodash": "^3.3.4",
|
||||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
|
||||||
"babel-plugin-transform-runtime": "^6.0.0",
|
|
||||||
"babel-plugin-transform-vue-jsx": "3",
|
|
||||||
"babel-preset-env": "^1.7.0",
|
|
||||||
"babel-preset-es2015": "^6.0.0",
|
|
||||||
"babel-preset-stage-2": "^6.0.0",
|
|
||||||
"babel-register": "^6.0.0",
|
|
||||||
"chai": "^3.5.0",
|
"chai": "^3.5.0",
|
||||||
"chalk": "^1.1.3",
|
"chalk": "^1.1.3",
|
||||||
"chromedriver": "^2.21.2",
|
"chromedriver": "^2.21.2",
|
||||||
|
|
|
@ -90,6 +90,7 @@ export default {
|
||||||
},
|
},
|
||||||
sitename () { return this.$store.state.instance.name },
|
sitename () { return this.$store.state.instance.name },
|
||||||
chat () { return this.$store.state.chat.channel.state === 'joined' },
|
chat () { return this.$store.state.chat.channel.state === 'joined' },
|
||||||
|
hideSitename () { return this.$store.state.instance.hideSitename },
|
||||||
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
|
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
|
||||||
showInstanceSpecificPanel () {
|
showInstanceSpecificPanel () {
|
||||||
return this.$store.state.instance.showInstanceSpecificPanel &&
|
return this.$store.state.instance.showInstanceSpecificPanel &&
|
||||||
|
@ -97,7 +98,8 @@ export default {
|
||||||
this.$store.state.instance.instanceSpecificPanelContent
|
this.$store.state.instance.instanceSpecificPanelContent
|
||||||
},
|
},
|
||||||
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
|
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
|
||||||
isMobileLayout () { return this.$store.state.interface.mobileLayout }
|
isMobileLayout () { return this.$store.state.interface.mobileLayout },
|
||||||
|
privateMode () { return this.$store.state.instance.private }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
scrollToTop () {
|
scrollToTop () {
|
||||||
|
|
13
src/App.scss
13
src/App.scss
|
@ -870,3 +870,16 @@ nav {
|
||||||
transform: rotate(359deg);
|
transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.new-status-notification {
|
||||||
|
position:relative;
|
||||||
|
margin-top: -1px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
border-width: 1px 0 0 0;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: var(--border, $fallback--border);
|
||||||
|
padding: 10px;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: $fallback--fg;
|
||||||
|
background-color: var(--panel, $fallback--fg);
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<router-link
|
<router-link
|
||||||
|
v-if="!hideSitename"
|
||||||
class="site-name"
|
class="site-name"
|
||||||
:to="{ name: 'root' }"
|
:to="{ name: 'root' }"
|
||||||
active-class="home"
|
active-class="home"
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="item right">
|
<div class="item right">
|
||||||
<search-bar
|
<search-bar
|
||||||
|
v-if="currentUser || !privateMode"
|
||||||
class="nav-icon mobile-hidden"
|
class="nav-icon mobile-hidden"
|
||||||
@toggled="onSearchBarToggled"
|
@toggled="onSearchBarToggled"
|
||||||
@click.stop.native
|
@click.stop.native
|
||||||
|
|
|
@ -108,6 +108,7 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
|
||||||
copyInstanceOption('alwaysShowSubjectInput')
|
copyInstanceOption('alwaysShowSubjectInput')
|
||||||
copyInstanceOption('noAttachmentLinks')
|
copyInstanceOption('noAttachmentLinks')
|
||||||
copyInstanceOption('showFeaturesPanel')
|
copyInstanceOption('showFeaturesPanel')
|
||||||
|
copyInstanceOption('hideSitename')
|
||||||
|
|
||||||
return store.dispatch('setTheme', config['theme'])
|
return store.dispatch('setTheme', config['theme'])
|
||||||
}
|
}
|
||||||
|
@ -218,12 +219,21 @@ const getNodeInfo = async ({ store }) => {
|
||||||
store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version })
|
store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version })
|
||||||
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' })
|
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' })
|
||||||
|
|
||||||
|
const priv = metadata.private
|
||||||
|
store.dispatch('setInstanceOption', { name: 'private', value: priv })
|
||||||
|
|
||||||
const frontendVersion = window.___pleromafe_commit_hash
|
const frontendVersion = window.___pleromafe_commit_hash
|
||||||
store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion })
|
store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion })
|
||||||
store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', value: metadata.federation.mrf_policies.includes('TagPolicy') })
|
store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', value: metadata.federation.mrf_policies.includes('TagPolicy') })
|
||||||
|
|
||||||
const federation = metadata.federation
|
const federation = metadata.federation
|
||||||
store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation })
|
store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation })
|
||||||
|
store.dispatch('setInstanceOption', {
|
||||||
|
name: 'federating',
|
||||||
|
value: typeof federation.enabled === 'undefined'
|
||||||
|
? true
|
||||||
|
: federation.enabled
|
||||||
|
})
|
||||||
|
|
||||||
const accounts = metadata.staffAccounts
|
const accounts = metadata.staffAccounts
|
||||||
await resolveStaffAccounts({ store, accounts })
|
await resolveStaffAccounts({ store, accounts })
|
||||||
|
|
|
@ -58,7 +58,7 @@ const LoginForm = {
|
||||||
).then((result) => {
|
).then((result) => {
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
if (result.error === 'mfa_required') {
|
if (result.error === 'mfa_required') {
|
||||||
this.requireMFA({ app: app, settings: result })
|
this.requireMFA({ settings: result })
|
||||||
} else if (result.identifier === 'password_reset_required') {
|
} else if (result.identifier === 'password_reset_required') {
|
||||||
this.$router.push({ name: 'password-reset', params: { passwordResetRequested: true } })
|
this.$router.push({ name: 'password-reset', params: { passwordResetRequested: true } })
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,18 +8,23 @@ export default {
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
authApp: 'authFlow/app',
|
|
||||||
authSettings: 'authFlow/settings'
|
authSettings: 'authFlow/settings'
|
||||||
}),
|
}),
|
||||||
...mapState({ instance: 'instance' })
|
...mapState({
|
||||||
|
instance: 'instance',
|
||||||
|
oauth: 'oauth'
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations('authFlow', ['requireTOTP', 'abortMFA']),
|
...mapMutations('authFlow', ['requireTOTP', 'abortMFA']),
|
||||||
...mapActions({ login: 'authFlow/login' }),
|
...mapActions({ login: 'authFlow/login' }),
|
||||||
clearError () { this.error = false },
|
clearError () { this.error = false },
|
||||||
submit () {
|
submit () {
|
||||||
|
const { clientId, clientSecret } = this.oauth
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
app: this.authApp,
|
clientId,
|
||||||
|
clientSecret,
|
||||||
instance: this.instance.server,
|
instance: this.instance.server,
|
||||||
mfaToken: this.authSettings.mfa_token,
|
mfaToken: this.authSettings.mfa_token,
|
||||||
code: this.code
|
code: this.code
|
||||||
|
|
|
@ -7,18 +7,23 @@ export default {
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
authApp: 'authFlow/app',
|
|
||||||
authSettings: 'authFlow/settings'
|
authSettings: 'authFlow/settings'
|
||||||
}),
|
}),
|
||||||
...mapState({ instance: 'instance' })
|
...mapState({
|
||||||
|
instance: 'instance',
|
||||||
|
oauth: 'oauth'
|
||||||
|
})
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
...mapMutations('authFlow', ['requireRecovery', 'abortMFA']),
|
...mapMutations('authFlow', ['requireRecovery', 'abortMFA']),
|
||||||
...mapActions({ login: 'authFlow/login' }),
|
...mapActions({ login: 'authFlow/login' }),
|
||||||
clearError () { this.error = false },
|
clearError () { this.error = false },
|
||||||
submit () {
|
submit () {
|
||||||
|
const { clientId, clientSecret } = this.oauth
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
app: this.authApp,
|
clientId,
|
||||||
|
clientSecret,
|
||||||
instance: this.instance.server,
|
instance: this.instance.server,
|
||||||
mfaToken: this.authSettings.mfa_token,
|
mfaToken: this.authSettings.mfa_token,
|
||||||
code: this.code
|
code: this.code
|
||||||
|
|
|
@ -29,6 +29,7 @@ const MobileNav = {
|
||||||
unseenNotificationsCount () {
|
unseenNotificationsCount () {
|
||||||
return this.unseenNotifications.length
|
return this.unseenNotifications.length
|
||||||
},
|
},
|
||||||
|
hideSitename () { return this.$store.state.instance.hideSitename },
|
||||||
sitename () { return this.$store.state.instance.name }
|
sitename () { return this.$store.state.instance.name }
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
<i class="button-icon icon-menu" />
|
<i class="button-icon icon-menu" />
|
||||||
</a>
|
</a>
|
||||||
<router-link
|
<router-link
|
||||||
|
v-if="!hideSitename"
|
||||||
class="site-name"
|
class="site-name"
|
||||||
:to="{ name: 'root' }"
|
:to="{ name: 'root' }"
|
||||||
active-class="home"
|
active-class="home"
|
||||||
|
|
|
@ -71,12 +71,7 @@ const ModerationTools = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleActivationStatus () {
|
toggleActivationStatus () {
|
||||||
const store = this.$store
|
this.$store.dispatch('toggleActivationStatus', { user: this.user })
|
||||||
const status = !!this.user.deactivated
|
|
||||||
store.state.api.backendInteractor.setActivationStatus({ user: this.user, status }).then(response => {
|
|
||||||
if (!response.ok) { return }
|
|
||||||
store.commit('updateActivationStatus', { user: this.user, status: status })
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
deleteUserDialog (show) {
|
deleteUserDialog (show) {
|
||||||
this.showDeleteUserDialog = show
|
this.showDeleteUserDialog = show
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
|
import { mapState } from 'vuex'
|
||||||
|
|
||||||
const NavPanel = {
|
const NavPanel = {
|
||||||
created () {
|
created () {
|
||||||
if (this.currentUser && this.currentUser.locked) {
|
if (this.currentUser && this.currentUser.locked) {
|
||||||
this.$store.dispatch('startFetchingFollowRequest')
|
this.$store.dispatch('startFetchingFollowRequest')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: mapState({
|
||||||
currentUser () {
|
currentUser: state => state.users.currentUser,
|
||||||
return this.$store.state.users.currentUser
|
chat: state => state.chat.channel,
|
||||||
},
|
followRequestCount: state => state.api.followRequests.length,
|
||||||
chat () {
|
privateMode: state => state.instance.private,
|
||||||
return this.$store.state.chat.channel
|
federating: state => state.instance.federating
|
||||||
},
|
})
|
||||||
followRequestCount () {
|
|
||||||
return this.$store.state.api.followRequests.length
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NavPanel
|
export default NavPanel
|
||||||
|
|
|
@ -4,22 +4,22 @@
|
||||||
<ul>
|
<ul>
|
||||||
<li v-if="currentUser">
|
<li v-if="currentUser">
|
||||||
<router-link :to="{ name: 'friends' }">
|
<router-link :to="{ name: 'friends' }">
|
||||||
{{ $t("nav.timeline") }}
|
<i class="button-icon icon-home-2" /> {{ $t("nav.timeline") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="currentUser">
|
<li v-if="currentUser">
|
||||||
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
|
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
|
||||||
{{ $t("nav.interactions") }}
|
<i class="button-icon icon-bell-alt" /> {{ $t("nav.interactions") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="currentUser">
|
<li v-if="currentUser">
|
||||||
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
||||||
{{ $t("nav.dms") }}
|
<i class="button-icon icon-mail-alt" /> {{ $t("nav.dms") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="currentUser && currentUser.locked">
|
<li v-if="currentUser && currentUser.locked">
|
||||||
<router-link :to="{ name: 'friend-requests' }">
|
<router-link :to="{ name: 'friend-requests' }">
|
||||||
{{ $t("nav.friend_requests") }}
|
<i class="button-icon icon-user-plus" /> {{ $t("nav.friend_requests") }}
|
||||||
<span
|
<span
|
||||||
v-if="followRequestCount > 0"
|
v-if="followRequestCount > 0"
|
||||||
class="badge follow-request-count"
|
class="badge follow-request-count"
|
||||||
|
@ -28,19 +28,19 @@
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li v-if="currentUser || !privateMode">
|
||||||
<router-link :to="{ name: 'public-timeline' }">
|
<router-link :to="{ name: 'public-timeline' }">
|
||||||
{{ $t("nav.public_tl") }}
|
<i class="button-icon icon-users" /> {{ $t("nav.public_tl") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li v-if="federating && !privateMode">
|
||||||
<router-link :to="{ name: 'public-external-timeline' }">
|
<router-link :to="{ name: 'public-external-timeline' }">
|
||||||
{{ $t("nav.twkn") }}
|
<i class="button-icon icon-globe" /> {{ $t("nav.twkn") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<router-link :to="{ name: 'about' }">
|
<router-link :to="{ name: 'about' }">
|
||||||
{{ $t("nav.about") }}
|
<i class="button-icon icon-info-circled" /> {{ $t("nav.about") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -113,4 +113,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav-panel .button-icon:before {
|
||||||
|
width: 1.1em;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -172,7 +172,7 @@
|
||||||
for="captcha-label"
|
for="captcha-label"
|
||||||
>{{ $t('captcha') }}</label>
|
>{{ $t('captcha') }}</label>
|
||||||
|
|
||||||
<template v-if="captcha.type == 'kocaptcha'">
|
<template v-if="['kocaptcha', 'native'].includes(captcha.type)">
|
||||||
<img
|
<img
|
||||||
:src="captcha.url"
|
:src="captcha.url"
|
||||||
@click="setCaptcha"
|
@click="setCaptcha"
|
||||||
|
|
|
@ -33,11 +33,20 @@ const SideDrawer = {
|
||||||
logo () {
|
logo () {
|
||||||
return this.$store.state.instance.logo
|
return this.$store.state.instance.logo
|
||||||
},
|
},
|
||||||
|
hideSitename () {
|
||||||
|
return this.$store.state.instance.hideSitename
|
||||||
|
},
|
||||||
sitename () {
|
sitename () {
|
||||||
return this.$store.state.instance.name
|
return this.$store.state.instance.name
|
||||||
},
|
},
|
||||||
followRequestCount () {
|
followRequestCount () {
|
||||||
return this.$store.state.api.followRequests.length
|
return this.$store.state.api.followRequests.length
|
||||||
|
},
|
||||||
|
privateMode () {
|
||||||
|
return this.$store.state.instance.private
|
||||||
|
},
|
||||||
|
federating () {
|
||||||
|
return this.$store.state.instance.federating
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
class="side-drawer-logo-wrapper"
|
class="side-drawer-logo-wrapper"
|
||||||
>
|
>
|
||||||
<img :src="logo">
|
<img :src="logo">
|
||||||
<span>{{ sitename }}</span>
|
<span v-if="!hideSitename">{{ sitename }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'login' }">
|
<router-link :to="{ name: 'login' }">
|
||||||
{{ $t("login.login") }}
|
<i class="button-icon icon-login" /> {{ $t("login.login") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
||||||
{{ $t("nav.dms") }}
|
<i class="button-icon icon-mail-alt" /> {{ $t("nav.dms") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
|
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
|
||||||
{{ $t("nav.interactions") }}
|
<i class="button-icon icon-bell-alt" /> {{ $t("nav.interactions") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'friends' }">
|
<router-link :to="{ name: 'friends' }">
|
||||||
{{ $t("nav.timeline") }}
|
<i class="button-icon icon-home-2" /> {{ $t("nav.timeline") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link to="/friend-requests">
|
<router-link to="/friend-requests">
|
||||||
{{ $t("nav.friend_requests") }}
|
<i class="button-icon icon-user-plus" /> {{ $t("nav.friend_requests") }}
|
||||||
<span
|
<span
|
||||||
v-if="followRequestCount > 0"
|
v-if="followRequestCount > 0"
|
||||||
class="badge follow-request-count"
|
class="badge follow-request-count"
|
||||||
|
@ -79,14 +79,20 @@
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleDrawer">
|
<li
|
||||||
|
v-if="currentUser || !privateMode"
|
||||||
|
@click="toggleDrawer"
|
||||||
|
>
|
||||||
<router-link to="/main/public">
|
<router-link to="/main/public">
|
||||||
{{ $t("nav.public_tl") }}
|
<i class="button-icon icon-users" /> {{ $t("nav.public_tl") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleDrawer">
|
<li
|
||||||
|
v-if="federating && !privateMode"
|
||||||
|
@click="toggleDrawer"
|
||||||
|
>
|
||||||
<router-link to="/main/all">
|
<router-link to="/main/all">
|
||||||
{{ $t("nav.twkn") }}
|
<i class="button-icon icon-globe" /> {{ $t("nav.twkn") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -94,14 +100,17 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'chat' }">
|
<router-link :to="{ name: 'chat' }">
|
||||||
{{ $t("nav.chat") }}
|
<i class="button-icon icon-chat" /> {{ $t("nav.chat") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ul>
|
<ul>
|
||||||
<li @click="toggleDrawer">
|
<li
|
||||||
|
v-if="currentUser || !privateMode"
|
||||||
|
@click="toggleDrawer"
|
||||||
|
>
|
||||||
<router-link :to="{ name: 'search' }">
|
<router-link :to="{ name: 'search' }">
|
||||||
{{ $t("nav.search") }}
|
<i class="button-icon icon-search" /> {{ $t("nav.search") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -109,17 +118,17 @@
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<router-link :to="{ name: 'who-to-follow' }">
|
<router-link :to="{ name: 'who-to-follow' }">
|
||||||
{{ $t("nav.who_to_follow") }}
|
<i class="button-icon icon-user-plus" /> {{ $t("nav.who_to_follow") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleDrawer">
|
<li @click="toggleDrawer">
|
||||||
<router-link :to="{ name: 'settings' }">
|
<router-link :to="{ name: 'settings' }">
|
||||||
{{ $t("settings.settings") }}
|
<i class="button-icon icon-cog" /> {{ $t("settings.settings") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleDrawer">
|
<li @click="toggleDrawer">
|
||||||
<router-link :to="{ name: 'about'}">
|
<router-link :to="{ name: 'about'}">
|
||||||
{{ $t("nav.about") }}
|
<i class="button-icon icon-info-circled" /> {{ $t("nav.about") }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -130,7 +139,7 @@
|
||||||
href="/pleroma/admin/#/login-pleroma"
|
href="/pleroma/admin/#/login-pleroma"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
{{ $t("nav.administration") }}
|
<i class="button-icon icon-gauge" /> {{ $t("nav.administration") }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
|
@ -141,7 +150,7 @@
|
||||||
href="#"
|
href="#"
|
||||||
@click="doLogout"
|
@click="doLogout"
|
||||||
>
|
>
|
||||||
{{ $t("login.logout") }}
|
<i class="button-icon icon-logout" /> {{ $t("login.logout") }}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -215,6 +224,10 @@
|
||||||
box-shadow: var(--panelShadow);
|
box-shadow: var(--panelShadow);
|
||||||
background-color: $fallback--bg;
|
background-color: $fallback--bg;
|
||||||
background-color: var(--bg, $fallback--bg);
|
background-color: var(--bg, $fallback--bg);
|
||||||
|
|
||||||
|
.button-icon:before {
|
||||||
|
width: 1.1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.side-drawer-logo-wrapper {
|
.side-drawer-logo-wrapper {
|
||||||
|
|
|
@ -36,21 +36,20 @@
|
||||||
|
|
||||||
.sticker-picker {
|
.sticker-picker {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: relative;
|
.contents {
|
||||||
.tab-switcher {
|
min-height: 250px;
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
.sticker-picker-content {
|
.sticker-picker-content {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 0 4px;
|
||||||
.sticker {
|
.sticker {
|
||||||
display: inline-block;
|
display: flex;
|
||||||
width: 20%;
|
flex: 1 1 auto;
|
||||||
height: 20%;
|
margin: 4px;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
img {
|
img {
|
||||||
width: 100%;
|
height: 100%;
|
||||||
&:hover {
|
&:hover {
|
||||||
filter: drop-shadow(0 0 5px var(--link, $fallback--link));
|
filter: drop-shadow(0 0 5px var(--link, $fallback--link));
|
||||||
}
|
}
|
||||||
|
@ -58,5 +57,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -36,7 +36,12 @@ const Timeline = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
timelineError () { return this.$store.state.statuses.error },
|
timelineError () {
|
||||||
|
return this.$store.state.statuses.error
|
||||||
|
},
|
||||||
|
errorData () {
|
||||||
|
return this.$store.state.statuses.errorData
|
||||||
|
},
|
||||||
newStatusCount () {
|
newStatusCount () {
|
||||||
return this.timeline.newStatusCount
|
return this.timeline.newStatusCount
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,15 +11,22 @@
|
||||||
>
|
>
|
||||||
{{ $t('timeline.error_fetching') }}
|
{{ $t('timeline.error_fetching') }}
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-else-if="errorData"
|
||||||
|
class="loadmore-error alert error"
|
||||||
|
@click.prevent
|
||||||
|
>
|
||||||
|
{{ errorData.statusText }}
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
v-if="timeline.newStatusCount > 0 && !timelineError"
|
v-if="timeline.newStatusCount > 0 && !timelineError && !errorData"
|
||||||
class="loadmore-button"
|
class="loadmore-button"
|
||||||
@click.prevent="showNewStatuses"
|
@click.prevent="showNewStatuses"
|
||||||
>
|
>
|
||||||
{{ $t('timeline.show_new') }}{{ newStatusCountStr }}
|
{{ $t('timeline.show_new') }}{{ newStatusCountStr }}
|
||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-if="!timeline.newStatusCount > 0 && !timelineError"
|
v-if="!timeline.newStatusCount > 0 && !timelineError && !errorData"
|
||||||
class="loadmore-text faint"
|
class="loadmore-text faint"
|
||||||
@click.prevent
|
@click.prevent
|
||||||
>
|
>
|
||||||
|
@ -67,12 +74,18 @@
|
||||||
{{ $t('timeline.no_more_statuses') }}
|
{{ $t('timeline.no_more_statuses') }}
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
v-else-if="!timeline.loading"
|
v-else-if="!timeline.loading && !errorData"
|
||||||
href="#"
|
href="#"
|
||||||
@click.prevent="fetchOlderStatuses()"
|
@click.prevent="fetchOlderStatuses()"
|
||||||
>
|
>
|
||||||
<div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div>
|
<div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div>
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
v-else-if="errorData"
|
||||||
|
href="#"
|
||||||
|
>
|
||||||
|
<div class="new-status-notification text-center panel-footer">{{ errorData.error }}</div>
|
||||||
|
</a>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="new-status-notification text-center panel-footer"
|
class="new-status-notification text-center panel-footer"
|
||||||
|
@ -93,17 +106,4 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-status-notification {
|
|
||||||
position:relative;
|
|
||||||
margin-top: -1px;
|
|
||||||
font-size: 1.1em;
|
|
||||||
border-width: 1px 0 0 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: var(--border, $fallback--border);
|
|
||||||
padding: 10px;
|
|
||||||
z-index: 1;
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--panel, $fallback--fg);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -65,7 +65,7 @@ const withLoadMore = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render (createElement) {
|
render (h) {
|
||||||
const props = {
|
const props = {
|
||||||
props: {
|
props: {
|
||||||
...this.$props,
|
...this.$props,
|
||||||
|
@ -74,7 +74,7 @@ const withLoadMore = ({
|
||||||
on: this.$listeners,
|
on: this.$listeners,
|
||||||
scopedSlots: this.$scopedSlots
|
scopedSlots: this.$scopedSlots
|
||||||
}
|
}
|
||||||
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
|
const children = Object.entries(this.$slots).map(([key, value]) => h('template', { slot: key }, value))
|
||||||
return (
|
return (
|
||||||
<div class="with-load-more">
|
<div class="with-load-more">
|
||||||
<WrappedComponent {...props}>
|
<WrappedComponent {...props}>
|
||||||
|
|
|
@ -49,7 +49,7 @@ const withSubscription = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
render (createElement) {
|
render (h) {
|
||||||
if (!this.error && !this.loading) {
|
if (!this.error && !this.loading) {
|
||||||
const props = {
|
const props = {
|
||||||
props: {
|
props: {
|
||||||
|
@ -59,7 +59,7 @@ const withSubscription = ({
|
||||||
on: this.$listeners,
|
on: this.$listeners,
|
||||||
scopedSlots: this.$scopedSlots
|
scopedSlots: this.$scopedSlots
|
||||||
}
|
}
|
||||||
const children = Object.entries(this.$slots).map(([key, value]) => createElement('template', { slot: key }, value))
|
const children = Object.entries(this.$slots).map(([key, value]) => h('template', { slot: key }, value))
|
||||||
return (
|
return (
|
||||||
<div class="with-subscription">
|
<div class="with-subscription">
|
||||||
<WrappedComponent {...props}>
|
<WrappedComponent {...props}>
|
||||||
|
|
|
@ -1,4 +1,23 @@
|
||||||
{
|
{
|
||||||
|
"about": {
|
||||||
|
"staff": "スタッフ",
|
||||||
|
"federation": "フェデレーション",
|
||||||
|
"mrf_policies": "ゆうこうなMRFポリシー",
|
||||||
|
"mrf_policies_desc": "MRFポリシーは、このインスタンスのフェデレーションのふるまいを、いじります。これらのMRFポリシーがゆうこうになっています:",
|
||||||
|
"mrf_policy_simple": "インスタンスのポリシー",
|
||||||
|
"mrf_policy_simple_accept": "うけいれ",
|
||||||
|
"mrf_policy_simple_accept_desc": "このインスンスは、これらのインスタンスからのメッセージのみをうけいれます:",
|
||||||
|
"mrf_policy_simple_reject": "おことわり",
|
||||||
|
"mrf_policy_simple_reject_desc": "このインスタンスは、これらのインスタンスからのメッセージをうけいれません:",
|
||||||
|
"mrf_policy_simple_quarantine": "けんえき",
|
||||||
|
"mrf_policy_simple_quarantine_desc": "このインスタンスは、これらのインスタンスに、パブリックなとうこうのみを、おくります:",
|
||||||
|
"mrf_policy_simple_ftl_removal": "「つながっているすべてのネットワーク」タイムラインからのぞく",
|
||||||
|
"mrf_policy_simple_ftl_removal_desc": "このインスタンスは、つながっているすべてのネットワーク」タイムラインから、これらのインスタンスを、とりのぞきます:",
|
||||||
|
"mrf_policy_simple_media_removal": "メディアをのぞく",
|
||||||
|
"mrf_policy_simple_media_removal_desc": "このインスタンスは、これらのインスタンスからおくられてきたメディアを、とりのぞきます:",
|
||||||
|
"mrf_policy_simple_media_nsfw": "メディアをすべてセンシティブにする",
|
||||||
|
"mrf_policy_simple_media_nsfw_desc": "このインスタンスは、これらのインスタンスからおくられてきたメディアを、すべて、センシティブにマークします:"
|
||||||
|
},
|
||||||
"chat": {
|
"chat": {
|
||||||
"title": "チャット"
|
"title": "チャット"
|
||||||
},
|
},
|
||||||
|
@ -68,6 +87,7 @@
|
||||||
},
|
},
|
||||||
"nav": {
|
"nav": {
|
||||||
"about": "これはなに?",
|
"about": "これはなに?",
|
||||||
|
"administration": "アドミニストレーション",
|
||||||
"back": "もどる",
|
"back": "もどる",
|
||||||
"chat": "ローカルチャット",
|
"chat": "ローカルチャット",
|
||||||
"friend_requests": "フォローリクエスト",
|
"friend_requests": "フォローリクエスト",
|
||||||
|
@ -113,7 +133,9 @@
|
||||||
"search_emoji": "えもじをさがす",
|
"search_emoji": "えもじをさがす",
|
||||||
"add_emoji": "えもじをうちこむ",
|
"add_emoji": "えもじをうちこむ",
|
||||||
"custom": "カスタムえもじ",
|
"custom": "カスタムえもじ",
|
||||||
"unicode": "ユニコードえもじ"
|
"unicode": "ユニコードえもじ",
|
||||||
|
"load_all_hint": "はじめの {saneAmount} このえもじだけがロードされています。すべてのえもじをロードすると、パフォーマンスがわるくなるかもしれません。",
|
||||||
|
"load_all": "すべてのえもじをロード ({emojiAmount} こあります)"
|
||||||
},
|
},
|
||||||
"stickers": {
|
"stickers": {
|
||||||
"add_sticker": "ステッカーをふやす"
|
"add_sticker": "ステッカーをふやす"
|
||||||
|
@ -173,6 +195,11 @@
|
||||||
"password_confirmation_match": "パスワードがちがいます"
|
"password_confirmation_match": "パスワードがちがいます"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"remote_user_resolver": {
|
||||||
|
"remote_user_resolver": "リモートユーザーリゾルバー",
|
||||||
|
"searching_for": "さがしています:",
|
||||||
|
"error": "みつかりませんでした。"
|
||||||
|
},
|
||||||
"selectable_list": {
|
"selectable_list": {
|
||||||
"select_all": "すべてえらぶ"
|
"select_all": "すべてえらぶ"
|
||||||
},
|
},
|
||||||
|
@ -220,6 +247,9 @@
|
||||||
"cGreen": "リピート",
|
"cGreen": "リピート",
|
||||||
"cOrange": "おきにいり",
|
"cOrange": "おきにいり",
|
||||||
"cRed": "キャンセル",
|
"cRed": "キャンセル",
|
||||||
|
"change_email": "メールアドレスをかえる",
|
||||||
|
"change_email_error": "メールアドレスをかえようとしましたが、なにかがおかしいです。",
|
||||||
|
"changed_email": "メールアドレスをかえることができました!",
|
||||||
"change_password": "パスワードをかえる",
|
"change_password": "パスワードをかえる",
|
||||||
"change_password_error": "パスワードをかえることが、できなかったかもしれません。",
|
"change_password_error": "パスワードをかえることが、できなかったかもしれません。",
|
||||||
"changed_password": "パスワードが、かわりました!",
|
"changed_password": "パスワードが、かわりました!",
|
||||||
|
@ -279,6 +309,7 @@
|
||||||
"use_contain_fit": "がぞうのサムネイルを、きりぬかない",
|
"use_contain_fit": "がぞうのサムネイルを、きりぬかない",
|
||||||
"name": "なまえ",
|
"name": "なまえ",
|
||||||
"name_bio": "なまえとプロフィール",
|
"name_bio": "なまえとプロフィール",
|
||||||
|
"new_email": "あたらしいメールアドレス",
|
||||||
"new_password": "あたらしいパスワード",
|
"new_password": "あたらしいパスワード",
|
||||||
"notification_visibility": "ひょうじするつうち",
|
"notification_visibility": "ひょうじするつうち",
|
||||||
"notification_visibility_follows": "フォロー",
|
"notification_visibility_follows": "フォロー",
|
||||||
|
@ -344,6 +375,8 @@
|
||||||
"false": "いいえ",
|
"false": "いいえ",
|
||||||
"true": "はい"
|
"true": "はい"
|
||||||
},
|
},
|
||||||
|
"fun": "おたのしみ",
|
||||||
|
"greentext": "ミームやじるし",
|
||||||
"notifications": "つうち",
|
"notifications": "つうち",
|
||||||
"notification_setting": "つうちをうけとる:",
|
"notification_setting": "つうちをうけとる:",
|
||||||
"notification_setting_follows": "あなたがフォローしているひとから",
|
"notification_setting_follows": "あなたがフォローしているひとから",
|
||||||
|
@ -391,6 +424,7 @@
|
||||||
"_tab_label": "くわしく",
|
"_tab_label": "くわしく",
|
||||||
"alert": "アラートのバックグラウンド",
|
"alert": "アラートのバックグラウンド",
|
||||||
"alert_error": "エラー",
|
"alert_error": "エラー",
|
||||||
|
"alert_warning": "けいこく",
|
||||||
"badge": "バッジのバックグラウンド",
|
"badge": "バッジのバックグラウンド",
|
||||||
"badge_notification": "つうち",
|
"badge_notification": "つうち",
|
||||||
"panel_header": "パネルヘッダー",
|
"panel_header": "パネルヘッダー",
|
||||||
|
@ -542,6 +576,7 @@
|
||||||
"followers": "フォロワー",
|
"followers": "フォロワー",
|
||||||
"following": "フォローしています!",
|
"following": "フォローしています!",
|
||||||
"follows_you": "フォローされました!",
|
"follows_you": "フォローされました!",
|
||||||
|
"hidden": "かくされています",
|
||||||
"its_you": "これはあなたです!",
|
"its_you": "これはあなたです!",
|
||||||
"media": "メディア",
|
"media": "メディア",
|
||||||
"mention": "メンション",
|
"mention": "メンション",
|
||||||
|
@ -559,6 +594,8 @@
|
||||||
"unmute": "ミュートをやめる",
|
"unmute": "ミュートをやめる",
|
||||||
"unmute_progress": "ミュートをとりけしています...",
|
"unmute_progress": "ミュートをとりけしています...",
|
||||||
"mute_progress": "ミュートしています...",
|
"mute_progress": "ミュートしています...",
|
||||||
|
"hide_repeats": "リピートをかくす",
|
||||||
|
"show_repeats": "リピートをみる",
|
||||||
"admin_menu": {
|
"admin_menu": {
|
||||||
"moderation": "モデレーション",
|
"moderation": "モデレーション",
|
||||||
"grant_admin": "アドミンにする",
|
"grant_admin": "アドミンにする",
|
||||||
|
@ -634,6 +671,8 @@
|
||||||
"return_home": "ホームページにもどる",
|
"return_home": "ホームページにもどる",
|
||||||
"not_found": "そのメールアドレスまたはユーザーめいを、みつけることができませんでした。",
|
"not_found": "そのメールアドレスまたはユーザーめいを、みつけることができませんでした。",
|
||||||
"too_many_requests": "パスワードリセットを、ためすことが、おおすぎます。しばらくしてから、ためしてください。",
|
"too_many_requests": "パスワードリセットを、ためすことが、おおすぎます。しばらくしてから、ためしてください。",
|
||||||
"password_reset_disabled": "このインスタンスでは、パスワードリセットは、できません。インスタンスのアドミニストレーターに、おといあわせください。"
|
"password_reset_disabled": "このインスタンスでは、パスワードリセットは、できません。インスタンスのアドミニストレーターに、おといあわせください。",
|
||||||
|
"password_reset_required": "ログインするには、パスワードをリセットしてください。",
|
||||||
|
"password_reset_required_but_mailer_is_disabled": "あなたはパスワードのリセットがひつようです。しかし、まずいことに、このインスタンスでは、パスワードのリセットができなくなっています。このインスタンスのアドミニストレーターに、おといあわせください。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ const RECOVERY_STRATEGY = 'recovery'
|
||||||
|
|
||||||
// initial state
|
// initial state
|
||||||
const state = {
|
const state = {
|
||||||
app: null,
|
|
||||||
settings: {},
|
settings: {},
|
||||||
strategy: PASSWORD_STRATEGY,
|
strategy: PASSWORD_STRATEGY,
|
||||||
initStrategy: PASSWORD_STRATEGY // default strategy from config
|
initStrategy: PASSWORD_STRATEGY // default strategy from config
|
||||||
|
@ -16,14 +15,10 @@ const state = {
|
||||||
const resetState = (state) => {
|
const resetState = (state) => {
|
||||||
state.strategy = state.initStrategy
|
state.strategy = state.initStrategy
|
||||||
state.settings = {}
|
state.settings = {}
|
||||||
state.app = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getters
|
// getters
|
||||||
const getters = {
|
const getters = {
|
||||||
app: (state, getters) => {
|
|
||||||
return state.app
|
|
||||||
},
|
|
||||||
settings: (state, getters) => {
|
settings: (state, getters) => {
|
||||||
return state.settings
|
return state.settings
|
||||||
},
|
},
|
||||||
|
@ -55,9 +50,8 @@ const mutations = {
|
||||||
requireToken (state) {
|
requireToken (state) {
|
||||||
state.strategy = TOKEN_STRATEGY
|
state.strategy = TOKEN_STRATEGY
|
||||||
},
|
},
|
||||||
requireMFA (state, { app, settings }) {
|
requireMFA (state, { settings }) {
|
||||||
state.settings = settings
|
state.settings = settings
|
||||||
state.app = app
|
|
||||||
state.strategy = TOTP_STRATEGY // default strategy of MFA
|
state.strategy = TOTP_STRATEGY // default strategy of MFA
|
||||||
},
|
},
|
||||||
requireRecovery (state) {
|
requireRecovery (state) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ const defaultState = {
|
||||||
scopeCopy: true,
|
scopeCopy: true,
|
||||||
subjectLineBehavior: 'email',
|
subjectLineBehavior: 'email',
|
||||||
postContentType: 'text/plain',
|
postContentType: 'text/plain',
|
||||||
|
hideSitename: false,
|
||||||
nsfwCensorImage: undefined,
|
nsfwCensorImage: undefined,
|
||||||
vapidPublicKey: undefined,
|
vapidPublicKey: undefined,
|
||||||
noAttachmentLinks: false,
|
noAttachmentLinks: false,
|
||||||
|
|
|
@ -38,6 +38,7 @@ export const defaultState = () => ({
|
||||||
notifications: emptyNotifications(),
|
notifications: emptyNotifications(),
|
||||||
favorites: new Set(),
|
favorites: new Set(),
|
||||||
error: false,
|
error: false,
|
||||||
|
errorData: null,
|
||||||
timelines: {
|
timelines: {
|
||||||
mentions: emptyTl(),
|
mentions: emptyTl(),
|
||||||
public: emptyTl(),
|
public: emptyTl(),
|
||||||
|
@ -479,6 +480,9 @@ export const mutations = {
|
||||||
setError (state, { value }) {
|
setError (state, { value }) {
|
||||||
state.error = value
|
state.error = value
|
||||||
},
|
},
|
||||||
|
setErrorData (state, { value }) {
|
||||||
|
state.errorData = value
|
||||||
|
},
|
||||||
setNotificationsLoading (state, { value }) {
|
setNotificationsLoading (state, { value }) {
|
||||||
state.notifications.loading = value
|
state.notifications.loading = value
|
||||||
},
|
},
|
||||||
|
@ -528,6 +532,9 @@ const statuses = {
|
||||||
setError ({ rootState, commit }, { value }) {
|
setError ({ rootState, commit }, { value }) {
|
||||||
commit('setError', { value })
|
commit('setError', { value })
|
||||||
},
|
},
|
||||||
|
setErrorData ({ rootState, commit }, { value }) {
|
||||||
|
commit('setErrorData', { value })
|
||||||
|
},
|
||||||
setNotificationsLoading ({ rootState, commit }, { value }) {
|
setNotificationsLoading ({ rootState, commit }, { value }) {
|
||||||
commit('setNotificationsLoading', { value })
|
commit('setNotificationsLoading', { value })
|
||||||
},
|
},
|
||||||
|
|
|
@ -95,9 +95,9 @@ export const mutations = {
|
||||||
newRights[right] = value
|
newRights[right] = value
|
||||||
set(user, 'rights', newRights)
|
set(user, 'rights', newRights)
|
||||||
},
|
},
|
||||||
updateActivationStatus (state, { user: { id }, status }) {
|
updateActivationStatus (state, { user: { id }, deactivated }) {
|
||||||
const user = state.usersObject[id]
|
const user = state.usersObject[id]
|
||||||
set(user, 'deactivated', !status)
|
set(user, 'deactivated', deactivated)
|
||||||
},
|
},
|
||||||
setCurrentUser (state, user) {
|
setCurrentUser (state, user) {
|
||||||
state.lastLoginName = user.screen_name
|
state.lastLoginName = user.screen_name
|
||||||
|
@ -331,6 +331,11 @@ const users = {
|
||||||
return rootState.api.backendInteractor.unsubscribeUser({ id })
|
return rootState.api.backendInteractor.unsubscribeUser({ id })
|
||||||
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
||||||
},
|
},
|
||||||
|
toggleActivationStatus ({ rootState, commit }, user) {
|
||||||
|
const api = user.deactivated ? rootState.api.backendInteractor.activateUser : rootState.api.backendInteractor.deactivateUser
|
||||||
|
api(user)
|
||||||
|
.then(({ deactivated }) => commit('updateActivationStatus', { user, deactivated }))
|
||||||
|
},
|
||||||
registerPushNotifications (store) {
|
registerPushNotifications (store) {
|
||||||
const token = store.state.currentUser.credentials
|
const token = store.state.currentUser.credentials
|
||||||
const vapidPublicKey = store.rootState.instance.vapidPublicKey
|
const vapidPublicKey = store.rootState.instance.vapidPublicKey
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { each, map, concat, last } from 'lodash'
|
import { each, map, concat, last, get } from 'lodash'
|
||||||
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
|
import { parseStatus, parseUser, parseNotification, parseAttachment } from '../entity_normalizer/entity_normalizer.service.js'
|
||||||
import 'whatwg-fetch'
|
import 'whatwg-fetch'
|
||||||
import { RegistrationError, StatusCodeError } from '../errors/errors'
|
import { RegistrationError, StatusCodeError } from '../errors/errors'
|
||||||
|
@ -12,7 +12,8 @@ const CHANGE_EMAIL_URL = '/api/pleroma/change_email'
|
||||||
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
|
||||||
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
const TAG_USER_URL = '/api/pleroma/admin/users/tag'
|
||||||
const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
|
const PERMISSION_GROUP_URL = (screenName, right) => `/api/pleroma/admin/users/${screenName}/permission_group/${right}`
|
||||||
const ACTIVATION_STATUS_URL = screenName => `/api/pleroma/admin/users/${screenName}/activation_status`
|
const ACTIVATE_USER_URL = '/api/pleroma/admin/users/activate'
|
||||||
|
const DEACTIVATE_USER_URL = '/api/pleroma/admin/users/deactivate'
|
||||||
const ADMIN_USERS_URL = '/api/pleroma/admin/users'
|
const ADMIN_USERS_URL = '/api/pleroma/admin/users'
|
||||||
const SUGGESTIONS_URL = '/api/v1/suggestions'
|
const SUGGESTIONS_URL = '/api/v1/suggestions'
|
||||||
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
const NOTIFICATION_SETTINGS_URL = '/api/pleroma/notification_settings'
|
||||||
|
@ -22,7 +23,7 @@ const MFA_BACKUP_CODES_URL = '/api/pleroma/accounts/mfa/backup_codes'
|
||||||
|
|
||||||
const MFA_SETUP_OTP_URL = '/api/pleroma/accounts/mfa/setup/totp'
|
const MFA_SETUP_OTP_URL = '/api/pleroma/accounts/mfa/setup/totp'
|
||||||
const MFA_CONFIRM_OTP_URL = '/api/pleroma/accounts/mfa/confirm/totp'
|
const MFA_CONFIRM_OTP_URL = '/api/pleroma/accounts/mfa/confirm/totp'
|
||||||
const MFA_DISABLE_OTP_URL = '/api/pleroma/account/mfa/totp'
|
const MFA_DISABLE_OTP_URL = '/api/pleroma/accounts/mfa/totp'
|
||||||
|
|
||||||
const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
|
const MASTODON_LOGIN_URL = '/api/v1/accounts/verify_credentials'
|
||||||
const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
|
const MASTODON_REGISTRATION_URL = '/api/v1/accounts'
|
||||||
|
@ -451,20 +452,26 @@ const deleteRight = ({ right, credentials, ...user }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const setActivationStatus = ({ status, credentials, ...user }) => {
|
const activateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
||||||
const screenName = user.screen_name
|
return promisedRequest({
|
||||||
const body = {
|
url: ACTIVATE_USER_URL,
|
||||||
status: status
|
method: 'PATCH',
|
||||||
|
credentials,
|
||||||
|
payload: {
|
||||||
|
nicknames: [nickname]
|
||||||
|
}
|
||||||
|
}).then(response => get(response, 'users.0'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = authHeaders(credentials)
|
const deactivateUser = ({ credentials, user: { screen_name: nickname } }) => {
|
||||||
headers['Content-Type'] = 'application/json'
|
return promisedRequest({
|
||||||
|
url: DEACTIVATE_USER_URL,
|
||||||
return fetch(ACTIVATION_STATUS_URL(screenName), {
|
method: 'PATCH',
|
||||||
method: 'PUT',
|
credentials,
|
||||||
headers: headers,
|
payload: {
|
||||||
body: JSON.stringify(body)
|
nicknames: [nickname]
|
||||||
})
|
}
|
||||||
|
}).then(response => get(response, 'users.0'))
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteUser = ({ credentials, ...user }) => {
|
const deleteUser = ({ credentials, ...user }) => {
|
||||||
|
@ -530,16 +537,24 @@ const fetchTimeline = ({
|
||||||
|
|
||||||
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
|
const queryString = map(params, (param) => `${param[0]}=${param[1]}`).join('&')
|
||||||
url += `?${queryString}`
|
url += `?${queryString}`
|
||||||
|
let status = ''
|
||||||
|
let statusText = ''
|
||||||
return fetch(url, { headers: authHeaders(credentials) })
|
return fetch(url, { headers: authHeaders(credentials) })
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.ok) {
|
status = data.status
|
||||||
|
statusText = data.statusText
|
||||||
return data
|
return data
|
||||||
}
|
|
||||||
throw new Error('Error fetching timeline', data)
|
|
||||||
})
|
})
|
||||||
.then((data) => data.json())
|
.then((data) => data.json())
|
||||||
.then((data) => data.map(isNotifications ? parseNotification : parseStatus))
|
.then((data) => {
|
||||||
|
if (!data.error) {
|
||||||
|
return data.map(isNotifications ? parseNotification : parseStatus)
|
||||||
|
} else {
|
||||||
|
data.status = status
|
||||||
|
data.statusText = statusText
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchPinnedStatuses = ({ id, credentials }) => {
|
const fetchPinnedStatuses = ({ id, credentials }) => {
|
||||||
|
@ -1065,7 +1080,8 @@ const apiService = {
|
||||||
deleteUser,
|
deleteUser,
|
||||||
addRight,
|
addRight,
|
||||||
deleteRight,
|
deleteRight,
|
||||||
setActivationStatus,
|
activateUser,
|
||||||
|
deactivateUser,
|
||||||
register,
|
register,
|
||||||
getCaptcha,
|
getCaptcha,
|
||||||
updateAvatar,
|
updateAvatar,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
const verifyOTPCode = ({ app, instance, mfaToken, code }) => {
|
const verifyOTPCode = ({ clientId, clientSecret, instance, mfaToken, code }) => {
|
||||||
const url = `${instance}/oauth/mfa/challenge`
|
const url = `${instance}/oauth/mfa/challenge`
|
||||||
const form = new window.FormData()
|
const form = new window.FormData()
|
||||||
|
|
||||||
form.append('client_id', app.client_id)
|
form.append('client_id', clientId)
|
||||||
form.append('client_secret', app.client_secret)
|
form.append('client_secret', clientSecret)
|
||||||
form.append('mfa_token', mfaToken)
|
form.append('mfa_token', mfaToken)
|
||||||
form.append('code', code)
|
form.append('code', code)
|
||||||
form.append('challenge_type', 'totp')
|
form.append('challenge_type', 'totp')
|
||||||
|
@ -14,12 +14,12 @@ const verifyOTPCode = ({ app, instance, mfaToken, code }) => {
|
||||||
}).then((data) => data.json())
|
}).then((data) => data.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
const verifyRecoveryCode = ({ app, instance, mfaToken, code }) => {
|
const verifyRecoveryCode = ({ clientId, clientSecret, instance, mfaToken, code }) => {
|
||||||
const url = `${instance}/oauth/mfa/challenge`
|
const url = `${instance}/oauth/mfa/challenge`
|
||||||
const form = new window.FormData()
|
const form = new window.FormData()
|
||||||
|
|
||||||
form.append('client_id', app.client_id)
|
form.append('client_id', clientId)
|
||||||
form.append('client_secret', app.client_secret)
|
form.append('client_secret', clientSecret)
|
||||||
form.append('mfa_token', mfaToken)
|
form.append('mfa_token', mfaToken)
|
||||||
form.append('code', code)
|
form.append('code', code)
|
||||||
form.append('challenge_type', 'recovery')
|
form.append('challenge_type', 'recovery')
|
||||||
|
|
|
@ -12,7 +12,7 @@ export const getOrCreateApp = ({ clientId, clientSecret, instance, commit }) =>
|
||||||
|
|
||||||
form.append('client_name', `PleromaFE_${window.___pleromafe_commit_hash}_${(new Date()).toISOString()}`)
|
form.append('client_name', `PleromaFE_${window.___pleromafe_commit_hash}_${(new Date()).toISOString()}`)
|
||||||
form.append('redirect_uris', REDIRECT_URI)
|
form.append('redirect_uris', REDIRECT_URI)
|
||||||
form.append('scopes', 'read write follow')
|
form.append('scopes', 'read write follow push admin')
|
||||||
|
|
||||||
return window.fetch(url, {
|
return window.fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -28,7 +28,7 @@ const login = ({ instance, clientId }) => {
|
||||||
response_type: 'code',
|
response_type: 'code',
|
||||||
client_id: clientId,
|
client_id: clientId,
|
||||||
redirect_uri: REDIRECT_URI,
|
redirect_uri: REDIRECT_URI,
|
||||||
scope: 'read write follow'
|
scope: 'read write follow push admin'
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataString = reduce(data, (acc, v, k) => {
|
const dataString = reduce(data, (acc, v, k) => {
|
||||||
|
|
|
@ -6,6 +6,7 @@ const update = ({ store, statuses, timeline, showImmediately, userId }) => {
|
||||||
const ccTimeline = camelCase(timeline)
|
const ccTimeline = camelCase(timeline)
|
||||||
|
|
||||||
store.dispatch('setError', { value: false })
|
store.dispatch('setError', { value: false })
|
||||||
|
store.dispatch('setErrorData', { value: null })
|
||||||
|
|
||||||
store.dispatch('addNewStatuses', {
|
store.dispatch('addNewStatuses', {
|
||||||
timeline: ccTimeline,
|
timeline: ccTimeline,
|
||||||
|
@ -45,6 +46,10 @@ const fetchAndUpdate = ({
|
||||||
|
|
||||||
return apiService.fetchTimeline(args)
|
return apiService.fetchTimeline(args)
|
||||||
.then((statuses) => {
|
.then((statuses) => {
|
||||||
|
if (statuses.error) {
|
||||||
|
store.dispatch('setErrorData', { value: statuses })
|
||||||
|
return
|
||||||
|
}
|
||||||
if (!older && statuses.length >= 20 && !timelineData.loading && numStatusesBeforeFetch > 0) {
|
if (!older && statuses.length >= 20 && !timelineData.loading && numStatusesBeforeFetch > 0) {
|
||||||
store.dispatch('queueFlush', { timeline: timeline, id: timelineData.maxId })
|
store.dispatch('queueFlush', { timeline: timeline, id: timelineData.maxId })
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,6 +303,36 @@
|
||||||
"css": "gauge",
|
"css": "gauge",
|
||||||
"code": 61668,
|
"code": 61668,
|
||||||
"src": "fontawesome"
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "31972e4e9d080eaa796290349ae6c1fd",
|
||||||
|
"css": "users",
|
||||||
|
"code": 59421,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "e82cedfa1d5f15b00c5a81c9bd731ea2",
|
||||||
|
"css": "info-circled",
|
||||||
|
"code": 59423,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "w3nzesrlbezu6f30q7ytyq919p6gdlb6",
|
||||||
|
"css": "home-2",
|
||||||
|
"code": 59425,
|
||||||
|
"src": "typicons"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "dcedf50ab1ede3283d7a6c70e2fe32f3",
|
||||||
|
"css": "chat",
|
||||||
|
"code": 59422,
|
||||||
|
"src": "fontawesome"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "3a00327e61b997b58518bd43ed83c3df",
|
||||||
|
"css": "login",
|
||||||
|
"code": 59424,
|
||||||
|
"src": "fontawesome"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
require('babel-register')
|
require('@babel/register')
|
||||||
var config = require('../../config')
|
var config = require('../../config')
|
||||||
|
|
||||||
// http://nightwatchjs.org/guide#settings-file
|
// http://nightwatchjs.org/guide#settings-file
|
||||||
|
|
Loading…
Reference in a new issue