This commit is contained in:
mattyatea 2024-02-03 14:09:30 +09:00
parent a46d816dc5
commit 6e1e883fb4
2 changed files with 368 additions and 369 deletions

View File

@ -4,58 +4,58 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと --> <!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと -->
<!-- フォルダの中にはカスタム絵文字だけUnicode絵文字もこっち --> <!-- フォルダの中にはカスタム絵文字だけUnicode絵文字もこっち -->
<section v-if="!hasChildSection" v-panel style="border-radius: 6px; border-bottom: 0.5px solid var(--divider);"> <section v-if="!hasChildSection" style="border-radius: 6px;">
<header class="_acrylic" @click="shown = !shown"> <header class="_acrylic" @click="shown = !shown" >
<i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> (<i class="ti ti-icons"></i>:{{ emojis.length }}) <i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> ({{ emojis.length }})
</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 emojis"
:key="emoji" :key="emoji"
:data-emoji="emoji" :data-emoji="emoji"
class="_button item" class="_button item"
@pointerenter="computeButtonTitle" @pointerenter="computeButtonTitle"
@click="emit('chosen', emoji, $event)" @click="emit('chosen', emoji, $event)"
> >
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> <MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/>
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> <MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/>
</button> </button>
</div> </div>
</section> </section>
<!-- フォルダの中にはカスタム絵文字やフォルダがある --> <!-- フォルダの中にはカスタム絵文字やフォルダがある -->
<section v-else v-panel style="border-radius: 6px; border-bottom: 0.5px solid var(--divider);"> <section v-else style="border-radius: 6px; padding-top: 9px;">
<header class="_acrylic" @click="shown = !shown"> <header class="_acrylic" @click="shown = !shown">
<i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> (<i class="ti ti-folder ti-fw"></i>:{{ customEmojiTree?.length }} <i class="ti ti-icons ti-fw"></i>:{{ emojis.length }}) <i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> (フォルダー)
</header> </header>
<div v-if="shown" style="padding-left: 9px;"> <div v-if="shown" style="padding-left: 9px; ">
<MkEmojiPickerSection <MkEmojiPickerSection
v-for="child in customEmojiTree" v-for="child in customEmojiTree"
:key="`custom:${child.value}`" :key="`custom:${child.value}`"
:initialShown="initialShown" :initialShown="initialShown"
:emojis="computed(() => customEmojis.filter(e => e.category === child.category).map(e => `:${e.name}:`))" :emojis="computed(() => customEmojis.filter(e => e.category === child.category || e.category === child.category+'/'+child.category).map(e => `:${e.name}:`))"
:hasChildSection="child.children.length !== 0" :hasChildSection="child.children.length !== 0"
:customEmojiTree="child.children" :customEmojiTree="child.children"
@chosen="nestedChosen" @chosen="nestedChosen"
> >
{{ child.value || i18n.ts.other }} {{ child.value || i18n.ts.other }}
</MkEmojiPickerSection> </MkEmojiPickerSection>
</div> </div>
<div v-if="shown" class="body"> <div v-if="shown" class="body">
<button <button
v-for="emoji in emojis" v-for="emoji in emojis"
:key="emoji" :key="emoji"
:data-emoji="emoji" :data-emoji="emoji"
class="_button item" class="_button item"
@pointerenter="computeButtonTitle" @pointerenter="computeButtonTitle"
@click="emit('chosen', emoji, $event)" @click="emit('chosen', emoji, $event)"
> >
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> <MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/>
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> <MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/>
</button> </button>
</div> </div>
</section> </section>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -66,15 +66,14 @@ import { customEmojis } from '@/custom-emojis.js';
import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue'; import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue';
const props = defineProps<{ const props = defineProps<{
category?: string[]; category?: string[];
emojis: string[] | Ref<string[]>; emojis: string[] | Ref<string[]>;
initialShown?: boolean; initialShown?: boolean;
hasChildSection?: boolean; hasChildSection?: boolean;
customEmojiTree?: CustomEmojiFolderTree[]; customEmojiTree?: CustomEmojiFolderTree[];
}>(); }>();
console.log(props.customEmojiTree);
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'chosen', v: string, event: MouseEvent): void; (ev: 'chosen', v: string, event: MouseEvent): void;
}>(); }>();
const emojis = computed(() => Array.isArray(props.emojis) ? props.emojis : props.emojis.value); const emojis = computed(() => Array.isArray(props.emojis) ? props.emojis : props.emojis.value);
@ -82,12 +81,12 @@ const shown = ref(!!props.initialShown);
/** @see MkEmojiPicker.vue */ /** @see MkEmojiPicker.vue */
function computeButtonTitle(ev: MouseEvent): void { function computeButtonTitle(ev: MouseEvent): void {
const elm = ev.target as HTMLElement; const elm = ev.target as HTMLElement;
const emoji = elm.dataset.emoji as string; const emoji = elm.dataset.emoji as string;
elm.title = getEmojiName(emoji) ?? emoji; elm.title = getEmojiName(emoji) ?? emoji;
} }
function nestedChosen(emoji: any, ev: MouseEvent) { function nestedChosen(emoji: any, ev?: MouseEvent) {
emit('chosen', emoji, ev); emit('chosen', emoji, ev);
} }
</script> </script>

View File

@ -4,103 +4,103 @@ SPDX-License-Identifier: AGPL-3.0-only
--> -->
<template> <template>
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"> <div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
<input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" autocapitalize="off" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter"> <input ref="searchEl" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" autocapitalize="off" @input="input()" @paste.stop="paste" @keydown.stop.prevent.enter="onEnter">
<!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 --> <!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 -->
<div ref="emojisEl" class="emojis" tabindex="-1"> <div ref="emojisEl" class="emojis" tabindex="-1">
<section class="result"> <section class="result">
<div v-if="searchResultCustom.length > 0" class="body"> <div v-if="searchResultCustom.length > 0" class="body">
<button
v-for="emoji in searchResultCustom"
:key="emoji.name"
class="_button item"
:title="emoji.name"
tabindex="0"
@click="chosen(emoji, $event)"
>
<MkCustomEmoji class="emoji" :name="emoji.name"/>
</button>
</div>
<div v-if="searchResultUnicode.length > 0" class="body">
<button
v-for="emoji in searchResultUnicode"
:key="emoji.name"
class="_button item"
:title="emoji.name"
tabindex="0"
@click="chosen(emoji, $event)"
>
<MkEmoji class="emoji" :emoji="emoji.char"/>
</button>
</div>
</section>
<div v-if="tab === 'index'" class="group index">
<section v-if="showPinned && (pinned && pinned.length > 0)">
<div style="display: flex; ">
<div v-for="a in profileMax" :key="a" :title="defaultStore.state[`pickerProfileName${a > 1 ? a - 1 : ''}`]" class="sllfktkhgl" :class="{ active: activeIndex === a || isDefaultProfile === a }" @click="pinnedProfileSelect(a)">
{{ defaultStore.state[`pickerProfileName${a > 1 ? a - 1 : ''}`] }}
</div>
</div>
<div class="body">
<button <button
v-for="emoji in pinnedEmojis" v-for="emoji in searchResultCustom"
:key="emoji" :key="emoji.name"
:data-emoji="emoji"
class="_button item" class="_button item"
:title="emoji.name"
tabindex="0" tabindex="0"
@pointerenter="computeButtonTitle"
@click="chosen(emoji, $event)" @click="chosen(emoji, $event)"
> >
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> <MkCustomEmoji class="emoji" :name="emoji.name"/>
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> </button>
</div>
<div v-if="searchResultUnicode.length > 0" class="body">
<button
v-for="emoji in searchResultUnicode"
:key="emoji.name"
class="_button item"
:title="emoji.name"
tabindex="0"
@click="chosen(emoji, $event)"
>
<MkEmoji class="emoji" :emoji="emoji.char"/>
</button> </button>
</div> </div>
</section> </section>
<section> <div v-if="tab === 'index'" class="group index">
<header class="_acrylic"><i class="ti ti-clock ti-fw"></i> {{ i18n.ts.recentUsed }}</header> <section v-if="showPinned">
<div class="body"> <div style="display: flex; ">
<button <div v-for="a in profileMax" :key="a" :title="defaultStore.state[`pickerProfileName${a > 1 ? a - 1 : ''}`]" class="sllfktkhgl" :class="{ active: activeIndex === a || isDefaultProfile === a }" @click="pinnedProfileSelect(a)">
v-for="emoji in recentlyUsedEmojis" {{ defaultStore.state[`pickerProfileName${a > 1 ? a - 1 : ''}`] }}
:key="emoji" </div>
class="_button item" </div>
:data-emoji="emoji" <div class="body">
@pointerenter="computeButtonTitle" <button
@click="chosen(emoji, $event)" v-for="emoji in pinnedEmojis"
> :key="emoji"
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/> :data-emoji="emoji"
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/> class="_button item"
</button> tabindex="0"
</div> @pointerenter="computeButtonTitle"
</section> @click="chosen(emoji, $event)"
>
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/>
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/>
</button>
</div>
</section>
<section>
<header class="_acrylic"><i class="ti ti-clock ti-fw"></i> {{ i18n.ts.recentUsed }}</header>
<div class="body">
<button
v-for="emoji in recentlyUsedEmojis"
:key="emoji"
class="_button item"
:data-emoji="emoji"
@pointerenter="computeButtonTitle"
@click="chosen(emoji, $event)"
>
<MkCustomEmoji v-if="emoji[0] === ':'" class="emoji" :name="emoji" :normal="true"/>
<MkEmoji v-else class="emoji" :emoji="emoji" :normal="true"/>
</button>
</div>
</section>
</div>
<div v-once class="group">
<header class="_acrylic">{{ i18n.ts.customEmojis }}</header>
<XSection
v-for="child in customEmojiFolderRoot.children"
:key="`custom:${child.value}`"
:initialShown="false"
:emojis="computed(() => customEmojis.filter(e => child.value === '' ? (e.category === 'null' || !e.category) : e.category === child.value && !customEmojis.some(emoji => emoji.category !== null && emoji.category.includes(e.category+'/')) || e.category === child.category+'/'+child.category && !e.category).filter(filterAvailable).map(e => `:${e.name}:`))"
:hasChildSection="child.children.length !== 0"
:customEmojiTree="child.children"
@chosen="chosen"
>
{{ child.value || i18n.ts.other }}
</XSection>
</div>
<div v-once class="group">
<header class="_acrylic">{{ i18n.ts.emoji }}</header>
<XSection v-for="category in categories" :key="category" :emojis="emojiCharByCategory.get(category) ?? []" :hasChildSection="false" @chosen="chosen">{{ category }}</XSection>
</div>
</div> </div>
<div v-once class="group"> <div class="tabs">
<header class="_acrylic">{{ i18n.ts.customEmojis }}</header> <button class="_button tab" :class="{ active: tab === 'index' }" @click="tab = 'index'"><i class="ti ti-asterisk ti-fw"></i></button>
<XSection <button class="_button tab" :class="{ active: tab === 'custom' }" @click="tab = 'custom'"><i class="ti ti-mood-happy ti-fw"></i></button>
v-for="child in customEmojiFolderRoot.children" <button class="_button tab" :class="{ active: tab === 'unicode' }" @click="tab = 'unicode'"><i class="ti ti-leaf ti-fw"></i></button>
:key="`custom:${child.value}`" <button class="_button tab" :class="{ active: tab === 'tags' }" @click="tab = 'tags'"><i class="ti ti-hash ti-fw"></i></button>
:initialShown="false"
:emojis="computed(() => customEmojis.filter(e => child.value === '' ? (e.category === 'null' || !e.category) : e.category === child.value && !customEmojis.some(emoji => emoji.category !== null && emoji.category.includes(e.category+'/')) || e.category === child.category+'/'+child.category && !e.category).filter(filterAvailable).map(e => `:${e.name}:`))"
:hasChildSection="child.children.length !== 0"
:customEmojiTree="child.children"
@chosen="chosen"
>
{{ child.value || i18n.ts.other }}
</XSection>
</div>
<div v-once class="group">
<header class="_acrylic">{{ i18n.ts.emoji }}</header>
<XSection v-for="category in categories" :key="category" :emojis="emojiCharByCategory.get(category) ?? []" :hasChildSection="false" @chosen="chosen">{{ category }}</XSection>
</div> </div>
</div> </div>
<div class="tabs">
<button class="_button tab" :class="{ active: tab === 'index' }" @click="tab = 'index'"><i class="ti ti-asterisk ti-fw"></i></button>
<button class="_button tab" :class="{ active: tab === 'custom' }" @click="tab = 'custom'"><i class="ti ti-mood-happy ti-fw"></i></button>
<button class="_button tab" :class="{ active: tab === 'unicode' }" @click="tab = 'unicode'"><i class="ti ti-leaf ti-fw"></i></button>
<button class="_button tab" :class="{ active: tab === 'tags' }" @click="tab = 'tags'"><i class="ti ti-hash ti-fw"></i></button>
</div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@ -127,18 +127,18 @@ import MkButton from '@/components/MkButton.vue';
import { deepClone } from '@/scripts/clone.js'; import { deepClone } from '@/scripts/clone.js';
const $i = signinRequired(); const $i = signinRequired();
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
showPinned?: boolean; showPinned?: boolean;
pinnedEmojis?: string[]; pinnedEmojis?: string[];
maxHeight?: number; maxHeight?: number;
asDrawer?: boolean; asDrawer?: boolean;
asWindow?: boolean; asWindow?: boolean;
asReactionPicker?: boolean; // 使使 asReactionPicker?: boolean; // 使使
}>(), { }>(), {
showPinned: true, showPinned: true,
}); });
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'chosen', v: string): void; (ev: 'chosen', v: string): void;
}>(); }>();
const profileMax = $i.policies.emojiPickerProfileLimit; const profileMax = $i.policies.emojiPickerProfileLimit;
const searchEl = shallowRef<HTMLInputElement>(); const searchEl = shallowRef<HTMLInputElement>();
@ -349,7 +349,7 @@ watch(q, () => {
}); });
function filterAvailable(emoji: Misskey.entities.EmojiSimple): boolean { function filterAvailable(emoji: Misskey.entities.EmojiSimple): boolean {
return ((emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction?.includes(r.id)))) ?? false; return (emoji.roleIdsThatCanBeUsedThisEmojiAsReaction == null || emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.length === 0) || ($i && $i.roles.some(r => emoji.roleIdsThatCanBeUsedThisEmojiAsReaction.includes(r.id)));
} }
function focus() { function focus() {
@ -461,262 +461,262 @@ defineExpose({
<style lang="scss" scoped> <style lang="scss" scoped>
.omfetrab { .omfetrab {
$pad: 8px; $pad: 8px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
&.s1 { &.s1 {
--eachSize: 40px; --eachSize: 40px;
} }
&.s2 { &.s2 {
--eachSize: 45px; --eachSize: 45px;
} }
&.s3 { &.s3 {
--eachSize: 50px; --eachSize: 50px;
} }
&.w1 { &.w1 {
width: calc((var(--eachSize) * 5) + (#{$pad} * 2)); width: calc((var(--eachSize) * 5) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr; --columns: 1fr 1fr 1fr 1fr 1fr;
} }
&.w2 { &.w2 {
width: calc((var(--eachSize) * 6) + (#{$pad} * 2)); width: calc((var(--eachSize) * 6) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr 1fr; --columns: 1fr 1fr 1fr 1fr 1fr 1fr;
} }
&.w3 { &.w3 {
width: calc((var(--eachSize) * 7) + (#{$pad} * 2)); width: calc((var(--eachSize) * 7) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; --columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
} }
&.w4 { &.w4 {
width: calc((var(--eachSize) * 8) + (#{$pad} * 2)); width: calc((var(--eachSize) * 8) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; --columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
} }
&.w5 { &.w5 {
width: calc((var(--eachSize) * 9) + (#{$pad} * 2)); width: calc((var(--eachSize) * 9) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; --columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
} }
&.h1 { &.h1 {
height: calc((var(--eachSize) * 4) + (#{$pad} * 2)); height: calc((var(--eachSize) * 4) + (#{$pad} * 2));
} }
&.h2 { &.h2 {
height: calc((var(--eachSize) * 6) + (#{$pad} * 2)); height: calc((var(--eachSize) * 6) + (#{$pad} * 2));
} }
&.h3 { &.h3 {
height: calc((var(--eachSize) * 8) + (#{$pad} * 2)); height: calc((var(--eachSize) * 8) + (#{$pad} * 2));
} }
&.h4 { &.h4 {
height: calc((var(--eachSize) * 10) + (#{$pad} * 2)); height: calc((var(--eachSize) * 10) + (#{$pad} * 2));
} }
&.asDrawer { &.asDrawer {
width: 100% !important; width: 100% !important;
> .emojis { > .emojis {
::v-deep(section) { ::v-deep(section) {
> header { > header {
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
padding: 0 12px; padding: 0 12px;
font-size: 15px; font-size: 15px;
} }
> .body { > .body {
display: grid; display: grid;
grid-template-columns: var(--columns); grid-template-columns: var(--columns);
font-size: 30px; font-size: 30px;
> .item { > .item {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
width: auto; width: auto;
height: auto; height: auto;
min-width: 0; min-width: 0;
} }
} }
} }
} }
} }
&.asWindow { &.asWindow {
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
> .emojis { > .emojis {
::v-deep(section) { ::v-deep(section) {
> .body { > .body {
display: grid; display: grid;
grid-template-columns: var(--columns); grid-template-columns: var(--columns);
font-size: 30px; font-size: 30px;
> .item { > .item {
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
width: auto; width: auto;
height: auto; height: auto;
min-width: 0; min-width: 0;
} }
} }
} }
} }
} }
> .search { > .search {
width: 100%; width: 100%;
padding: 12px; padding: 12px;
box-sizing: border-box; box-sizing: border-box;
font-size: 1em; font-size: 1em;
outline: none; outline: none;
border: none; border: none;
background: transparent; background: transparent;
color: var(--fg); color: var(--fg);
&:not(:focus):not(.filled) { &:not(:focus):not(.filled) {
margin-bottom: env(safe-area-inset-bottom, 0px); margin-bottom: env(safe-area-inset-bottom, 0px);
} }
&:not(.filled) { &:not(.filled) {
order: 1; order: 1;
z-index: 2; z-index: 2;
box-shadow: 0px -1px 0 0px var(--divider); box-shadow: 0px -1px 0 0px var(--divider);
} }
} }
> .tabs { > .tabs {
display: flex; display: flex;
display: none; display: none;
> .tab { > .tab {
flex: 1; flex: 1;
height: 38px; height: 38px;
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
&.active { &.active {
border-top: solid 1px var(--accent); border-top: solid 1px var(--accent);
color: var(--accent); color: var(--accent);
} }
} }
} }
> .emojis { > .emojis {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
scrollbar-width: none; scrollbar-width: none;
&::-webkit-scrollbar { &::-webkit-scrollbar {
display: none; display: none;
} }
> .group { > .group {
&:not(.index) { &:not(.index) {
padding: 4px 0 8px 0; padding: 4px 0 8px 0;
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
} }
> header { > header {
/*position: sticky; /*position: sticky;
top: 0; top: 0;
left: 0;*/ left: 0;*/
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
z-index: 2; z-index: 2;
padding: 0 8px; padding: 0 8px;
font-size: 12px; font-size: 12px;
} }
} }
::v-deep(section) { ::v-deep(section) {
> header { > header {
position: sticky; position: sticky;
top: 0; top: 0;
left: 0; left: 0;
height: 32px; height: 32px;
line-height: 32px; line-height: 32px;
z-index: 1; z-index: 1;
padding: 0 8px; padding: 0 8px;
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: var(--accent); color: var(--accent);
} }
} }
> .body { > .body {
position: relative; position: relative;
padding: $pad; padding: $pad;
> .item { > .item {
position: relative; position: relative;
padding: 0; padding: 0;
width: var(--eachSize); width: var(--eachSize);
height: var(--eachSize); height: var(--eachSize);
contain: strict; contain: strict;
border-radius: 4px; border-radius: 4px;
font-size: 24px; font-size: 24px;
&:focus-visible { &:focus-visible {
outline: solid 2px var(--focus); outline: solid 2px var(--focus);
z-index: 1; z-index: 1;
} }
&:hover { &:hover {
background: rgba(0, 0, 0, 0.05); background: rgba(0, 0, 0, 0.05);
} }
&:active { &:active {
background: var(--accent); background: var(--accent);
box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15); box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15);
} }
> .emoji { > .emoji {
height: 1.25em; height: 1.25em;
vertical-align: -.25em; vertical-align: -.25em;
pointer-events: none; pointer-events: none;
width: 100%; width: 100%;
object-fit: contain; object-fit: contain;
} }
} }
} }
&.result { &.result {
border-bottom: solid 0.5px var(--divider); border-bottom: solid 0.5px var(--divider);
&:empty { &:empty {
display: none; display: none;
} }
} }
} }
} }
} }
.sllfktkhgl{ .sllfktkhgl{
display: inline-block; display: inline-block;
padding: 0 4px; padding: 0 4px;
font-size: 12px; font-size: 12px;
line-height: 32px; line-height: 32px;
text-align: center; text-align: center;
color: var(--fg); color: var(--fg);
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;
transition: transform 0.3s ease; transition: transform 0.3s ease;
box-shadow: 0 1.5px 0 var(--divider); box-shadow: 0 1.5px 0 var(--divider);
height: 32px; height: 32px;
overflow: hidden; overflow: hidden;
&:hover { &:hover {
transform: translateY(1.5px); transform: translateY(1.5px);
} }
&.active { &.active {
transform: translateY(5px); transform: translateY(5px);
} }
} }
</style> </style>