feat: skin tone selector in category

This commit is contained in:
ThatOneCalculator 2023-06-23 16:51:13 -07:00
parent 9e1fbed9b9
commit 3a17ef6d42
No known key found for this signature in database
GPG key ID: 8703CACD01000000
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 * 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,

View file

@ -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>

View file

@ -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)

View file

@ -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 || [],
}; };
}); });