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:
Henry Jameson 2021-06-08 16:34:12 +03:00
commit 59d8a3bd92
16 changed files with 289 additions and 56 deletions

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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>

View 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

View 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);
}
}
}

View 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" />

View file

@ -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

View file

@ -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') }}

View file

@ -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 ||

View file

@ -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;

View file

@ -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

View file

@ -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 => {

View file

@ -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"

View file

@ -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",

View file

@ -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