From fdd42fc2d7ee1aa84489e668971f013b6c06c3df Mon Sep 17 00:00:00 2001
From: MeiMei <30769358+mei23@users.noreply.github.com>
Date: Thu, 27 Dec 2018 23:14:30 +0900
Subject: [PATCH] user mention (#3771)

---
 locales/ja-JP.yml                                    |  3 +++
 src/client/app/common/views/components/note-menu.vue | 11 +++++++++++
 src/client/app/desktop/script.ts                     |  1 +
 .../desktop/views/components/post-form-window.vue    |  5 +++++
 .../app/desktop/views/components/post-form.vue       | 11 ++++++++++-
 .../desktop/views/pages/deck/deck.user-column.vue    | 12 +++++++++++-
 .../app/desktop/views/pages/user/user.header.vue     |  4 ++++
 src/client/app/mobile/script.ts                      |  1 +
 .../app/mobile/views/components/post-form-dialog.vue |  5 +++++
 src/client/app/mobile/views/components/post-form.vue |  9 +++++++++
 src/client/app/mobile/views/pages/user.vue           |  8 ++++++++
 11 files changed, 68 insertions(+), 2 deletions(-)

diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 638568466d..d8f2ed9bfb 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -360,6 +360,7 @@ common/views/components/nav.vue:
   feedback: "フィードバック"
 
 common/views/components/note-menu.vue:
+  mention: "メンション"
   detail: "詳細"
   copy-link: "リンクをコピー"
   favorite: "お気に入り"
@@ -1365,6 +1366,7 @@ desktop/views/pages/user/user.header.vue:
   posts: "投稿"
   following: "フォロー"
   followers: "フォロワー"
+  mention: "メンション"
   is-bot: "このアカウントはBotです"
   years-old: "{age}歳"
   year: "年"
@@ -1715,6 +1717,7 @@ deck/deck.user-column.vue:
   posts: "投稿"
   following: "フォロー"
   followers: "フォロワー"
+  mention: "メンション"
   images: "画像"
   activity: "アクティビティ"
   timeline: "タイムライン"
diff --git a/src/client/app/common/views/components/note-menu.vue b/src/client/app/common/views/components/note-menu.vue
index b8f34beb0c..df52df26cb 100644
--- a/src/client/app/common/views/components/note-menu.vue
+++ b/src/client/app/common/views/components/note-menu.vue
@@ -17,6 +17,13 @@ export default Vue.extend({
 	computed: {
 		items(): any[] {
 			return concat(intersperse([null], [
+				[
+					[{
+						icon: 'at',
+						text: this.$t('mention'),
+						action: this.mention
+					}]
+				],
 				[
 					[{
 						icon: 'info-circle',
@@ -66,6 +73,10 @@ export default Vue.extend({
 	},
 
 	methods: {
+		mention() {
+			this.$post({ mention: this.note.user });
+		},
+
 		detail() {
 			this.$router.push(`/notes/${this.note.id}`);
 		},
diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts
index 1dd55910c1..95bfe6ec1d 100644
--- a/src/client/app/desktop/script.ts
+++ b/src/client/app/desktop/script.ts
@@ -70,6 +70,7 @@ init(async (launch) => {
 				} else {
 					const vm = this.$root.new(PostFormWindow, {
 						reply: o.reply,
+						mention: o.mention,
 						animation: o.animation == null ? true : o.animation
 					});
 					if (o.cb) vm.$once('closed', o.cb);
diff --git a/src/client/app/desktop/views/components/post-form-window.vue b/src/client/app/desktop/views/components/post-form-window.vue
index cebf480bf1..1ed88ec1d9 100644
--- a/src/client/app/desktop/views/components/post-form-window.vue
+++ b/src/client/app/desktop/views/components/post-form-window.vue
@@ -12,6 +12,7 @@
 		<mk-note-preview v-if="reply" class="notePreview" :note="reply"/>
 		<mk-post-form ref="form"
 			:reply="reply"
+			:mention="mention"
 			@posted="onPosted"
 			@change-uploadings="onChangeUploadings"
 			@change-attached-files="onChangeFiles"
@@ -32,6 +33,10 @@ export default Vue.extend({
 			type: Object,
 			required: false
 		},
+		mention: {
+			type: Object,
+			required: false
+		},
 
 		animation: {
 			type: Boolean,
diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue
index 9417db0f85..7e402f2b59 100644
--- a/src/client/app/desktop/views/components/post-form.vue
+++ b/src/client/app/desktop/views/components/post-form.vue
@@ -92,6 +92,10 @@ export default Vue.extend({
 			type: Object,
 			required: false
 		},
+		mention: {
+			type: Object,
+			required: false
+		},
 		initialText: {
 			type: String,
 			required: false
@@ -178,6 +182,11 @@ export default Vue.extend({
 			this.text = this.initialText;
 		}
 
+		if (this.mention) {
+			this.text = this.mention.host ? `@${this.mention.username}@${toASCII(this.mention.host)}` : `@${this.mention.username}`;
+			this.text += ' ';
+		}
+
 		if (this.reply && this.reply.user.host != null) {
 			this.text = `@${this.reply.user.username}@${toASCII(this.reply.user.host)} `;
 		}
@@ -215,7 +224,7 @@ export default Vue.extend({
 
 		this.$nextTick(() => {
 			// 書きかけの投稿を復元
-			if (!this.instant) {
+			if (!this.instant && !this.mention) {
 				const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[this.draftId];
 				if (draft) {
 					this.text = draft.data.text;
diff --git a/src/client/app/desktop/views/pages/deck/deck.user-column.vue b/src/client/app/desktop/views/pages/deck/deck.user-column.vue
index 9281d63cf0..f87b828cf0 100644
--- a/src/client/app/desktop/views/pages/deck/deck.user-column.vue
+++ b/src/client/app/desktop/views/pages/deck/deck.user-column.vue
@@ -49,6 +49,9 @@
 					<b>{{ user.followersCount | number }}</b>
 					<span>{{ $t('followers') }}</span>
 				</div>
+				<div class="mention">
+					<button @click="mention" :title="$t('mention')"><fa icon="at"/></button>
+				</div>
 			</div>
 		</div>
 		<div class="pinned" v-if="user.pinnedNotes && user.pinnedNotes.length > 0">
@@ -307,6 +310,10 @@ export default Vue.extend({
 			return promise;
 		},
 
+		mention() {
+			this.$post({ mention: this.user });
+		},
+
 		menu() {
 			let menu = [{
 				icon: 'list',
@@ -454,7 +461,7 @@ export default Vue.extend({
 
 		> .counts
 			display grid
-			grid-template-columns 1fr 1fr 1fr
+			grid-template-columns 2fr 2fr 2fr 1fr
 			margin-top 8px
 			border-top solid 1px var(--faceDivider)
 
@@ -471,6 +478,9 @@ export default Vue.extend({
 					font-size 80%
 					opacity 0.7
 
+			> .mention
+				display flex
+
 	> *
 		> p.caption
 			margin 0
diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue
index 685eff7326..1bc035eeac 100644
--- a/src/client/app/desktop/views/pages/user/user.header.vue
+++ b/src/client/app/desktop/views/pages/user/user.header.vue
@@ -36,6 +36,7 @@
 			<span class="notes-count"><b>{{ user.notesCount | number }}</b>{{ $t('posts') }}</span>
 			<router-link :to="user | userPage('following')" class="following clickable"><b>{{ user.followingCount | number }}</b>{{ $t('following') }}</router-link>
 			<router-link :to="user | userPage('followers')" class="followers clickable"><b>{{ user.followersCount | number }}</b>{{ $t('followers') }}</router-link>
+			<button @click="mention" :title="$t('mention')"><fa icon="at"/></button>
 		</div>
 	</div>
 </div>
@@ -77,6 +78,9 @@ export default Vue.extend({
 		}
 	},
 	methods: {
+		mention() {
+			this.$post({ mention: this.user });
+		},
 		onScroll() {
 			const banner = this.$refs.banner as any;
 
diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts
index e0ccbad792..52b0d9bbb2 100644
--- a/src/client/app/mobile/script.ts
+++ b/src/client/app/mobile/script.ts
@@ -60,6 +60,7 @@ init((launch) => {
 
 				const vm = this.$root.new(PostForm, {
 					reply: o.reply,
+					mention: o.mention,
 					renote: o.renote
 				});
 
diff --git a/src/client/app/mobile/views/components/post-form-dialog.vue b/src/client/app/mobile/views/components/post-form-dialog.vue
index 15b36db945..616623cda7 100644
--- a/src/client/app/mobile/views/components/post-form-dialog.vue
+++ b/src/client/app/mobile/views/components/post-form-dialog.vue
@@ -5,6 +5,7 @@
 		<mk-post-form ref="form"
 			:reply="reply"
 			:renote="renote"
+			:mention="mention"
 			:initial-text="initialText"
 			:instant="instant"
 			@posted="onPosted"
@@ -27,6 +28,10 @@ export default Vue.extend({
 			type: Object,
 			required: false
 		},
+		mention: {
+			type: Object,
+			required: false
+		},
 		initialText: {
 			type: String,
 			required: false
diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue
index bd3154576b..282ecc387c 100644
--- a/src/client/app/mobile/views/components/post-form.vue
+++ b/src/client/app/mobile/views/components/post-form.vue
@@ -84,6 +84,10 @@ export default Vue.extend({
 			type: Object,
 			required: false
 		},
+		mention: {
+			type: Object,
+			required: false
+		},
 		initialText: {
 			type: String,
 			required: false
@@ -172,6 +176,11 @@ export default Vue.extend({
 			this.text = `@${this.reply.user.username}@${toASCII(this.reply.user.host)} `;
 		}
 
+		if (this.mention) {
+			this.text = this.mention.host ? `@${this.mention.username}@${toASCII(this.mention.host)}` : `@${this.mention.username}`;
+			this.text += ' ';
+		}
+
 		if (this.reply && this.reply.text != null) {
 			const ast = parse(this.reply.text);
 
diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue
index 1a4f9f7cd7..fdfe4ce52f 100644
--- a/src/client/app/mobile/views/pages/user.vue
+++ b/src/client/app/mobile/views/pages/user.vue
@@ -55,6 +55,7 @@
 						<b>{{ user.followersCount | number }}</b>
 						<i>{{ $t('followers') }}</i>
 					</a>
+					<button @click="mention"><fa icon="at"/></button>
 				</div>
 			</div>
 		</header>
@@ -126,6 +127,10 @@ export default Vue.extend({
 			});
 		},
 
+		mention() {
+			this.$post({ mention: this.user });
+		},
+
 		menu() {
 			let menu = [{
 				icon: ['fas', 'list'],
@@ -365,6 +370,9 @@ main
 					> i
 						font-size 14px
 
+				> button
+					color var(--text)
+
 	> nav
 		position -webkit-sticky
 		position sticky