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 * as os from "@/os";
|
||||||
import { MFM_TAGS } from "@/scripts/mfm-tags";
|
import { MFM_TAGS } from "@/scripts/mfm-tags";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
import { emojilist } from "@/scripts/emojilist";
|
import { emojilist, addSkinTone } from "@/scripts/emojilist";
|
||||||
import { instance } from "@/instance";
|
import { instance } from "@/instance";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
|
|
||||||
|
@ -113,6 +113,12 @@ type EmojiDef = {
|
||||||
|
|
||||||
const lib = emojilist.filter((x) => x.category !== "flags");
|
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) => ({
|
const emjdb: EmojiDef[] = lib.map((x) => ({
|
||||||
emoji: x.emoji,
|
emoji: x.emoji,
|
||||||
name: x.slug,
|
name: x.slug,
|
||||||
|
|
|
@ -1,20 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと -->
|
|
||||||
<section>
|
<section>
|
||||||
<header class="_acrylic" @click="shown = !shown">
|
<header class="_acrylic" @click="shown = !shown">
|
||||||
<i
|
<i
|
||||||
class="toggle ph-fw ph-lg"
|
class="toggle ph-fw ph-lg"
|
||||||
:class="
|
:class="
|
||||||
shown
|
shown
|
||||||
? 'ph-caret-down-bold ph-lg'
|
? 'ph-caret-down ph-bold ph-lg'
|
||||||
: 'ph-caret-up ph-bold ph-lg'
|
: 'ph-caret-up ph-bold ph-lg'
|
||||||
"
|
"
|
||||||
></i>
|
></i>
|
||||||
<slot></slot> ({{ emojis.length }})
|
<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>
|
</header>
|
||||||
<div v-if="shown" class="body">
|
<div v-if="shown" class="body">
|
||||||
<button
|
<button
|
||||||
v-for="emoji in emojis"
|
v-for="emoji in localEmojis"
|
||||||
:key="emoji"
|
:key="emoji"
|
||||||
class="_button item"
|
class="_button item"
|
||||||
@click="emit('chosen', emoji, $event)"
|
@click="emit('chosen', emoji, $event)"
|
||||||
|
@ -26,18 +37,50 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref, watch, onMounted } from "vue";
|
||||||
|
import { addSkinTone } from "@/scripts/emojilist";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
emojis: string[];
|
emojis: string[];
|
||||||
initialShown?: boolean;
|
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<{
|
const emit = defineEmits<{
|
||||||
(ev: "chosen", v: string, event: MouseEvent): void;
|
(ev: "chosen", v: string, event: MouseEvent): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const shown = ref(!!props.initialShown);
|
const shown = ref(!!props.initialShown);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.skinToneSelector) {
|
||||||
|
applySkinTone();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.emojis,
|
||||||
|
(newVal) => {
|
||||||
|
localEmojis.value = [...newVal];
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|
|
@ -113,6 +113,7 @@
|
||||||
<XSection
|
<XSection
|
||||||
v-for="category in unicodeEmojiCategories"
|
v-for="category in unicodeEmojiCategories"
|
||||||
:key="category"
|
:key="category"
|
||||||
|
:skin-tone-selector="category === 'people'"
|
||||||
:emojis="
|
:emojis="
|
||||||
emojilist
|
emojilist
|
||||||
.filter((e) => e.category === category)
|
.filter((e) => e.category === category)
|
||||||
|
|
|
@ -3,6 +3,14 @@ import emojiComponents from "unicode-emoji-json/data-emoji-components.json";
|
||||||
import keywordSet from "emojilib";
|
import keywordSet from "emojilib";
|
||||||
import { defaultStore } from "@/store";
|
import { defaultStore } from "@/store";
|
||||||
|
|
||||||
|
export type UnicodeEmojiDef = {
|
||||||
|
emoji: string;
|
||||||
|
category: typeof unicodeEmojiCategories[number];
|
||||||
|
skin_tone_support: boolean;
|
||||||
|
slug: string;
|
||||||
|
keywords?: string[];
|
||||||
|
};
|
||||||
|
|
||||||
export const unicodeEmojiCategories = [
|
export const unicodeEmojiCategories = [
|
||||||
"emotion",
|
"emotion",
|
||||||
"people",
|
"people",
|
||||||
|
@ -27,15 +35,17 @@ export const categoryMapping = {
|
||||||
"Flags": "flags",
|
"Flags": "flags",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
function addSkinTone(emoji: string) {
|
export function addSkinTone(emoji: string, skinTone?: number) {
|
||||||
const skinTone = defaultStore.state.reactionPickerSkinTone;
|
const chosenSkinTone = skinTone || defaultStore.state.reactionPickerSkinTone;
|
||||||
if (skinTone === 1) return emoji;
|
const skinToneModifiers = [
|
||||||
if (skinTone === 2) return emoji + emojiComponents.light_skin_tone;
|
"",
|
||||||
if (skinTone === 3) return emoji + emojiComponents.medium_light_skin_tone;
|
emojiComponents.light_skin_tone,
|
||||||
if (skinTone === 4) return emoji + emojiComponents.medium_skin_tone;
|
emojiComponents.medium_light_skin_tone,
|
||||||
if (skinTone === 5) return emoji + emojiComponents.medium_dark_skin_tone;
|
emojiComponents.medium_skin_tone,
|
||||||
if (skinTone === 6) return emoji + emojiComponents.dark_skin_tone;
|
emojiComponents.medium_dark_skin_tone,
|
||||||
return emoji;
|
emojiComponents.dark_skin_tone
|
||||||
|
];
|
||||||
|
return emoji + (skinToneModifiers[chosenSkinTone - 1] || "");
|
||||||
}
|
}
|
||||||
|
|
||||||
const unicodeFifteenEmojis = [
|
const unicodeFifteenEmojis = [
|
||||||
|
@ -58,9 +68,6 @@ Object.keys(data).forEach((originalCategory) => {
|
||||||
if (unicodeFifteenEmojis.includes(emojiObj.emoji)) {
|
if (unicodeFifteenEmojis.includes(emojiObj.emoji)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (emojiObj.skin_tone_support) {
|
|
||||||
emojiObj.emoji = addSkinTone(emojiObj.emoji);
|
|
||||||
}
|
|
||||||
emojiObj.category = newCategory;
|
emojiObj.category = newCategory;
|
||||||
emojiObj.keywords = keywordSet[emojiObj.emoji];
|
emojiObj.keywords = keywordSet[emojiObj.emoji];
|
||||||
newData[newCategory].push(emojiObj);
|
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) => {
|
export const emojilist: UnicodeEmojiDef[] = Object.keys(newData).reduce((acc, category) => {
|
||||||
const categoryItems = newData[category].map((item) => {
|
const categoryItems = newData[category].map((item) => {
|
||||||
return {
|
return {
|
||||||
emoji: item.emoji,
|
emoji: item.emoji,
|
||||||
slug: item.slug,
|
slug: item.slug,
|
||||||
category: item.category,
|
category: item.category,
|
||||||
|
skin_tone_support: item.skin_tone_support || false,
|
||||||
keywords: item.keywords || [],
|
keywords: item.keywords || [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue