Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enh(NcEmojiPicker): Always show skin tone selector + save selection #5103

Merged
merged 4 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions l10n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ msgstr ""
msgid "Custom"
msgstr ""

msgid "Dark skin tone"
msgstr ""

#. TRANSLATORS: A color name for RGB(136, 85, 168)
msgid "Deluge"
msgstr ""
Expand Down Expand Up @@ -164,13 +167,25 @@ msgstr ""
msgid "Keyboard navigation help"
msgstr ""

msgid "Light skin tone"
msgstr ""

msgid "Load more \"{options}\""
msgstr ""

#. TRANSLATORS: A color name for RGB(45, 115, 190)
msgid "Mariner"
msgstr ""

msgid "Medium dark skin tone"
msgstr ""

msgid "Medium light skin tone"
msgstr ""

msgid "Medium skin tone"
msgstr ""

msgid "Message limit of {count} characters reached"
msgstr ""

Expand All @@ -180,6 +195,9 @@ msgstr ""
msgid "More options"
msgstr ""

msgid "Neutral skin color"
msgstr ""

msgid "Next"
msgstr ""

Expand Down Expand Up @@ -316,6 +334,9 @@ msgstr ""
msgid "Show password"
msgstr ""

msgid "Skin tone"
msgstr ""

msgid "Skip to app navigation"
msgstr ""

Expand Down
26 changes: 10 additions & 16 deletions src/components/NcColorPicker/NcColorPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export default {
:disable-fields="!advancedFields"
@input="pickColor" />
</Transition>
<div class="color-picker__navigation">
<div v-if="!paletteOnly" class="color-picker__navigation">
<NcButton v-if="advanced"
type="tertiary"
:aria-label="ariaBack"
Expand Down Expand Up @@ -235,20 +235,6 @@ import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'

import { Chrome } from 'vue-color'

/**
* Convert RGB object to a HEX string color
*
* @param {object} color - The color to convert
* @param {string} [color.r] - Red value
* @param {string} [color.g] - Green value
* @param {string} [color.b] - Blue value
* @return {string} The hex value
*/
export function rgbToHex({ r, g, b }) {
const toHex = (number) => number.toString(16).padStart(2, '0')
return `#${toHex(r)}${toHex(g)}${toHex(b)}`
}

const HEX_REGEX = /^#([a-f0-9]{3}|[a-f0-9]{6})$/i

export default {
Expand Down Expand Up @@ -280,6 +266,14 @@ export default {
default: false,
},

/**
* Limit selectable colors to only the provided palette
*/
paletteOnly: {
type: Boolean,
default: false,
},

/**
* Provide a custom array of colors to show.
* Can be either an array of string hexadecimal colors,
Expand All @@ -290,7 +284,7 @@ export default {
*/
palette: {
type: Array,
default: () => defaultPalette.map(item => ({ color: rgbToHex(item), name: item.name })),
default: () => [...defaultPalette],
validator: (palette) => palette.every(item =>
(typeof item === 'string' && HEX_REGEX.test(item))
|| (typeof item === 'object' && item.color && HEX_REGEX.test(item.color)),
Expand Down
115 changes: 89 additions & 26 deletions src/components/NcEmojiPicker/NcEmojiPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -145,23 +145,37 @@ This component allows the user to pick an emoji.
:per-line="8"
:picker-styles="{ width: '320px' }"
:show-preview="showPreview"
:skin="currentSkinTone"
:show-skin-tones="false"
:title="previewFallbackName"
role="dialog"
:aria-label="t('Emoji picker')"
v-bind="$attrs"
@select="select">
<template #searchTemplate="slotProps">
<NcTextField ref="search"
class="search"
:value.sync="search"
:label="t('Search')"
:label-visible="true"
:placeholder="i18n.search"
trailing-button-icon="close"
:trailing-button-label="t('Clear search')"
:show-trailing-button="search !== ''"
@trailing-button-click="clearSearch(); slotProps.onSearch(search);"
@update:value="slotProps.onSearch(search)" />
<div class="search__wrapper">
<NcTextField ref="search"
class="search"
:value.sync="search"
:label="t('Search')"
:label-visible="true"
:placeholder="i18n.search"
trailing-button-icon="close"
:trailing-button-label="t('Clear search')"
:show-trailing-button="search !== ''"
@trailing-button-click="clearSearch(); slotProps.onSearch(search);"
@update:value="slotProps.onSearch(search)" />
<NcColorPicker palette-only
:palette="skinTonePalette"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing a container here for inner NcPopover. Because of that, skin tones are rendered always on 'body'

:value="currentColor.color"
@update:value="onChangeSkinTone">
<NcButton :aria-label="t('Skin tone')" type="tertiary-no-background">
<template #icon>
<IconCircle :style="{ color: currentColor.color }" :title="currentColor.name" :size="20" />
</template>
</NcButton>
</NcColorPicker>
</div>
</template>
<template v-if="allowUnselect && selectedEmoji" #customCategory>
<div class="emoji-mart-category-label">
Expand All @@ -187,14 +201,19 @@ This component allows the user to pick an emoji.
</template>

<script>
import NcPopover from '../NcPopover/index.js'
import NcTextField from '../NcTextField/index.js'
import { Picker, Emoji, EmojiIndex } from 'emoji-mart-vue-fast'
import { t } from '../../l10n.js'
import { getCurrentSkinTone, setCurrentSkinTone } from '../../functions/emoji/emoji.ts'
import { Color } from '../../utils/GenColors.js'

import { Picker, Emoji, EmojiIndex } from 'emoji-mart-vue-fast'
import data from 'emoji-mart-vue-fast/data/all.json'
import IconCircle from 'vue-material-design-icons/Circle.vue'
import NcButton from '../NcButton/index.js'
import NcColorPicker from '../NcColorPicker/NcColorPicker.vue'
import NcPopover from '../NcPopover/index.js'
import NcTextField from '../NcTextField/index.js'

// Shared emoji index for all NcEmojiPicker instances
// Shared emoji index and skinTone for all NcEmojiPicker instances
// Will be initialized on the first NcEmojiPicker creating
let emojiIndex

Expand All @@ -217,14 +236,28 @@ const i18n = {
},
}

const skinTonePalette = [
new Color(255, 222, 52, t('Neutral skin color')),
new Color(228, 205, 166, t('Light skin tone')),
new Color(250, 221, 192, t('Medium light skin tone')),
new Color(174, 129, 87, t('Medium skin tone')),
new Color(158, 113, 88, t('Medium dark skin tone')),
new Color(96, 79, 69, t('Dark skin tone')),
]

export default {
name: 'NcEmojiPicker',

components: {
Emoji,
IconCircle,
NcButton,
NcColorPicker,
NcPopover,
NcTextField,
Emoji,
Picker,
},

props: {
/**
* The emoji-set
Expand Down Expand Up @@ -299,21 +332,35 @@ export default {
return {
// Non-reactive constants
emojiIndex,
skinTonePalette,
i18n,
}
},

data() {
const currentSkinTone = getCurrentSkinTone()

return {
/**
* The current active color from the skin tone palette
*/
currentColor: skinTonePalette[currentSkinTone - 1],
/**
* The current active skin tone
* @type {1|2|3|4|5|6}
*/
currentSkinTone,
search: '',
open: false,
}
},

computed: {
native() {
return this.activeSet === 'native'
},
},

methods: {
t,

Expand All @@ -325,6 +372,19 @@ export default {
}
},

/**
* Update the current skin tone by the result of the color picker
* @param {string} color Color set
*/
onChangeSkinTone(color) {
const index = this.skinTonePalette.findIndex((tone) => tone.color.toLowerCase() === color.toLowerCase())
if (index > -1) {
this.currentSkinTone = index + 1
this.currentColor = this.skinTonePalette[index]
setCurrentSkinTone(this.currentSkinTone)
}
},

select(emojiObject) {
/**
* Emits a string containing the emoji e.g. '👩🏿‍💻'
Expand Down Expand Up @@ -491,20 +551,23 @@ export default {
}

}

.search {
padding: 4px 8px;
}

</style>

<style scoped>
.row-selected span {
vertical-align: middle;
<style scoped lang="scss">
.search {
&__wrapper {
display: flex;
flex-direction: row;
gap: 4px; // for focus-visible outlines
align-items: end;
padding: 4px 8px;
}
}

.row-selected button {
vertical-align: middle;
.row-selected {
button, span {
vertical-align: middle;
}
}

.emoji-delete {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ import { t } from '../../l10n.js'
import NcAutoCompleteResult from './NcAutoCompleteResult.vue'
import richEditor from '../../mixins/richEditor/index.js'
import Tooltip from '../../directives/Tooltip/index.js'
import { emojiSearch, emojiAddRecent } from '../../functions/emoji/index.js'
import { emojiSearch, emojiAddRecent } from '../../functions/emoji/index.ts'
import { searchProvider, getLinkWithPicker } from '../NcRichText/index.js'

import Tribute from 'tributejs/dist/tribute.esm.js'
Expand Down
50 changes: 0 additions & 50 deletions src/functions/emoji/emoji.js

This file was deleted.

Loading
Loading