custom emojis
BIN
public/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/android-chrome-384x384.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
public/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
9
public/browserconfig.xml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
BIN
public/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
public/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -1,30 +1,65 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<title>Nertivia</title>
|
||||
<!-- Google recaptcha -->
|
||||
<script src="https://www.google.com/recaptcha/api.js?onload=vueRecaptchaApiLoaded&render=explicit" async defer>
|
||||
</script>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-131765299-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'UA-131765299-1');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but Nertivia doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="<%= BASE_URL %>apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="<%= BASE_URL %>favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="<%= BASE_URL %>favicon-16x16.png">
|
||||
<link rel="manifest" href="<%= BASE_URL %>site.webmanifest">
|
||||
<meta name="msapplication-TileColor" content="#da532c">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
|
||||
<!-- Preview meta tags -->
|
||||
<!-- Search Tags -->
|
||||
<title>Nertivia - Chat Client</title>
|
||||
<meta name="description" content="The best chat client that won’t sell your data. ">
|
||||
<meta name="robots" content="follow, index">
|
||||
|
||||
<!-- FB Open Graph data -->
|
||||
<meta property="og:title" content="Nertivia - Chat Client">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:image" content="https://nertivia.supertiger.tk/img/logo.3287e62d.png">
|
||||
<meta property="og:description" content="The best chat client that won’t sell your data. ">
|
||||
<meta property="og:url" content="https://nertivia.tk/">
|
||||
|
||||
<!-- Twitter Card data -->
|
||||
<meta name="twitter:card" content="app">
|
||||
<meta name="twitter:title" content="Nertivia - Chat Client">
|
||||
<meta name="twitter:description" content="The best chat client that won’t sell your data. ">
|
||||
<meta name="twitter:image" content="https://nertivia.supertiger.tk/img/logo.3287e62d.png">
|
||||
<meta name="twitter:url" content="https://nertivia.tk/">
|
||||
|
||||
<!-- Preview meta tags -->
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<!-- Google recaptcha -->
|
||||
<script src="https://www.google.com/recaptcha/api.js?onload=vueRecaptchaApiLoaded&render=explicit" async defer>
|
||||
</script>
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-131765299-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'UA-131765299-1');
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but Nertivia doesn't work properly without JavaScript enabled. Please enable it to
|
||||
continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
public/mstile-150x150.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
19
public/site.webmanifest
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"name": "",
|
||||
"short_name": "",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 64 KiB |
|
|
@ -283,8 +283,8 @@ export default {
|
|||
</style>
|
||||
<style>
|
||||
img.emoji {
|
||||
height: 1.5em;
|
||||
width: 1.5em;
|
||||
height: 1.7em;
|
||||
width: 1.7em;
|
||||
margin: 0 .05em 0 .1em;
|
||||
vertical-align: -0.1em;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ export default {
|
|||
this.messageLength = 0;
|
||||
|
||||
const msg = emojiParser.replaceShortcode(this.message);
|
||||
|
||||
const tempID = this.generateNum(25);
|
||||
|
||||
this.$store.dispatch("addMessage", {
|
||||
|
|
@ -270,9 +271,10 @@ export default {
|
|||
this.showEmojiPopout(event);
|
||||
},
|
||||
enterEmojiSuggestion(){
|
||||
this.$store.dispatch('setLastEmoji', this.emojiArray[this.emojiIndex].shortcodes[0])
|
||||
const emoji = this.emojiArray[this.emojiIndex];
|
||||
this.$store.dispatch('settingsModule/addRecentEmoji', emoji.name || emoji.shortcodes[0])
|
||||
this.$refs["input-box"].focus();
|
||||
const emojiShortCode = `:${this.emojiArray[this.emojiIndex].shortcodes[0]}: `
|
||||
const emojiShortCode = `:${emoji.name || emoji.shortcodes[0]}: `
|
||||
const cursorPosition = this.$refs['input-box'].selectionStart;
|
||||
const cursorWord = this.ReturnWord(this.message, cursorPosition);
|
||||
|
||||
|
|
@ -286,7 +288,7 @@ export default {
|
|||
const target = this.$refs["input-box"];
|
||||
target.focus();
|
||||
document.execCommand('insertText', false, `:${shortcode}: `);
|
||||
this.$store.dispatch('setLastEmoji', shortcode)
|
||||
this.$store.dispatch('settingsModule/addRecentEmoji', shortcode)
|
||||
},
|
||||
keyDown(event) {
|
||||
this.resize(event);
|
||||
|
|
|
|||
|
|
@ -3,72 +3,79 @@
|
|||
<div class="settings-box">
|
||||
<div class="tabs">
|
||||
|
||||
<div
|
||||
:class="{tab: true, selected: currentTab == 'my-profile'}"
|
||||
@click="tabClicked('my-profile','account_circle', 'My Profile')">
|
||||
<div class="material-icons">account_circle</div>
|
||||
<div>My Profile</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{tab: true, selected: currentTab == 'ddddd'}"
|
||||
@click="tabClicked('ddddd','palette', 'Coming soon!')">
|
||||
<div class="material-icons">palette</div>
|
||||
<div>Message Themes</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
:class="{tab: true, selected: currentTab == 'eee'}"
|
||||
@click="tabClicked('eee','error', 'Spoopi')">
|
||||
<div class="material-icons">error</div>
|
||||
<div>Another Tab</div>
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="index"
|
||||
:class="{tab: true, selected: currentTab === index}"
|
||||
@click="currentTab = index"
|
||||
>
|
||||
<div class="material-icons">{{tab.icon}}</div>
|
||||
<div class="tab-name">{{tab.name}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="panel">
|
||||
<div class="title">
|
||||
<div class="material-icons">{{icon}}</div>
|
||||
<div class="in-title">{{title}}</div>
|
||||
<div class="material-icons">{{tabs[currentTab].icon}}</div>
|
||||
<div class="in-title">{{tabs[currentTab].tabName}}</div>
|
||||
<div class="close-button" @click="close">
|
||||
<div class="material-icons">close</div>
|
||||
</div>
|
||||
</div>
|
||||
<component :is="currentTab"></component>
|
||||
<component :is="tabs[currentTab].component"></component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {bus} from '../../main'
|
||||
import MyProfile from './SettingsPanels/MyProfile.vue'
|
||||
import { bus } from "../../main";
|
||||
import MyProfile from "./SettingsPanels/MyProfile.vue";
|
||||
import ManageEmojis from "./SettingsPanels/ManageEmojis.vue";
|
||||
export default {
|
||||
components: {
|
||||
MyProfile
|
||||
MyProfile,
|
||||
ManageEmojis
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentTab: "my-profile",
|
||||
icon: "account_circle",
|
||||
title: "My Profile"
|
||||
}
|
||||
currentTab: 0,
|
||||
tabs: [
|
||||
{
|
||||
name: "My Profile",
|
||||
tabName: "My Profile",
|
||||
icon: "account_circle",
|
||||
component: "my-profile"
|
||||
},
|
||||
{
|
||||
name: "Message Themes",
|
||||
tabName: "Coming soon!",
|
||||
icon: "palette",
|
||||
component: "ddddsd"
|
||||
},
|
||||
{
|
||||
name: "Manage Emojis",
|
||||
tabName: "Manage Emojis",
|
||||
icon: "face",
|
||||
component: "manage-emojis"
|
||||
}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
tabClicked(currentTab, icon, title) {
|
||||
this.currentTab = currentTab;
|
||||
this.icon = icon;
|
||||
this.title = title;
|
||||
},
|
||||
close() {
|
||||
this.$store.dispatch('setPopoutVisibility', {name: 'settings', visibility: false})
|
||||
this.$store.dispatch("setPopoutVisibility", {
|
||||
name: "settings",
|
||||
visibility: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.settings-darken-background{
|
||||
.settings-darken-background {
|
||||
position: absolute;
|
||||
background: rgba(0, 0, 0, 0.541);
|
||||
top: 0;
|
||||
|
|
@ -79,17 +86,19 @@ export default {
|
|||
display: flex;
|
||||
color: white;
|
||||
}
|
||||
.settings-box{
|
||||
.settings-box {
|
||||
display: flex;
|
||||
margin: auto;
|
||||
box-shadow: 0px 0px 20px rgba(0, 0, 0, 0.507);
|
||||
}
|
||||
.tabs{
|
||||
.tabs {
|
||||
background: rgba(24, 24, 24, 0.938);
|
||||
height: 600px;
|
||||
width: 200px;
|
||||
}
|
||||
.panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgba(31, 31, 31, 0.924);
|
||||
height: 600px;
|
||||
width: 600px;
|
||||
|
|
@ -103,24 +112,25 @@ export default {
|
|||
cursor: default;
|
||||
user-select: none;
|
||||
transition: 0.3s;
|
||||
align-items: center;
|
||||
}
|
||||
.tab-name {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.tab.selected {
|
||||
background: rgb(61, 61, 61) !important;
|
||||
}
|
||||
.tab div {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
background: rgba(61, 61, 61, 0.616);
|
||||
}
|
||||
.title{
|
||||
.title {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
font-size: 25px;
|
||||
background: rgb(20, 20, 20);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.title .material-icons{
|
||||
.title .material-icons {
|
||||
font-size: 40px;
|
||||
}
|
||||
.title div {
|
||||
|
|
@ -129,9 +139,9 @@ export default {
|
|||
margin-right: 5px;
|
||||
}
|
||||
.in-title {
|
||||
flex:1;
|
||||
flex: 1;
|
||||
}
|
||||
.close-button{
|
||||
.close-button {
|
||||
display: flex;
|
||||
border-radius: 50%;
|
||||
padding: 5px;
|
||||
|
|
@ -139,7 +149,7 @@ export default {
|
|||
user-select: none;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.close-button:hover{
|
||||
.close-button:hover {
|
||||
background: rgba(37, 37, 37, 0.692);
|
||||
}
|
||||
.close-button .material-icons {
|
||||
|
|
@ -148,9 +158,9 @@ export default {
|
|||
}
|
||||
|
||||
@media (max-width: 815px) {
|
||||
.settings-box{
|
||||
width:100%
|
||||
.settings-box {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
|
|||
316
src/components/app/SettingsPanels/ManageEmojis.vue
Normal file
|
|
@ -0,0 +1,316 @@
|
|||
<template>
|
||||
<div class="manage-emoji-panel">
|
||||
<div class="info">
|
||||
<div
|
||||
class="title"
|
||||
>Upload your own pretty emojis for free! Emojis must be 1MB or less. (png, jpg, gif)</div>
|
||||
<div class="button" @click="addEmojiBtn">
|
||||
<i class="material-icons">add_box</i>Add Emoji
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="emojis-list">
|
||||
<div class="emoji" v-for="emoji in customEmojis" :key="emoji.emojiID">
|
||||
<img class="preview" :src="`${domain}${emoji.emojiID}`">
|
||||
<div class="emoji-name">
|
||||
<input
|
||||
type="text"
|
||||
:value="emoji.name"
|
||||
@keydown="keyDownEvent"
|
||||
@blur="blurEvent(emoji.emojiID, $event)"
|
||||
>
|
||||
</div>
|
||||
<div class="delete-button" @click="removeEmoji(emoji.emojiID)">
|
||||
<div class="material-icons">close</div>
|
||||
<div class="inner"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input type="file" accept="image/*" ref="emojiBrowser" @change="emojiBrowse" class="hidden">
|
||||
<!-- <div class="option" @click="changePassword">Change Password</div> -->
|
||||
|
||||
<div class="alert-outer" v-if="alert.show">
|
||||
<div class="alert">
|
||||
<div class="alert-title">Error</div>
|
||||
<div class="alert-content">{{alert.content}}</div>
|
||||
<div class="alert-buttons">
|
||||
<div class="alert-button" @click="alert.show = false">Okay</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProfilePicture from "@/components/ProfilePictureTemplate.vue";
|
||||
import customEmoji from "@/services/customEmoji.js";
|
||||
import config from "@/config.js";
|
||||
import { bus } from "@/main";
|
||||
import path from "path";
|
||||
import { mapState } from "vuex";
|
||||
import emojiParser from "@/utils/emojiParser.js";
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
alert: {
|
||||
content: "",
|
||||
show: false
|
||||
},
|
||||
domain: config.domain + "/files/"
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
keyDownEvent(event) {
|
||||
const keyCode = event.keyCode;
|
||||
if (keyCode == 13) {
|
||||
event.target.blur();
|
||||
}
|
||||
},
|
||||
async blurEvent(emojiID, event) {
|
||||
// send put request
|
||||
const { ok, error, result } = await customEmoji.put({emojiID, name: event.target.value});
|
||||
if (!ok) {
|
||||
this.alert.content =
|
||||
"Upload failed - " + error.response.data.message ||
|
||||
"Something weng wrong. Try again later.";
|
||||
return (this.alert.show = true);
|
||||
}
|
||||
},
|
||||
onProgress(percent) {
|
||||
//update vue
|
||||
console.log("emoji upload progress: ", percent);
|
||||
},
|
||||
async emojiBrowse(event) {
|
||||
const file = event.target.files[0];
|
||||
event.target.value = "";
|
||||
const allowedFormats = [".png", ".jpeg", ".gif", ".jpg"];
|
||||
if (!allowedFormats.includes(path.extname(file.name).toLowerCase())) {
|
||||
this.alert.content = "Upload failed - Unsupported image file.";
|
||||
return (this.alert.show = true);
|
||||
} else if (file.size >= 1048576) {
|
||||
// 1048576 = 1mb
|
||||
this.alert.content =
|
||||
"Upload failed - Image size must be less than 1 megabytes.";
|
||||
return (this.alert.show = true);
|
||||
}
|
||||
const formData = new FormData();
|
||||
//check if emoji name is already used by twemoji
|
||||
const fileName = path.basename(file.name, path.extname(file.name));
|
||||
|
||||
const emojiExists = emojiParser.allEmojis.find(e =>
|
||||
e.shortcodes.find(ee => ee === fileName.toLowerCase())
|
||||
);
|
||||
if (emojiExists) {
|
||||
formData.append(
|
||||
"emoji",
|
||||
file,
|
||||
`${fileName}-1${path.extname(file.name)}`
|
||||
);
|
||||
} else {
|
||||
formData.append("emoji", file);
|
||||
}
|
||||
const { ok, error, result } = await customEmoji.post(
|
||||
formData,
|
||||
this.onProgress
|
||||
);
|
||||
if (!ok) {
|
||||
this.alert.content =
|
||||
"Upload failed - " + error.response.data.message ||
|
||||
"Something weng wrong. Try again later.";
|
||||
return (this.alert.show = true);
|
||||
}
|
||||
},
|
||||
addEmojiBtn() {
|
||||
if (!this.GDriveLinked) {
|
||||
return this.$store.dispatch("setPopoutVisibility", {
|
||||
name: "GDLinkMenu",
|
||||
visibility: true
|
||||
});
|
||||
}
|
||||
this.$refs.emojiBrowser.click();
|
||||
},
|
||||
async removeEmoji(emojiID) {
|
||||
|
||||
const { ok, error, result } = await customEmoji.delete(emojiID);
|
||||
if (!ok) {
|
||||
this.alert.content =
|
||||
"Upload failed - " + error.response.data.message ||
|
||||
"Something weng wrong. Try again later.";
|
||||
return (this.alert.show = true);
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState("settingsModule", ["GDriveLinked", "customEmojis"])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
input {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
background: none;
|
||||
}
|
||||
input:hover {
|
||||
background: rgba(26, 26, 26, 0.24);
|
||||
}
|
||||
input:focus {
|
||||
background: rgba(26, 26, 26, 0.527);
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
display: flex;
|
||||
align-items: right;
|
||||
align-content: right;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
height: 100%;
|
||||
width: 50px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.delete-button .material-icons {
|
||||
margin: auto;
|
||||
margin-right: 10px;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.delete-button:hover > .inner {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.delete-button .inner {
|
||||
background: rgba(255, 0, 0, 0.205);
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
right: 0;
|
||||
transition: 0.3s;
|
||||
border-top-left-radius: 60px;
|
||||
border-bottom-left-radius: 60px;
|
||||
}
|
||||
|
||||
.preview {
|
||||
height: 30px;
|
||||
width: auto;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.title {
|
||||
margin: 10px;
|
||||
}
|
||||
.manage-emoji-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.emojis-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgba(47, 47, 47, 0.767);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: calc(100% - 120px);
|
||||
width: calc(100% - 30px);
|
||||
margin: auto;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.emoji {
|
||||
background: rgba(63, 63, 63, 0.411);
|
||||
height: 50px;
|
||||
width: calc(100% - 10px);
|
||||
display: flex;
|
||||
margin: 5px;
|
||||
align-items: center;
|
||||
transition: 0.3s;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.emoji:hover {
|
||||
background: rgba(75, 75, 75, 0.712);
|
||||
}
|
||||
.emoji-name {
|
||||
margin: auto;
|
||||
margin-left: 5px;
|
||||
flex: 1;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
width: inherit;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background: rgba(54, 54, 54, 0.603);
|
||||
margin-bottom: 10px;
|
||||
margin-left: 20px;
|
||||
user-select: none;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.button:hover {
|
||||
background: rgb(54, 54, 54);
|
||||
}
|
||||
.button .material-icons {
|
||||
vertical-align: -6px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.alert-title {
|
||||
background: rgb(34, 34, 34);
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
}
|
||||
.alert-outer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
background: rgba(0, 0, 0, 0.267);
|
||||
}
|
||||
.alert {
|
||||
margin: auto;
|
||||
background: rgb(49, 49, 49);
|
||||
width: 500px;
|
||||
box-shadow: 0px 0px 30px #000000;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
}
|
||||
.alert-content {
|
||||
margin: auto;
|
||||
font-size: 16px;
|
||||
color: white;
|
||||
padding: 10px;
|
||||
padding-top: 30px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
.alert-buttons {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.alert-button {
|
||||
color: white;
|
||||
margin: auto;
|
||||
background: rgba(73, 53, 53, 0.712);
|
||||
padding: 10px;
|
||||
transition: 0.3s;
|
||||
}
|
||||
.alert-button:hover {
|
||||
background: rgb(83, 53, 53);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -35,6 +35,7 @@ import AvatarUpload from "@/services/AvatarUpload.js";
|
|||
import config from "@/config.js";
|
||||
import { bus } from "@/main";
|
||||
import path from "path";
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
|
@ -88,7 +89,7 @@ export default {
|
|||
return (this.alert.show = true);
|
||||
},
|
||||
editAvatarBtn() {
|
||||
if (!this.$store.getters.settings.GDriveLinked) {
|
||||
if (!this.GDriveLinked) {
|
||||
return this.$store.dispatch("setPopoutVisibility", {
|
||||
name: "GDLinkMenu",
|
||||
visibility: true
|
||||
|
|
@ -98,6 +99,7 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState('settingsModule', ['GDriveLinked']),
|
||||
user() {
|
||||
return this.$store.getters.user;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,19 +2,40 @@
|
|||
<div class="emoji-panel" v-click-outside="closePanel">
|
||||
<div class="emoji-panel-inner">
|
||||
<div class="emojis-list">
|
||||
<!-- Recent Emojis Category -->
|
||||
<div class="category">
|
||||
<div class="category-name">Recent</div>
|
||||
<div class="list">
|
||||
<div class="emoji-item" v-for="(recentEmoji, index) in recentEmojiList" :key="index" @click="clickEvent(recentEmoji)">
|
||||
<div
|
||||
class="emoji-item"
|
||||
v-for="(recentEmoji, index) in this.recentEmojisList"
|
||||
:key="index"
|
||||
@click="emojiClickEvent(recentEmoji)"
|
||||
>
|
||||
<img
|
||||
class="panel emoji"
|
||||
v-lazyload
|
||||
:data-url="emojiShortcodeToPath(':' + recentEmoji + ':')"
|
||||
:data-url=" getCustomEmoji(recentEmoji) || emojiShortcodeToPath(':' + recentEmoji + ':')"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Emojis Category -->
|
||||
<div class="category">
|
||||
<div class="category-name">Custom Emojis</div>
|
||||
<div class="list">
|
||||
<div
|
||||
class="emoji-item"
|
||||
v-for="(customEmoji, index) in this.customEmojisList"
|
||||
:key="index"
|
||||
@click="customEmojiClickEvent(customEmoji)"
|
||||
>
|
||||
<img class="panel emoji" v-lazyload :data-url="customEmojiPath + customEmoji.emojiID">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="category" v-for="(group, index) in groups" :key="group">
|
||||
<div class="category-name">{{group}}</div>
|
||||
<div class="list">
|
||||
|
|
@ -22,7 +43,7 @@
|
|||
class="emoji-item"
|
||||
v-for="emojiSorted in emojiByGroup(index)"
|
||||
:key="emojiSorted.shortcodes[0]"
|
||||
@click="clickEvent(emojiSorted.shortcodes[0])"
|
||||
@click="emojiClickEvent(emojiSorted.shortcodes[0])"
|
||||
>
|
||||
<img class="panel emoji" v-lazyload :data-url="parseEmojiPath(emojiSorted.unicode)">
|
||||
</div>
|
||||
|
|
@ -39,7 +60,7 @@
|
|||
v-for="(emoji, index) in groupUnicodes"
|
||||
:key="index"
|
||||
@mouseenter="mouseHover(emoji, $event)"
|
||||
@click="scrollToCategory(index + 1)"
|
||||
@click="scrollToCategory(index + 2)"
|
||||
>
|
||||
<img class="panel-emoji" :src="selectRandom(emoji)">
|
||||
<div class="tooltip">{{ groups[index]}}</div>
|
||||
|
|
@ -54,7 +75,8 @@
|
|||
import { bus } from "@/main";
|
||||
import emojiParser from "@/utils/emojiParser.js";
|
||||
import lazyLoad from "@/directives/LazyLoad.js";
|
||||
|
||||
import {mapState} from 'vuex'
|
||||
import config from "@/config.js";
|
||||
|
||||
|
||||
export default {
|
||||
|
|
@ -312,12 +334,19 @@ export default {
|
|||
"🇨🇭"
|
||||
]
|
||||
],
|
||||
emojis: emojiParser.getAllEmojis(),
|
||||
groups: emojiParser.getGroups(),
|
||||
recentEmojiList: this.$store.getters.recentEmojis
|
||||
emojis: emojiParser.allEmojis,
|
||||
groups: emojiParser.allGroups,
|
||||
recentEmojisList: null,
|
||||
customEmojisList : null,
|
||||
customEmojiPath: config.domain + "/files/"
|
||||
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getCustomEmoji(shortCode){
|
||||
const customEmoji = emojiParser.getCustomEmojisByShortCode(shortCode)
|
||||
return (customEmoji ? this.customEmojiPath + customEmoji.emojiID : undefined)
|
||||
},
|
||||
closePanel() {
|
||||
this.$store.dispatch("setPopoutVisibility", {
|
||||
name: "emojiPanel",
|
||||
|
|
@ -338,7 +367,10 @@ export default {
|
|||
const randomNum = Math.floor(Math.random() * array.length);
|
||||
return this.parseEmojiPath(array[randomNum]);
|
||||
},
|
||||
clickEvent(shortcode) {
|
||||
customEmojiClickEvent(emoji) {
|
||||
bus.$emit("emojiPanel:Selected", emoji.name);
|
||||
},
|
||||
emojiClickEvent(shortcode) {
|
||||
bus.$emit("emojiPanel:Selected", shortcode);
|
||||
},
|
||||
mouseHover(emoji, event) {
|
||||
|
|
@ -349,8 +381,12 @@ export default {
|
|||
elements[index].scrollIntoView();
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.recentEmojiList = this.$store.getters.recentEmojis
|
||||
beforeMount() {
|
||||
this.recentEmojisList = this.recentEmojis
|
||||
this.customEmojisList = this.customEmojis
|
||||
},
|
||||
computed: {
|
||||
...mapState('settingsModule', ['recentEmojis', 'customEmojis'])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -408,7 +444,7 @@ export default {
|
|||
padding: 2px;
|
||||
border-radius: 5px;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
min-width: 30px;
|
||||
}
|
||||
.emoji-item:hover {
|
||||
background: rgb(59, 59, 59);
|
||||
|
|
@ -429,7 +465,7 @@ export default {
|
|||
}
|
||||
.tabs img {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
width: auto;
|
||||
margin: auto;
|
||||
filter: grayscale(100%);
|
||||
transition: 0.1s;
|
||||
|
|
@ -482,7 +518,7 @@ export default {
|
|||
align-self: flex-end;
|
||||
margin-right: 70px;
|
||||
}
|
||||
.tooltip{
|
||||
.tooltip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
|
|
@ -499,5 +535,6 @@ img.panel.emoji {
|
|||
margin-left: 3px;
|
||||
margin-top: 3px;
|
||||
margin: auto;
|
||||
width: auto;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,15 @@
|
|||
:class="{emojiItem: true, selected: index === emojiIndex}"
|
||||
@mouseenter="hoverEvent"
|
||||
@click="clickEvent"
|
||||
:key="emoji.hexcode"
|
||||
:key="emoji.hexcode || emoji.emojiID"
|
||||
>
|
||||
<div class="preview" v-html="emojiParser(emoji.unicode)"></div>
|
||||
<div class="short-code">:{{emoji.shortcodes[0]}}:</div>
|
||||
<div class="preview">
|
||||
<span v-if="emoji.unicode" v-html="emojiParser(emoji.unicode)"></span>
|
||||
<span v-else >
|
||||
<img class="custom-emoji" :src="customEmojiPath + emoji.emojiID" >
|
||||
</span>
|
||||
</div>
|
||||
<div class="short-code">:{{emoji.name || emoji.shortcodes[0]}}:</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -16,8 +21,14 @@
|
|||
<script>
|
||||
import { bus } from "@/main";
|
||||
import emojiParser from "@/utils/emojiParser.js";
|
||||
import config from "@/config.js";
|
||||
export default {
|
||||
props: ["emojiArray"],
|
||||
data(){
|
||||
return {
|
||||
customEmojiPath: config.domain + "/files/"
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
emojiParser(emoji) {
|
||||
return emojiParser.replaceEmojis(emoji);
|
||||
|
|
@ -70,6 +81,10 @@ export default {
|
|||
|
||||
|
||||
<style scoped>
|
||||
.custom-emoji {
|
||||
height: 1.5em;
|
||||
width: auto;
|
||||
}
|
||||
.selected {
|
||||
background: rgba(66, 66, 66, 0.89);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import filesize from "filesize";
|
|||
import emojiParser from "@/utils/emojiParser.js";
|
||||
import messagesService from "@/services/messagesService";
|
||||
import { bus } from "../../main";
|
||||
import {mapState} from 'vuex';
|
||||
export default {
|
||||
props: ["file"],
|
||||
data() {
|
||||
|
|
@ -140,7 +141,7 @@ export default {
|
|||
visibility: false
|
||||
});
|
||||
}
|
||||
if (!this.$store.getters.settings.GDriveLinked) {
|
||||
if (!this.GDriveLinked) {
|
||||
this.$store.dispatch("setPopoutVisibility", {
|
||||
name: "uploadDialog",
|
||||
visibility: false
|
||||
|
|
@ -161,6 +162,7 @@ export default {
|
|||
document.removeEventListener("keydown", this.keyDownEvent);
|
||||
},
|
||||
computed: {
|
||||
...mapState('settingsModule', ['GDriveLinked']),
|
||||
selectedChannelID() {
|
||||
return this.$store.getters.selectedChannelID;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ export default {
|
|||
height: 150px;
|
||||
width: 150px;
|
||||
background: url(./../../assets/logo.png);
|
||||
background-size: 129%;
|
||||
background-size: 105%;
|
||||
background-position: center;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 0px 96px -4px rgba(69,212,255,1);
|
||||
|
|
|
|||
29
src/services/customEmoji.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import {
|
||||
instance,
|
||||
wrapper
|
||||
} from './Api';
|
||||
|
||||
export default {
|
||||
post (data, onProgress) {
|
||||
const url = `/settings/emoji`;
|
||||
let config = {
|
||||
onUploadProgress(progressEvent) {
|
||||
var percentCompleted = Math.round((progressEvent.loaded * 100) /
|
||||
progressEvent.total);
|
||||
|
||||
// execute the callback
|
||||
if (onProgress) onProgress(percentCompleted)
|
||||
|
||||
return percentCompleted;
|
||||
},
|
||||
};
|
||||
return wrapper(instance().post(url, data, config));
|
||||
},
|
||||
delete(emojiID) {
|
||||
return wrapper(instance().delete(`/settings/emoji`, {data: {emojiID}}));
|
||||
},
|
||||
put(data) {
|
||||
return wrapper(instance().put(`/settings/emoji`, {emojiID: data.emojiID, name: data.name}));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ export const store = new Vuex.Store({
|
|||
emojiSuggestionModule
|
||||
},
|
||||
state: {
|
||||
|
||||
|
||||
},
|
||||
getters: {
|
||||
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ import {
|
|||
|
||||
|
||||
const state = {
|
||||
settings: {
|
||||
recentEmojis: []
|
||||
}
|
||||
GDriveLinked: false,
|
||||
customEmojis: [],
|
||||
recentEmojis: JSON.parse(localStorage.getItem('recentEmojis')) || []
|
||||
}
|
||||
|
||||
const getters = {
|
||||
settings(state) {
|
||||
return state.settings;
|
||||
return state;
|
||||
},
|
||||
recentEmojis() {
|
||||
return state.settings.recentEmojis || JSON.parse(localStorage.getItem('recentEmojis'))
|
||||
return state.recentEmojis || JSON.parse(localStorage.getItem('recentEmojis'))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ const actions = {
|
|||
setGDriveLinked(context, status) {
|
||||
context.commit('GoogleDriveLinked', status)
|
||||
},
|
||||
setLastEmoji(context, shortcode) {
|
||||
addRecentEmoji(context, shortcode) {
|
||||
const recentEmojis = JSON.parse(localStorage.getItem('recentEmojis')) || [];
|
||||
|
||||
let filter = recentEmojis.filter(function (item) {
|
||||
|
|
@ -38,25 +38,66 @@ const actions = {
|
|||
filter = filter.slice(0, 16)
|
||||
|
||||
localStorage.setItem("recentEmojis", JSON.stringify(filter));
|
||||
context.commit('setLastEmoji', filter)
|
||||
}
|
||||
context.commit('setRecentEmojis', filter)
|
||||
},
|
||||
|
||||
addCustomEmoji(context, customEmoji){
|
||||
context.commit('addCustomEmoji', customEmoji)
|
||||
},
|
||||
removeCustomEmoji(context, customEmoji) {
|
||||
const emojiID = customEmoji.emoji.emojiID;
|
||||
const customEmojiList = context.state.customEmojis;
|
||||
|
||||
for (let index = 0; index < customEmojiList.length; index++) {
|
||||
const element = customEmojiList[index];
|
||||
if (element.emojiID === emojiID){
|
||||
context.commit('removeCustomEmoji', index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
renameCustomEmoji(context, renamedEmoji){
|
||||
const customEmojiList = context.state.customEmojis;
|
||||
|
||||
for (let index = 0; index < customEmojiList.length; index++) {
|
||||
const element = customEmojiList[index];
|
||||
if (element.emojiID === renamedEmoji.emoji.emojiID){
|
||||
context.commit('renameCustomEmoji', {emoji: renamedEmoji.emoji, index});
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
setCustomEmojis({commit}, customEmojis) {
|
||||
commit('setCustomEmojis', customEmojis)
|
||||
},
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
setSettings(state, settings) {
|
||||
state.settings = settings;
|
||||
state = Object.assign(state, settings)
|
||||
},
|
||||
GoogleDriveLinked(state, status) {
|
||||
Vue.set(state.settings, 'GDriveLinked', status)
|
||||
Vue.set(state, 'GDriveLinked', status)
|
||||
},
|
||||
setLastEmoji(state, newEmojiList) {
|
||||
Vue.set(state.settings, 'recentEmojis', newEmojiList)
|
||||
addCustomEmoji(state, customEmoji) {
|
||||
const customEmojisList = state.customEmojis || [];
|
||||
customEmojisList.push(customEmoji.emoji)
|
||||
|
||||
Vue.set(state, "customEmojis", customEmojisList)
|
||||
},
|
||||
removeCustomEmoji(state, index) {
|
||||
Vue.delete(state.customEmojis, index)
|
||||
},
|
||||
renameCustomEmoji(state, {emoji, index}) {
|
||||
Vue.set(state.customEmojis, index, emoji)
|
||||
},
|
||||
setRecentEmojis(state, newEmojiList) {
|
||||
Vue.set(state, 'recentEmojis', newEmojiList)
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
namespace: true,
|
||||
namespaced: true,
|
||||
state,
|
||||
getters,
|
||||
actions,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ const actions = {
|
|||
}
|
||||
context.commit('addAllChannels', channelsObject)
|
||||
context.dispatch('addAllNotifications', notifications)
|
||||
context.dispatch('setSettings', settings)
|
||||
context.dispatch('settingsModule/setSettings', settings)
|
||||
|
||||
|
||||
},
|
||||
|
|
@ -105,7 +105,16 @@ const actions = {
|
|||
},
|
||||
['socket_googleDrive:linked'](context) {
|
||||
context.dispatch('setPopoutVisibility', {name: 'GDLinkMenu', visibility: false})
|
||||
context.dispatch('setGDriveLinked', true)
|
||||
context.dispatch('settingsModule/setGDriveLinked', true)
|
||||
},
|
||||
['socket_customEmoji:uploaded'](context, emoji) {
|
||||
context.dispatch('settingsModule/addCustomEmoji', emoji)
|
||||
},
|
||||
['socket_customEmoji:remove'](context, emoji) {
|
||||
context.dispatch('settingsModule/removeCustomEmoji', emoji)
|
||||
},
|
||||
['socket_customEmoji:rename'](context, emoji) {
|
||||
context.dispatch('settingsModule/renameCustomEmoji', emoji)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ const config = [
|
|||
{
|
||||
title: 'Custom emojis!',
|
||||
shortTitle: 'Custom emojis!',
|
||||
date: '23/03/2019',
|
||||
headColor: "rgba(255, 48, 48, 0.87)",
|
||||
date: '29/03/2019',
|
||||
headColor: "rgba(255, 48, 48, 0.77)",
|
||||
new: [
|
||||
'You can now add your own emojis for free.',
|
||||
"User status in the top bar to easily view if someone is still online or, if you're talking to a wall on the phone."
|
||||
"User status in the top bar to easily view if someone is still online or, if you're talking to a wall on the phone.",
|
||||
'Switching dms should be faster now.'
|
||||
],
|
||||
next: ['Servers']
|
||||
},
|
||||
|
|
@ -14,7 +15,7 @@ const config = [
|
|||
title: 'Emoji tabs and recent emojis',
|
||||
shortTitle: 'Emoji tabs and recent emojis',
|
||||
date: '22/03/2019',
|
||||
headColor: "rgba(244, 169, 65, 0.87)",
|
||||
headColor: "rgba(244, 169, 65, 0.77)",
|
||||
new: [
|
||||
'Tabs in emoji panel',
|
||||
'Recent Emojis now show in the emoji panel'
|
||||
|
|
@ -28,7 +29,7 @@ const config = [
|
|||
title: 'Emojis :D',
|
||||
shortTitle: 'Emojis',
|
||||
date: '20/03/2019',
|
||||
headColor: "rgba(17, 153, 69, 0.87)",
|
||||
headColor: "rgba(17, 153, 69, 0.77)",
|
||||
new: [
|
||||
'Emoji suggestions in chat when typing in any emoji :ok_hand:',
|
||||
'Emoji picker',
|
||||
|
|
@ -44,7 +45,7 @@ const config = [
|
|||
title: 'Upload anything!',
|
||||
shortTitle: 'Upload anything!',
|
||||
date: '08/03/2019',
|
||||
headColor: "rgba(38, 139, 255, 0.87)",
|
||||
headColor: "rgba(38, 139, 255, 0.77)",
|
||||
new: [
|
||||
'You can now upload any kind of files to friends. (Google drive required)',
|
||||
'Shift + enter should expand the text area.',
|
||||
|
|
|
|||
|
|
@ -2,19 +2,32 @@ import twemoji from "twemoji";
|
|||
import matchSorter from "match-sorter";
|
||||
import emojis from "@/utils/emojiData/emojis.json";
|
||||
import groups from "@/utils/emojiData/groups.json";
|
||||
|
||||
import config from "@/config.js";
|
||||
import {
|
||||
store
|
||||
} from '@/store/index';
|
||||
|
||||
export default {
|
||||
getCustomEmojisByShortCode(shortcode) {
|
||||
const customEmojis = store.state['settingsModule'].customEmojis;
|
||||
return customEmojis.find(emoji => emoji.name === shortcode)
|
||||
},
|
||||
replaceShortcode: (message) => {
|
||||
const customEmojis = store.state['settingsModule'].customEmojis;
|
||||
|
||||
const regex = /:([\w]+):/g;
|
||||
|
||||
return message.replace(regex, (x) => {
|
||||
const emoji = emojiExists(x.replace(/[::]+/g, ''))
|
||||
if (emoji) return emoji.unicode
|
||||
|
||||
const customEmoji = customEmojis.find(e => e.name === x.substr(1).slice(0, -1))
|
||||
if (customEmoji) return `:${customEmoji.name}&${customEmoji.emojiID}:`
|
||||
return x
|
||||
});
|
||||
},
|
||||
replaceEmojis: (string) => {
|
||||
|
||||
return twemoji.parse(string,
|
||||
function (icon, options, variant) {
|
||||
if (!icon) return string;
|
||||
|
|
@ -26,15 +39,20 @@ export default {
|
|||
twemoji.parse(string,
|
||||
function (icon, options, variant) {
|
||||
if (!icon) return string;
|
||||
emojiPath = require("twemoji/2/svg/" + icon + ".svg")
|
||||
emojiPath = require("twemoji/2/svg/" + icon + ".svg")
|
||||
})
|
||||
return emojiPath;
|
||||
},
|
||||
searchEmoji: (shortCode) => {
|
||||
return matchSorter(emojis, shortCode, {keys: ['shortcodes']});
|
||||
const customEmojis = store.state['settingsModule'].customEmojis;
|
||||
return [...matchSorter(customEmojis, shortCode, {
|
||||
keys: ['name']
|
||||
}), ...matchSorter(emojis, shortCode, {
|
||||
keys: ['shortcodes']
|
||||
})];
|
||||
},
|
||||
getAllEmojis: _ => emojis,
|
||||
getGroups: _ => groups
|
||||
allEmojis: emojis,
|
||||
allGroups: groups
|
||||
}
|
||||
|
||||
function emojiExists(shortCode) {
|
||||
|
|
|
|||
|
|
@ -1,63 +1,73 @@
|
|||
import futoji from 'futoji'
|
||||
import twemoji from 'twemoji'
|
||||
import emojiParser from '@/utils/emojiParser';
|
||||
import config from "@/config.js";
|
||||
|
||||
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'custom emoji',
|
||||
symbol: ':',
|
||||
recursive: false,
|
||||
transformer: text => {
|
||||
const split = text.split('&');
|
||||
if (!split || split.length <= 1) return `:${text}:`;
|
||||
const url = split[split.length - 1].slice(4);
|
||||
return `<img class="emoji" draggable="false" alt=":${split[0]}:" src="${config.domain + "/files/" + url}">`
|
||||
}
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'bold-and-italic',
|
||||
symbol: '***',
|
||||
transformer: text => `<strong><em>${text}</em></strong>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'bold',
|
||||
symbol: '**',
|
||||
transformer: text => `<strong>${text}</strong>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'italic',
|
||||
symbol: '*',
|
||||
transformer: text => `<em>${text}</em>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'underline',
|
||||
symbol: '__',
|
||||
transformer: text => `<u>${text}</u>`
|
||||
})
|
||||
futoji.addTransformer({
|
||||
name: 'italic',
|
||||
symbol: '_',
|
||||
transformer: text => `<em>${text}</em>`
|
||||
})
|
||||
futoji.addTransformer({
|
||||
name: 'srike',
|
||||
symbol: '~~',
|
||||
transformer: text => `<s>${text.trim()}</s>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'code-block',
|
||||
symbol: '```',
|
||||
recursive: false,
|
||||
transformer: text => `<div class="codeblock"><code>${formatCode(text).trim()}</code></div>`,
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'code',
|
||||
symbol: '`',
|
||||
recursive: false,
|
||||
transformer: text => `<code>${text}</code>`,
|
||||
})
|
||||
|
||||
export default (message) => {
|
||||
|
||||
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'bold-and-italic',
|
||||
symbol: '***',
|
||||
transformer: text => `<strong><em>${text}</em></strong>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'bold',
|
||||
symbol: '**',
|
||||
transformer: text => `<strong>${text}</strong>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'italic',
|
||||
symbol: '*',
|
||||
transformer: text => `<em>${text}</em>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'underline',
|
||||
symbol: '__',
|
||||
transformer: text => `<u>${text}</u>`
|
||||
})
|
||||
futoji.addTransformer({
|
||||
name: 'italic',
|
||||
symbol: '_',
|
||||
transformer: text => `<em>${text}</em>`
|
||||
})
|
||||
futoji.addTransformer({
|
||||
name: 'srike',
|
||||
symbol: '~~',
|
||||
transformer: text => `<s>${text.trim()}</s>`
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'code-block',
|
||||
symbol: '```',
|
||||
recursive: false,
|
||||
transformer: text => `<div class="codeblock"><code>${formatCode(text).trim()}</code></div>`,
|
||||
})
|
||||
|
||||
futoji.addTransformer({
|
||||
name: 'code',
|
||||
symbol: '`',
|
||||
recursive: false,
|
||||
transformer: text => `<code>${text}</code>`,
|
||||
})
|
||||
|
||||
|
||||
message = futoji.format(escapeHtml(message));
|
||||
|
||||
message = emojiParser.replaceEmojis(message);
|
||||
|
||||
return message;
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ button {
|
|||
height: 30px;
|
||||
width: 30px;
|
||||
background: url(./../assets/logo.png);
|
||||
background-size: 125%;
|
||||
background-size: 105%;
|
||||
background-position: center;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0px 0px 96px -4px rgba(69,212,255,1);
|
||||
|
|
|
|||