WIP(usernames): display in chat areas

This commit is contained in:
Sabe Jones
2018-10-17 12:57:57 -05:00
parent 6f5b9ef119
commit 23815e89e1
6 changed files with 167 additions and 45 deletions

View File

@@ -48,7 +48,6 @@
.avatar {
width: 140px;
height: 147px;
image-rendering: pixelated;
position: relative;
cursor: pointer;

View File

@@ -1,17 +1,68 @@
<template lang="pug">
div.autocomplete-selection(v-if='searchResults.length > 0', :style='autocompleteStyle')
.autocomplete-results(v-for='result in searchResults', @click='select(result)') {{ result }}
.autocomplete-selection(v-if='searchResults.length > 0', :style='autocompleteStyle')
.autocomplete-results.d-flex.align-items-center(
v-for='result in searchResults',
@click='select(result)',
@mouseenter='result.hover = true',
@mouseleave='result.hover = false',
:class='{"hover-background": result.hover}',
)
span
h3.profile-name(:class='userLevelStyle(result.msg)') {{ result.displayName }}
.svg-icon(v-html="tierIcon(result.msg)", v-if='showTierStyle(result.msg)')
span.username.ml-2(v-if='result.username', :class='{"hover-foreground": result.hover}') @{{ result.username }}
</template>
<style scoped>
<style lang="scss" scoped>
@import '~client/assets/scss/tiers.scss';
@import '~client/assets/scss/colors.scss';
.autocomplete-results {
padding: .5em;
}
.autocomplete-selection {
box-shadow: 1px 1px 1px #efefef;
}
.hover-background {
background-color: rgba(213, 200, 255, 0.32);
}
.hover-foreground {
color: $purple-300 !important;
}
.profile-name {
display: inline-block;
font-size: 14px;
margin-bottom: 0rem;
}
.svg-icon {
width: 10px;
display: inline-block;
margin-left: .5em;
}
.username {
color: $gray-200;
}
</style>
<script>
import groupBy from 'lodash/groupBy';
import styleHelper from 'client/mixins/styleHelper';
import tier1 from 'assets/svg/tier-1.svg';
import tier2 from 'assets/svg/tier-2.svg';
import tier3 from 'assets/svg/tier-3.svg';
import tier4 from 'assets/svg/tier-4.svg';
import tier5 from 'assets/svg/tier-5.svg';
import tier6 from 'assets/svg/tier-6.svg';
import tier7 from 'assets/svg/tier-7.svg';
import tier8 from 'assets/svg/tier-mod.svg';
import tier9 from 'assets/svg/tier-staff.svg';
import tierNPC from 'assets/svg/tier-npc.svg';
export default {
props: ['selections', 'text', 'coords', 'chat', 'textbox'],
@@ -21,6 +72,18 @@ export default {
searchActive: false,
currentSearchPosition: 0,
tmpSelections: [],
icons: Object.freeze({
tier1,
tier2,
tier3,
tier4,
tier5,
tier6,
tier7,
tier8,
tier9,
tierNPC,
}),
};
},
computed: {
@@ -45,8 +108,8 @@ export default {
if (!this.searchActive) return [];
let currentSearch = this.text.substring(this.currentSearchPosition + 1, this.text.length);
return this.tmpSelections.filter((option) => {
return option.toLowerCase().indexOf(currentSearch.toLowerCase()) !== -1;
});
return option.displayName.toLowerCase().indexOf(currentSearch.toLowerCase()) !== -1 || option.username && option.username.toLowerCase().indexOf(currentSearch.toLowerCase()) !== -1;
}).slice(0, 4);
},
},
@@ -59,9 +122,9 @@ export default {
this.searchActive = false;
}
if (newText[newText.length - 1] !== '@') return;
if (newText[newText.length - 2] !== '@') return;
this.searchActive = true;
this.currentSearchPosition = newText.length - 1;
this.currentSearchPosition = newText.length - 2;
},
chat () {
this.resetDefaults();
@@ -79,18 +142,44 @@ export default {
},
grabUserNames () {
let usersThatMessage = groupBy(this.chat, 'user');
for (let userName in usersThatMessage) {
let systemMessage = userName === 'undefined';
if (!systemMessage && this.tmpSelections.indexOf(userName) === -1) {
this.tmpSelections.push(userName);
for (let userKey in usersThatMessage) {
let systemMessage = userKey === 'undefined';
if (!systemMessage && this.tmpSelections.indexOf(userKey) === -1) {
this.tmpSelections.push({
displayName: userKey,
username: usersThatMessage[userKey][0].username,
msg: {
backer: usersThatMessage[userKey][0].backer,
contributor: usersThatMessage[userKey][0].contributor,
},
hover: false,
});
}
}
},
showTierStyle (message) {
const isContributor = Boolean(message.contributor && message.contributor.level);
const isNPC = Boolean(message.backer && message.backer.npc);
return isContributor || isNPC;
},
tierIcon (message) {
const isNPC = Boolean(message.backer && message.backer.npc);
if (isNPC) {
return this.icons.tierNPC;
}
return this.icons[`tier${message.contributor.level}`];
},
select (result) {
let newText = this.text.slice(0, this.currentSearchPosition + 1) + result;
let newText = this.text.slice(0, this.currentSearchPosition + 1);
if (result.username) {
newText = newText.concat(result.username);
} else {
newText = newText.concat(result.displayName);
}
this.searchActive = false;
this.$emit('select', newText);
},
},
mixins: [styleHelper],
};
</script>

View File

@@ -4,36 +4,48 @@ div
.message-hidden(v-if='msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
.message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden
.card-body
h3.leader(
:class='userLevelStyle(msg)',
@click="showMemberModal(msg.uuid)",
v-b-tooltip.hover.top="tierTitle",
)
| {{msg.user}}
.svg-icon(v-html="tierIcon", v-if='showShowTierStyle')
p.time(v-b-tooltip="", :title="msg.timestamp | date") {{msg.timestamp | timeAgo}}
.text(v-markdown='msg.text')
hr
div(v-if='msg.id')
.action(@click='like()', v-if='!inbox && msg.likes', :class='{active: msg.likes[user._id]}')
h3.leader(
:class='userLevelStyle(msg)',
@click="showMemberModal(msg.uuid)",
v-b-tooltip.hover.top="tierTitle",
v-if="msg.user"
)
| {{msg.user}}
.svg-icon(v-html="tierIcon", v-if='showShowTierStyle')
p.time(v-b-tooltip="", :title="msg.timestamp | date")
span(v-if="msg.username") @{{ msg.username }}
span {{ msg.timestamp | timeAgo }}
.text(v-html='atHighlight(parseMarkdown(msg.text))')
hr
.d-flex(v-if='msg.id')
.action.d-flex.align-items-center(v-if='!inbox', @click='copyAsTodo(msg)')
.svg-icon(v-html="icons.copy")
div {{$t('copyAsTodo')}}
.action.d-flex.align-items-center(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
.svg-icon(v-html="icons.report")
div {{$t('report')}}
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
.action.d-flex.align-items-center(v-if='msg.uuid === user._id || inbox || user.contributor.admin', @click='remove()')
.svg-icon(v-html="icons.delete")
| {{$t('delete')}}
.ml-auto.d-flex
.action.liked.d-flex.align-items-center(v-if='likeCount > 0')
.svg-icon(v-html="icons.liked")
| + {{ likeCount }}
.action.d-flex.align-items-center(@click='like()', v-if='!inbox && msg.likes', :class='{active: msg.likes[user._id]}')
.svg-icon(v-html="icons.like")
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
span(v-if='msg.likes[user._id]') {{ $t('liked') }}
span.action(v-if='!inbox', @click='copyAsTodo(msg)')
.svg-icon(v-html="icons.copy")
| {{$t('copyAsTodo')}}
span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
.svg-icon(v-html="icons.report")
| {{$t('report')}}
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
span.action(v-if='msg.uuid === user._id || inbox || user.contributor.admin', @click='remove()')
.svg-icon(v-html="icons.delete")
| {{$t('delete')}}
span.action.float-right.liked(v-if='likeCount > 0')
.svg-icon(v-html="icons.liked")
| + {{ likeCount }}
</template>
<style lang="scss">
.at-highlight {
background-color: rgba(213, 200, 255, 0.32);
color: #6133b4;
padding: 0.1rem;
}
</style>
<style lang="scss" scoped>
@import '~client/assets/scss/tiers.scss';
@@ -54,7 +66,14 @@ div
color: red;
}
hr {
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}
.card-body {
padding: 1rem 1rem 0.5rem 1rem;
.leader {
margin-bottom: 0;
}
@@ -62,6 +81,7 @@ div
h3 { // this is the user name
cursor: pointer;
display: inline-block;
font-size: 14px;
.svg-icon {
width: 10px;
@@ -73,7 +93,7 @@ div
.time {
font-size: 12px;
color: #878190;
width: 150px;
margin-bottom: 0.5rem;
}
.text {
@@ -87,6 +107,7 @@ div
display: inline-block;
color: #878190;
margin-right: 1em;
font-size: 12px;
}
.action:hover {
@@ -115,7 +136,7 @@ import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep';
import escapeRegExp from 'lodash/escapeRegExp';
import markdownDirective from 'client/directives/markdown';
import habiticaMarkdown from 'habitica-markdown';
import { mapState } from 'client/libs/store';
import styleHelper from 'client/mixins/styleHelper';
@@ -161,9 +182,6 @@ export default {
}),
};
},
directives: {
markdown: markdownDirective,
},
filters: {
timeAgo (value) {
return moment(value).fromNow();
@@ -273,6 +291,14 @@ export default {
showMemberModal (memberId) {
this.$emit('show-member-modal', memberId);
},
atHighlight (text) {
return text.replace(new RegExp(/@\w+\b/g), match => {
return `<span class="at-highlight">${match}</span>`;
});
},
parseMarkdown (text) {
return habiticaMarkdown.render(text);
},
},
};
</script>

View File

@@ -14,6 +14,7 @@
v-if='msg.userStyles || (cachedProfileData[msg.uuid] && !cachedProfileData[msg.uuid].rejected)',
:member="msg.userStyles || cachedProfileData[msg.uuid]",
:avatarOnly="true",
:overrideTopPadding='"14px"',
:hideClassBadge='true',
@click.native="showMemberModal(msg.uuid)",
)
@@ -40,6 +41,7 @@
:member="msg.userStyles || cachedProfileData[msg.uuid]",
:avatarOnly="true",
:hideClassBadge='true',
:overrideTopPadding='"14px"',
@click.native="showMemberModal(msg.uuid)",
)
</template>
@@ -47,6 +49,10 @@
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
.avatar {
margin-left: -1.75rem;
}
.hr {
width: 100%;
height: 20px;
@@ -71,6 +77,7 @@
.card {
margin-bottom: .5em;
padding: 0rem;
}
</style>

View File

@@ -194,7 +194,6 @@
width: 100%;
background-color: $white;
border: solid 1px $gray-400;
font-size: 16px;
font-style: italic;
line-height: 1.43;
color: $gray-300;

View File

@@ -9,7 +9,8 @@ const defaultSchema = () => ({
text: String,
// sender properties
user: String, // profile name
user: String, // profile name (unfortunately)
username: String,
contributor: {type: mongoose.Schema.Types.Mixed},
backer: {type: mongoose.Schema.Types.Mixed},
uuid: String, // sender uuid
@@ -115,6 +116,7 @@ export function messageDefaults (msg, user) {
contributor: user.contributor && user.contributor.toObject(),
backer: user.backer && user.backer.toObject(),
user: user.profile.name,
username: user.auth.local.username,
});
} else {
message.uuid = 'system';