re worked on emojis panel

This commit is contained in:
supertiger1234 2020-02-15 10:32:51 +00:00
parent 667fa4e467
commit 5b7a5135b6
8 changed files with 7061 additions and 15061 deletions

BIN
src/assets/emojiSprites.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View file

@ -0,0 +1,59 @@
<template>
<div class="emoji-item">
<div
v-if="!emoji.emojiID"
class="emoji"
:style="{ backgroundPosition: emoji.pos }"
/>
<div
v-else
class="emoji custom"
:style="{
backgroundImage: `url(${customEmojiUrl + emoji.emojiID})`
}"
/>
</div>
</template>
<script>
import config from "@/config.js";
export default {
props: ["emoji"],
data() {
return {
customEmojiUrl: config.domain + "/media/"
};
}
};
</script>
<style lang="scss" scoped>
.emoji-item {
display: flex;
justify-content: center;
align-content: center;
align-items: center;
height: 37px;
width: 37px;
flex-shrink: 0;
cursor: pointer;
transition: 0.2s;
&:hover {
background: rgba(255, 255, 255, 0.2);
}
}
.emoji {
background-image: url("../../../assets/emojiSprites.png");
background-position: 0px 0px;
background-repeat: no-repeat;
background-size: 1000px;
user-select: none;
height: 25px;
width: 25px;
flex-shrink: 0;
&.custom {
background-size: contain;
background-position: center;
}
}
</style>

View file

@ -2,84 +2,73 @@
<div v-click-outside="closePanel" class="emoji-panel"> <div v-click-outside="closePanel" class="emoji-panel">
<div class="emoji-panel-inner"> <div class="emoji-panel-inner">
<div class="emojis-list"> <div class="emojis-list">
<!-- Recent Emojis Category --> <virtual-list :size="37" :remain="11" ref="virtualList">
<div class="category"> <div class="category">Recents</div>
<div class="category-name">Recent</div>
<div class="list">
<div
v-for="(recentEmoji, index) in this.recentEmojisList"
:key="index"
class="emoji-item"
@click="emojiClickEvent(recentEmoji)"
>
<img
v-lazyload
class="panel emoji"
:data-url="
getCustomEmoji(recentEmoji) ||
emojiShortcodeToPath(':' + recentEmoji + ':')
"
/>
</div>
</div>
</div>
<!-- Custom Emojis Category --> <div
<div class="category"> class="emoji-row"
<div class="category-name">Custom Emojis</div> v-for="(e, i) in allRecentEmojis"
<div class="list"> :key="i + 'r'"
<div >
v-for="(customEmoji, index) in this.customEmojisList" <div class="wrapper">
:key="index" <emoji-template
class="emoji-item" v-for="(em, ind) in e"
@click="customEmojiClickEvent(customEmoji)" :key="ind"
> :emoji="em"
<img @click.native="emojiClick(em)"
v-lazyload
class="panel emoji"
:data-url="customEmojiPath + customEmoji.emojiID"
/> />
</div> </div>
</div> </div>
</div> <div class="category">Custom Emojis</div>
<div
<!-- Custom Emojis Category --> class="emoji-row"
<div v-for="(group, index) in groups" :key="group" class="category"> v-for="(e, i) in allCustomEmojis"
<div class="category-name">{{ group }}</div> :key="i + 'c'"
<div class="list"> >
<div <div class="wrapper">
v-for="emojiSorted in emojiByGroup(index)" <emoji-template
:key="emojiSorted.shortcodes[0]" v-for="(em, ind) in e"
class="emoji-item" :key="ind"
@click="emojiClickEvent(emojiSorted.shortcodes[0])" :emoji="em"
> @click.native="emojiClick(em)"
<img
v-lazyload
class="panel emoji"
:data-url="parseEmojiPath(emojiSorted.unicode)"
/> />
</div> </div>
</div> </div>
</div> <div
v-for="(e, i) in emojiWithGroup"
:class="`${e.gname ? 'category' : 'emoji-row'}`"
:key="i"
>
<div class="name" v-if="e.gname">{{ e.gname }}</div>
<div class="wrapper" v-if="!e.gname">
<emoji-template
v-for="(em, ind) in e"
:key="ind"
:emoji="em"
@click.native="emojiClick(em)"
/>
</div>
</div>
</virtual-list>
</div> </div>
<div class="tabs"> <div class="tabs">
<div class="tab" @click="scrollToCategory(0)"> <div class="tab" @click="tabClicked(0)">
<i class="material-icons">history</i> <i class="material-icons">history</i>
<div class="tooltip">Recent</div>
</div> </div>
<div class="tab" @click="scrollToCategory(1)"> <div class="tab" @click="tabClicked(1)">
<i class="material-icons">face</i> <i class="material-icons">face</i>
<div class="tooltip">Custom Emojis</div>
</div> </div>
<div <div
v-for="(emoji, index) in groupUnicodes"
:key="index"
class="tab" class="tab"
@mouseenter="mouseHover(emoji, $event)" v-for="(e, i) in groupUnicodes"
@click="scrollToCategory(index + 2)" :key="i"
@click="tabClicked(i + 2)"
> >
<img class="panel-emoji" :src="selectRandom(emoji)" /> <!-- {{ e[0] }} -->
<div class="tooltip">{{ groups[index] }}</div> <div
class="tab-emoji"
:style="{ backgroundPosition: findGroupEmojiPos(e[0]) }"
/>
</div> </div>
</div> </div>
</div> </div>
@ -88,18 +77,19 @@
</template> </template>
<script> <script>
import { bus } from "@/main"; import EmojiTemplate from "./EmojiTemplate";
import VirtualList from "vue-virtual-scroll-list";
import emojiParser from "@/utils/emojiParser.js"; import emojiParser from "@/utils/emojiParser.js";
import lazyLoad from "@/directives/LazyLoad.js";
import { mapState } from "vuex"; import { mapState } from "vuex";
import config from "@/config.js"; import { bus } from "@/main";
export default { export default {
directives: { components: { VirtualList, EmojiTemplate },
lazyload: lazyLoad
},
data() { data() {
return { return {
emojiWithGroup: [],
allRecentEmojis: [],
allCustomEmojis: [],
groupUnicodes: [ groupUnicodes: [
[ [
"😀", "😀",
@ -348,54 +338,157 @@ export default {
"🇮🇳", "🇮🇳",
"🇨🇭" "🇨🇭"
] ]
], ]
emojis: emojiParser.allEmojis,
groups: emojiParser.allGroups,
recentEmojisList: null,
customEmojisList: null,
customEmojiPath: config.domain + "/media/"
}; };
}, },
beforeMount() {
this.recentEmojisList = this.recentEmojis; mounted() {
this.customEmojisList = this.customEmojis; setTimeout(() => {
const z = performance.now();
this.allCustomEmojis = this.arrToRows(this.customEmojis);
const o = performance.now();
console.log("custom emojis took " + Math.round(o - z) + "ms to load.");
});
setTimeout(() => {
const z = performance.now();
this.allRecentEmojis = this.arrToRows(this.allRecentEmojisArr());
const o = performance.now();
console.log("recent emojis took " + Math.round(o - z) + "ms to load.");
});
setTimeout(() => {
const z = performance.now();
this.emojiWithGroup = this.emojisWithGroup();
const o = performance.now();
console.log("emojis took " + Math.round(o - z) + "ms to load.");
});
}, },
methods: { methods: {
getCustomEmoji(shortCode) { closePanel() {
const customEmoji = emojiParser.getCustomEmojisByShortCode(shortCode);
return customEmoji
? this.customEmojiPath + customEmoji.emojiID
: undefined;
},
closePanel(event) {
if (!event.target.closest(".emojis-button")) this.$emit("close"); if (!event.target.closest(".emojis-button")) this.$emit("close");
}, },
emojiByGroup(index) { emojisWithGroup() {
index = parseInt(index); const emojis = emojiParser.allEmojis;
return this.emojis.filter(_emoji => _emoji.group === index); const groups = emojiParser.allGroups;
const emojisWithGroups = [];
const row = 10;
let rowIndex = 0;
let rowItemIndex = 0;
let currentGroup = 0;
for (let index = 0; index < emojis.length; index++) {
const emoji = emojis[index];
let math = rowItemIndex % row;
let startNewRow = math === 0;
if (index === 0) {
emojisWithGroups[rowIndex] = { gname: groups[emoji.group] };
}
if (currentGroup != emoji.group) {
currentGroup = emoji.group;
rowIndex += 1;
emojisWithGroups[rowIndex] = { gname: groups[emoji.group] };
startNewRow = true;
}
if (startNewRow) {
rowIndex += 1;
emojisWithGroups[rowIndex] = [emoji];
rowItemIndex = 1;
} else {
emojisWithGroups[rowIndex].push(emoji);
rowItemIndex += 1;
}
}
return emojisWithGroups;
}, },
parseEmojiPath(emoji) { allRecentEmojisArr() {
return emojiParser.GetEmojiPath(emoji); const emojis = [];
for (let index = 0; index < this.recentEmojis.length; index++) {
const shortcode = this.recentEmojis[index];
const emoji = emojiParser.allEmojis.find(
e => e.shortcodes[0] === shortcode
);
if (!emoji) {
const cusEmoji = this.customEmojis.find(
emoji => emoji.name === shortcode
);
if (cusEmoji) {
emojis.push(cusEmoji);
}
} else {
emojis.push(emoji);
}
}
return emojis;
}, },
emojiShortcodeToPath(shortcode) { emojiSpritePos(emojiIndex) {
return this.parseEmojiPath(emojiParser.replaceShortcode(shortcode)); const SIZE = -25;
const row = 40;
let top = 0;
let left = 0;
for (let index = 0; index < emojiIndex + 1; index++) {
if (index != 0) {
if (index % row === 0) {
top += SIZE;
left = 0;
} else {
left += SIZE;
}
}
}
return `${left}px ${top}px`;
}, },
selectRandom(array) { arrToRows(emojis) {
const randomNum = Math.floor(Math.random() * array.length); const row = 10;
return this.parseEmojiPath(array[randomNum]); let rowIndex = 0;
const newArr = [];
for (let index = 0; index < emojis.length; index++) {
const emoji = emojis[index];
if (index === 0) {
newArr[rowIndex] = [emoji];
} else if (index % row === 0) {
rowIndex += 1;
newArr[rowIndex] = [emoji];
} else {
newArr[rowIndex].push(emoji);
}
}
return newArr;
}, },
customEmojiClickEvent(emoji) { emojiClick(emoji) {
bus.$emit("emojiPanel:Selected", emoji.name); if (emoji.emojiID) {
bus.$emit("emojiPanel:Selected", emoji.name);
} else {
bus.$emit("emojiPanel:Selected", emoji.shortcodes[0]);
}
}, },
emojiClickEvent(shortcode) { tabClicked(index) {
bus.$emit("emojiPanel:Selected", shortcode); const ROW_SIZE = 37;
const recentRows = this.allRecentEmojis.length + 1;
const customEmojiRows = this.allCustomEmojis.length + 1;
if (index === 0) {
this.$refs.virtualList.setScrollTop(0);
return;
}
if (index === 1) {
this.$refs.virtualList.setScrollTop(recentRows * ROW_SIZE);
return;
}
const rowIndex = this.emojiWithGroup.findIndex(
r => r.find && r.find(e => e.group === index - 2)
);
this.$refs.virtualList.setScrollTop(
(recentRows + customEmojiRows + rowIndex) * ROW_SIZE - ROW_SIZE
);
}, },
mouseHover(emoji, event) { findGroupEmojiPos(unicode) {
event.target.children[0].src = this.selectRandom(emoji); return emojiParser.allEmojis.find(e => e.unicode === unicode).pos;
},
scrollToCategory(index) {
const elements = document.querySelectorAll(".category-name");
elements[index].scrollIntoView();
} }
}, },
computed: { computed: {
@ -404,121 +497,49 @@ export default {
}; };
</script> </script>
<style scoped> <style scoped lang="scss">
.emoji-panel { .emoji-panel {
position: absolute; position: absolute;
bottom: -50px; bottom: -50px;
right: 20px; right: 20px;
max-width: 410px; width: 380px;
width: calc(100% - 50px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
z-index: 99999; z-index: 99999;
} }
.emoji-panel-inner { .emoji-panel-inner {
display: flex;
flex-direction: column;
background: rgba(0, 0, 0, 0.7); background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
border-radius: 4px; border-radius: 4px;
transition: 0.3s; transition: 0.3s;
z-index: 99999; z-index: 99999;
} height: 350px;
.emojis-list {
color: white;
padding: 5px;
user-select: none;
cursor: default;
height: 300px;
overflow-y: auto;
transition: 0.32s;
z-index: 99999;
margin-left: 10px;
}
.category {
}
.category-name {
padding: 5px;
padding-left: 3px;
text-transform: capitalize;
color: rgb(195, 195, 195);
}
.list {
}
.emoji-item {
background: rgba(59, 59, 59, 0.521);
transition: 0.3s;
display: inline-flex;
flex-direction: column;
overflow: hidden; overflow: hidden;
margin: 4px;
padding: 2px;
min-width: 30px;
cursor: pointer;
border-radius: 4px;
} }
.emoji-item:hover { .emojis-list {
background: rgb(59, 59, 59);
}
.tabs {
display: flex; display: flex;
color: white; flex-direction: column;
align-content: center; height: 100%;
align-items: center; width: 100%;
align-self: center;
padding-top: 5px;
padding-bottom: 5px;
transition: 0.3s;
overflow: auto; overflow: auto;
} }
.tabs img { .category {
height: 18px;
width: auto;
margin: auto;
filter: grayscale(100%);
transition: 0.1s;
}
.tabs .material-icons {
margin: auto;
color: rgb(185, 185, 185);
transition: 0.1s;
user-select: none;
}
.tab {
background: rgba(59, 59, 59, 0.521);
margin-left: 3px;
margin-right: 3px;
display: flex; display: flex;
flex-direction: column; height: 37px;
transition: 0.1s;
height: 35px;
width: 35px;
overflow: hidden;
align-content: center;
align-items: center;
justify-content: center;
flex-shrink: 0;
cursor: pointer;
border-radius: 4px;
}
.tab:hover {
background: rgb(73, 73, 73);
}
.tab:hover .tooltip {
display: flex;
}
.tab:hover img {
transform: scale(1.3);
filter: grayscale(0);
}
.tab:hover .material-icons {
transform: scale(1.3);
color: white; color: white;
padding-left: 10px;
align-items: center;
align-content: center;
background: rgba(255, 255, 255, 0.1);
}
.emoji-row .wrapper {
height: 37px;
display: flex;
flex-direction: row;
} }
.triangle { .triangle {
width: 0; width: 0;
height: 0; height: 0;
@ -529,30 +550,38 @@ export default {
align-self: flex-end; align-self: flex-end;
margin-right: 46px; margin-right: 46px;
} }
.tooltip { .tabs {
display: none; height: 37px;
position: absolute; display: flex;
margin: auto; align-content: center;
background: rgba(0, 0, 0, 0.7); align-items: center;
backdrop-filter: blur(5px); justify-content: center;
padding: 5px; width: 100%;
border-radius: 4px; background: rgba(0, 110, 255, 0.8);
bottom: -30px; flex-shrink: 0;
text-transform: capitalize; }
.tab {
display: flex;
justify-content: center;
align-content: center;
align-items: center;
user-select: none; user-select: none;
height: 37px;
width: 37px;
flex-shrink: 0;
cursor: pointer;
transition: 0.2s;
color: white;
&:hover {
background: rgba(255, 255, 255, 0.2);
}
} }
.tab .tab-emoji {
::-webkit-scrollbar { background-image: url("../../../assets/emojiSprites.png");
width: 3px; background-position: 0px 0px;
height: 3px; background-repeat: no-repeat;
} background-size: 1000px;
</style> height: 25px;
<style> width: 25px;
img.panel.emoji {
margin: auto;
padding: 2px;
object-fit: contain;
height: 1.6em;
width: 1.6em;
} }
</style> </style>

View file

@ -786,6 +786,11 @@ export default {
message(message) { message(message) {
this.messageLength = message.length; this.messageLength = message.length;
this.$nextTick(this.resize); this.$nextTick(this.resize);
},
selectedChannelID() {
this.$nextTick(() => {
this.$refs["input-box"].focus();
})
} }
}, },
computed: { computed: {

View file

@ -1,6 +1,7 @@
<template> <template>
<div <div
class="container" class="container"
:class="{ mentioned }"
@mouseover="mouseOverEvent" @mouseover="mouseOverEvent"
@mouseleave="hover = false" @mouseleave="hover = false"
> >

View file

@ -50,7 +50,7 @@ export default {
components: {}, components: {},
data() { data() {
return { return {
domain: config.domain + "/files/" domain: config.domain + "/media/"
}; };
}, },
methods: { methods: {

View file

@ -1,4 +1,15 @@
const config = [ const config = [
{
version: 10.0,
title: "Speedy emojis",
shortTitle: "",
date: "15/02/2020",
new: [
"Re-worked on emojji panel. Should be way faster to load now ",
"When changing channels/dms, focus should change to the inpur area.",
"mentions class have been added to the message container. (for theme develoeprs)"
],
},
{ {
version: 9.9, version: 9.9,
title: "New notification sounds!", title: "New notification sounds!",

File diff suppressed because it is too large Load diff