Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
6edccad4dd | |||
8fa47dbcb1 | |||
157f4bbc21 | |||
3b0d0df068 | |||
69802a9f00 | |||
b940da45af | |||
bd6de0e204 | |||
958074e347 | |||
988ac80087 | |||
1c7c72181e | |||
6857153367 | |||
0a3a0f3beb | |||
e92e83746d | |||
3b34b3e9ea | |||
9506f53691 | |||
92dc6db134 | |||
1b88a7bc03 |
14
CHANGELOG.md
14
CHANGELOG.md
@ -1,7 +1,19 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
12.0.0 indigo (unreleased)
|
12.1.0 (2020/02/06)
|
||||||
|
--------------------
|
||||||
|
### ✨Improvements
|
||||||
|
* サーバー切断時に自動でリロードできるように
|
||||||
|
|
||||||
|
### 🐛Fixes
|
||||||
|
* もっと読み込むを続けていくと表示が遅くなっていく問題を修正
|
||||||
|
* Renote メニューが自分の投稿のRenoteでない限り表示されない問題を修正
|
||||||
|
* MFM jump, spin, title が効かない問題を修正
|
||||||
|
* AP: Likeで正しいActivity IDを提示するように修正
|
||||||
|
* AP: Misskey以外からのトークの返信が受け取れないのを修正
|
||||||
|
|
||||||
|
12.0.0 indigo (2020/02/06)
|
||||||
--------------------
|
--------------------
|
||||||
Misskey v12では、クライアントが設計し直され、全く新しいUIに生まれ変わりました。
|
Misskey v12では、クライアントが設計し直され、全く新しいUIに生まれ変わりました。
|
||||||
レスポンシブになり、ひとつのコードで様々なデバイスに対応できるようにしました。
|
レスポンシブになり、ひとつのコードで様々なデバイスに対応できるようにしました。
|
||||||
|
@ -28,7 +28,7 @@ gotIt: "わかった"
|
|||||||
cancel: "キャンセル"
|
cancel: "キャンセル"
|
||||||
enterUsername: "ユーザー名を入力"
|
enterUsername: "ユーザー名を入力"
|
||||||
renotedBy: "{user}がRenote"
|
renotedBy: "{user}がRenote"
|
||||||
noNotes: "投稿はありません"
|
noNotes: ノートはありません"
|
||||||
noNotifications: "通知はありません"
|
noNotifications: "通知はありません"
|
||||||
instance: "インスタンス"
|
instance: "インスタンス"
|
||||||
settings: "設定"
|
settings: "設定"
|
||||||
@ -66,13 +66,13 @@ import: "インポート"
|
|||||||
export: "エクスポート"
|
export: "エクスポート"
|
||||||
files: "ファイル"
|
files: "ファイル"
|
||||||
download: "ダウンロード"
|
download: "ダウンロード"
|
||||||
driveFileDeleteConfirm: "ファイル「{name}」を削除しますか?このファイルを添付した投稿も消えます。"
|
driveFileDeleteConfirm: "ファイル「{name}」を削除しますか?このファイルを添付したノートも消えます。"
|
||||||
unfollowConfirm: "{name}のフォローを解除しますか?"
|
unfollowConfirm: "{name}のフォローを解除しますか?"
|
||||||
exportRequested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、「ドライブ」に追加されます。"
|
exportRequested: "エクスポートをリクエストしました。これには時間がかかる場合があります。エクスポートが終わると、「ドライブ」に追加されます。"
|
||||||
importRequested: "インポートをリクエストしました。これには時間がかかる場合があります。"
|
importRequested: "インポートをリクエストしました。これには時間がかかる場合があります。"
|
||||||
lists: "リスト"
|
lists: "リスト"
|
||||||
noLists: "リストはありません"
|
noLists: "リストはありません"
|
||||||
notes: "投稿"
|
notes: "ノート"
|
||||||
following: "フォロー"
|
following: "フォロー"
|
||||||
followers: "フォロワー"
|
followers: "フォロワー"
|
||||||
followsYou: "フォローされています"
|
followsYou: "フォローされています"
|
||||||
@ -95,7 +95,7 @@ enterEmoji: "絵文字を入力"
|
|||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
unrenote: "Renote解除"
|
unrenote: "Renote解除"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
pinnedNote: "ピン留めされた投稿"
|
pinnedNote: "ピン留めされたノート"
|
||||||
you: "あなた"
|
you: "あなた"
|
||||||
clickToShow: "クリックして表示"
|
clickToShow: "クリックして表示"
|
||||||
sensitive: "閲覧注意"
|
sensitive: "閲覧注意"
|
||||||
@ -179,7 +179,7 @@ mutedUsers: "ミュートしたユーザー"
|
|||||||
blockedUsers: "ブロックしたユーザー"
|
blockedUsers: "ブロックしたユーザー"
|
||||||
noUsers: "ユーザーはいません"
|
noUsers: "ユーザーはいません"
|
||||||
editProfile: "プロフィールを編集"
|
editProfile: "プロフィールを編集"
|
||||||
noteDeleteConfirm: "この投稿を削除しますか?"
|
noteDeleteConfirm: "このノートを削除しますか?"
|
||||||
pinLimitExceeded: "これ以上ピン留めできません"
|
pinLimitExceeded: "これ以上ピン留めできません"
|
||||||
intro: "Misskeyのインストールが完了しました!管理者アカウントを作成しましょう。"
|
intro: "Misskeyのインストールが完了しました!管理者アカウントを作成しましょう。"
|
||||||
done: "完了"
|
done: "完了"
|
||||||
@ -304,8 +304,8 @@ name: "名前"
|
|||||||
antennaSource: "受信ソース"
|
antennaSource: "受信ソース"
|
||||||
antennaKeywords: "受信キーワード"
|
antennaKeywords: "受信キーワード"
|
||||||
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
|
antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
|
||||||
notifyAntenna: "新しい投稿を通知する"
|
notifyAntenna: "新しいノートを通知する"
|
||||||
withFileAntenna: "ファイルが添付された投稿のみ"
|
withFileAntenna: "ファイルが添付されたノートのみ"
|
||||||
serviceworker: "ServiceWorker"
|
serviceworker: "ServiceWorker"
|
||||||
enableServiceworker: "ServiceWorkerを有効にする"
|
enableServiceworker: "ServiceWorkerを有効にする"
|
||||||
antennaUsersDescription: "ユーザー名を改行で区切って指定します"
|
antennaUsersDescription: "ユーザー名を改行で区切って指定します"
|
||||||
@ -348,6 +348,8 @@ resetPassword: "パスワードをリセット"
|
|||||||
newPasswordIs: "新しいパスワードは「{password}」です"
|
newPasswordIs: "新しいパスワードは「{password}」です"
|
||||||
post: "投稿"
|
post: "投稿"
|
||||||
posted: "投稿しました"
|
posted: "投稿しました"
|
||||||
|
autoReloadWhenDisconnected: "サーバー切断時に自動リロード"
|
||||||
|
autoNoteWatch: "ノートの自動ウォッチ"
|
||||||
|
|
||||||
_2fa:
|
_2fa:
|
||||||
registerDevice: "デバイスを登録"
|
registerDevice: "デバイスを登録"
|
||||||
@ -372,7 +374,7 @@ _permissions:
|
|||||||
"write:messaging": "トークを操作する"
|
"write:messaging": "トークを操作する"
|
||||||
"read:mutes": "ミュートを見る"
|
"read:mutes": "ミュートを見る"
|
||||||
"write:mutes": "ミュートを操作する"
|
"write:mutes": "ミュートを操作する"
|
||||||
"write:notes": "投稿を作成・削除する"
|
"write:notes": "ノートを作成・削除する"
|
||||||
"read:notifications": "通知を見る"
|
"read:notifications": "通知を見る"
|
||||||
"write:notifications": "通知を操作する"
|
"write:notifications": "通知を操作する"
|
||||||
"read:reactions": "リアクションを見る"
|
"read:reactions": "リアクションを見る"
|
||||||
@ -390,10 +392,10 @@ _auth:
|
|||||||
permissionAsk: "このアプリは次の権限を要求しています"
|
permissionAsk: "このアプリは次の権限を要求しています"
|
||||||
|
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "全ての投稿"
|
all: "全てのノート"
|
||||||
homeTimeline: "フォローしているユーザーの投稿"
|
homeTimeline: "フォローしているユーザーのノート"
|
||||||
users: "指定した一人または複数のユーザーの投稿"
|
users: "指定した一人または複数のユーザーのノート"
|
||||||
userList: "指定したリストのユーザーの投稿"
|
userList: "指定したリストのユーザーのノート"
|
||||||
|
|
||||||
_weekday:
|
_weekday:
|
||||||
sunday: "日曜日"
|
sunday: "日曜日"
|
||||||
@ -453,8 +455,8 @@ _visibility:
|
|||||||
specifiedDescription: "指定したユーザーのみに公開"
|
specifiedDescription: "指定したユーザーのみに公開"
|
||||||
|
|
||||||
_postForm:
|
_postForm:
|
||||||
replyPlaceholder: "この投稿に返信..."
|
replyPlaceholder: "このノートに返信..."
|
||||||
quotePlaceholder: "この投稿を引用..."
|
quotePlaceholder: "このノートを引用..."
|
||||||
_placeholders:
|
_placeholders:
|
||||||
a: "いまどうしてる?"
|
a: "いまどうしてる?"
|
||||||
b: "何かありましたか?"
|
b: "何かありましたか?"
|
||||||
@ -473,7 +475,7 @@ _profile:
|
|||||||
metadataContent: "内容"
|
metadataContent: "内容"
|
||||||
|
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "全ての投稿"
|
allNotes: "全てのノート"
|
||||||
followingList: "フォロー"
|
followingList: "フォロー"
|
||||||
muteList: "ミュート"
|
muteList: "ミュート"
|
||||||
blockingList: "ブロック"
|
blockingList: "ブロック"
|
||||||
@ -485,10 +487,10 @@ _charts:
|
|||||||
usersIncDec: "ユーザーの増減"
|
usersIncDec: "ユーザーの増減"
|
||||||
usersTotal: "ユーザーの合計"
|
usersTotal: "ユーザーの合計"
|
||||||
activeUsers: "アクティブユーザー数"
|
activeUsers: "アクティブユーザー数"
|
||||||
notesIncDec: "投稿の増減"
|
notesIncDec: "ノートの増減"
|
||||||
localNotesIncDec: "ローカルの投稿の増減"
|
localNotesIncDec: "ローカルのノートの増減"
|
||||||
remoteNotesIncDec: "リモートの投稿の増減"
|
remoteNotesIncDec: "リモートのノートの増減"
|
||||||
notesTotal: "投稿の合計"
|
notesTotal: "ノートの合計"
|
||||||
filesIncDec: "ファイルの増減"
|
filesIncDec: "ファイルの増減"
|
||||||
filesTotal: "ファイルの合計"
|
filesTotal: "ファイルの合計"
|
||||||
storageUsageIncDec: "ストレージ使用量の増減"
|
storageUsageIncDec: "ストレージ使用量の増減"
|
||||||
@ -498,8 +500,8 @@ _instanceCharts:
|
|||||||
requests: "リクエスト"
|
requests: "リクエスト"
|
||||||
users: "ユーザーの増減"
|
users: "ユーザーの増減"
|
||||||
usersTotal: "ユーザーの積算"
|
usersTotal: "ユーザーの積算"
|
||||||
notes: "投稿の増減"
|
notes: "ノートの増減"
|
||||||
notesTotal: "投稿の積算"
|
notesTotal: "ノートの積算"
|
||||||
ff: "フォロー/フォロワーの増減"
|
ff: "フォロー/フォロワーの増減"
|
||||||
ffTotal: "フォロー/フォロワーの積算"
|
ffTotal: "フォロー/フォロワーの積算"
|
||||||
cacheSize: "キャッシュサイズの増減"
|
cacheSize: "キャッシュサイズの増減"
|
||||||
|
@ -222,6 +222,10 @@ export default Vue.extend({
|
|||||||
|
|
||||||
this.$root.stream.on('_disconnected_', () => {
|
this.$root.stream.on('_disconnected_', () => {
|
||||||
if (!this.disconnectedDialog) {
|
if (!this.disconnectedDialog) {
|
||||||
|
if (this.$store.state.device.autoReload) {
|
||||||
|
location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.disconnectedDialog = this.$root.dialog({
|
this.disconnectedDialog = this.$root.dialog({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
showCancelButton: true,
|
showCancelButton: true,
|
||||||
@ -572,12 +576,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@keyframes blink {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
30% { opacity: 1; }
|
|
||||||
90% { opacity: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-enter-active, .header-leave-active {
|
.header-enter-active, .header-leave-active {
|
||||||
transition: opacity 0.5s, transform 0.5s !important;
|
transition: opacity 0.5s, transform 0.5s !important;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<sequential-entrance class="sqadhkmv" ref="list" :direction="direction">
|
<sequential-entrance class="sqadhkmv" ref="list" :direction="direction" :reversed="reversed">
|
||||||
<template v-for="(item, i) in items">
|
<template v-for="(item, i) in items">
|
||||||
<slot :item="item" :i="i"></slot>
|
<slot :item="item" :i="i"></slot>
|
||||||
<div class="separator" :key="item.id + '_date'" :data-index="i" v-if="i != items.length - 1 && new Date(item.createdAt).getDate() != new Date(items[i + 1].createdAt).getDate()">
|
<div class="separator" :key="item.id + '_date'" v-if="i != items.length - 1 && new Date(item.createdAt).getDate() != new Date(items[i + 1].createdAt).getDate()">
|
||||||
<p class="date">
|
<p class="date">
|
||||||
<span><fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span>
|
<span><fa class="icon" :icon="faAngleUp"/>{{ getDateText(item.createdAt) }}</span>
|
||||||
<span>{{ getDateText(items[i + 1].createdAt) }}<fa class="icon" :icon="faAngleDown"/></span>
|
<span>{{ getDateText(items[i + 1].createdAt) }}<fa class="icon" :icon="faAngleDown"/></span>
|
||||||
@ -28,6 +28,11 @@ export default Vue.extend({
|
|||||||
direction: {
|
direction: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: false
|
||||||
|
},
|
||||||
|
reversed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -2,26 +2,26 @@
|
|||||||
<x-popup :source="source" :no-center="noCenter" :fixed="fixed" :width="width" ref="popup" @closed="() => { $emit('closed'); destroyDom(); }">
|
<x-popup :source="source" :no-center="noCenter" :fixed="fixed" :width="width" ref="popup" @closed="() => { $emit('closed'); destroyDom(); }">
|
||||||
<sequential-entrance class="rrevdjwt" :class="{ left: align === 'left' }" :delay="15" :direction="direction">
|
<sequential-entrance class="rrevdjwt" :class="{ left: align === 'left' }" :delay="15" :direction="direction">
|
||||||
<template v-for="(item, i) in items.filter(item => item !== undefined)">
|
<template v-for="(item, i) in items.filter(item => item !== undefined)">
|
||||||
<div v-if="item === null" class="divider" :key="i" :data-index="i"></div>
|
<div v-if="item === null" class="divider" :key="i"></div>
|
||||||
<span v-else-if="item.type === 'label'" class="label item" :key="i" :data-index="i">
|
<span v-else-if="item.type === 'label'" class="label item" :key="i">
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
</span>
|
</span>
|
||||||
<router-link v-else-if="item.type === 'link'" :to="item.to" @click.native="close()" :tabindex="i" class="_button item" :key="i" :data-index="i">
|
<router-link v-else-if="item.type === 'link'" :to="item.to" @click.native="close()" :tabindex="i" class="_button item" :key="i">
|
||||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||||
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||||
</router-link>
|
</router-link>
|
||||||
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item" :key="i" :data-index="i">
|
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item" :key="i">
|
||||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||||
</a>
|
</a>
|
||||||
<button v-else-if="item.type === 'user'" @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i" :data-index="i">
|
<button v-else-if="item.type === 'user'" @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i">
|
||||||
<mk-avatar :user="item.user" class="avatar"/><mk-user-name :user="item.user"/>
|
<mk-avatar :user="item.user" class="avatar"/><mk-user-name :user="item.user"/>
|
||||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-else @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i" :data-index="i">
|
<button v-else @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i">
|
||||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||||
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
@ -88,12 +88,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@keyframes blink {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
30% { opacity: 1; }
|
|
||||||
90% { opacity: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.rrevdjwt {
|
.rrevdjwt {
|
||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
|
|
||||||
|
@ -36,5 +36,10 @@ export default Vue.extend({
|
|||||||
::v-deep pre {
|
::v-deep pre {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::v-deep .title {
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: solid 1px var(--divider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -458,7 +458,7 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
showRenoteMenu(ev) {
|
showRenoteMenu(ev) {
|
||||||
if (!this.isMyNote) return;
|
if (!this.$store.getters.isSignedIn || (this.$store.state.i.id !== this.note.userId)) return;
|
||||||
this.$root.menu({
|
this.$root.menu({
|
||||||
items: [{
|
items: [{
|
||||||
text: this.$t('unrenote'),
|
text: this.$t('unrenote'),
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<mk-error v-if="error" @retry="init()"/>
|
<mk-error v-if="error" @retry="init()"/>
|
||||||
|
|
||||||
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note, i }">
|
<x-list ref="notes" class="notes" :items="notes" v-slot="{ item: note, i }">
|
||||||
<x-note :note="note" :detail="detail" :key="note.id" :data-index="i"/>
|
<x-note :note="note" :detail="detail" :key="note.id"/>
|
||||||
</x-list>
|
</x-list>
|
||||||
|
|
||||||
<footer v-if="more">
|
<footer v-if="more">
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="mk-notifications">
|
<div class="mk-notifications">
|
||||||
<div class="contents">
|
<div class="contents">
|
||||||
<x-list class="notifications" :items="items" v-slot="{ item: notification, i }">
|
<x-list class="notifications" :items="items" v-slot="{ item: notification, i }">
|
||||||
<x-notification :notification="notification" :with-time="true" :full="true" class="notification" :key="notification.id" :data-index="i"/>
|
<x-notification :notification="notification" :with-time="true" :full="true" class="notification" :key="notification.id"/>
|
||||||
</x-list>
|
</x-list>
|
||||||
|
|
||||||
<button class="more _button" v-if="more" @click="fetchMore" :disabled="moreFetching">
|
<button class="more _button" v-if="more" @click="fetchMore" :disabled="moreFetching">
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
mode="out-in"
|
mode="out-in"
|
||||||
appear
|
appear
|
||||||
>
|
>
|
||||||
<button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :data-index="i" :tabindex="i + 1" :title="/^[a-z]+$/.test(reaction) ? $t('@.reactions.' + reaction) : reaction"><x-reaction-icon :reaction="reaction"/></button>
|
<button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :tabindex="i + 1" :title="/^[a-z]+$/.test(reaction) ? $t('@.reactions.' + reaction) : reaction"><x-reaction-icon :reaction="reaction"/></button>
|
||||||
</transition-group>
|
</transition-group>
|
||||||
<input class="text" v-model="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
<input class="text" v-model="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,27 +27,37 @@ export default Vue.extend({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false,
|
required: false,
|
||||||
default: 'down'
|
default: 'down'
|
||||||
|
},
|
||||||
|
reversed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
i: 0,
|
||||||
methods: {
|
methods: {
|
||||||
beforeEnter(el) {
|
beforeEnter(el) {
|
||||||
el.style.opacity = 0;
|
el.style.opacity = 0;
|
||||||
el.style.transform = this.direction === 'down' ? 'translateY(-64px)' : 'translateY(64px)';
|
el.style.transform = this.direction === 'down' ? 'translateY(-64px)' : 'translateY(64px)';
|
||||||
|
let index = this.$options.i;
|
||||||
|
const delay = this.delay * index;
|
||||||
|
el.style.transition = [getComputedStyle(el).transition, `transform 0.7s cubic-bezier(0.23, 1, 0.32, 1) ${delay}ms`, `opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1) ${delay}ms`].filter(x => x != '').join(',');
|
||||||
|
this.$options.i++;
|
||||||
},
|
},
|
||||||
enter(el, done) {
|
enter(el, done) {
|
||||||
el.style.transition = [getComputedStyle(el).transition, 'transform 0.7s cubic-bezier(0.23, 1, 0.32, 1)', 'opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1)'].filter(x => x != '').join(',');
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
el.style.opacity = 1;
|
el.style.opacity = 1;
|
||||||
el.style.transform = 'translateY(0px)';
|
el.style.transform = 'translateY(0px)';
|
||||||
setTimeout(done, 700);
|
el.addEventListener('transitionend', () => {
|
||||||
}, this.delay * el.dataset.index)
|
el.style.transition = '';
|
||||||
|
this.$options.i--;
|
||||||
|
done();
|
||||||
|
}, { once: true });
|
||||||
|
});
|
||||||
},
|
},
|
||||||
leave(el, done) {
|
leave(el) {
|
||||||
setTimeout(() => {
|
|
||||||
el.style.opacity = 0;
|
el.style.opacity = 0;
|
||||||
el.style.transform = this.direction === 'down' ? 'translateY(64px)' : 'translateY(-64px)';
|
el.style.transform = this.direction === 'down' ? 'translateY(64px)' : 'translateY(-64px)';
|
||||||
setTimeout(done, 700);
|
|
||||||
}, this.delay * el.dataset.index)
|
|
||||||
},
|
},
|
||||||
focus() {
|
focus() {
|
||||||
this.$slots.default[0].elm.focus();
|
this.$slots.default[0].elm.focus();
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<sequential-entrance class="users">
|
<sequential-entrance class="users">
|
||||||
<router-link v-for="(item, i) in items" class="user" :key="item.id" :data-index="i" :to="extract ? extract(item) : item | userPage">
|
<router-link v-for="(item, i) in items" class="user" :key="item.id" :to="extract ? extract(item) : item | userPage">
|
||||||
<mk-avatar :user="extract ? extract(item) : item" class="avatar" :disable-link="true"/>
|
<mk-avatar :user="extract ? extract(item) : item" class="avatar" :disable-link="true"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-user-name :user="extract ? extract(item) : item" class="name"/>
|
<mk-user-name :user="extract ? extract(item) : item" class="name"/>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<portal to="title">{{ $t('announcements') }}</portal>
|
<portal to="title">{{ $t('announcements') }}</portal>
|
||||||
|
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="ruryvtyk" ref="list">
|
<mk-pagination :pagination="pagination" #default="{items}" class="ruryvtyk" ref="list">
|
||||||
<section class="_card announcement" v-for="(announcement, i) in items" :key="announcement.id" :data-index="i">
|
<section class="_card announcement" v-for="(announcement, i) in items" :key="announcement.id">
|
||||||
<div class="_title"><span v-if="$store.getters.isSignedIn && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
|
<div class="_title"><span v-if="$store.getters.isSignedIn && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<mfm :text="announcement.text"/>
|
<mfm :text="announcement.text"/>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="mk-follow-requests" ref="list">
|
<mk-pagination :pagination="pagination" #default="{items}" class="mk-follow-requests" ref="list">
|
||||||
<div class="user _panel" v-for="(req, i) in items" :key="req.id" :data-index="i">
|
<div class="user _panel" v-for="(req, i) in items" :key="req.id">
|
||||||
<mk-avatar class="avatar" :user="req.follower"/>
|
<mk-avatar class="avatar" :user="req.follower"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
|
@ -173,12 +173,6 @@ export default Vue.extend({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@keyframes blink {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
30% { opacity: 1; }
|
|
||||||
90% { opacity: 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
._kjvfvyph_ {
|
._kjvfvyph_ {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<mk-pagination :pagination="pagination" class="emojis" ref="emojis">
|
<mk-pagination :pagination="pagination" class="emojis" ref="emojis">
|
||||||
<template #empty><span>{{ $t('noCustomEmojis') }}</span></template>
|
<template #empty><span>{{ $t('noCustomEmojis') }}</span></template>
|
||||||
<template #default="{items}">
|
<template #default="{items}">
|
||||||
<div class="emoji" v-for="(emoji, i) in items" :key="emoji.id" :data-index="i" @click="selected = emoji" :class="{ selected: selected && (selected.id === emoji.id) }">
|
<div class="emoji" v-for="(emoji, i) in items" :key="emoji.id" @click="selected = emoji" :class="{ selected: selected && (selected.id === emoji.id) }">
|
||||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<span class="name">{{ emoji.name }}</span>
|
<span class="name">{{ emoji.name }}</span>
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<mk-pagination :pagination="remotePagination" class="emojis" ref="remoteEmojis">
|
<mk-pagination :pagination="remotePagination" class="emojis" ref="remoteEmojis">
|
||||||
<template #empty><span>{{ $t('noCustomEmojis') }}</span></template>
|
<template #empty><span>{{ $t('noCustomEmojis') }}</span></template>
|
||||||
<template #default="{items}">
|
<template #default="{items}">
|
||||||
<div class="emoji" v-for="(emoji, i) in items" :key="emoji.id" :data-index="i" @click="selectedRemote = emoji" :class="{ selected: selectedRemote && (selectedRemote.id === emoji.id) }">
|
<div class="emoji" v-for="(emoji, i) in items" :key="emoji.id" @click="selectedRemote = emoji" :class="{ selected: selectedRemote && (selectedRemote.id === emoji.id) }">
|
||||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<span class="name">{{ emoji.name }}</span>
|
<span class="name">{{ emoji.name }}</span>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="instances" ref="instances" :key="host + state">
|
<mk-pagination :pagination="pagination" #default="{items}" class="instances" ref="instances" :key="host + state">
|
||||||
<div class="instance" v-for="(instance, i) in items" :key="instance.id" :data-index="i" @click="info(instance)">
|
<div class="instance" v-for="(instance, i) in items" :key="instance.id" @click="info(instance)">
|
||||||
<div class="host"><fa :icon="faCircle" class="indicator" :class="getStatus(instance)"/><b>{{ instance.host }}</b></div>
|
<div class="host"><fa :icon="faCircle" class="indicator" :class="getStatus(instance)"/><b>{{ instance.host }}</b></div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<span class="sub" v-if="instance.followersCount > 0"><fa :icon="faCaretDown" class="icon"/>Sub</span>
|
<span class="sub" v-if="instance.followersCount > 0"><fa :icon="faCaretDown" class="icon"/>Sub</span>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="_content" style="max-height: 180px; overflow: auto;">
|
<div class="_content" style="max-height: 180px; overflow: auto;">
|
||||||
<sequential-entrance :delay="15" v-if="jobs.length > 0">
|
<sequential-entrance :delay="15" v-if="jobs.length > 0">
|
||||||
<div v-for="(job, i) in jobs" :key="job[0]" :data-index="i">
|
<div v-for="(job, i) in jobs" :key="job[0]">
|
||||||
<span>{{ job[0] }}</span>
|
<span>{{ job[0] }}</span>
|
||||||
<span style="margin-left: 8px; opacity: 0.7;">({{ job[1] | number }} jobs)</span>
|
<span style="margin-left: 8px; opacity: 0.7;">({{ job[1] | number }} jobs)</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
<div class="_title"><fa :icon="faUsers"/> {{ $t('users') }}</div>
|
<div class="_title"><fa :icon="faUsers"/> {{ $t('users') }}</div>
|
||||||
<div class="_content _list">
|
<div class="_content _list">
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="users" ref="users" :auto-margin="false">
|
<mk-pagination :pagination="pagination" #default="{items}" class="users" ref="users" :auto-margin="false">
|
||||||
<button class="user _button _listItem" v-for="(user, i) in items" :key="user.id" :data-index="i" @click="show(user)">
|
<button class="user _button _listItem" v-for="(user, i) in items" :key="user.id" @click="show(user)">
|
||||||
<mk-avatar :user="user" class="avatar"/>
|
<mk-avatar :user="user" class="avatar"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-user-name :user="user" class="name"/>
|
<mk-user-name :user="user" class="name"/>
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
<button class="more _button" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
|
<button class="more _button" :class="{ fetching: fetchingMoreMessages }" v-if="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
|
||||||
<template v-if="fetchingMoreMessages"><fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $t('@.loading') : $t('@.load-more') }}
|
<template v-if="fetchingMoreMessages"><fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $t('@.loading') : $t('@.load-more') }}
|
||||||
</button>
|
</button>
|
||||||
<x-list class="messages" :items="messages" v-slot="{ item: message, i }" direction="up">
|
<x-list class="messages" :items="messages" v-slot="{ item: message, i }" direction="up" reversed>
|
||||||
<x-message :message="message" :is-group="group != null" :key="message.id" :data-index="messages.length - i"/>
|
<x-message :message="message" :is-group="group != null" :key="message.id"/>
|
||||||
</x-list>
|
</x-list>
|
||||||
</div>
|
</div>
|
||||||
<footer>
|
<footer>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<x-antenna v-if="draft" :antenna="draft" @created="onAntennaCreated" style="margin-bottom: var(--margin);"/>
|
<x-antenna v-if="draft" :antenna="draft" @created="onAntennaCreated" style="margin-bottom: var(--margin);"/>
|
||||||
|
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="antennas" ref="list">
|
<mk-pagination :pagination="pagination" #default="{items}" class="antennas" ref="list">
|
||||||
<x-antenna v-for="(antenna, i) in items" :key="antenna.id" :data-index="i" :antenna="antenna" @created="onAntennaDeleted"/>
|
<x-antenna v-for="(antenna, i) in items" :key="antenna.id" :antenna="antenna" @created="onAntennaDeleted"/>
|
||||||
</mk-pagination>
|
</mk-pagination>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<mk-button @click="create" primary class="add"><fa :icon="faPlus"/> {{ $t('createList') }}</mk-button>
|
<mk-button @click="create" primary class="add"><fa :icon="faPlus"/> {{ $t('createList') }}</mk-button>
|
||||||
|
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="lists" ref="list">
|
<mk-pagination :pagination="pagination" #default="{items}" class="lists" ref="list">
|
||||||
<div class="list _panel" v-for="(list, i) in items" :key="list.id" :data-index="i">
|
<div class="list _panel" v-for="(list, i) in items" :key="list.id">
|
||||||
<router-link :to="`/lists/${ list.id }`">{{ list.name }}</router-link>
|
<router-link :to="`/lists/${ list.id }`">{{ list.name }}</router-link>
|
||||||
</div>
|
</div>
|
||||||
</mk-pagination>
|
</mk-pagination>
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<div class="_title">{{ list.name }}</div>
|
<div class="_title">{{ list.name }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<div class="users">
|
<div class="users">
|
||||||
<div class="user" v-for="(user, i) in users" :key="user.id" :data-index="i">
|
<div class="user" v-for="(user, i) in users" :key="user.id">
|
||||||
<mk-avatar :user="user" class="avatar"/>
|
<mk-avatar :user="user" class="avatar"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<mk-user-name :user="user" class="name"/>
|
<mk-user-name :user="user" class="name"/>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="_title"><fa :icon="faCloud"/> {{ $t('drive') }}</div>
|
<div class="_title"><fa :icon="faCloud"/> {{ $t('drive') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<mk-pagination :pagination="drivePagination" #default="{items}" class="drive" ref="drive">
|
<mk-pagination :pagination="drivePagination" #default="{items}" class="drive" ref="drive">
|
||||||
<div class="file" v-for="(file, i) in items" :key="file.id" :data-index="i" @click="selected = file" :class="{ selected: selected && (selected.id === file.id) }">
|
<div class="file" v-for="(file, i) in items" :key="file.id" @click="selected = file" :class="{ selected: selected && (selected.id === file.id) }">
|
||||||
<x-file-thumbnail class="thumbnail" :file="file" fit="cover"/>
|
<x-file-thumbnail class="thumbnail" :file="file" fit="cover"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p class="name">
|
<p class="name">
|
||||||
|
@ -10,8 +10,11 @@
|
|||||||
<mk-button primary :disabled="$store.state.settings.wallpaper == null" @click="delWallpaper()">{{ $t('removeWallpaper') }}</mk-button>
|
<mk-button primary :disabled="$store.state.settings.wallpaper == null" @click="delWallpaper()">{{ $t('removeWallpaper') }}</mk-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
|
<mk-switch v-model="autoReload">
|
||||||
|
{{ $t('autoReloadWhenDisconnected') }}
|
||||||
|
</mk-switch>
|
||||||
<mk-switch v-model="$store.state.i.autoWatch" @change="onChangeAutoWatch">
|
<mk-switch v-model="$store.state.i.autoWatch" @change="onChangeAutoWatch">
|
||||||
{{ $t('auto-watch') }}<template #desc>{{ $t('auto-watch-desc') }}</template>
|
{{ $t('autoNoteWatch') }}<template #desc>{{ $t('auto-watch-desc') }}</template>
|
||||||
</mk-switch>
|
</mk-switch>
|
||||||
</div>
|
</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
@ -52,6 +55,11 @@ export default Vue.extend({
|
|||||||
get() { return this.$store.state.settings.wallpaper; },
|
get() { return this.$store.state.settings.wallpaper; },
|
||||||
set(value) { this.$store.dispatch('settings/set', { key: 'wallpaper', value }); }
|
set(value) { this.$store.dispatch('settings/set', { key: 'wallpaper', value }); }
|
||||||
},
|
},
|
||||||
|
|
||||||
|
autoReload: {
|
||||||
|
get() { return this.$store.state.device.autoReload; },
|
||||||
|
set(value) { this.$store.commit('device/set', { key: 'autoReload', value }); }
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<mk-pagination :pagination="mutingPagination" class="muting">
|
<mk-pagination :pagination="mutingPagination" class="muting">
|
||||||
<template #empty><span>{{ $t('noUsers') }}</span></template>
|
<template #empty><span>{{ $t('noUsers') }}</span></template>
|
||||||
<template #default="{items}">
|
<template #default="{items}">
|
||||||
<div class="user" v-for="(mute, i) in items" :key="mute.id" :data-index="i">
|
<div class="user" v-for="(mute, i) in items" :key="mute.id">
|
||||||
<router-link class="name" :to="mute.mutee | userPage">
|
<router-link class="name" :to="mute.mutee | userPage">
|
||||||
<mk-acct :user="mute.mutee"/>
|
<mk-acct :user="mute.mutee"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<mk-pagination :pagination="blockingPagination" class="blocking">
|
<mk-pagination :pagination="blockingPagination" class="blocking">
|
||||||
<template #empty><span>{{ $t('noUsers') }}</span></template>
|
<template #empty><span>{{ $t('noUsers') }}</span></template>
|
||||||
<template #default="{items}">
|
<template #default="{items}">
|
||||||
<div class="user" v-for="(block, i) in items" :key="block.id" :data-index="i">
|
<div class="user" v-for="(block, i) in items" :key="block.id">
|
||||||
<router-link class="name" :to="block.blockee | userPage">
|
<router-link class="name" :to="block.blockee | userPage">
|
||||||
<mk-acct :user="block.blockee"/>
|
<mk-acct :user="block.blockee"/>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<mk-pagination :pagination="pagination" #default="{items}" class="mk-following-or-followers" ref="list">
|
<mk-pagination :pagination="pagination" #default="{items}" class="mk-following-or-followers" ref="list">
|
||||||
<div class="user _panel" v-for="(user, i) in items.map(x => type === 'following' ? x.followee : x.follower)" :key="user.id" :data-index="i">
|
<div class="user _panel" v-for="(user, i) in items.map(x => type === 'following' ? x.followee : x.follower)" :key="user.id">
|
||||||
<mk-avatar class="avatar" :user="user"/>
|
<mk-avatar class="avatar" :user="user"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
|
@ -83,7 +83,7 @@
|
|||||||
<router-view :user="user"></router-view>
|
<router-view :user="user"></router-view>
|
||||||
<template v-if="$route.name == 'user'">
|
<template v-if="$route.name == 'user'">
|
||||||
<sequential-entrance class="pins">
|
<sequential-entrance class="pins">
|
||||||
<x-note v-for="(note, i) in user.pinnedNotes" class="note" :note="note" :key="note.id" :data-index="i" :detail="true" :pinned="true"/>
|
<x-note v-for="(note, i) in user.pinnedNotes" class="note" :note="note" :key="note.id" :detail="true" :pinned="true"/>
|
||||||
</sequential-entrance>
|
</sequential-entrance>
|
||||||
<mk-container :body-togglable="true" class="content">
|
<mk-container :body-togglable="true" class="content">
|
||||||
<template #header><fa :icon="faImage"/>{{ $t('images') }}</template>
|
<template #header><fa :icon="faImage"/>{{ $t('images') }}</template>
|
||||||
@ -269,10 +269,11 @@ export default Vue.extend({
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 12px;
|
top: 12px;
|
||||||
left: 12px;
|
left: 12px;
|
||||||
padding: 4px 6px;
|
padding: 4px 8px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
background: rgba(0, 0, 0, 0.7);
|
background: rgba(0, 0, 0, 0.7);
|
||||||
font-size: 12px;
|
font-size: 0.7em;
|
||||||
|
border-radius: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .actions {
|
> .actions {
|
||||||
|
@ -22,6 +22,7 @@ const defaultDeviceSettings = {
|
|||||||
loadRawImages: false,
|
loadRawImages: false,
|
||||||
alwaysShowNsfw: false,
|
alwaysShowNsfw: false,
|
||||||
useOsDefaultEmojis: false,
|
useOsDefaultEmojis: false,
|
||||||
|
autoReload: false,
|
||||||
accounts: [],
|
accounts: [],
|
||||||
recentEmojis: [],
|
recentEmojis: [],
|
||||||
visibility: 'public',
|
visibility: 'public',
|
||||||
|
@ -339,3 +339,22 @@ a {
|
|||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes jump {
|
||||||
|
0% { transform: translateY(0); }
|
||||||
|
25% { transform: translateY(-16px); }
|
||||||
|
50% { transform: translateY(0); }
|
||||||
|
75% { transform: translateY(-8px); }
|
||||||
|
100% { transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blink {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
30% { opacity: 1; }
|
||||||
|
90% { opacity: 0; }
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ import { apLogger } from '../logger';
|
|||||||
import { DriveFile } from '../../../models/entities/drive-file';
|
import { DriveFile } from '../../../models/entities/drive-file';
|
||||||
import { deliverQuestionUpdate } from '../../../services/note/polls/update';
|
import { deliverQuestionUpdate } from '../../../services/note/polls/update';
|
||||||
import { extractDbHost, toPuny } from '../../../misc/convert-host';
|
import { extractDbHost, toPuny } from '../../../misc/convert-host';
|
||||||
import { Notes, Emojis, Polls } from '../../../models';
|
import { Notes, Emojis, Polls, MessagingMessages } from '../../../models';
|
||||||
import { Note } from '../../../models/entities/note';
|
import { Note } from '../../../models/entities/note';
|
||||||
import { IObject, getOneApId, getApId, validPost, ICreate, isCreate, IPost } from '../type';
|
import { IObject, getOneApId, getApId, validPost, ICreate, isCreate, IPost } from '../type';
|
||||||
import { Emoji } from '../../../models/entities/emoji';
|
import { Emoji } from '../../../models/entities/emoji';
|
||||||
@ -129,6 +129,8 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isTalk = note._misskey_talk && visibility === 'specified';
|
||||||
|
|
||||||
const apHashtags = await extractHashtags(note.tag);
|
const apHashtags = await extractHashtags(note.tag);
|
||||||
|
|
||||||
// 添付ファイル
|
// 添付ファイル
|
||||||
@ -153,7 +155,18 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
|
|||||||
} else {
|
} else {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
}).catch(async e => {
|
||||||
|
// トークだったらinReplyToのエラーは無視
|
||||||
|
const uri = getApId(note.inReplyTo);
|
||||||
|
if (uri.startsWith(config.url + '/')) {
|
||||||
|
const id = uri.split('/').pop();
|
||||||
|
const talk = await MessagingMessages.findOne(id);
|
||||||
|
if (talk) {
|
||||||
|
isTalk = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`);
|
logger.warn(`Error in inReplyTo ${note.inReplyTo} - ${e.statusCode || e}`);
|
||||||
throw e;
|
throw e;
|
||||||
})
|
})
|
||||||
@ -250,7 +263,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
|
|||||||
if (actor.uri) updatePerson(actor.uri);
|
if (actor.uri) updatePerson(actor.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note._misskey_talk && visibility === 'specified') {
|
if (isTalk) {
|
||||||
for (const recipient of visibleUsers) {
|
for (const recipient of visibleUsers) {
|
||||||
await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null, object.id);
|
await createMessage(actor, recipient, undefined, text || undefined, (files && files.length > 0) ? files[0] : null, object.id);
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import config from '../../../config';
|
import config from '../../../config';
|
||||||
import { ILocalUser } from '../../../models/entities/user';
|
import { NoteReaction } from '../../../models/entities/note-reaction';
|
||||||
import { Note } from '../../../models/entities/note';
|
import { Note } from '../../../models/entities/note';
|
||||||
|
|
||||||
export default (user: ILocalUser, note: Note, reaction: string) => ({
|
export const renderLike = (noteReaction: NoteReaction, note: Note) => ({
|
||||||
type: 'Like',
|
type: 'Like',
|
||||||
actor: `${config.url}/users/${user.id}`,
|
id: `${config.url}/likes/${noteReaction.id}`,
|
||||||
object: note.uri ? note.uri : `${config.url}/notes/${note.id}`,
|
actor: `${config.url}/users/${noteReaction.userId}`,
|
||||||
_misskey_reaction: reaction
|
object: note.uri ? note.uri : `${config.url}/notes/${noteReaction.noteId}`,
|
||||||
|
content: noteReaction.reaction,
|
||||||
|
_misskey_reaction: noteReaction.reaction
|
||||||
});
|
});
|
||||||
|
@ -13,10 +13,11 @@ import Following from './activitypub/following';
|
|||||||
import Featured from './activitypub/featured';
|
import Featured from './activitypub/featured';
|
||||||
import { inbox as processInbox } from '../queue';
|
import { inbox as processInbox } from '../queue';
|
||||||
import { isSelfHost } from '../misc/convert-host';
|
import { isSelfHost } from '../misc/convert-host';
|
||||||
import { Notes, Users, Emojis, UserKeypairs } from '../models';
|
import { Notes, Users, Emojis, UserKeypairs, NoteReactions } from '../models';
|
||||||
import { ILocalUser, User } from '../models/entities/user';
|
import { ILocalUser, User } from '../models/entities/user';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { ensure } from '../prelude/ensure';
|
import { ensure } from '../prelude/ensure';
|
||||||
|
import { renderLike } from '../remote/activitypub/renderer/like';
|
||||||
|
|
||||||
// Init router
|
// Init router
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
@ -202,4 +203,25 @@ router.get('/emojis/:emoji', async ctx => {
|
|||||||
setResponseType(ctx);
|
setResponseType(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// like
|
||||||
|
router.get('/likes/:like', async ctx => {
|
||||||
|
const reaction = await NoteReactions.findOne(ctx.params.like);
|
||||||
|
|
||||||
|
if (reaction == null) {
|
||||||
|
ctx.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const note = await Notes.findOne(reaction.noteId);
|
||||||
|
|
||||||
|
if (note == null) {
|
||||||
|
ctx.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = renderActivity(await renderLike(reaction, note));
|
||||||
|
ctx.set('Cache-Control', 'public, max-age=180');
|
||||||
|
setResponseType(ctx);
|
||||||
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { publishNoteStream } from '../../stream';
|
import { publishNoteStream } from '../../stream';
|
||||||
import watch from '../watch';
|
import watch from '../watch';
|
||||||
import renderLike from '../../../remote/activitypub/renderer/like';
|
import { renderLike } from '../../../remote/activitypub/renderer/like';
|
||||||
import DeliverManager from '../../../remote/activitypub/deliver-manager';
|
import DeliverManager from '../../../remote/activitypub/deliver-manager';
|
||||||
import { renderActivity } from '../../../remote/activitypub/renderer';
|
import { renderActivity } from '../../../remote/activitypub/renderer';
|
||||||
import { IdentifiableError } from '../../../misc/identifiable-error';
|
import { IdentifiableError } from '../../../misc/identifiable-error';
|
||||||
@ -38,7 +38,7 @@ export default async (user: User, note: Note, reaction?: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create reaction
|
// Create reaction
|
||||||
await NoteReactions.save({
|
const inserted = await NoteReactions.save({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
noteId: note.id,
|
noteId: note.id,
|
||||||
@ -94,7 +94,7 @@ export default async (user: User, note: Note, reaction?: string) => {
|
|||||||
|
|
||||||
//#region 配信
|
//#region 配信
|
||||||
if (Users.isLocalUser(user) && !note.localOnly) {
|
if (Users.isLocalUser(user) && !note.localOnly) {
|
||||||
const content = renderActivity(renderLike(user, note, reaction));
|
const content = renderActivity(renderLike(inserted, note));
|
||||||
const dm = new DeliverManager(user, content);
|
const dm = new DeliverManager(user, content);
|
||||||
if (note.userHost !== null) {
|
if (note.userHost !== null) {
|
||||||
const reactee = await Users.findOne(note.userId)
|
const reactee = await Users.findOne(note.userId)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { publishNoteStream } from '../../stream';
|
import { publishNoteStream } from '../../stream';
|
||||||
import renderLike from '../../../remote/activitypub/renderer/like';
|
import { renderLike } from '../../../remote/activitypub/renderer/like';
|
||||||
import renderUndo from '../../../remote/activitypub/renderer/undo';
|
import renderUndo from '../../../remote/activitypub/renderer/undo';
|
||||||
import { renderActivity } from '../../../remote/activitypub/renderer';
|
import { renderActivity } from '../../../remote/activitypub/renderer';
|
||||||
import DeliverManager from '../../../remote/activitypub/deliver-manager';
|
import DeliverManager from '../../../remote/activitypub/deliver-manager';
|
||||||
@ -40,7 +40,7 @@ export default async (user: User, note: Note) => {
|
|||||||
|
|
||||||
//#region 配信
|
//#region 配信
|
||||||
if (Users.isLocalUser(user) && !note.localOnly) {
|
if (Users.isLocalUser(user) && !note.localOnly) {
|
||||||
const content = renderActivity(renderUndo(renderLike(user, note, exist.reaction), user));
|
const content = renderActivity(renderUndo(renderLike(exist, note), user));
|
||||||
const dm = new DeliverManager(user, content);
|
const dm = new DeliverManager(user, content);
|
||||||
if (note.userHost !== null) {
|
if (note.userHost !== null) {
|
||||||
const reactee = await Users.findOne(note.userId)
|
const reactee = await Users.findOne(note.userId)
|
||||||
|
Reference in New Issue
Block a user