Merge branch 'develop' into 'notifications'

# Conflicts:
#   src/main.js
This commit is contained in:
kaniini 2018-08-24 23:00:56 +00:00
commit fe906cc3f0
16 changed files with 224 additions and 101 deletions

View file

@ -29,7 +29,7 @@ export default {
style () { return { 'background-image': `url(${this.background})` } }, style () { return { 'background-image': `url(${this.background})` } },
sitename () { return this.$store.state.config.name }, sitename () { return this.$store.state.config.name },
chat () { return this.$store.state.chat.channel.state === 'joined' }, chat () { return this.$store.state.chat.channel.state === 'joined' },
showWhoToFollowPanel () { return this.$store.state.config.showWhoToFollowPanel }, suggestionsEnabled () { return this.$store.state.config.suggestionsEnabled },
showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel } showInstanceSpecificPanel () { return this.$store.state.config.showInstanceSpecificPanel }
}, },
methods: { methods: {

View file

@ -63,8 +63,6 @@ button{
box-shadow: 0px 0px 2px black; box-shadow: 0px 0px 2px black;
font-size: 14px; font-size: 14px;
font-family: sans-serif; font-family: sans-serif;
min-width: 10em;
min-height: 2em;
&:hover { &:hover {
box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3); box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3);

View file

@ -24,7 +24,7 @@
<user-panel></user-panel> <user-panel></user-panel>
<nav-panel></nav-panel> <nav-panel></nav-panel>
<instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel> <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
<who-to-follow-panel v-if="currentUser && showWhoToFollowPanel"></who-to-follow-panel> <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
<notifications v-if="currentUser"></notifications> <notifications v-if="currentUser"></notifications>
</div> </div>
</div> </div>

View file

@ -34,6 +34,11 @@
@import '../../_variables.scss'; @import '../../_variables.scss';
.login-form { .login-form {
.btn {
min-height: 28px;
width: 10em;
}
.error { .error {
text-align: center; text-align: center;
} }

View file

@ -107,6 +107,10 @@
padding: 0.5em; padding: 0.5em;
height: 32px; height: 32px;
button {
width: 10em;
}
p { p {
margin: 0.35em; margin: 0.35em;
padding: 0.35em; padding: 0.35em;

View file

@ -8,6 +8,7 @@ const settings = {
hideAttachmentsLocal: this.$store.state.config.hideAttachments, hideAttachmentsLocal: this.$store.state.config.hideAttachments,
hideAttachmentsInConvLocal: this.$store.state.config.hideAttachmentsInConv, hideAttachmentsInConvLocal: this.$store.state.config.hideAttachmentsInConv,
hideNsfwLocal: this.$store.state.config.hideNsfw, hideNsfwLocal: this.$store.state.config.hideNsfw,
replyVisibilityLocal: this.$store.state.config.replyVisibility,
loopVideoLocal: this.$store.state.config.loopVideo, loopVideoLocal: this.$store.state.config.loopVideo,
loopVideoSilentOnlyLocal: this.$store.state.config.loopVideoSilentOnly, loopVideoSilentOnlyLocal: this.$store.state.config.loopVideoSilentOnly,
muteWordsString: this.$store.state.config.muteWords.join('\n'), muteWordsString: this.$store.state.config.muteWords.join('\n'),
@ -44,6 +45,9 @@ const settings = {
hideNsfwLocal (value) { hideNsfwLocal (value) {
this.$store.dispatch('setOption', { name: 'hideNsfw', value }) this.$store.dispatch('setOption', { name: 'hideNsfw', value })
}, },
replyVisibilityLocal (value) {
this.$store.dispatch('setOption', { name: 'replyVisibility', value })
},
loopVideoLocal (value) { loopVideoLocal (value) {
this.$store.dispatch('setOption', { name: 'loopVideo', value }) this.$store.dispatch('setOption', { name: 'loopVideo', value })
}, },

View file

@ -38,6 +38,16 @@
<input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal"> <input type="checkbox" id="hoverPreview" v-model="hoverPreviewLocal">
<label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label> <label for="hoverPreview">{{$t('settings.reply_link_preview')}}</label>
</li> </li>
<li>
<label for="replyVisibility" class="select">
<select id="replyVisibility" v-model="replyVisibilityLocal">
<option value="all" selected>{{$t('settings.reply_visibility_all')}}</option>
<option value="following">{{$t('settings.reply_visibility_following')}}</option>
<option value="self">{{$t('settings.reply_visibility_self')}}</option>
</select>
<i class="icon-down-open"/>
</label>
</li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-item">
@ -117,6 +127,8 @@
.btn { .btn {
margin-top: 1em; margin-top: 1em;
min-height: 28px;
width: 10em;
} }
} }
.setting-list { .setting-list {

View file

@ -83,7 +83,6 @@ const Status = {
return hits return hits
}, },
muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) }, muted () { return !this.unmuted && (this.status.user.muted || this.muteWordHits.length > 0) },
isReply () { return !!this.status.in_reply_to_status_id },
isFocused () { isFocused () {
// retweet or root of an expanded conversation // retweet or root of an expanded conversation
if (this.focused) { if (this.focused) {
@ -105,6 +104,48 @@ const Status = {
const lengthScore = this.status.statusnet_html.split(/<p|<br/).length + this.status.text.length / 80 const lengthScore = this.status.statusnet_html.split(/<p|<br/).length + this.status.text.length / 80
return lengthScore > 20 return lengthScore > 20
}, },
isReply () {
if (this.status.in_reply_to_status_id) {
return true
}
// For private replies where we can't see the OP, in_reply_to_status_id will be null.
// So instead, check that the post starts with a @mention.
if (this.status.visibility === 'private') {
var textBody = this.status.text
if (this.status.summary !== null) {
textBody = textBody.substring(this.status.summary.length, textBody.length)
}
return textBody.startsWith('@')
}
return false
},
hideReply () {
if (this.$store.state.config.replyVisibility === 'all') {
return false
}
if (this.inlineExpanded || this.expanded || this.inConversation || !this.isReply) {
return false
}
if (this.status.user.id === this.$store.state.users.currentUser.id) {
return false
}
if (this.status.activity_type === 'repeat') {
return false
}
var checkFollowing = this.$store.state.config.replyVisibility === 'following'
for (var i = 0; i < this.status.attentions.length; ++i) {
if (this.status.user.id === this.status.attentions[i].id) {
continue
}
if (checkFollowing && this.status.attentions[i].following) {
return false
}
if (this.status.attentions[i].id === this.$store.state.users.currentUser.id) {
return false
}
}
return this.status.attentions.length > 0
},
hideSubjectStatus () { hideSubjectStatus () {
if (this.tallStatus && !this.$store.state.config.collapseMessageWithSubject) { if (this.tallStatus && !this.$store.state.config.collapseMessageWithSubject) {
return false return false

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="status-el" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]"> <div class="status-el" v-if="!hideReply" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]">
<template v-if="muted && !noReplyLinks"> <template v-if="muted && !noReplyLinks">
<div class="media status container muted"> <div class="media status container muted">
<small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small> <small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small>

View file

@ -105,8 +105,8 @@
<span>{{user.followers_count}}</span> <span>{{user.followers_count}}</span>
</div> </div>
</div> </div>
<p v-if="!hideBio && user.description_html" v-html="user.description_html"></p> <p v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
<p v-else-if="!hideBio">{{ user.description }}</p> <p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
</div> </div>
</div> </div>
</template> </template>
@ -130,7 +130,11 @@
.profile-panel-body { .profile-panel-body {
word-wrap: break-word; word-wrap: break-word;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%);
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%) background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%);
.profile-bio {
text-align: center;
}
} }
.user-info { .user-info {

View file

@ -1,5 +1,7 @@
function showWhoToFollow (panel, reply, aHost, aUser) { import apiService from '../../services/api/api.service.js'
var users = reply.ids
function showWhoToFollow (panel, reply) {
var users = reply
var cn var cn
var index = 0 var index = 0
var random = Math.floor(Math.random() * 10) var random = Math.floor(Math.random() * 10)
@ -7,12 +9,12 @@ function showWhoToFollow (panel, reply, aHost, aUser) {
var user var user
user = users[cn] user = users[cn]
var img var img
if (user.icon) { if (user.avatar) {
img = user.icon img = user.avatar
} else { } else {
img = '/images/avi.png' img = '/images/avi.png'
} }
var name = user.to_id var name = user.acct
if (index === 0) { if (index === 0) {
panel.img1 = img panel.img1 = img
panel.name1 = name panel.name1 = name
@ -52,27 +54,15 @@ function showWhoToFollow (panel, reply, aHost, aUser) {
} }
function getWhoToFollow (panel) { function getWhoToFollow (panel) {
var user = panel.$store.state.users.currentUser.screen_name var credentials = panel.$store.state.users.currentUser.credentials
if (user) { if (credentials) {
panel.name1 = 'Loading...' panel.name1 = 'Loading...'
panel.name2 = 'Loading...' panel.name2 = 'Loading...'
panel.name3 = 'Loading...' panel.name3 = 'Loading...'
var host = window.location.hostname apiService.suggestions({credentials: credentials})
var whoToFollowProvider = panel.$store.state.config.whoToFollowProvider .then((reply) => {
var url showWhoToFollow(panel, reply)
url = whoToFollowProvider.replace(/{{host}}/g, encodeURIComponent(host)) })
url = url.replace(/{{user}}/g, encodeURIComponent(user))
window.fetch(url, {mode: 'cors'}).then(function (response) {
if (response.ok) {
return response.json()
} else {
panel.name1 = ''
panel.name2 = ''
panel.name3 = ''
}
}).then(function (reply) {
showWhoToFollow(panel, reply, host, user)
})
} }
} }
@ -95,26 +85,26 @@ const WhoToFollowPanel = {
moreUrl: function () { moreUrl: function () {
var host = window.location.hostname var host = window.location.hostname
var user = this.user var user = this.user
var whoToFollowLink = this.$store.state.config.whoToFollowLink var suggestionsWeb = this.$store.state.config.suggestionsWeb
var url var url
url = whoToFollowLink.replace(/{{host}}/g, encodeURIComponent(host)) url = suggestionsWeb.replace(/{{host}}/g, encodeURIComponent(host))
url = url.replace(/{{user}}/g, encodeURIComponent(user)) url = url.replace(/{{user}}/g, encodeURIComponent(user))
return url return url
}, },
showWhoToFollowPanel () { suggestionsEnabled () {
return this.$store.state.config.showWhoToFollowPanel return this.$store.state.config.suggestionsEnabled
} }
}, },
watch: { watch: {
user: function (user, oldUser) { user: function (user, oldUser) {
if (this.showWhoToFollowPanel) { if (this.suggestionsEnabled) {
getWhoToFollow(this) getWhoToFollow(this)
} }
} }
}, },
mounted: mounted:
function () { function () {
if (this.showWhoToFollowPanel) { if (this.suggestionsEnabled) {
getWhoToFollow(this) getWhoToFollow(this)
} }
} }

View file

@ -3,7 +3,7 @@
<div class="panel panel-default base01-background"> <div class="panel panel-default base01-background">
<div class="panel-heading timeline-heading base02-background base04"> <div class="panel-heading timeline-heading base02-background base04">
<div class="title"> <div class="title">
Who to follow {{$t('who_to_follow.who_to_follow')}}
</div> </div>
</div> </div>
<div class="panel-body who-to-follow"> <div class="panel-body who-to-follow">
@ -11,7 +11,7 @@
<img v-bind:src="img1"/> <router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br> <img v-bind:src="img1"/> <router-link :to="{ name: 'user-profile', params: { id: id1 } }">{{ name1 }}</router-link><br>
<img v-bind:src="img2"/> <router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br> <img v-bind:src="img2"/> <router-link :to="{ name: 'user-profile', params: { id: id2 } }">{{ name2 }}</router-link><br>
<img v-bind:src="img3"/> <router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br> <img v-bind:src="img3"/> <router-link :to="{ name: 'user-profile', params: { id: id3 } }">{{ name3 }}</router-link><br>
<img v-bind:src="$store.state.config.logo"> <a v-bind:href="moreUrl" target="_blank">More</a> <img v-bind:src="$store.state.config.logo"> <a v-bind:href="moreUrl" target="_blank">{{$t('who_to_follow.more')}}</a>
</p> </p>
</div> </div>
</div> </div>

View file

@ -325,6 +325,9 @@ const en = {
loop_video: 'Loop videos', loop_video: 'Loop videos',
loop_video_silent_only: 'Loop only videos without sound (i.e. Mastodon\'s "gifs")', loop_video_silent_only: 'Loop only videos without sound (i.e. Mastodon\'s "gifs")',
reply_link_preview: 'Enable reply-link preview on mouse hover', reply_link_preview: 'Enable reply-link preview on mouse hover',
reply_visibility_all: 'Show all replies',
reply_visibility_following: 'Only show replies directed at me or users I\'m following',
reply_visibility_self: 'Only show replies directed at me',
follow_import: 'Follow import', follow_import: 'Follow import',
import_followers_from_a_csv_file: 'Import follows from a csv file', import_followers_from_a_csv_file: 'Import follows from a csv file',
follows_imported: 'Follows imported! Processing them will take a while.', follows_imported: 'Follows imported! Processing them will take a while.',
@ -398,6 +401,10 @@ const en = {
}, },
user_profile: { user_profile: {
timeline_title: 'User Timeline' timeline_title: 'User Timeline'
},
who_to_follow: {
who_to_follow: 'Who to follow',
more: 'More'
} }
} }
@ -781,115 +788,147 @@ const ja = {
chat: 'ローカルチャット', chat: 'ローカルチャット',
timeline: 'タイムライン', timeline: 'タイムライン',
mentions: 'メンション', mentions: 'メンション',
public_tl: '公開タイムライン', public_tl: 'パブリックタイムライン',
twkn: '接続しているすべてのネットワーク' twkn: 'つながっているすべてのネットワーク',
friend_requests: 'Follow Requests'
}, },
user_card: { user_card: {
follows_you: 'フォローされました!', follows_you: 'フォローされました!',
following: 'フォロー', following: 'フォローしています',
follow: 'フォロー', follow: 'フォロー',
blocked: 'ブロック済み', blocked: 'ブロックしています',
block: 'ブロック', block: 'ブロック',
statuses: '投稿', statuses: 'ステータス',
mute: 'ミュート', mute: 'ミュート',
muted: 'ミュート済み', muted: 'ミュートしています!',
followers: 'フォロワー', followers: 'フォロワー',
followees: 'フォロー', followees: 'フォロー',
per_day: '/日', per_day: '/日',
remote_follow: 'リモートフォロー' remote_follow: 'リモートフォロー',
approve: 'Approve',
deny: 'Deny'
}, },
timeline: { timeline: {
show_new: '更新', show_new: 'よみこみ',
error_fetching: '更新の取得中にエラーが発生しました。', error_fetching: 'よみこみがエラーになりました。',
up_to_date: '最新', up_to_date: 'さいしん',
load_older: '古い投稿を読み込む', load_older: 'ふるいステータス',
conversation: '会話', conversation: 'スレッド',
collapse: '折り畳む', collapse: 'たたむ',
repeated: 'リピート' repeated: 'リピート'
}, },
settings: { settings: {
user_settings: 'ユーザー設定', user_settings: 'ユーザーせってい',
name_bio: '名前とプロフィール', name_bio: 'なまえとプロフィール',
name: '名前', name: 'なまえ',
bio: 'プロフィール', bio: 'プロフィール',
avatar: 'アバター', avatar: 'アバター',
current_avatar: 'あなたの現在のアバター', current_avatar: 'いまのアバター',
set_new_avatar: '新しいアバターを設定する', set_new_avatar: 'あたらしいアバターをせっていする',
profile_banner: 'プロフィールバナー', profile_banner: 'プロフィールバナー',
current_profile_banner: '現在のプロフィールバナー', current_profile_banner: 'いまのプロフィールバナー',
set_new_profile_banner: 'しいプロフィールバナーを設定する', set_new_profile_banner: 'あたらしいプロフィールバナーを設定する',
profile_background: 'プロフィールの背景', profile_background: 'プロフィールのバックグラウンド',
set_new_profile_background: '新しいプロフィールの背景を設定する', set_new_profile_background: 'あたらしいプロフィールのバックグラウンドをせっていする',
settings: '設定', settings: 'せってい',
theme: 'テーマ', theme: 'テーマ',
presets: 'プリセット', presets: 'プリセット',
theme_help: '16進数カラーコード (#aabbcc) を使用してカラーテーマをカスタマイズ出来ます。', theme_help: 'カラーテーマをカスタマイズできます。',
radii_help: 'インターフェースの縁の丸さを設定する。', radii_help: 'インターフェースのまるさをせっていする。',
background: '背景', background: 'バックグラウンド',
foreground: '前景', foreground: 'フォアグラウンド',
text: '文字', text: 'もじ',
links: 'リンク', links: 'リンク',
cBlue: '青 (返信, フォロー)', cBlue: 'あお (リプライ, フォロー)',
cRed: ' (キャンセル)', cRed: 'あか (キャンセル)',
cOrange: 'オレンジ (お気に入り)', cOrange: 'オレンジ (おきにいり)',
cGreen: '緑 (リツイート)', cGreen: 'みどり (リピート)',
btnRadius: 'ボタン', btnRadius: 'ボタン',
inputRadius: 'Input fields',
panelRadius: 'パネル', panelRadius: 'パネル',
avatarRadius: 'アバター', avatarRadius: 'アバター',
avatarAltRadius: 'アバター (通知)', avatarAltRadius: 'アバター (つうち)',
tooltipRadius: 'ツールチップ/アラート', tooltipRadius: 'ツールチップ/アラート',
attachmentRadius: 'ファイル', attachmentRadius: 'ファイル',
filtering: 'フィルタリング', filtering: 'フィルタリング',
filtering_explanation: 'これらの単語を含むすべてのものがミュートされます。1行に1つの単語を入力してください。', filtering_explanation: 'これらのことばをふくむすべてのものがミュートされます。1行に1つのことばをかいてください。',
attachments: 'ファイル', attachments: 'ファイル',
hide_attachments_in_tl: 'タイムラインのファイルをす。', hide_attachments_in_tl: 'タイムラインのファイルをかくす。',
hide_attachments_in_convo: '会話の中のファイルを隠す。', hide_attachments_in_convo: 'スレッドのファイルをかくす。',
nsfw_clickthrough: 'NSFWファイルの非表示を有効にする。', nsfw_clickthrough: 'NSFWなファイルをかくす。',
stop_gifs: 'カーソルを重ねた時にGIFを再生する。', stop_gifs: 'カーソルをかさねたとき、GIFをうごかす。',
autoload: '下にスクロールした時に自動で読み込むようにする。', autoload: 'したにスクロールしたとき、じどうてきによみこむ。',
streaming: '上までスクロールした時に自動でストリーミングされるようにする。', streaming: 'うえまでスクロールしたとき、じどうてきにストリーミングする。',
reply_link_preview: 'マウスカーソルを重ねた時に返信のプレビューを表示するようにする。', reply_link_preview: 'カーソルをかさねたとき、リプライのプレビューをみる。',
follow_import: 'フォローインポート', follow_import: 'フォローインポート',
import_followers_from_a_csv_file: 'CSVファイルからフォローをインポートする。', import_followers_from_a_csv_file: 'CSVファイルからフォローをインポートする。',
follows_imported: 'フォローがインポートされました!処理に少し時間がかかるかもしれません。', follows_imported: 'フォローがインポートされました! すこしじかんがかかるかもしれません。',
follow_import_error: 'フォロワーのインポート中にエラーが発生しました。' follow_import_error: 'フォローのインポートがエラーになりました。',
delete_account: 'アカウントをけす',
delete_account_description: 'あなたのアカウントとメッセージが、きえます。',
delete_account_instructions: 'ほんとうにアカウントをけしてもいいなら、パスワードをかいてください。',
delete_account_error: 'アカウントをけすことが、できなかったかもしれません。インスタンスのかんりしゃに、れんらくしてください。',
follow_export: 'フォローのエクスポート',
follow_export_processing: 'おまちください。まもなくファイルをダウンロードできます。',
follow_export_button: 'エクスポート',
change_password: 'パスワードをかえる',
current_password: 'いまのパスワード',
new_password: 'あたらしいパスワード',
confirm_new_password: 'あたらしいパスワードのかくにん',
changed_password: 'パスワードが、かわりました!',
change_password_error: 'パスワードをかえることが、できなかったかもしれません。',
lock_account_description: 'あなたがみとめたひとだけ、あなたのアカウントをフォローできます。'
}, },
notifications: { notifications: {
notifications: '通知', notifications: 'つうち',
read: '読んだ!', read: 'んだ!',
followed_you: 'フォローされました', followed_you: 'フォローされました',
favorited_you: 'あなたの投稿がお気に入りされました', favorited_you: 'あなたのステータスがおきにいりされました',
repeated_you: 'あなたの投稿がリピートされました' repeated_you: 'あなたのステータスがリピートされました'
}, },
login: { login: {
login: 'ログイン', login: 'ログイン',
username: 'ユーザー名', username: 'ユーザーめい',
placeholder: '例えば lain', placeholder: 'れい: lain',
password: 'パスワード', password: 'パスワード',
register: '登録', register: 'はじめる',
logout: 'ログアウト' logout: 'ログアウト'
}, },
registration: { registration: {
registration: '登録', registration: 'はじめる',
fullname: '表示名', fullname: 'スクリーンネーム',
email: 'Eメール', email: 'Eメール',
bio: 'プロフィール', bio: 'プロフィール',
password_confirm: 'パスワードの確認' password_confirm: 'パスワードのかくにん'
}, },
post_status: { post_status: {
posting: '投稿', posting: 'とうこう',
default: 'ちょうどL.A.に着陸しました。' content_warning: 'せつめい (かかなくてもよい)',
default: 'はねだくうこうに、つきました。',
account_not_locked_warning: 'あなたのアカウントは {0} ではありません。あなたをフォローすれば、だれでも、フォロワーげんていのステータスをよむことができます。',
account_not_locked_warning_link: 'ロックされたアカウント',
direct_warning: 'このステータスは、メンションされたユーザーだけが、よむことができます。',
scope: {
public: 'パブリック - パブリックタイムラインにとどきます。',
unlisted: 'アンリステッド - パブリックタイムラインにとどきません。',
private: 'フォロワーげんてい - フォロワーのみにとどきます。',
direct: 'ダイレクト - メンションされたユーザーのみにとどきます。'
}
}, },
finder: { finder: {
find_user: 'ユーザー検索', find_user: 'ユーザーをさがす',
error_fetching_user: 'ユーザー検索でエラーが発生しました' error_fetching_user: 'ユーザーけんさくがエラーになりました。'
}, },
general: { general: {
submit: '送信', submit: 'そうしん',
apply: '適用' apply: 'てきよう'
}, },
user_profile: { user_profile: {
timeline_title: 'ユーザータイムライン' timeline_title: 'ユーザータイムライン'
},
who_to_follow: {
who_to_follow: 'おすすめユーザー',
more: 'くわしく'
} }
} }
@ -1595,6 +1634,8 @@ const ru = {
set_new_profile_background: 'Загрузить новый фон профиля', set_new_profile_background: 'Загрузить новый фон профиля',
settings: 'Настройки', settings: 'Настройки',
theme: 'Тема', theme: 'Тема',
export_theme: 'Экспортировать текущую тему',
import_theme: 'Загрузить сохранённую тему',
presets: 'Пресеты', presets: 'Пресеты',
theme_help: 'Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.', theme_help: 'Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.',
radii_help: 'Округление краёв элементов интерфейса (в пикселях)', radii_help: 'Округление краёв элементов интерфейса (в пикселях)',
@ -1643,7 +1684,12 @@ const ru = {
confirm_new_password: 'Подтверждение нового пароля', confirm_new_password: 'Подтверждение нового пароля',
changed_password: 'Пароль изменён успешно.', changed_password: 'Пароль изменён успешно.',
change_password_error: 'Произошла ошибка при попытке изменить пароль.', change_password_error: 'Произошла ошибка при попытке изменить пароль.',
limited_availability: 'Не доступно в вашем браузере' lock_account_description: 'Аккаунт доступен только подтверждённым подписчикам',
limited_availability: 'Не доступно в вашем браузере',
profile_tab: 'Профиль',
security_tab: 'Безопасность',
data_import_export_tab: 'Импорт / Экспорт данных',
collapse_subject: 'Сворачивать посты с темой'
}, },
notifications: { notifications: {
notifications: 'Уведомления', notifications: 'Уведомления',

View file

@ -49,6 +49,7 @@ const persistedStateOptions = {
'config.hideAttachments', 'config.hideAttachments',
'config.hideAttachmentsInConv', 'config.hideAttachmentsInConv',
'config.hideNsfw', 'config.hideNsfw',
'config.replyVisibility',
'config.autoLoad', 'config.autoLoad',
'config.hoverPreview', 'config.hoverPreview',
'config.streaming', 'config.streaming',
@ -192,3 +193,12 @@ window.fetch('/instance/panel.html')
.then((html) => { .then((html) => {
store.dispatch('setOption', { name: 'instanceSpecificPanelContent', value: html }) store.dispatch('setOption', { name: 'instanceSpecificPanelContent', value: html })
}) })
window.fetch('/nodeinfo/2.0.json')
.then((res) => res.json())
.then((data) => {
const suggestions = data.metadata.suggestions
store.dispatch('setOption', { name: 'suggestionsEnabled', value: suggestions.enabled })
store.dispatch('setOption', { name: 'suggestionsWeb', value: suggestions.web })
})

View file

@ -15,6 +15,7 @@ const defaultState = {
hoverPreview: true, hoverPreview: true,
pauseOnUnfocused: true, pauseOnUnfocused: true,
stopGifs: false, stopGifs: false,
replyVisibility: 'all',
muteWords: [], muteWords: [],
highlight: {} highlight: {}
} }

View file

@ -37,6 +37,7 @@ const CHANGE_PASSWORD_URL = '/api/pleroma/change_password'
const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests' const FOLLOW_REQUESTS_URL = '/api/pleroma/friend_requests'
const APPROVE_USER_URL = '/api/pleroma/friendships/approve' const APPROVE_USER_URL = '/api/pleroma/friendships/approve'
const DENY_USER_URL = '/api/pleroma/friendships/deny' const DENY_USER_URL = '/api/pleroma/friendships/deny'
const SUGGESTIONS_URL = '/api/v1/suggestions'
import { each, map } from 'lodash' import { each, map } from 'lodash'
import 'whatwg-fetch' import 'whatwg-fetch'
@ -454,6 +455,12 @@ const fetchMutes = ({credentials}) => {
}).then((data) => data.json()) }).then((data) => data.json())
} }
const suggestions = ({credentials}) => {
return fetch(SUGGESTIONS_URL, {
headers: authHeaders(credentials)
}).then((data) => data.json())
}
const apiService = { const apiService = {
verifyCredentials, verifyCredentials,
fetchTimeline, fetchTimeline,
@ -487,7 +494,8 @@ const apiService = {
changePassword, changePassword,
fetchFollowRequests, fetchFollowRequests,
approveUser, approveUser,
denyUser denyUser,
suggestions
} }
export default apiService export default apiService