Merge branch 'better-still-emoji' into shigusegubu
* better-still-emoji: change defaults bump limit to a saner one moved mentions into a separate component - MentionLine, added collapsing of mentions when there's too many of 'em fix empty spaces again configurable mentions placement moving mentions into separate row moved transparent button styles into button itself
This commit is contained in:
commit
59d8a3bd92
16 changed files with 289 additions and 56 deletions
|
@ -88,6 +88,10 @@ a {
|
|||
font-family: sans-serif;
|
||||
font-family: var(--interfaceFont, sans-serif);
|
||||
|
||||
&.-sublime {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
i[class*=icon-],
|
||||
.svg-inline--fa {
|
||||
color: $fallback--text;
|
||||
|
|
|
@ -13,9 +13,10 @@ const MentionLink = {
|
|||
required: true,
|
||||
type: String
|
||||
},
|
||||
origattrs: {
|
||||
required: true,
|
||||
type: Object
|
||||
firstMention: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -50,6 +51,12 @@ const MentionLink = {
|
|||
highlightClass () {
|
||||
if (this.highlight) return highlightClass(this.user)
|
||||
},
|
||||
oldPlace () {
|
||||
return !this.mergedConfig.mentionsOwnLine
|
||||
},
|
||||
oldStyle () {
|
||||
return !this.mergedConfig.mentionsNewStyle
|
||||
},
|
||||
style () {
|
||||
if (this.highlight) {
|
||||
const {
|
||||
|
@ -61,6 +68,17 @@ const MentionLink = {
|
|||
return rest
|
||||
}
|
||||
},
|
||||
classnames () {
|
||||
return [
|
||||
{
|
||||
'-you': this.isYou,
|
||||
'-highlighted': this.highlight,
|
||||
'-firstMention': this.firstMention,
|
||||
'-oldStyle': this.oldStyle
|
||||
},
|
||||
this.highlightType
|
||||
]
|
||||
},
|
||||
...mapGetters(['mergedConfig']),
|
||||
...mapState({
|
||||
currentUser: state => state.users.currentUser
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
}
|
||||
|
||||
.original {
|
||||
opacity: 0.5;
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
|
||||
.full {
|
||||
|
@ -33,23 +33,31 @@
|
|||
& .short,
|
||||
& .full {
|
||||
&::before {
|
||||
color: var(--faint);
|
||||
content: '@';
|
||||
}
|
||||
}
|
||||
|
||||
.new:not(.-highlighted) {
|
||||
.short {
|
||||
background: none;
|
||||
}
|
||||
}
|
||||
.new {
|
||||
&,
|
||||
&.-highlighted {
|
||||
margin-right: 0.25em;
|
||||
|
||||
&.-firstMention {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.-you {
|
||||
& .shortName,
|
||||
& .full {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.-oldStyle) {
|
||||
.short {
|
||||
line-height: 1.5;
|
||||
font-size: inherit;
|
||||
|
||||
&::before {
|
||||
color: var(--faint);
|
||||
display: inline-block;
|
||||
height: 50%;
|
||||
line-height: 1;
|
||||
|
@ -111,15 +119,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.new {
|
||||
&.-you {
|
||||
& .shortName,
|
||||
& .full {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .new .full {
|
||||
opacity: 1;
|
||||
pointer-events: initial;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<template>
|
||||
<span class="MentionLink">
|
||||
<span
|
||||
class="MentionLink"
|
||||
:class="{ '-oldPlace': oldPlace }"
|
||||
>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<a
|
||||
v-if="!user"
|
||||
|
@ -12,15 +15,22 @@
|
|||
v-if="user"
|
||||
class="new"
|
||||
:style="style"
|
||||
:class="[{ '-you': isYou, '-highlighted': highlight }, highlightType]"
|
||||
:class="classnames"
|
||||
>
|
||||
<button
|
||||
class="short"
|
||||
:class="highlight ? 'button-default' : 'button-default' "
|
||||
:class="[{ '-sublime': !highlight }, oldStyle ? 'button-unstyled' : 'button-default']"
|
||||
@click.prevent="onClick"
|
||||
>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<span class="shortName"><span class="userName" v-html="userName" /></span><span class="you" v-if="isYou">{{ $t('status.you')}}</span>
|
||||
<span class="shortName"><span
|
||||
class="userName"
|
||||
v-html="userName"
|
||||
/></span>
|
||||
<span
|
||||
v-if="isYou"
|
||||
class="you"
|
||||
>{{ $t('status.you') }}</span>
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
</button>
|
||||
<span
|
||||
|
@ -29,7 +39,10 @@
|
|||
:class="[highlightType]"
|
||||
>
|
||||
<!-- eslint-disable vue/no-v-html -->
|
||||
<span class="userNameFull" v-html="userNameFull" />
|
||||
<span
|
||||
class="userNameFull"
|
||||
v-html="userNameFull"
|
||||
/>
|
||||
<!-- eslint-enable vue/no-v-html -->
|
||||
</span>
|
||||
</span>
|
||||
|
|
51
src/components/mentions_line/mentions_line.js
Normal file
51
src/components/mentions_line/mentions_line.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
import MentionLink from 'src/components/mention_link/mention_link.vue'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
const MentionsLine = {
|
||||
name: 'MentionsLine',
|
||||
props: {
|
||||
attentions: {
|
||||
required: true,
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data: () => ({ expanded: false }),
|
||||
components: {
|
||||
MentionLink
|
||||
},
|
||||
computed: {
|
||||
oldStyle () {
|
||||
return !this.mergedConfig.mentionsNewStyle
|
||||
},
|
||||
limit () {
|
||||
return 6
|
||||
},
|
||||
mentions () {
|
||||
return this.attentions.slice(0, this.limit)
|
||||
},
|
||||
extraMentions () {
|
||||
return this.attentions.slice(this.limit)
|
||||
},
|
||||
manyMentions () {
|
||||
return this.extraMentions.length > 0
|
||||
},
|
||||
buttonClasses () {
|
||||
return [
|
||||
this.oldStyle
|
||||
? 'button-unstyled'
|
||||
: 'button-default -sublime',
|
||||
this.oldStyle
|
||||
? '-oldStyle'
|
||||
: '-newStyle'
|
||||
]
|
||||
},
|
||||
...mapGetters(['mergedConfig'])
|
||||
},
|
||||
methods: {
|
||||
toggleShowMore () {
|
||||
this.expanded = !this.expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default MentionsLine
|
15
src/components/mentions_line/mentions_line.scss
Normal file
15
src/components/mentions_line/mentions_line.scss
Normal file
|
@ -0,0 +1,15 @@
|
|||
.MentionsLine {
|
||||
.showMoreLess {
|
||||
&.-newStyle {
|
||||
line-height: 1.5;
|
||||
font-size: inherit;
|
||||
display: inline-block;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&.-oldStyle {
|
||||
color: var(--link);
|
||||
}
|
||||
}
|
||||
}
|
45
src/components/mentions_line/mentions_line.vue
Normal file
45
src/components/mentions_line/mentions_line.vue
Normal file
|
@ -0,0 +1,45 @@
|
|||
<template>
|
||||
<span class="MentionsLine">
|
||||
<MentionLink
|
||||
v-for="mention in mentions"
|
||||
:key="mention.statusnet_profile_url"
|
||||
class="mention-link"
|
||||
:content="mention.statusnet_profile_url"
|
||||
:url="mention.statusnet_profile_url"
|
||||
:first-mention="false"
|
||||
/><span
|
||||
v-if="manyMentions"
|
||||
class="extraMentions"
|
||||
>
|
||||
<span
|
||||
v-if="expanded"
|
||||
class="fullExtraMentions"
|
||||
>
|
||||
<MentionLink
|
||||
v-for="mention in extraMentions"
|
||||
:key="mention.statusnet_profile_url"
|
||||
class="mention-link"
|
||||
:content="mention.statusnet_profile_url"
|
||||
:url="mention.statusnet_profile_url"
|
||||
:first-mention="false"
|
||||
/>
|
||||
</span><button
|
||||
v-if="!expanded"
|
||||
class="showMoreLess"
|
||||
:class="buttonClasses"
|
||||
@click="toggleShowMore"
|
||||
>
|
||||
{{ $t('status.plus_more', { number: extraMentions.length }) }}
|
||||
</button><button
|
||||
v-if="expanded"
|
||||
class="showMoreLess"
|
||||
:class="buttonClasses"
|
||||
@click="toggleShowMore"
|
||||
>
|
||||
{{ $t('general.show_less') }}
|
||||
</button>
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
<script src="./mentions_line.js" ></script>
|
||||
<style lang="scss" src="./mentions_line.scss" />
|
|
@ -33,21 +33,31 @@ export default Vue.component('RichContent', {
|
|||
class="img"
|
||||
/>
|
||||
}
|
||||
const renderMention = (attrs, children) => {
|
||||
const renderMention = (attrs, children, encounteredText) => {
|
||||
return <MentionLink
|
||||
url={attrs.href}
|
||||
content={flattenDeep(children).join('')}
|
||||
origattrs={attrs}
|
||||
firstMention={!encounteredText}
|
||||
/>
|
||||
}
|
||||
|
||||
let encounteredText = false
|
||||
// Processor to use with mini_html_converter
|
||||
const processItem = (item) => {
|
||||
// Handle text noes - just add emoji
|
||||
if (typeof item === 'string') {
|
||||
const emptyText = item.trim() === ''
|
||||
if (emptyText) {
|
||||
return encounteredText ? item : item.trim()
|
||||
}
|
||||
let unescapedItem = unescape(item)
|
||||
if (!encounteredText) {
|
||||
unescapedItem = unescapedItem.trimStart()
|
||||
encounteredText = true
|
||||
}
|
||||
if (item.includes(':')) {
|
||||
return processTextForEmoji(
|
||||
unescape(item),
|
||||
unescapedItem,
|
||||
this.emoji,
|
||||
({ shortcode, url }) => {
|
||||
return <StillImage
|
||||
|
@ -59,7 +69,7 @@ export default Vue.component('RichContent', {
|
|||
}
|
||||
)
|
||||
} else {
|
||||
return unescape(item)
|
||||
return unescapedItem
|
||||
}
|
||||
}
|
||||
// Handle tag nodes
|
||||
|
@ -73,7 +83,7 @@ export default Vue.component('RichContent', {
|
|||
if (!this.handleLinks) break
|
||||
const attrs = getAttrs(opener)
|
||||
if (attrs['class'] && attrs['class'].includes('mention')) {
|
||||
return renderMention(attrs, children)
|
||||
return renderMention(attrs, children, encounteredText)
|
||||
}
|
||||
}
|
||||
// Render tag as is
|
||||
|
|
|
@ -26,6 +26,16 @@
|
|||
{{ $t('settings.stop_gifs') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="mentionsOwnLine">
|
||||
{{ $t('settings.mentions_new_place') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="mentionsNewStyle">
|
||||
{{ $t('settings.mentions_new_style') }}
|
||||
</BooleanSetting>
|
||||
</li>
|
||||
<li>
|
||||
<BooleanSetting path="streaming">
|
||||
{{ $t('settings.streaming') }}
|
||||
|
|
|
@ -13,6 +13,8 @@ import RichContent from 'src/components/rich_content/rich_content.jsx'
|
|||
import StatusPopover from '../status_popover/status_popover.vue'
|
||||
import UserListPopover from '../user_list_popover/user_list_popover.vue'
|
||||
import EmojiReactions from '../emoji_reactions/emoji_reactions.vue'
|
||||
import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
|
||||
import MentionLink from 'src/components/mention_link/mention_link.vue'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||
import { muteWordHits } from '../../services/status_parser/status_parser.js'
|
||||
|
@ -33,7 +35,8 @@ import {
|
|||
faStar,
|
||||
faEyeSlash,
|
||||
faEye,
|
||||
faThumbtack
|
||||
faThumbtack,
|
||||
faAt,
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
|
@ -50,7 +53,8 @@ library.add(
|
|||
faEllipsisH,
|
||||
faEyeSlash,
|
||||
faEye,
|
||||
faThumbtack
|
||||
faThumbtack,
|
||||
faAt
|
||||
)
|
||||
|
||||
const Status = {
|
||||
|
@ -70,7 +74,9 @@ const Status = {
|
|||
UserListPopover,
|
||||
EmojiReactions,
|
||||
StatusContent,
|
||||
RichContent
|
||||
RichContent,
|
||||
MentionLink,
|
||||
MentionsLine
|
||||
},
|
||||
props: [
|
||||
'statusoid',
|
||||
|
@ -133,9 +139,7 @@ const Status = {
|
|||
return this.generateUserProfileLink(this.status.user.id, this.status.user.screen_name)
|
||||
},
|
||||
replyProfileLink () {
|
||||
if (this.isReply) {
|
||||
return this.generateUserProfileLink(this.status.in_reply_to_user_id, this.replyToName)
|
||||
}
|
||||
return this.$store.getters.findUser(this.status.in_reply_to_user_id).statusnet_profile_url
|
||||
},
|
||||
retweet () { return !!this.statusoid.retweeted_status },
|
||||
retweeterUser () { return this.statusoid.user },
|
||||
|
@ -159,6 +163,18 @@ const Status = {
|
|||
muteWordHits () {
|
||||
return muteWordHits(this.status, this.muteWords)
|
||||
},
|
||||
mentionsOwnLine () {
|
||||
return this.mergedConfig.mentionsOwnLine
|
||||
},
|
||||
mentions () {
|
||||
return this.statusoid.attentions.filter(attn => {
|
||||
return attn.screen_name !== this.replyToName &&
|
||||
attn.screen_name !== this.statusoid.user.screen_name
|
||||
})
|
||||
},
|
||||
hasMentions () {
|
||||
return this.mentions.length > 0
|
||||
},
|
||||
muted () {
|
||||
if (this.statusoid.user.id === this.currentUser.id) return false
|
||||
const reasonsToMute = this.userIsMuted ||
|
||||
|
|
|
@ -155,7 +155,8 @@ $status-margin: 0.75em;
|
|||
margin-right: 0.2em;
|
||||
}
|
||||
|
||||
.heading-reply-row {
|
||||
& .heading-mentions-row,
|
||||
& .heading-reply-row {
|
||||
position: relative;
|
||||
align-content: baseline;
|
||||
font-size: 12px;
|
||||
|
|
|
@ -221,7 +221,6 @@
|
|||
</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="heading-reply-row">
|
||||
<div
|
||||
v-if="isReply"
|
||||
|
@ -258,13 +257,13 @@
|
|||
>
|
||||
<span class="reply-to-text">{{ $t('status.reply_to') }}</span>
|
||||
</span>
|
||||
<router-link
|
||||
class="reply-to-link"
|
||||
:title="replyToName"
|
||||
:to="replyProfileLink"
|
||||
>
|
||||
{{ replyToName }}
|
||||
</router-link>
|
||||
|
||||
<MentionLink
|
||||
class="mention-link"
|
||||
:content="replyToName"
|
||||
:url="replyProfileLink"
|
||||
:first-mention="false"
|
||||
/>
|
||||
<span
|
||||
v-if="replies && replies.length"
|
||||
class="faint replies-separator"
|
||||
|
@ -291,6 +290,35 @@
|
|||
</StatusPopover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="hasMentions && mentionsOwnLine"
|
||||
class="heading-mentions-row"
|
||||
>
|
||||
<div
|
||||
class="mentions"
|
||||
>
|
||||
<span
|
||||
class="button-unstyled reply-to"
|
||||
:aria-label="$t('tool_tip.reply')"
|
||||
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
|
||||
>
|
||||
<FAIcon
|
||||
class="fa-scale-110 fa-old-padding"
|
||||
icon="at"
|
||||
/>
|
||||
<span
|
||||
class="faint-link reply-to-text"
|
||||
>
|
||||
{{ $t('status.mentions') }}
|
||||
</span>
|
||||
</span>
|
||||
<MentionsLine
|
||||
:attentions="mentions"
|
||||
class="mentions-line"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<StatusContent
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import fileType from 'src/services/file_type/file_type.service'
|
||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||
import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
|
||||
import { processHtml } from 'src/services/tiny_post_html_processor/tiny_post_html_processor.service.js'
|
||||
import { extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
@ -104,10 +105,17 @@ const StatusContent = {
|
|||
attachmentTypes () {
|
||||
return this.status.attachments.map(file => fileType.fileType(file.mimetype))
|
||||
},
|
||||
mentionsOwnLine () {
|
||||
return this.mergedConfig.mentionsOwnLine
|
||||
},
|
||||
mentions () {
|
||||
return this.status.attentions
|
||||
},
|
||||
...mapGetters(['mergedConfig'])
|
||||
},
|
||||
components: {
|
||||
RichContent
|
||||
RichContent,
|
||||
MentionsLine
|
||||
},
|
||||
mounted () {
|
||||
this.status.attentions && this.status.attentions.forEach(attn => {
|
||||
|
|
|
@ -39,15 +39,24 @@
|
|||
>
|
||||
{{ $t("general.show_more") }}
|
||||
</button>
|
||||
<RichContent
|
||||
<span
|
||||
v-if="!hideSubjectStatus && !(singleLine && status.summary_html)"
|
||||
:class="{ '-single-line': singleLine }"
|
||||
class="text media-body"
|
||||
:html="postBodyHtml"
|
||||
:emoji="status.emojis"
|
||||
:handle-links="true"
|
||||
@click.prevent="linkClicked"
|
||||
/>
|
||||
>
|
||||
<MentionsLine
|
||||
v-if="!mentionsOwnLine"
|
||||
:attentions="status.attentions"
|
||||
class="mentions-line"
|
||||
/>
|
||||
<RichContent
|
||||
:class="{ '-single-line': singleLine }"
|
||||
class="text media-body"
|
||||
:html="postBodyHtml"
|
||||
:emoji="status.emojis"
|
||||
:handle-links="true"
|
||||
@click.prevent="linkClicked"
|
||||
/>
|
||||
</span>
|
||||
|
||||
<button
|
||||
v-if="hideSubjectStatus"
|
||||
class="button-unstyled -link cw-status-hider"
|
||||
|
|
|
@ -260,6 +260,8 @@
|
|||
"setting_changed": "Setting is different from default",
|
||||
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
|
||||
"post_look_feel": "Posts Look & Feel",
|
||||
"mentions_old_style": "Old style mentions",
|
||||
"mentions_old_place": "Leave mentions inside post",
|
||||
"mfa": {
|
||||
"otp": "OTP",
|
||||
"setup_otp": "Setup OTP",
|
||||
|
@ -703,6 +705,7 @@
|
|||
"unbookmark": "Unbookmark",
|
||||
"delete_confirm": "Do you really want to delete this status?",
|
||||
"reply_to": "Reply to",
|
||||
"mentions": "Mentions",
|
||||
"replies_list": "Replies:",
|
||||
"mute_conversation": "Mute conversation",
|
||||
"unmute_conversation": "Unmute conversation",
|
||||
|
@ -718,7 +721,8 @@
|
|||
"status_deleted": "This post was deleted",
|
||||
"nsfw": "NSFW",
|
||||
"expand": "Expand",
|
||||
"you": "(You)"
|
||||
"you": "(You)",
|
||||
"plus_more": "+{number} more"
|
||||
},
|
||||
"user_card": {
|
||||
"approve": "Approve",
|
||||
|
|
|
@ -56,6 +56,8 @@ export const defaultState = {
|
|||
interfaceLanguage: browserLocale,
|
||||
hideScopeNotice: false,
|
||||
useStreamingApi: false,
|
||||
mentionsOwnLine: false,
|
||||
mentionsNewStyle: false,
|
||||
sidebarRight: undefined, // instance default
|
||||
scopeCopy: undefined, // instance default
|
||||
subjectLineBehavior: undefined, // instance default
|
||||
|
|
Loading…
Add table
Reference in a new issue