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 { .avatar {
width: 140px; width: 140px;
height: 147px;
image-rendering: pixelated; image-rendering: pixelated;
position: relative; position: relative;
cursor: pointer; cursor: pointer;

View File

@@ -1,17 +1,68 @@
<template lang="pug"> <template lang="pug">
div.autocomplete-selection(v-if='searchResults.length > 0', :style='autocompleteStyle') .autocomplete-selection(v-if='searchResults.length > 0', :style='autocompleteStyle')
.autocomplete-results(v-for='result in searchResults', @click='select(result)') {{ result }} .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> </template>
<style scoped> <style lang="scss" scoped>
@import '~client/assets/scss/tiers.scss';
@import '~client/assets/scss/colors.scss';
.autocomplete-results { .autocomplete-results {
padding: .5em; padding: .5em;
}
.autocomplete-selection {
box-shadow: 1px 1px 1px #efefef; 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> </style>
<script> <script>
import groupBy from 'lodash/groupBy'; 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 { export default {
props: ['selections', 'text', 'coords', 'chat', 'textbox'], props: ['selections', 'text', 'coords', 'chat', 'textbox'],
@@ -21,6 +72,18 @@ export default {
searchActive: false, searchActive: false,
currentSearchPosition: 0, currentSearchPosition: 0,
tmpSelections: [], tmpSelections: [],
icons: Object.freeze({
tier1,
tier2,
tier3,
tier4,
tier5,
tier6,
tier7,
tier8,
tier9,
tierNPC,
}),
}; };
}, },
computed: { computed: {
@@ -45,8 +108,8 @@ export default {
if (!this.searchActive) return []; if (!this.searchActive) return [];
let currentSearch = this.text.substring(this.currentSearchPosition + 1, this.text.length); let currentSearch = this.text.substring(this.currentSearchPosition + 1, this.text.length);
return this.tmpSelections.filter((option) => { 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; this.searchActive = false;
} }
if (newText[newText.length - 1] !== '@') return; if (newText[newText.length - 2] !== '@') return;
this.searchActive = true; this.searchActive = true;
this.currentSearchPosition = newText.length - 1; this.currentSearchPosition = newText.length - 2;
}, },
chat () { chat () {
this.resetDefaults(); this.resetDefaults();
@@ -79,18 +142,44 @@ export default {
}, },
grabUserNames () { grabUserNames () {
let usersThatMessage = groupBy(this.chat, 'user'); let usersThatMessage = groupBy(this.chat, 'user');
for (let userName in usersThatMessage) { for (let userKey in usersThatMessage) {
let systemMessage = userName === 'undefined'; let systemMessage = userKey === 'undefined';
if (!systemMessage && this.tmpSelections.indexOf(userName) === -1) { if (!systemMessage && this.tmpSelections.indexOf(userKey) === -1) {
this.tmpSelections.push(userName); 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) { 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.searchActive = false;
this.$emit('select', newText); this.$emit('select', newText);
}, },
}, },
mixins: [styleHelper],
}; };
</script> </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 flagged once, not hidden
.message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden .message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden
.card-body .card-body
h3.leader( h3.leader(
:class='userLevelStyle(msg)', :class='userLevelStyle(msg)',
@click="showMemberModal(msg.uuid)", @click="showMemberModal(msg.uuid)",
v-b-tooltip.hover.top="tierTitle", v-b-tooltip.hover.top="tierTitle",
) v-if="msg.user"
| {{msg.user}} )
.svg-icon(v-html="tierIcon", v-if='showShowTierStyle') | {{msg.user}}
p.time(v-b-tooltip="", :title="msg.timestamp | date") {{msg.timestamp | timeAgo}} .svg-icon(v-html="tierIcon", v-if='showShowTierStyle')
.text(v-markdown='msg.text') p.time(v-b-tooltip="", :title="msg.timestamp | date")
hr span(v-if="msg.username") @{{ msg.username }}
div(v-if='msg.id') span {{ msg.timestamp | timeAgo }}
.action(@click='like()', v-if='!inbox && msg.likes', :class='{active: msg.likes[user._id]}') .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") .svg-icon(v-html="icons.like")
span(v-if='!msg.likes[user._id]') {{ $t('like') }} span(v-if='!msg.likes[user._id]') {{ $t('like') }}
span(v-if='msg.likes[user._id]') {{ $t('liked') }} 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> </template>
<style lang="scss">
.at-highlight {
background-color: rgba(213, 200, 255, 0.32);
color: #6133b4;
padding: 0.1rem;
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '~client/assets/scss/tiers.scss'; @import '~client/assets/scss/tiers.scss';
@@ -54,7 +66,14 @@ div
color: red; color: red;
} }
hr {
margin-bottom: 0.5rem;
margin-top: 0.5rem;
}
.card-body { .card-body {
padding: 1rem 1rem 0.5rem 1rem;
.leader { .leader {
margin-bottom: 0; margin-bottom: 0;
} }
@@ -62,6 +81,7 @@ div
h3 { // this is the user name h3 { // this is the user name
cursor: pointer; cursor: pointer;
display: inline-block; display: inline-block;
font-size: 14px;
.svg-icon { .svg-icon {
width: 10px; width: 10px;
@@ -73,7 +93,7 @@ div
.time { .time {
font-size: 12px; font-size: 12px;
color: #878190; color: #878190;
width: 150px; margin-bottom: 0.5rem;
} }
.text { .text {
@@ -87,6 +107,7 @@ div
display: inline-block; display: inline-block;
color: #878190; color: #878190;
margin-right: 1em; margin-right: 1em;
font-size: 12px;
} }
.action:hover { .action:hover {
@@ -115,7 +136,7 @@ import moment from 'moment';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import escapeRegExp from 'lodash/escapeRegExp'; import escapeRegExp from 'lodash/escapeRegExp';
import markdownDirective from 'client/directives/markdown'; import habiticaMarkdown from 'habitica-markdown';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
import styleHelper from 'client/mixins/styleHelper'; import styleHelper from 'client/mixins/styleHelper';
@@ -161,9 +182,6 @@ export default {
}), }),
}; };
}, },
directives: {
markdown: markdownDirective,
},
filters: { filters: {
timeAgo (value) { timeAgo (value) {
return moment(value).fromNow(); return moment(value).fromNow();
@@ -273,6 +291,14 @@ export default {
showMemberModal (memberId) { showMemberModal (memberId) {
this.$emit('show-member-modal', 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> </script>

View File

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

View File

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

View File

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