feat: ✨ skin tone selector in category
This commit is contained in:
parent
9e1fbed9b9
commit
3a17ef6d42
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
<XSection
|
||||
v-for="category in unicodeEmojiCategories"
|
||||
:key="category"
|
||||
:skin-tone-selector="category === 'people'"
|
||||
:emojis="
|
||||
emojilist
|
||||
.filter((e) => e.category === category)
|
||||
|
|
|
@ -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 || [],
|
||||
};
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue