diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue index d61c598ec..af68d8374 100644 --- a/src/client/app/common/views/components/autocomplete.vue +++ b/src/client/app/common/views/components/autocomplete.vue @@ -3,7 +3,9 @@ <ol class="users" ref="suggests" v-if="users.length > 0"> <li v-for="user in users" @click="complete(type, user)" @keydown="onKeydown" tabindex="-1"> <img class="avatar" :src="user.avatarUrl" alt=""/> - <span class="name">{{ user | userName }}</span> + <span class="name"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </span> <span class="username">@{{ user | acct }}</span> </li> </ol> diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index a8fef35b8..4ea2ea941 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -1,5 +1,5 @@ <template> -<img v-if="customEmoji" class="fvgwvorwhxigeolkkrcderjzcawqrscl custom" :src="url" :alt="alt" :title="alt"/> +<img v-if="customEmoji" class="fvgwvorwhxigeolkkrcderjzcawqrscl custom" :class="{ normal: normal }" :src="url" :alt="alt" :title="alt"/> <img v-else-if="char && !useOsDefaultEmojis" class="fvgwvorwhxigeolkkrcderjzcawqrscl" :src="url" :alt="alt" :title="alt"/> <span v-else-if="char && useOsDefaultEmojis">{{ char }}</span> <span v-else>:{{ name }}:</span> @@ -20,6 +20,11 @@ export default Vue.extend({ type: String, required: false }, + normal: { + type: Boolean, + required: false, + default: false + }, customEmojis: { required: false, default: () => [] @@ -83,4 +88,11 @@ export default Vue.extend({ &:hover transform scale(1.2) + &.normal + height 1.25em + vertical-align -0.25em + + &:hover + transform none + </style> diff --git a/src/client/app/common/views/components/mfm.ts b/src/client/app/common/views/components/mfm.ts index accacf150..8d7d36052 100644 --- a/src/client/app/common/views/components/mfm.ts +++ b/src/client/app/common/views/components/mfm.ts @@ -49,6 +49,10 @@ export default Vue.component('misskey-flavored-markdown', { type: Boolean, default: true }, + plainText: { + type: Boolean, + default: false + }, author: { type: Object, default: null @@ -69,7 +73,7 @@ export default Vue.component('misskey-flavored-markdown', { if (this.ast == null) { // Parse text to ast - ast = parse(this.text); + ast = parse(this.text, this.plainText); } else { ast = this.ast as Node[]; } @@ -254,7 +258,8 @@ export default Vue.component('misskey-flavored-markdown', { name: token.props.name }, props: { - customEmojis: this.customEmojis || customEmojis + customEmojis: this.customEmojis || customEmojis, + normal: this.plainText } })]; } diff --git a/src/client/app/common/views/components/note-header.vue b/src/client/app/common/views/components/note-header.vue index 1e457d2d7..5204b78a4 100644 --- a/src/client/app/common/views/components/note-header.vue +++ b/src/client/app/common/views/components/note-header.vue @@ -1,7 +1,9 @@ <template> <header class="bvonvjxbwzaiskogyhbwgyxvcgserpmu"> <mk-avatar class="avatar" :user="note.user" v-if="$store.state.device.postStyle == 'smart'"/> - <router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link> + <router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id"> + <misskey-flavored-markdown :text="note.user.name || note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="note.user.emojis"/> + </router-link> <span class="is-admin" v-if="note.user.isAdmin">admin</span> <span class="is-bot" v-if="note.user.isBot">bot</span> <span class="is-cat" v-if="note.user.isCat">cat</span> diff --git a/src/client/app/common/views/components/renote.vue b/src/client/app/common/views/components/renote.vue index bfefc3cc9..58d0f597c 100644 --- a/src/client/app/common/views/components/renote.vue +++ b/src/client/app/common/views/components/renote.vue @@ -3,7 +3,9 @@ <mk-avatar class="avatar" :user="note.user"/> <fa icon="retweet"/> <i18n path="@.renoted-by" tag="span"> - <router-link class="name" :to="note.user | userPage" v-user-preview="note.userId" place="user">{{ note.user | userName }}</router-link> + <router-link class="name" :to="note.user | userPage" v-user-preview="note.userId" place="user"> + <misskey-flavored-markdown :text="note.user.name || note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="note.user.emojis"/> + </router-link> </i18n> <div class="info"> <span class="mobile" v-if="note.viaMobile"><fa icon="mobile-alt"/></span> diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue index d075f0693..f25bc0222 100644 --- a/src/client/app/common/views/components/welcome-timeline.vue +++ b/src/client/app/common/views/components/welcome-timeline.vue @@ -5,7 +5,9 @@ <mk-avatar class="avatar" :user="note.user" target="_blank"/> <div class="body"> <header> - <router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id">{{ note.user | userName }}</router-link> + <router-link class="name" :to="note.user | userPage" v-user-preview="note.user.id"> + <misskey-flavored-markdown :text="note.user.name || note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="note.user.emojis"/> + </router-link> <span class="username">@{{ note.user | acct }}</span> <div class="info"> <router-link class="created-at" :to="note | notePage"> diff --git a/src/client/app/common/views/pages/follow.vue b/src/client/app/common/views/pages/follow.vue index 72b0b73e0..22f5478d3 100644 --- a/src/client/app/common/views/pages/follow.vue +++ b/src/client/app/common/views/pages/follow.vue @@ -6,10 +6,12 @@ <div class="banner" :style="bannerStyle"></div> <mk-avatar class="avatar" :user="user" :disable-preview="true"/> <div class="body"> - <router-link :to="user | userPage" class="name">{{ user | userName }}</router-link> + <router-link :to="user | userPage" class="name"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </router-link> <span class="username">@{{ user | acct }}</span> <div class="description"> - <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> </div> </main> diff --git a/src/client/app/desktop/views/components/friends-maker.vue b/src/client/app/desktop/views/components/friends-maker.vue index 36526283e..4b81b2f95 100644 --- a/src/client/app/desktop/views/components/friends-maker.vue +++ b/src/client/app/desktop/views/components/friends-maker.vue @@ -5,7 +5,9 @@ <div class="user" v-for="user in users" :key="user.id"> <mk-avatar class="avatar" :user="user" target="_blank"/> <div class="body"> - <router-link class="name" :to="user | userPage" v-user-preview="user.id">{{ user | userName }}</router-link> + <router-link class="name" :to="user | userPage" v-user-preview="user.id"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </router-link> <p class="username">@{{ user | acct }}</p> </div> </div> diff --git a/src/client/app/desktop/views/components/note-detail.vue b/src/client/app/desktop/views/components/note-detail.vue index 3ada2b9b8..ba537d922 100644 --- a/src/client/app/desktop/views/components/note-detail.vue +++ b/src/client/app/desktop/views/components/note-detail.vue @@ -20,7 +20,9 @@ <article> <mk-avatar class="avatar" :user="appearNote.user"/> <header> - <router-link class="name" :to="appearNote.user | userPage" v-user-preview="appearNote.user.id">{{ appearNote.user | userName }}</router-link> + <router-link class="name" :to="appearNote.user | userPage" v-user-preview="appearNote.user.id"> + <misskey-flavored-markdown :text="appearNote.user.name || appearNote.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="appearNote.user.emojis"/> + </router-link> <span class="username"><mk-acct :user="appearNote.user"/></span> <div class="info"> <router-link class="time" :to="appearNote | notePage"> diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue index 54253b220..47dce22df 100644 --- a/src/client/app/desktop/views/components/notifications.vue +++ b/src/client/app/desktop/views/components/notifications.vue @@ -18,7 +18,9 @@ <div class="text"> <p> <mk-reaction-icon :reaction="notification.reaction"/> - <router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage" v-user-preview="notification.user.id"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> </p> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> <fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/> @@ -30,7 +32,9 @@ <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> <p><fa icon="retweet"/> - <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link> + <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId"> + <misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/> + </router-link> </p> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)"> <fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/> @@ -42,7 +46,9 @@ <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> <p><fa icon="quote-left"/> - <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link> + <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId"> + <misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/> + </router-link> </p> <router-link class="note-preview" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">{{ getNoteSummary(notification.note) }}</router-link> </div> @@ -52,7 +58,9 @@ <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> <p><fa icon="user-plus"/> - <router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage" v-user-preview="notification.user.id"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> </p> </div> </template> @@ -61,7 +69,9 @@ <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> <p><fa icon="user-clock"/> - <router-link :to="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage" v-user-preview="notification.user.id"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> </p> </div> </template> @@ -70,7 +80,9 @@ <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> <p><fa icon="reply"/> - <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link> + <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId"> + <misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/> + </router-link> </p> <router-link class="note-preview" :to="notification.note | notePage" :title="getNoteSummary(notification.note)">{{ getNoteSummary(notification.note) }}</router-link> </div> @@ -80,7 +92,9 @@ <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> <p><fa icon="at"/> - <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId">{{ notification.note.user | userName }}</router-link> + <router-link :to="notification.note.user | userPage" v-user-preview="notification.note.userId"> + <misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/> + </router-link> </p> <a class="note-preview" :href="notification.note | notePage" :title="getNoteSummary(notification.note)">{{ getNoteSummary(notification.note) }}</a> </div> @@ -89,7 +103,9 @@ <template v-if="notification.type == 'poll_vote'"> <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> - <p><fa icon="chart-pie"/><a :href="notification.user | userPage" v-user-preview="notification.user.id">{{ notification.user | userName }}</a></p> + <p><fa icon="chart-pie"/><a :href="notification.user | userPage" v-user-preview="notification.user.id"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </a></p> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> <fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/> </router-link> diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue index 0a971b51f..9b1d4fb95 100644 --- a/src/client/app/desktop/views/components/post-form.vue +++ b/src/client/app/desktop/views/components/post-form.vue @@ -7,7 +7,9 @@ > <div class="content"> <div v-if="visibility == 'specified'" class="visibleUsers"> - <span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span> + <span v-for="u in visibleUsers"> + <misskey-flavored-markdown :text="u.name || u.username" :shouldBreak="false" :plainText="true" :custom-emojis="u.emojis"/> + <a @click="removeVisibleUser(u)">[x]</a></span> <a @click="addVisibleUser">{{ $t('add-visible-user') }}</a> </div> <div class="hashtags" v-if="recentHashtags.length > 0 && $store.state.settings.suggestRecentHashtags"> diff --git a/src/client/app/desktop/views/components/received-follow-requests-window.vue b/src/client/app/desktop/views/components/received-follow-requests-window.vue index cadf195d3..61bddf530 100644 --- a/src/client/app/desktop/views/components/received-follow-requests-window.vue +++ b/src/client/app/desktop/views/components/received-follow-requests-window.vue @@ -4,7 +4,9 @@ <div class="slpqaxdoxhvglersgjukmvizkqbmbokc"> <div v-for="req in requests"> - <router-link :key="req.id" :to="req.follower | userPage">{{ req.follower | userName }}</router-link> + <router-link :key="req.id" :to="req.follower | userPage"> + <misskey-flavored-markdown :text="req.follower.name || req.follower.username" :shouldBreak="false" :plainText="true" :custom-emojis="req.follower.emojis"/> + </router-link> <span> <a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a> </span> diff --git a/src/client/app/desktop/views/components/user-card.vue b/src/client/app/desktop/views/components/user-card.vue index c5d925fe6..ffea85d41 100644 --- a/src/client/app/desktop/views/components/user-card.vue +++ b/src/client/app/desktop/views/components/user-card.vue @@ -4,10 +4,12 @@ <mk-avatar class="avatar" :user="user" :disable-preview="true"/> <mk-follow-button :user="user" class="follow" mini/> <div class="body"> - <router-link :to="user | userPage" class="name">{{ user | userName }}</router-link> + <router-link :to="user | userPage" class="name"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </router-link> <span class="username">@{{ user | acct }}</span> <div class="description"> - <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> </div> </div> diff --git a/src/client/app/desktop/views/components/user-preview.vue b/src/client/app/desktop/views/components/user-preview.vue index a4e7eb735..e1146c25b 100644 --- a/src/client/app/desktop/views/components/user-preview.vue +++ b/src/client/app/desktop/views/components/user-preview.vue @@ -4,10 +4,14 @@ <div class="banner" :style="u.bannerUrl ? `background-image: url(${u.bannerUrl})` : ''"></div> <mk-avatar class="avatar" :user="u" :disable-preview="true"/> <div class="title"> - <router-link class="name" :to="u | userPage">{{ u | userName }}</router-link> + <router-link class="name" :to="u | userPage"> + <misskey-flavored-markdown :text="u.name || u.username" :shouldBreak="false" :plainText="true" :custom-emojis="u.emojis"/> + </router-link> <p class="username"><mk-acct :user="u"/></p> </div> - <div class="description">{{ u.description }}</div> + <div class="description"> + <misskey-flavored-markdown v-if="u.description" :text="u.description" :author="u" :i="$store.state.i" :custom-emojis="u.emojis"/> + </div> <div class="status"> <div> <p>{{ $t('notes') }}</p><span>{{ u.notesCount }}</span> diff --git a/src/client/app/desktop/views/pages/deck/deck.notification.vue b/src/client/app/desktop/views/pages/deck/deck.notification.vue index fce9853b6..4347d8c12 100644 --- a/src/client/app/desktop/views/pages/deck/deck.notification.vue +++ b/src/client/app/desktop/views/pages/deck/deck.notification.vue @@ -5,7 +5,9 @@ <div> <header> <mk-reaction-icon :reaction="notification.reaction"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> <mk-time :time="notification.createdAt"/> </header> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> @@ -20,7 +22,9 @@ <div> <header> <fa icon="retweet"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> <mk-time :time="notification.createdAt"/> </header> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)"> @@ -34,7 +38,9 @@ <div> <header> <fa icon="user-plus"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> <mk-time :time="notification.createdAt"/> </header> </div> @@ -45,7 +51,9 @@ <div> <header> <fa icon="user-clock"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> <mk-time :time="notification.createdAt"/> </header> </div> @@ -56,7 +64,9 @@ <div> <header> <fa icon="chart-pie"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"> + <misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/> + </router-link> <mk-time :time="notification.createdAt"/> </header> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> 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 404e93442..f1bcc48af 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 @@ -16,13 +16,15 @@ <button class="menu" @click="menu" ref="menu"><fa icon="ellipsis-h"/></button> <mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" class="follow" mini/> <mk-avatar class="avatar" :user="user" :disable-preview="true"/> - <span class="name">{{ user | userName }}</span> + <span class="name"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </span> <span class="acct">@{{ user | acct }}</span> </div> </header> <div class="info"> <div class="description"> - <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> <div class="counts"> <div> diff --git a/src/client/app/desktop/views/pages/user-following-or-followers.vue b/src/client/app/desktop/views/pages/user-following-or-followers.vue index 6cb634008..0b0114cc2 100644 --- a/src/client/app/desktop/views/pages/user-following-or-followers.vue +++ b/src/client/app/desktop/views/pages/user-following-or-followers.vue @@ -4,7 +4,9 @@ <header> <mk-avatar class="avatar" :user="user"/> <i18n :path="isFollowing ? 'following' : 'followers'" tag="p"> - <router-link :to="user | userPage" place="user">{{ user | userName }}</router-link> + <router-link :to="user | userPage" place="user"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </router-link> </i18n> </header> <div class="users"> 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 9eacbe391..1904acd96 100644 --- a/src/client/app/desktop/views/pages/user/user.header.vue +++ b/src/client/app/desktop/views/pages/user/user.header.vue @@ -4,7 +4,9 @@ <div class="banner" ref="banner" :style="style" @click="onBannerClick"></div> <div class="fade"></div> <div class="title"> - <p class="name">{{ user | userName }}</p> + <p class="name"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </p> <div> <span class="username"><mk-acct :user="user" :detail="true" /></span> <span v-if="user.isBot" :title="$t('title')"><fa icon="robot"/></span> @@ -14,7 +16,7 @@ <mk-avatar class="avatar" :user="user" :disable-preview="true"/> <div class="body"> <div class="description"> - <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> <div class="info"> <span class="location" v-if="user.host === null && user.profile.location"><fa icon="map-marker"/> {{ user.profile.location }}</span> diff --git a/src/client/app/desktop/views/widgets/profile.vue b/src/client/app/desktop/views/widgets/profile.vue index 47429cd58..1abd655c1 100644 --- a/src/client/app/desktop/views/widgets/profile.vue +++ b/src/client/app/desktop/views/widgets/profile.vue @@ -15,7 +15,9 @@ @click="() => os.apis.updateAvatar()" :title="$t('update-avatar')" /> - <router-link class="name" :to="$store.state.i | userPage">{{ $store.state.i | userName }}</router-link> + <router-link class="name" :to="$store.state.i | userPage"> + <misskey-flavored-markdown :text="$store.state.i.name || $store.state.i.username" :shouldBreak="false" :plainText="true" :custom-emojis="$store.state.i.emojis"/> + </router-link> <p class="username">@{{ $store.state.i | acct }}</p> </div> </mk-widget-container> diff --git a/src/client/app/desktop/views/widgets/users.vue b/src/client/app/desktop/views/widgets/users.vue index 7890b6df0..cfc1afe14 100644 --- a/src/client/app/desktop/views/widgets/users.vue +++ b/src/client/app/desktop/views/widgets/users.vue @@ -13,7 +13,9 @@ <div class="user" v-for="_user in users"> <mk-avatar class="avatar" :user="_user"/> <div class="body"> - <router-link class="name" :to="_user | userPage" v-user-preview="_user.id">{{ _user | userName }}</router-link> + <router-link class="name" :to="_user | userPage" v-user-preview="_user.id"> + <misskey-flavored-markdown :text="_user.name || _user.username" :shouldBreak="false" :plainText="true" :custom-emojis="_user.emojis"/> + </router-link> <p class="username">@{{ _user | acct }}</p> </div> </div> diff --git a/src/client/app/mobile/views/components/note-card.vue b/src/client/app/mobile/views/components/note-card.vue index de9c9c145..013997dd0 100644 --- a/src/client/app/mobile/views/components/note-card.vue +++ b/src/client/app/mobile/views/components/note-card.vue @@ -2,7 +2,9 @@ <div class="mk-note-card"> <a :href="note | notePage"> <header> - <img :src="note.user.avatarUrl" alt="avatar"/><h3>{{ note.user | userName }}</h3> + <img :src="note.user.avatarUrl" alt="avatar"/><h3> + <misskey-flavored-markdown :text="note.user.name || note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="note.user.emojis"/> + </h3> </header> <div> {{ text }} diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue index bcf11696c..e91d66440 100644 --- a/src/client/app/mobile/views/components/note-detail.vue +++ b/src/client/app/mobile/views/components/note-detail.vue @@ -20,7 +20,9 @@ <header> <mk-avatar class="avatar" :user="appearNote.user"/> <div> - <router-link class="name" :to="appearNote.user | userPage">{{ appearNote.user | userName }}</router-link> + <router-link class="name" :to="appearNote.user | userPage"> + <misskey-flavored-markdown :text="appearNote.user.name || appearNote.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="appearNote.user.emojis"/> + </router-link> <span class="username"><mk-acct :user="appearNote.user"/></span> </div> </header> diff --git a/src/client/app/mobile/views/components/notification-preview.vue b/src/client/app/mobile/views/components/notification-preview.vue index 45a2d3b06..7deee66e7 100644 --- a/src/client/app/mobile/views/components/notification-preview.vue +++ b/src/client/app/mobile/views/components/notification-preview.vue @@ -3,7 +3,7 @@ <template v-if="notification.type == 'reaction'"> <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> - <p><mk-reaction-icon :reaction="notification.reaction"/>{{ notification.user | userName }}</p> + <p><mk-reaction-icon :reaction="notification.reaction"/><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></p> <p class="note-ref"><fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/></p> </div> </template> @@ -11,7 +11,7 @@ <template v-if="notification.type == 'renote'"> <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> - <p><fa icon="retweet"/>{{ notification.note.user | userName }}</p> + <p><fa icon="retweet"/><misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/></p> <p class="note-ref"><fa icon="quote-left"/>{{ getNoteSummary(notification.note.renote) }}<fa icon="quote-right"/></p> </div> </template> @@ -19,7 +19,7 @@ <template v-if="notification.type == 'quote'"> <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> - <p><fa icon="quote-left"/>{{ notification.note.user | userName }}</p> + <p><fa icon="quote-left"/><misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/></p> <p class="note-preview">{{ getNoteSummary(notification.note) }}</p> </div> </template> @@ -27,21 +27,21 @@ <template v-if="notification.type == 'follow'"> <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> - <p><fa icon="user-plus"/>{{ notification.user | userName }}</p> + <p><fa icon="user-plus"/><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></p> </div> </template> <template v-if="notification.type == 'receiveFollowRequest'"> <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> - <p><fa icon="user-clock"/>{{ notification.user | userName }}</p> + <p><fa icon="user-clock"/><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></p> </div> </template> <template v-if="notification.type == 'reply'"> <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> - <p><fa icon="reply"/>{{ notification.note.user | userName }}</p> + <p><fa icon="reply"/><misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/></p> <p class="note-preview">{{ getNoteSummary(notification.note) }}</p> </div> </template> @@ -49,7 +49,7 @@ <template v-if="notification.type == 'mention'"> <mk-avatar class="avatar" :user="notification.note.user"/> <div class="text"> - <p><fa icon="at"/>{{ notification.note.user | userName }}</p> + <p><fa icon="at"/><misskey-flavored-markdown :text="notification.note.user.name || notification.note.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.note.user.emojis"/></p> <p class="note-preview">{{ getNoteSummary(notification.note) }}</p> </div> </template> @@ -57,7 +57,7 @@ <template v-if="notification.type == 'poll_vote'"> <mk-avatar class="avatar" :user="notification.user"/> <div class="text"> - <p><fa icon="chart-pie"/>{{ notification.user | userName }}</p> + <p><fa icon="chart-pie"/><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></p> <p class="note-ref"><fa icon="quote-left"/>{{ getNoteSummary(notification.note) }}<fa icon="quote-right"/></p> </div> </template> diff --git a/src/client/app/mobile/views/components/notification.vue b/src/client/app/mobile/views/components/notification.vue index 1228047c9..72cda1b11 100644 --- a/src/client/app/mobile/views/components/notification.vue +++ b/src/client/app/mobile/views/components/notification.vue @@ -5,7 +5,7 @@ <div> <header> <mk-reaction-icon :reaction="notification.reaction"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></router-link> <mk-time :time="notification.createdAt"/> </header> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> @@ -20,7 +20,7 @@ <div> <header> <fa icon="retweet"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></router-link> <mk-time :time="notification.createdAt"/> </header> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note.renote)"> @@ -34,7 +34,7 @@ <div> <header> <fa icon="user-plus"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></router-link> <mk-time :time="notification.createdAt"/> </header> </div> @@ -45,7 +45,7 @@ <div> <header> <fa icon="user-clock"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></router-link> <mk-time :time="notification.createdAt"/> </header> </div> @@ -56,7 +56,7 @@ <div> <header> <fa icon="chart-pie"/> - <router-link :to="notification.user | userPage">{{ notification.user | userName }}</router-link> + <router-link :to="notification.user | userPage"><misskey-flavored-markdown :text="notification.user.name || notification.user.username" :shouldBreak="false" :plainText="true" :custom-emojis="notification.user.emojis"/></router-link> <mk-time :time="notification.createdAt"/> </header> <router-link class="note-ref" :to="notification.note | notePage" :title="getNoteSummary(notification.note)"> diff --git a/src/client/app/mobile/views/components/post-form.vue b/src/client/app/mobile/views/components/post-form.vue index 7757875eb..604e756ad 100644 --- a/src/client/app/mobile/views/components/post-form.vue +++ b/src/client/app/mobile/views/components/post-form.vue @@ -13,7 +13,10 @@ <mk-note-preview class="preview" v-if="reply" :note="reply"/> <mk-note-preview class="preview" v-if="renote" :note="renote"/> <div v-if="visibility == 'specified'" class="visibleUsers"> - <span v-for="u in visibleUsers">{{ u | userName }}<a @click="removeVisibleUser(u)">[x]</a></span> + <span v-for="u in visibleUsers"> + <misskey-flavored-markdown :text="u.name || u.username" :shouldBreak="false" :plainText="true" :custom-emojis="u.emojis"/> + <a @click="removeVisibleUser(u)">[x]</a> + </span> <a @click="addVisibleUser">+{{ $t('add-visible-user') }}</a> </div> <input v-show="useCw" ref="cw" v-model="cw" :placeholder="$t('annotations')" v-autocomplete="'cw'"> diff --git a/src/client/app/mobile/views/components/ui.nav.vue b/src/client/app/mobile/views/components/ui.nav.vue index df4a161e1..8e79f5565 100644 --- a/src/client/app/mobile/views/components/ui.nav.vue +++ b/src/client/app/mobile/views/components/ui.nav.vue @@ -11,7 +11,9 @@ <div class="body" v-if="isOpen"> <router-link class="me" v-if="$store.getters.isSignedIn" :to="`/@${$store.state.i.username}`"> <img class="avatar" :src="$store.state.i.avatarUrl" alt="avatar"/> - <p class="name">{{ $store.state.i | userName }}</p> + <p class="name"> + <misskey-flavored-markdown :text="$store.state.i.name || $store.state.i.username" :shouldBreak="false" :plainText="true" :custom-emojis="$store.state.i.emojis"/> + </p> </router-link> <div class="links"> <ul> diff --git a/src/client/app/mobile/views/components/user-card.vue b/src/client/app/mobile/views/components/user-card.vue index 6d79e7a87..7275cbfed 100644 --- a/src/client/app/mobile/views/components/user-card.vue +++ b/src/client/app/mobile/views/components/user-card.vue @@ -3,7 +3,9 @@ <header :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"> <mk-avatar class="avatar" :user="user"/> </header> - <a class="name" :href="user | userPage" target="_blank">{{ user | userName }}</a> + <a class="name" :href="user | userPage" target="_blank"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </a> <p class="username"><mk-acct :user="user"/></p> <mk-follow-button class="follow-button" :user="user"/> </div> diff --git a/src/client/app/mobile/views/components/user-preview.vue b/src/client/app/mobile/views/components/user-preview.vue index a165e66a9..47960f981 100644 --- a/src/client/app/mobile/views/components/user-preview.vue +++ b/src/client/app/mobile/views/components/user-preview.vue @@ -3,11 +3,15 @@ <mk-avatar class="avatar" :user="user"/> <div class="main"> <header> - <router-link class="name" :to="user | userPage">{{ user | userName }}</router-link> + <router-link class="name" :to="user | userPage"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </router-link> <span class="username"><mk-acct :user="user"/></span> </header> <div class="body"> - <div class="description">{{ user.description }}</div> + <div class="description"> + <misskey-flavored-markdown v-if="u.description" :text="u.description" :author="u" :i="$store.state.i" :custom-emojis="u.emojis"/> + </div> </div> </div> </div> diff --git a/src/client/app/mobile/views/pages/received-follow-requests.vue b/src/client/app/mobile/views/pages/received-follow-requests.vue index 48c46f64c..838ed8adb 100644 --- a/src/client/app/mobile/views/pages/received-follow-requests.vue +++ b/src/client/app/mobile/views/pages/received-follow-requests.vue @@ -4,7 +4,9 @@ <main> <div v-for="req in requests"> - <router-link :key="req.id" :to="req.follower | userPage">{{ req.follower | userName }}</router-link> + <router-link :key="req.id" :to="req.follower | userPage"> + <misskey-flavored-markdown :text="req.follower.name || req.follower.username" :shouldBreak="false" :plainText="true" :custom-emojis="req.follower.emojis"/> + </router-link> <span> <a @click="accept(req.follower)">{{ $t('accept') }}</a>|<a @click="reject(req.follower)">{{ $t('reject') }}</a> </span> diff --git a/src/client/app/mobile/views/pages/user-list.vue b/src/client/app/mobile/views/pages/user-list.vue index fdc621ef7..95f100d61 100644 --- a/src/client/app/mobile/views/pages/user-list.vue +++ b/src/client/app/mobile/views/pages/user-list.vue @@ -4,7 +4,9 @@ <main v-if="!fetching"> <ul> - <li v-for="user in users" :key="user.id"><router-link :to="user | userPage">{{ user | userName }}</router-link></li> + <li v-for="user in users" :key="user.id"><router-link :to="user | userPage"> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </router-link></li> </ul> </main> </mk-ui> diff --git a/src/client/app/mobile/views/pages/user.vue b/src/client/app/mobile/views/pages/user.vue index 15c5fbb9a..183e105a2 100644 --- a/src/client/app/mobile/views/pages/user.vue +++ b/src/client/app/mobile/views/pages/user.vue @@ -1,6 +1,8 @@ <template> <mk-ui> - <template slot="header" v-if="!fetching"><img :src="user.avatarUrl" alt="">{{ user | userName }}</template> + <template slot="header" v-if="!fetching"><img :src="user.avatarUrl" alt=""> + <misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/> + </template> <main v-if="!fetching"> <div class="is-suspended" v-if="user.isSuspended"><p><fa icon="exclamation-triangle"/> {{ $t('is-suspended') }}</p></div> <div class="is-remote" v-if="user.host != null"><p><fa icon="exclamation-triangle"/> {{ $t('@.is-remote-user') }}<a :href="user.url || user.uri" target="_blank">{{ $t('@.view-on-remote') }}</a></p></div> @@ -15,12 +17,12 @@ <mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/> </div> <div class="title"> - <h1>{{ user | userName }}</h1> + <h1><misskey-flavored-markdown :text="user.name || user.username" :shouldBreak="false" :plainText="true" :custom-emojis="user.emojis"/></h1> <span class="username"><mk-acct :user="user" :detail="true" /></span> <span class="followed" v-if="user.isFollowed">{{ $t('follows-you') }}</span> </div> <div class="description"> - <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i"/> + <misskey-flavored-markdown v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> <div class="info"> <p class="location" v-if="user.host === null && user.profile.location"> diff --git a/src/client/app/mobile/views/widgets/profile.vue b/src/client/app/mobile/views/widgets/profile.vue index 6ce3468c4..f6ca793dc 100644 --- a/src/client/app/mobile/views/widgets/profile.vue +++ b/src/client/app/mobile/views/widgets/profile.vue @@ -8,7 +8,9 @@ :src="$store.state.i.avatarUrl" alt="avatar" /> - <router-link :class="$style.name" :to="$store.state.i | userPage">{{ $store.state.i | userName }}</router-link> + <router-link :class="$style.name" :to="$store.state.i | userPage"> + <misskey-flavored-markdown :text="$store.state.i.name || $store.state.i.username" :shouldBreak="false" :plainText="true" :custom-emojis="$store.state.i.emojis"/> + </router-link> </mk-widget-container> </div> </template> diff --git a/src/mfm/parse.ts b/src/mfm/parse.ts index 01c8cc7d7..0dc749a5f 100644 --- a/src/mfm/parse.ts +++ b/src/mfm/parse.ts @@ -1,13 +1,13 @@ -import parser, { Node } from './parser'; +import parser, { Node, plainParser } from './parser'; import * as A from '../prelude/array'; import * as S from '../prelude/string'; -export default (source: string): Node[] => { +export default (source: string, plainText = false): Node[] => { if (source == null || source == '') { return null; } - let nodes: Node[] = parser.root.tryParse(source); + let nodes: Node[] = plainText ? plainParser.root.tryParse(source) : parser.root.tryParse(source); const combineText = (es: Node[]): Node => ({ name: 'text', props: { text: S.concat(es.map(e => e.props.text)) } }); diff --git a/src/mfm/parser.ts b/src/mfm/parser.ts index 9a1264220..de1bc89d2 100644 --- a/src/mfm/parser.ts +++ b/src/mfm/parser.ts @@ -64,6 +64,29 @@ const newline = P((input, i) => { } }); +export const plainParser = P.createLanguage({ + root: r => P.alt( + r.emoji, + r.text + ).atLeast(1), + + text: () => P.any.map(x => makeNode('text', { text: x })), + + //#region Emoji + emoji: r => + P.alt( + P.regexp(/:([a-z0-9_+-]+):/i, 1) + .map(x => makeNode('emoji', { + name: x + })), + P.regexp(emojiRegex) + .map(x => makeNode('emoji', { + emoji: x + })), + ), + //#endregion +}); + const mfm = P.createLanguage({ root: r => P.alt( r.big, diff --git a/src/models/user.ts b/src/models/user.ts index 18e45dbae..90c74fe27 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -11,6 +11,7 @@ import { getFriendIds } from '../server/api/common/get-friends'; import config from '../config'; import FollowRequest from './follow-request'; import fetchMeta from '../misc/fetch-meta'; +import Emoji from './emoji'; const User = db.get<IUser>('users'); @@ -46,6 +47,7 @@ type IUserBase = { description: string; lang?: string; pinnedNoteIds: mongo.ObjectID[]; + emojis?: string[]; /** * 凍結されているか否か @@ -247,6 +249,7 @@ export const pack = ( host: true, avatarColor: true, avatarUrl: true, + emojis: true, isCat: true, isBot: true, isAdmin: true, @@ -377,6 +380,16 @@ export const pack = ( delete _user.hasUnreadMentions; } + // カスタム絵文字添付 + if (_user.emojis) { + _user.emojis = Emoji.find({ + name: { $in: _user.emojis }, + host: _user.host + }, { + fields: { _id: false } + }); + } + // resolve promises in _user object _user = await rap(_user); diff --git a/src/remote/activitypub/models/note.ts b/src/remote/activitypub/models/note.ts index a45946a05..10aa83342 100644 --- a/src/remote/activitypub/models/note.ts +++ b/src/remote/activitypub/models/note.ts @@ -164,7 +164,7 @@ export async function resolveNote(value: string | IObject, resolver?: Resolver): return await createNote(uri, resolver); } -async function extractEmojis(tags: ITag[], host_: string) { +export async function extractEmojis(tags: ITag[], host_: string) { const host = toUnicode(host_.toLowerCase()); if (!tags) return []; diff --git a/src/remote/activitypub/models/person.ts b/src/remote/activitypub/models/person.ts index 90d58a124..9bbc41e62 100644 --- a/src/remote/activitypub/models/person.ts +++ b/src/remote/activitypub/models/person.ts @@ -12,10 +12,11 @@ import Meta from '../../../models/meta'; import htmlToMFM from '../../../mfm/html-to-mfm'; import usersChart from '../../../chart/users'; import { URL } from 'url'; -import { resolveNote } from './note'; +import { resolveNote, extractEmojis } from './note'; import registerInstance from '../../../services/register-instance'; import Instance from '../../../models/instance'; import getDriveFileUrl from '../../../misc/get-drive-file-url'; +import { IEmoji } from '../../../models/emoji'; const log = debug('misskey:activitypub'); @@ -234,6 +235,21 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<IU user.bannerColor = bannerColor; //#endregion + //#region カスタム絵文字取得 + const emojis = await extractEmojis(person.tag, host).catch(e => { + console.log(`extractEmojis: ${e}`); + return [] as IEmoji[]; + }); + + const emojiNames = emojis.map(emoji => emoji.name); + + await User.update({ _id: user._id }, { + $set: { + emojis: emojiNames + } + }); + //#endregion + await updateFeatured(user._id).catch(err => console.log(err)); return user; @@ -301,6 +317,14 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje : resolveImage(exist, img).catch(() => null) ))); + // カスタム絵文字取得 + const emojis = await extractEmojis(person.tag, exist.host).catch(e => { + console.log(`extractEmojis: ${e}`); + return [] as IEmoji[]; + }); + + const emojiNames = emojis.map(emoji => emoji.name); + // Update user await User.update({ _id: exist._id }, { $set: { @@ -314,6 +338,7 @@ export async function updatePerson(uri: string, resolver?: Resolver, hint?: obje bannerUrl: getDriveFileUrl(banner, false), avatarColor: avatar && avatar.metadata.properties.avgColor ? avatar.metadata.properties.avgColor : null, bannerColor: banner && banner.metadata.properties.avgColor ? banner.metadata.properties.avgColor : null, + emojis: emojiNames, description: htmlToMFM(person.summary), followersCount, followingCount, diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts index 76a527e9a..1445429ee 100644 --- a/src/remote/activitypub/renderer/note.ts +++ b/src/remote/activitypub/renderer/note.ts @@ -137,7 +137,7 @@ export default async function renderNote(note: INote, dive = true): Promise<any> }; } -async function getEmojis(names: string[]): Promise<IEmoji[]> { +export async function getEmojis(names: string[]): Promise<IEmoji[]> { if (names == null || names.length < 1) return []; const emojis = await Promise.all( diff --git a/src/remote/activitypub/renderer/person.ts b/src/remote/activitypub/renderer/person.ts index f02710aad..4a6a54881 100644 --- a/src/remote/activitypub/renderer/person.ts +++ b/src/remote/activitypub/renderer/person.ts @@ -5,6 +5,8 @@ import { ILocalUser } from '../../../models/user'; import toHtml from '../../../mfm/html'; import parse from '../../../mfm/parse'; import DriveFile from '../../../models/drive-file'; +import { getEmojis } from './note'; +import renderEmoji from './emoji'; export default async (user: ILocalUser) => { const id = `${config.url}/users/${user._id}`; @@ -36,6 +38,13 @@ export default async (user: ILocalUser) => { value: `<a href="https://discordapp.com/users/${user.discord.id}" rel="me nofollow noopener" target="_blank"><span>@${user.discord.username}#${user.discord.discriminator}</span></a>` }); + const emojis = await getEmojis(user.emojis); + const apemojis = emojis.map(emoji => renderEmoji(emoji)); + + const tag = [ + ...apemojis, + ]; + return { type: user.isBot ? 'Service' : 'Person', id, @@ -51,6 +60,7 @@ export default async (user: ILocalUser) => { summary: toHtml(parse(user.description)), icon: user.avatarId && renderImage(avatar), image: user.bannerId && renderImage(banner), + tag, manuallyApprovesFollowers: user.isLocked, publicKey: renderKey(user), isCat: user.isCat, diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index b87c3c47e..031955010 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -6,6 +6,8 @@ import acceptAllFollowRequests from '../../../../services/following/requests/acc import { publishToFollowers } from '../../../../services/i/update'; import define from '../../define'; import getDriveFileUrl from '../../../../misc/get-drive-file-url'; +import parse from '../../../../mfm/parse'; +import { extractEmojis } from '../../../../services/note/create'; const langmap = require('langmap'); export const meta = { @@ -191,6 +193,24 @@ export default define(meta, (ps, user, app) => new Promise(async (res, rej) => { } } + //#region emojis + if (updates.name != null || updates.description != null) { + let emojis = [] as string[]; + + if (updates.name != null) { + const match = updates.name.match(/:\w{1,100}:/g) as string[]; + if (match) emojis = emojis.concat(match.map(m => m.replace(/:(\w+):/, '$1'))); + } + + if (updates.description != null) { + const tokens = parse(updates.description); + emojis = emojis.concat(extractEmojis(tokens)); + } + + updates.emojis = emojis; + } + //#endregion + await User.update(user._id, { $set: updates }); diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 49b465b94..6fe64d3ee 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -482,7 +482,7 @@ function extractHashtags(tokens: ReturnType<typeof parse>): string[] { return unique(hashtags); } -function extractEmojis(tokens: ReturnType<typeof parse>): string[] { +export function extractEmojis(tokens: ReturnType<typeof parse>): string[] { const emojis: string[] = []; const extract = (tokens: Node[]) => {