feat: Improve sidebar UI, add emoji icons instead of ionicons (#1605)
Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
parent
346830ab1d
commit
764c90174e
10 changed files with 195 additions and 52 deletions
|
@ -74,12 +74,10 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation--details {
|
.conversation--details {
|
||||||
border-top: 1px solid $color-border-light;
|
padding: 0 var(--space-normal);
|
||||||
padding: var(--space-normal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact-conversation--panel {
|
.contact-conversation--panel {
|
||||||
border-top: 1px solid $color-border-light;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,14 @@
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
:title="$t('CONTACT_PANEL.CONVERSATIONS.TITLE')"
|
:title="$t('CONTACT_PANEL.CONVERSATIONS.TITLE')"
|
||||||
icon="ion-chatboxes"
|
icon="ion-chatboxes"
|
||||||
|
emoji="💬"
|
||||||
/>
|
/>
|
||||||
<div v-if="!uiFlags.isFetching">
|
<div v-if="!uiFlags.isFetching" class="contact-conversation__wrap">
|
||||||
<p v-if="!previousConversations.length" class="no-results">
|
<div v-if="!previousConversations.length" class="no-label-message">
|
||||||
{{ $t('CONTACT_PANEL.CONVERSATIONS.NO_RECORDS_FOUND') }}
|
<span>
|
||||||
</p>
|
{{ $t('CONTACT_PANEL.CONVERSATIONS.NO_RECORDS_FOUND') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
<div v-else class="contact-conversation--list">
|
<div v-else class="contact-conversation--list">
|
||||||
<conversation-card
|
<conversation-card
|
||||||
v-for="conversation in previousConversations"
|
v-for="conversation in previousConversations"
|
||||||
|
@ -78,11 +81,18 @@ export default {
|
||||||
@import '~dashboard/assets/scss/mixins';
|
@import '~dashboard/assets/scss/mixins';
|
||||||
|
|
||||||
.contact-conversation--panel {
|
.contact-conversation--panel {
|
||||||
padding: $space-normal;
|
padding: 0 var(--space-slab) var(--space-two);
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-results {
|
.contact-conversation__wrap {
|
||||||
margin: 0;
|
margin-left: var(--space-medium);
|
||||||
color: $color-gray;
|
}
|
||||||
|
|
||||||
|
.no-label-message {
|
||||||
|
color: var(--b-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.conv-details--item {
|
||||||
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
:title="$t('CONTACT_PANEL.CUSTOM_ATTRIBUTES.TITLE')"
|
:title="$t('CONTACT_PANEL.CUSTOM_ATTRIBUTES.TITLE')"
|
||||||
icon="ion-code"
|
icon="ion-code"
|
||||||
|
emoji="📕"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
v-for="attribute in listOfAttributes"
|
v-for="attribute in listOfAttributes"
|
||||||
|
@ -45,12 +46,15 @@ export default {
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.custom-attributes--panel {
|
.custom-attributes--panel {
|
||||||
border-top: 1px solid var(--b-100);
|
padding: 0 var(--space-slab) var(--space-slab);
|
||||||
padding: var(--space-normal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.conv-details--item {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
.custom-attribute--row {
|
.custom-attribute--row {
|
||||||
margin-bottom: var(--space-small);
|
margin-bottom: var(--space-small);
|
||||||
|
margin-left: var(--space-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-attribute--row__attribute {
|
.custom-attribute--row__attribute {
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="conv-details--item">
|
<div class="conv-details--item">
|
||||||
<h4 class="conv-details--item__label">
|
<h4 class="conv-details--item__label text-block-title">
|
||||||
<div>
|
<div class="title--icon">
|
||||||
<i v-if="icon" :class="icon" class="conv-details--item__icon"></i>
|
<emoji-or-icon :icon="icon" :emoji="emoji" />
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</div>
|
</div>
|
||||||
<button v-if="showEdit" @click="onEdit">
|
<button
|
||||||
|
v-if="showEdit"
|
||||||
|
class="button clear small edit-button"
|
||||||
|
@click="onEdit"
|
||||||
|
>
|
||||||
{{ $t('CONTACT_PANEL.EDIT_LABEL') }}
|
{{ $t('CONTACT_PANEL.EDIT_LABEL') }}
|
||||||
</button>
|
</button>
|
||||||
</h4>
|
</h4>
|
||||||
|
@ -18,10 +22,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import EmojiOrIcon from 'shared/components/EmojiOrIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
EmojiOrIcon,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
title: { type: String, required: true },
|
title: { type: String, required: true },
|
||||||
icon: { type: String, default: '' },
|
icon: { type: String, default: '' },
|
||||||
|
emoji: { type: String, default: '' },
|
||||||
value: { type: [String, Number], default: '' },
|
value: { type: [String, Number], default: '' },
|
||||||
showEdit: { type: Boolean, default: false },
|
showEdit: { type: Boolean, default: false },
|
||||||
},
|
},
|
||||||
|
@ -38,29 +48,32 @@ export default {
|
||||||
@import '~dashboard/assets/scss/mixins';
|
@import '~dashboard/assets/scss/mixins';
|
||||||
|
|
||||||
.conv-details--item {
|
.conv-details--item {
|
||||||
padding-bottom: var(--space-slab);
|
padding-bottom: var(--space-normal);
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conv-details--item__label {
|
.conv-details--item__label {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: $font-size-small;
|
|
||||||
font-weight: $font-weight-medium;
|
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: $space-micro;
|
margin-bottom: var(--space-smaller);
|
||||||
|
|
||||||
button {
|
.edit-button {
|
||||||
cursor: pointer;
|
padding: 0;
|
||||||
color: $color-body;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.conv-details--item__value {
|
.conv-details--item__value {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
margin-top: $space-small;
|
margin-left: var(--space-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title--icon .icon--emoji,
|
||||||
|
.title--icon .icon--font {
|
||||||
|
margin-right: var(--space-small);
|
||||||
|
}
|
||||||
|
|
||||||
|
.title--icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -10,30 +10,35 @@
|
||||||
:title="$t('EDIT_CONTACT.FORM.LOCATION.LABEL')"
|
:title="$t('EDIT_CONTACT.FORM.LOCATION.LABEL')"
|
||||||
:value="location"
|
:value="location"
|
||||||
icon="ion-map"
|
icon="ion-map"
|
||||||
|
emoji="📍"
|
||||||
/>
|
/>
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
v-if="ipAddress"
|
v-if="ipAddress"
|
||||||
:title="$t('CONTACT_PANEL.IP_ADDRESS')"
|
:title="$t('CONTACT_PANEL.IP_ADDRESS')"
|
||||||
:value="ipAddress"
|
:value="ipAddress"
|
||||||
icon="ion-android-locate"
|
icon="ion-android-locate"
|
||||||
|
emoji="🧭"
|
||||||
/>
|
/>
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
v-if="browser.browser_name"
|
v-if="browser.browser_name"
|
||||||
:title="$t('CONTACT_PANEL.BROWSER')"
|
:title="$t('CONTACT_PANEL.BROWSER')"
|
||||||
:value="browserName"
|
:value="browserName"
|
||||||
icon="ion-ios-world-outline"
|
icon="ion-ios-world-outline"
|
||||||
|
emoji="🌐"
|
||||||
/>
|
/>
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
v-if="browser.platform_name"
|
v-if="browser.platform_name"
|
||||||
:title="$t('CONTACT_PANEL.OS')"
|
:title="$t('CONTACT_PANEL.OS')"
|
||||||
:value="platformName"
|
:value="platformName"
|
||||||
icon="ion-laptop"
|
icon="ion-laptop"
|
||||||
|
emoji="💻"
|
||||||
/>
|
/>
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
v-if="referer"
|
v-if="referer"
|
||||||
:title="$t('CONTACT_PANEL.INITIATED_FROM')"
|
:title="$t('CONTACT_PANEL.INITIATED_FROM')"
|
||||||
:value="referer"
|
:value="referer"
|
||||||
icon="ion-link"
|
icon="ion-link"
|
||||||
|
emoji="🔗"
|
||||||
>
|
>
|
||||||
<a :href="referer" rel="noopener noreferrer nofollow" target="_blank">
|
<a :href="referer" rel="noopener noreferrer nofollow" target="_blank">
|
||||||
{{ referer }}
|
{{ referer }}
|
||||||
|
@ -44,6 +49,7 @@
|
||||||
:title="$t('CONTACT_PANEL.INITIATED_AT')"
|
:title="$t('CONTACT_PANEL.INITIATED_AT')"
|
||||||
:value="initiatedAt.timestamp"
|
:value="initiatedAt.timestamp"
|
||||||
icon="ion-clock"
|
icon="ion-clock"
|
||||||
|
emoji="🕰"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<contact-custom-attributes
|
<contact-custom-attributes
|
||||||
|
@ -211,8 +217,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation--details {
|
.conversation--details {
|
||||||
border-top: 1px solid $color-border-light;
|
padding: 0 var(--space-slab);
|
||||||
padding: $space-normal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.conversation--labels {
|
.conversation--labels {
|
||||||
|
@ -230,10 +235,6 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact-conversation--panel {
|
|
||||||
border-top: 1px solid $color-border-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact--mute {
|
.contact--mute {
|
||||||
color: $alert-color;
|
color: $alert-color;
|
||||||
display: block;
|
display: block;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
:href="contact.email ? `mailto:${contact.email}` : ''"
|
:href="contact.email ? `mailto:${contact.email}` : ''"
|
||||||
:value="contact.email"
|
:value="contact.email"
|
||||||
icon="ion-email"
|
icon="ion-email"
|
||||||
|
emoji="✉️"
|
||||||
:title="$t('CONTACT_PANEL.EMAIL_ADDRESS')"
|
:title="$t('CONTACT_PANEL.EMAIL_ADDRESS')"
|
||||||
show-copy
|
show-copy
|
||||||
/>
|
/>
|
||||||
|
@ -30,24 +31,27 @@
|
||||||
:href="contact.phone_number ? `tel:${contact.phone_number}` : ''"
|
:href="contact.phone_number ? `tel:${contact.phone_number}` : ''"
|
||||||
:value="contact.phone_number"
|
:value="contact.phone_number"
|
||||||
icon="ion-ios-telephone"
|
icon="ion-ios-telephone"
|
||||||
|
emoji="📞"
|
||||||
:title="$t('CONTACT_PANEL.PHONE_NUMBER')"
|
:title="$t('CONTACT_PANEL.PHONE_NUMBER')"
|
||||||
/>
|
/>
|
||||||
<contact-info-row
|
<contact-info-row
|
||||||
v-if="additionalAttributes.location"
|
v-if="additionalAttributes.location"
|
||||||
:value="additionalAttributes.location"
|
:value="additionalAttributes.location"
|
||||||
icon="ion-map"
|
icon="ion-map"
|
||||||
|
emoji="🌍"
|
||||||
:title="$t('CONTACT_PANEL.LOCATION')"
|
:title="$t('CONTACT_PANEL.LOCATION')"
|
||||||
/>
|
/>
|
||||||
<contact-info-row
|
<contact-info-row
|
||||||
:value="additionalAttributes.company_name"
|
:value="additionalAttributes.company_name"
|
||||||
icon="ion-briefcase"
|
icon="ion-briefcase"
|
||||||
|
emoji="🏢"
|
||||||
:title="$t('CONTACT_PANEL.COMPANY')"
|
:title="$t('CONTACT_PANEL.COMPANY')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<woot-button
|
<woot-button
|
||||||
class="expanded"
|
class="clear edit-contact"
|
||||||
variant="hollow primary small"
|
variant="primary small"
|
||||||
@click="toggleEditModal"
|
@click="toggleEditModal"
|
||||||
>
|
>
|
||||||
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
|
{{ $t('EDIT_CONTACT.BUTTON_LABEL') }}
|
||||||
|
@ -115,7 +119,7 @@ export default {
|
||||||
@import '~dashboard/assets/scss/mixins';
|
@import '~dashboard/assets/scss/mixins';
|
||||||
.contact--profile {
|
.contact--profile {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
padding: $space-normal;
|
padding: var(--space-normal) var(--space-normal) var(--space-large);
|
||||||
|
|
||||||
.user-thumbnail-box {
|
.user-thumbnail-box {
|
||||||
margin-right: $space-normal;
|
margin-right: $space-normal;
|
||||||
|
@ -151,7 +155,7 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact--metadata {
|
.contact--metadata {
|
||||||
margin: $space-small 0 $space-normal;
|
margin: var(--space-normal) 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.social--icons {
|
.social--icons {
|
||||||
|
@ -159,4 +163,10 @@ export default {
|
||||||
font-size: $font-weight-normal;
|
font-size: $font-weight-normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-contact {
|
||||||
|
padding: 0 var(--space-slab);
|
||||||
|
margin-left: var(--space-slab);
|
||||||
|
margin-top: var(--space-smaller);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="contact-info--row">
|
<div class="contact-info--row">
|
||||||
<a v-if="href" :href="href" class="contact-info--details">
|
<a v-if="href" :href="href" class="contact-info--details">
|
||||||
<i :class="icon" class="contact-info--icon" />
|
<emoji-or-icon :icon="icon" :emoji="emoji" />
|
||||||
<span v-if="value" class="text-truncate" :title="value">{{ value }}</span>
|
<span v-if="value" class="text-truncate" :title="value">{{ value }}</span>
|
||||||
<span v-else class="text-muted">{{
|
<span v-else class="text-muted">{{
|
||||||
$t('CONTACT_PANEL.NOT_AVAILABLE')
|
$t('CONTACT_PANEL.NOT_AVAILABLE')
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<div v-else class="contact-info--details">
|
<div v-else class="contact-info--details">
|
||||||
<i :class="icon" class="contact-info--icon" />
|
<emoji-or-icon :icon="icon" :emoji="emoji" />
|
||||||
<span v-if="value" class="text-truncate">{{ value }}</span>
|
<span v-if="value" class="text-truncate">{{ value }}</span>
|
||||||
<span v-else class="text-muted">{{
|
<span v-else class="text-muted">{{
|
||||||
$t('CONTACT_PANEL.NOT_AVAILABLE')
|
$t('CONTACT_PANEL.NOT_AVAILABLE')
|
||||||
|
@ -29,7 +29,12 @@
|
||||||
<script>
|
<script>
|
||||||
import copy from 'copy-text-to-clipboard';
|
import copy from 'copy-text-to-clipboard';
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
|
import EmojiOrIcon from 'shared/components/EmojiOrIcon';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
EmojiOrIcon,
|
||||||
|
},
|
||||||
mixins: [alertMixin],
|
mixins: [alertMixin],
|
||||||
props: {
|
props: {
|
||||||
href: {
|
href: {
|
||||||
|
@ -40,6 +45,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
emoji: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
|
@ -71,7 +80,7 @@ export default {
|
||||||
.contact-info--details {
|
.contact-info--details {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: $space-smaller;
|
margin-bottom: var(--space-one);
|
||||||
color: $color-body;
|
color: $color-body;
|
||||||
|
|
||||||
.copy-icon {
|
.copy-icon {
|
||||||
|
@ -87,4 +96,9 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contact-info--details .icon--emoji,
|
||||||
|
.contact-info--details .icon--font {
|
||||||
|
margin-right: var(--space-small);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,18 +7,21 @@
|
||||||
<contact-details-item
|
<contact-details-item
|
||||||
:title="$t('CONTACT_PANEL.LABELS.TITLE')"
|
:title="$t('CONTACT_PANEL.LABELS.TITLE')"
|
||||||
icon="ion-pricetags"
|
icon="ion-pricetags"
|
||||||
|
emoji="🏷️"
|
||||||
:show-edit="true"
|
:show-edit="true"
|
||||||
@edit="onEdit"
|
@edit="onEdit"
|
||||||
/>
|
/>
|
||||||
<woot-label
|
<div class="label-wrap">
|
||||||
v-for="label in activeLabels"
|
<woot-label
|
||||||
:key="label.id"
|
v-for="label in activeLabels"
|
||||||
:title="label.title"
|
:key="label.id"
|
||||||
:description="label.description"
|
:title="label.title"
|
||||||
:bg-color="label.color"
|
:description="label.description"
|
||||||
/>
|
:bg-color="label.color"
|
||||||
<div v-if="!activeLabels.length">
|
/>
|
||||||
{{ $t('CONTACT_PANEL.LABELS.NO_AVAILABLE_LABELS') }}
|
<div v-if="!activeLabels.length" class="no-label-message">
|
||||||
|
<span>{{ $t('CONTACT_PANEL.LABELS.NO_AVAILABLE_LABELS') }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<add-label-to-conversation
|
<add-label-to-conversation
|
||||||
v-if="isEditing"
|
v-if="isEditing"
|
||||||
|
@ -119,15 +122,24 @@ export default {
|
||||||
@import '~dashboard/assets/scss/mixins';
|
@import '~dashboard/assets/scss/mixins';
|
||||||
|
|
||||||
.contact-conversation--panel {
|
.contact-conversation--panel {
|
||||||
padding: $space-normal;
|
padding: var(--space-medium) var(--space-slab) var(--space-two);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contact-conversation--list .conv-details--item {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
.conversation--label {
|
.conversation--label {
|
||||||
color: $color-white;
|
color: $color-white;
|
||||||
margin-right: $space-small;
|
margin-right: $space-small;
|
||||||
font-size: $font-size-small;
|
font-size: $font-size-small;
|
||||||
padding: $space-smaller;
|
padding: $space-smaller;
|
||||||
}
|
}
|
||||||
|
.label-wrap {
|
||||||
|
margin-left: var(--space-medium);
|
||||||
|
}
|
||||||
|
.no-label-message {
|
||||||
|
color: var(--b-500);
|
||||||
|
}
|
||||||
|
|
||||||
.select-tags {
|
.select-tags {
|
||||||
.multiselect {
|
.multiselect {
|
||||||
|
|
47
app/javascript/shared/components/EmojiOrIcon.vue
Normal file
47
app/javascript/shared/components/EmojiOrIcon.vue
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<i v-if="showWrap" :class="className">{{ iconContent }}</i>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { hasEmojiSupport } from 'shared/helpers/emoji';
|
||||||
|
import { mapGetters } from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
icon: { type: String, default: '' },
|
||||||
|
emoji: { type: String, default: '' },
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapGetters({ uiSettings: 'getUISettings' }),
|
||||||
|
isIconTypeEmoji() {
|
||||||
|
const { icon_type: iconType } = this.uiSettings;
|
||||||
|
return iconType === 'emoji';
|
||||||
|
},
|
||||||
|
showEmoji() {
|
||||||
|
return this.isIconTypeEmoji && this.emoji && hasEmojiSupport(this.emoji);
|
||||||
|
},
|
||||||
|
showIcon() {
|
||||||
|
return !this.showEmoji && this.icon;
|
||||||
|
},
|
||||||
|
showWrap() {
|
||||||
|
return this.showEmoji || this.showIcon;
|
||||||
|
},
|
||||||
|
iconContent() {
|
||||||
|
return this.showEmoji ? this.emoji : '';
|
||||||
|
},
|
||||||
|
className() {
|
||||||
|
return {
|
||||||
|
'icon--emoji': this.showEmoji,
|
||||||
|
'icon--font': this.showIcon,
|
||||||
|
[this.icon]: this.showIcon,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.icon--emoji {
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
</style>
|
34
app/javascript/shared/helpers/emoji.js
Normal file
34
app/javascript/shared/helpers/emoji.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* Detects support for emoji character sets.
|
||||||
|
*
|
||||||
|
* Based on the Modernizr emoji detection.
|
||||||
|
* https://github.com/Modernizr/Modernizr/blob/347ddb078116cee91b25b6e897e211b023f9dcb4/feature-detects/emoji.js
|
||||||
|
*
|
||||||
|
* @return {Boolean} true or false
|
||||||
|
* @example
|
||||||
|
*
|
||||||
|
* hasEmojiSupport()
|
||||||
|
* // => true|false
|
||||||
|
*/
|
||||||
|
export const hasEmojiSupport = () => {
|
||||||
|
const pixelRatio = window.devicePixelRatio || 1;
|
||||||
|
const offset = 12 * pixelRatio;
|
||||||
|
const node = document.createElement('canvas');
|
||||||
|
|
||||||
|
// canvastext support
|
||||||
|
if (
|
||||||
|
!node.getContext ||
|
||||||
|
!node.getContext('2d') ||
|
||||||
|
typeof node.getContext('2d').fillText !== 'function'
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = node.getContext('2d');
|
||||||
|
|
||||||
|
ctx.fillStyle = '#f00';
|
||||||
|
ctx.textBaseline = 'top';
|
||||||
|
ctx.font = '32px Arial';
|
||||||
|
ctx.fillText('\ud83d\udc28', 0, 0); // U+1F428 KOALA
|
||||||
|
return ctx.getImageData(offset, offset, 1, 1).data[0] !== 0;
|
||||||
|
};
|
Loading…
Reference in a new issue