feat: skin tone selector in category

This commit is contained in:
ThatOneCalculator 2023-06-23 16:51:13 -07:00
parent 0d166acfd9
commit 8f16d0b223
4 changed files with 75 additions and 24 deletions

View File

@ -99,7 +99,7 @@ import { acct } from "@/filters/user";
import * as os from "@/os";
import { MFM_TAGS } from "@/scripts/mfm-tags";
import { defaultStore } from "@/store";
import { emojilist } from "@/scripts/emojilist";
import { emojilist, addSkinTone } from "@/scripts/emojilist";
import { instance } from "@/instance";
import { i18n } from "@/i18n";
@ -113,6 +113,12 @@ type EmojiDef = {
const lib = emojilist.filter((x) => x.category !== "flags");
for (const emoji of lib) {
if (emoji.skin_tone_support) {
emoji.emoji = addSkinTone(emoji.emoji);
}
}
const emjdb: EmojiDef[] = lib.map((x) => ({
emoji: x.emoji,
name: x.slug,

View File

@ -1,20 +1,31 @@
<template>
<!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと -->
<section>
<header class="_acrylic" @click="shown = !shown">
<i
class="toggle ph-fw ph-lg"
:class="
shown
? 'ph-caret-down-bold ph-lg'
? 'ph-caret-down ph-bold ph-lg'
: 'ph-caret-up ph-bold ph-lg'
"
></i>
<slot></slot> ({{ emojis.length }})
<span v-if="props.skinToneSelector">
<button
v-for="skinTone in skinTones"
class="_button"
@click="applySkinTone(skinTones.indexOf(skinTone))"
>
<i
class="ph-circle ph-fill ph-fw ph-lg"
:style="{ color: skinTone + '!important' }"
></i>
</button>
</span>
</header>
<div v-if="shown" class="body">
<button
v-for="emoji in emojis"
v-for="emoji in localEmojis"
:key="emoji"
class="_button item"
@click="emit('chosen', emoji, $event)"
@ -26,18 +37,50 @@
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { ref, watch, onMounted } from "vue";
import { addSkinTone } from "@/scripts/emojilist";
const props = defineProps<{
emojis: string[];
initialShown?: boolean;
skinToneSelector?: boolean;
}>();
const skinTones = [
"#FFDC5E",
"#F7DFCF",
"#F3D3A3",
"#D6AE89",
"#B17F56",
"#7D523C",
];
const localEmojis = ref([...props.emojis]);
function applySkinTone(custom?: number) {
for (let i = 0; i < localEmojis.value.length; i++) {
localEmojis.value[i] = addSkinTone(localEmojis.value[i], custom);
}
}
const emit = defineEmits<{
(ev: "chosen", v: string, event: MouseEvent): void;
}>();
const shown = ref(!!props.initialShown);
onMounted(() => {
if (props.skinToneSelector) {
applySkinTone();
}
});
watch(
() => props.emojis,
(newVal) => {
localEmojis.value = [...newVal];
}
);
</script>
<style lang="scss" scoped></style>

View File

@ -113,6 +113,7 @@
<XSection
v-for="category in unicodeEmojiCategories"
:key="category"
:skin-tone-selector="category === 'people'"
:emojis="
emojilist
.filter((e) => e.category === category)

View File

@ -3,6 +3,14 @@ import emojiComponents from "unicode-emoji-json/data-emoji-components.json";
import keywordSet from "emojilib";
import { defaultStore } from "@/store";
export type UnicodeEmojiDef = {
emoji: string;
category: typeof unicodeEmojiCategories[number];
skin_tone_support: boolean;
slug: string;
keywords?: string[];
};
export const unicodeEmojiCategories = [
"emotion",
"people",
@ -27,15 +35,17 @@ export const categoryMapping = {
"Flags": "flags",
} as const;
function addSkinTone(emoji: string) {
const skinTone = defaultStore.state.reactionPickerSkinTone;
if (skinTone === 1) return emoji;
if (skinTone === 2) return emoji + emojiComponents.light_skin_tone;
if (skinTone === 3) return emoji + emojiComponents.medium_light_skin_tone;
if (skinTone === 4) return emoji + emojiComponents.medium_skin_tone;
if (skinTone === 5) return emoji + emojiComponents.medium_dark_skin_tone;
if (skinTone === 6) return emoji + emojiComponents.dark_skin_tone;
return emoji;
export function addSkinTone(emoji: string, skinTone?: number) {
const chosenSkinTone = skinTone || defaultStore.state.reactionPickerSkinTone;
const skinToneModifiers = [
"",
emojiComponents.light_skin_tone,
emojiComponents.medium_light_skin_tone,
emojiComponents.medium_skin_tone,
emojiComponents.medium_dark_skin_tone,
emojiComponents.dark_skin_tone
];
return emoji + (skinToneModifiers[chosenSkinTone - 1] || "");
}
const unicodeFifteenEmojis = [
@ -58,9 +68,6 @@ Object.keys(data).forEach((originalCategory) => {
if (unicodeFifteenEmojis.includes(emojiObj.emoji)) {
return;
}
if (emojiObj.skin_tone_support) {
emojiObj.emoji = addSkinTone(emojiObj.emoji);
}
emojiObj.category = newCategory;
emojiObj.keywords = keywordSet[emojiObj.emoji];
newData[newCategory].push(emojiObj);
@ -68,19 +75,13 @@ Object.keys(data).forEach((originalCategory) => {
}
});
export type UnicodeEmojiDef = {
emoji: string;
category: typeof unicodeEmojiCategories[number];
slug: string;
keywords?: string[];
};
export const emojilist: UnicodeEmojiDef[] = Object.keys(newData).reduce((acc, category) => {
const categoryItems = newData[category].map((item) => {
return {
emoji: item.emoji,
slug: item.slug,
category: item.category,
skin_tone_support: item.skin_tone_support || false,
keywords: item.keywords || [],
};
});