emoji
This commit is contained in:
		
							parent
							
								
									a46d816dc5
								
							
						
					
					
						commit
						6e1e883fb4
					
				|  | @ -4,58 +4,58 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| --> | ||||
| 
 | ||||
| <template> | ||||
| <!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと --> | ||||
| <!-- フォルダの中にはカスタム絵文字だけ(Unicode絵文字もこっち) --> | ||||
| <section v-if="!hasChildSection" v-panel style="border-radius: 6px; border-bottom: 0.5px solid var(--divider);"> | ||||
| 	<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 }}) | ||||
| 	</header> | ||||
| 	<div v-if="shown" class="body"> | ||||
| 		<button | ||||
| 			v-for="emoji in emojis" | ||||
| 			:key="emoji" | ||||
| 			:data-emoji="emoji" | ||||
| 			class="_button item" | ||||
| 			@pointerenter="computeButtonTitle" | ||||
| 			@click="emit('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 v-else v-panel style="border-radius: 6px; border-bottom: 0.5px solid var(--divider);"> | ||||
| 	<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 }}) | ||||
| 	</header> | ||||
| 	<div v-if="shown" style="padding-left: 9px;"> | ||||
| 		<MkEmojiPickerSection | ||||
| 			v-for="child in customEmojiTree" | ||||
| 			:key="`custom:${child.value}`" | ||||
| 			:initialShown="initialShown" | ||||
| 			:emojis="computed(() => customEmojis.filter(e => e.category === child.category).map(e => `:${e.name}:`))" | ||||
| 			:hasChildSection="child.children.length !== 0" | ||||
| 			:customEmojiTree="child.children" | ||||
| 			@chosen="nestedChosen" | ||||
| 		> | ||||
| 			{{ child.value || i18n.ts.other }} | ||||
| 		</MkEmojiPickerSection> | ||||
| 	</div> | ||||
| 	<div v-if="shown" class="body"> | ||||
| 		<button | ||||
| 			v-for="emoji in emojis" | ||||
| 			:key="emoji" | ||||
| 			:data-emoji="emoji" | ||||
| 			class="_button item" | ||||
| 			@pointerenter="computeButtonTitle" | ||||
| 			@click="emit('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> | ||||
| 	<!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと --> | ||||
| 	<!-- フォルダの中にはカスタム絵文字だけ(Unicode絵文字もこっち) --> | ||||
| 	<section v-if="!hasChildSection" style="border-radius: 6px;"> | ||||
| 		<header class="_acrylic" @click="shown = !shown" > | ||||
| 			<i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> ({{ emojis.length }}) | ||||
| 		</header> | ||||
| 		<div v-if="shown" class="body"> | ||||
| 			<button | ||||
| 				v-for="emoji in emojis" | ||||
| 				:key="emoji" | ||||
| 				:data-emoji="emoji" | ||||
| 				class="_button item" | ||||
| 				@pointerenter="computeButtonTitle" | ||||
| 				@click="emit('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 v-else style="border-radius: 6px; padding-top: 9px;"> | ||||
| 		<header class="_acrylic" @click="shown = !shown"> | ||||
| 			<i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> <slot></slot> (フォルダー) | ||||
| 		</header> | ||||
| 		<div v-if="shown" style="padding-left: 9px; "> | ||||
| 			<MkEmojiPickerSection | ||||
| 				v-for="child in customEmojiTree" | ||||
| 				:key="`custom:${child.value}`" | ||||
| 				:initialShown="initialShown" | ||||
| 				:emojis="computed(() => customEmojis.filter(e => e.category === child.category || e.category === child.category+'/'+child.category).map(e => `:${e.name}:`))" | ||||
| 				:hasChildSection="child.children.length !== 0" | ||||
| 				:customEmojiTree="child.children" | ||||
| 				@chosen="nestedChosen" | ||||
| 			> | ||||
| 				{{ child.value || i18n.ts.other }} | ||||
| 			</MkEmojiPickerSection> | ||||
| 		</div> | ||||
| 		<div v-if="shown" class="body"> | ||||
| 			<button | ||||
| 				v-for="emoji in emojis" | ||||
| 				:key="emoji" | ||||
| 				:data-emoji="emoji" | ||||
| 				class="_button item" | ||||
| 				@pointerenter="computeButtonTitle" | ||||
| 				@click="emit('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> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
|  | @ -66,15 +66,14 @@ import { customEmojis } from '@/custom-emojis.js'; | |||
| import MkEmojiPickerSection from '@/components/MkEmojiPicker.section.vue'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
|     category?: string[]; | ||||
|     emojis: string[] | Ref<string[]>; | ||||
|     initialShown?: boolean; | ||||
|     hasChildSection?: boolean; | ||||
|     customEmojiTree?: CustomEmojiFolderTree[]; | ||||
| 	category?: string[]; | ||||
| 	emojis: string[] | Ref<string[]>; | ||||
| 	initialShown?: boolean; | ||||
| 	hasChildSection?: boolean; | ||||
| 	customEmojiTree?: CustomEmojiFolderTree[]; | ||||
| }>(); | ||||
| console.log(props.customEmojiTree); | ||||
| 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); | ||||
|  | @ -82,12 +81,12 @@ const shown = ref(!!props.initialShown); | |||
| 
 | ||||
| /** @see MkEmojiPicker.vue */ | ||||
| function computeButtonTitle(ev: MouseEvent): void { | ||||
|     const elm = ev.target as HTMLElement; | ||||
|     const emoji = elm.dataset.emoji as string; | ||||
|     elm.title = getEmojiName(emoji) ?? emoji; | ||||
| 	const elm = ev.target as HTMLElement; | ||||
| 	const emoji = elm.dataset.emoji as string; | ||||
| 	elm.title = getEmojiName(emoji) ?? emoji; | ||||
| } | ||||
| 
 | ||||
| function nestedChosen(emoji: any, ev: MouseEvent) { | ||||
|     emit('chosen', emoji, ev); | ||||
| function nestedChosen(emoji: any, ev?: MouseEvent) { | ||||
| 	emit('chosen', emoji, ev); | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -4,103 +4,103 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| --> | ||||
| 
 | ||||
| <template> | ||||
| <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"> | ||||
| 	<!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 --> | ||||
| 	<div ref="emojisEl" class="emojis" tabindex="-1"> | ||||
| 		<section class="result"> | ||||
| 			<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"> | ||||
| 	<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"> | ||||
| 		<!-- FirefoxのTabフォーカスが想定外の挙動となるためtabindex="-1"を追加 https://github.com/misskey-dev/misskey/issues/10744 --> | ||||
| 		<div ref="emojisEl" class="emojis" tabindex="-1"> | ||||
| 			<section class="result"> | ||||
| 				<div v-if="searchResultCustom.length > 0" class="body"> | ||||
| 					<button | ||||
| 						v-for="emoji in pinnedEmojis" | ||||
| 						:key="emoji" | ||||
| 						:data-emoji="emoji" | ||||
| 						v-for="emoji in searchResultCustom" | ||||
| 						:key="emoji.name" | ||||
| 						class="_button item" | ||||
| 						:title="emoji.name" | ||||
| 						tabindex="0" | ||||
| 						@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"/> | ||||
| 						<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> | ||||
| 
 | ||||
| 			<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 v-if="tab === 'index'" class="group index"> | ||||
| 				<section v-if="showPinned"> | ||||
| 					<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 | ||||
| 							v-for="emoji in pinnedEmojis" | ||||
| 							:key="emoji" | ||||
| 							:data-emoji="emoji" | ||||
| 							class="_button item" | ||||
| 							tabindex="0" | ||||
| 							@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> | ||||
| 
 | ||||
| 				<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 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 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> | ||||
| 	<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> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
|  | @ -127,18 +127,18 @@ import MkButton from '@/components/MkButton.vue'; | |||
| import { deepClone } from '@/scripts/clone.js'; | ||||
| const $i = signinRequired(); | ||||
| const props = withDefaults(defineProps<{ | ||||
|     showPinned?: boolean; | ||||
|     pinnedEmojis?: string[]; | ||||
|     maxHeight?: number; | ||||
|     asDrawer?: boolean; | ||||
|     asWindow?: boolean; | ||||
|     asReactionPicker?: boolean; // 今は使われてないが将来的に使いそう | ||||
| 	showPinned?: boolean; | ||||
| 	pinnedEmojis?: string[]; | ||||
| 	maxHeight?: number; | ||||
| 	asDrawer?: boolean; | ||||
| 	asWindow?: boolean; | ||||
| 	asReactionPicker?: boolean; // 今は使われてないが将来的に使いそう | ||||
| }>(), { | ||||
| 	showPinned: true, | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
|     (ev: 'chosen', v: string): void; | ||||
| 	(ev: 'chosen', v: string): void; | ||||
| }>(); | ||||
| const profileMax = $i.policies.emojiPickerProfileLimit; | ||||
| const searchEl = shallowRef<HTMLInputElement>(); | ||||
|  | @ -349,7 +349,7 @@ watch(q, () => { | |||
| }); | ||||
| 
 | ||||
| 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() { | ||||
|  | @ -461,262 +461,262 @@ defineExpose({ | |||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .omfetrab { | ||||
|   $pad: 8px; | ||||
| 	$pad: 8px; | ||||
| 
 | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| 	display: flex; | ||||
| 	flex-direction: column; | ||||
| 
 | ||||
|   &.s1 { | ||||
|     --eachSize: 40px; | ||||
|   } | ||||
| 	&.s1 { | ||||
| 		--eachSize: 40px; | ||||
| 	} | ||||
| 
 | ||||
|   &.s2 { | ||||
|     --eachSize: 45px; | ||||
|   } | ||||
| 	&.s2 { | ||||
| 		--eachSize: 45px; | ||||
| 	} | ||||
| 
 | ||||
|   &.s3 { | ||||
|     --eachSize: 50px; | ||||
|   } | ||||
| 	&.s3 { | ||||
| 		--eachSize: 50px; | ||||
| 	} | ||||
| 
 | ||||
|   &.w1 { | ||||
|     width: calc((var(--eachSize) * 5) + (#{$pad} * 2)); | ||||
|     --columns: 1fr 1fr 1fr 1fr 1fr; | ||||
|   } | ||||
| 	&.w1 { | ||||
| 		width: calc((var(--eachSize) * 5) + (#{$pad} * 2)); | ||||
| 		--columns: 1fr 1fr 1fr 1fr 1fr; | ||||
| 	} | ||||
| 
 | ||||
|   &.w2 { | ||||
|     width: calc((var(--eachSize) * 6) + (#{$pad} * 2)); | ||||
|     --columns: 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
|   } | ||||
| 	&.w2 { | ||||
| 		width: calc((var(--eachSize) * 6) + (#{$pad} * 2)); | ||||
| 		--columns: 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
| 	} | ||||
| 
 | ||||
|   &.w3 { | ||||
|     width: calc((var(--eachSize) * 7) + (#{$pad} * 2)); | ||||
|     --columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
|   } | ||||
| 	&.w3 { | ||||
| 		width: calc((var(--eachSize) * 7) + (#{$pad} * 2)); | ||||
| 		--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
| 	} | ||||
| 
 | ||||
|   &.w4 { | ||||
|     width: calc((var(--eachSize) * 8) + (#{$pad} * 2)); | ||||
|     --columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
|   } | ||||
| 	&.w4 { | ||||
| 		width: calc((var(--eachSize) * 8) + (#{$pad} * 2)); | ||||
| 		--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
| 	} | ||||
| 
 | ||||
|   &.w5 { | ||||
|     width: calc((var(--eachSize) * 9) + (#{$pad} * 2)); | ||||
|     --columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
|   } | ||||
| 	&.w5 { | ||||
| 		width: calc((var(--eachSize) * 9) + (#{$pad} * 2)); | ||||
| 		--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr; | ||||
| 	} | ||||
| 
 | ||||
|   &.h1 { | ||||
|     height: calc((var(--eachSize) * 4) + (#{$pad} * 2)); | ||||
|   } | ||||
| 	&.h1 { | ||||
| 		height: calc((var(--eachSize) * 4) + (#{$pad} * 2)); | ||||
| 	} | ||||
| 
 | ||||
|   &.h2 { | ||||
|     height: calc((var(--eachSize) * 6) + (#{$pad} * 2)); | ||||
|   } | ||||
| 	&.h2 { | ||||
| 		height: calc((var(--eachSize) * 6) + (#{$pad} * 2)); | ||||
| 	} | ||||
| 
 | ||||
|   &.h3 { | ||||
|     height: calc((var(--eachSize) * 8) + (#{$pad} * 2)); | ||||
|   } | ||||
| 	&.h3 { | ||||
| 		height: calc((var(--eachSize) * 8) + (#{$pad} * 2)); | ||||
| 	} | ||||
| 
 | ||||
|   &.h4 { | ||||
|     height: calc((var(--eachSize) * 10) + (#{$pad} * 2)); | ||||
|   } | ||||
| 	&.h4 { | ||||
| 		height: calc((var(--eachSize) * 10) + (#{$pad} * 2)); | ||||
| 	} | ||||
| 
 | ||||
|   &.asDrawer { | ||||
|     width: 100% !important; | ||||
| 	&.asDrawer { | ||||
| 		width: 100% !important; | ||||
| 
 | ||||
|     > .emojis { | ||||
|       ::v-deep(section) { | ||||
|         > header { | ||||
|           height: 32px; | ||||
|           line-height: 32px; | ||||
|           padding: 0 12px; | ||||
|           font-size: 15px; | ||||
|         } | ||||
| 		> .emojis { | ||||
| 			::v-deep(section) { | ||||
| 				> header { | ||||
| 					height: 32px; | ||||
| 					line-height: 32px; | ||||
| 					padding: 0 12px; | ||||
| 					font-size: 15px; | ||||
| 				} | ||||
| 
 | ||||
|         > .body { | ||||
|           display: grid; | ||||
|           grid-template-columns: var(--columns); | ||||
|           font-size: 30px; | ||||
| 				> .body { | ||||
| 					display: grid; | ||||
| 					grid-template-columns: var(--columns); | ||||
| 					font-size: 30px; | ||||
| 
 | ||||
|           > .item { | ||||
|             aspect-ratio: 1 / 1; | ||||
|             width: auto; | ||||
|             height: auto; | ||||
|             min-width: 0; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 					> .item { | ||||
| 						aspect-ratio: 1 / 1; | ||||
| 						width: auto; | ||||
| 						height: auto; | ||||
| 						min-width: 0; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|   &.asWindow { | ||||
|     width: 100% !important; | ||||
|     height: 100% !important; | ||||
| 	&.asWindow { | ||||
| 		width: 100% !important; | ||||
| 		height: 100% !important; | ||||
| 
 | ||||
|     > .emojis { | ||||
|       ::v-deep(section) { | ||||
|         > .body { | ||||
|           display: grid; | ||||
|           grid-template-columns: var(--columns); | ||||
|           font-size: 30px; | ||||
| 		> .emojis { | ||||
| 			::v-deep(section) { | ||||
| 				> .body { | ||||
| 					display: grid; | ||||
| 					grid-template-columns: var(--columns); | ||||
| 					font-size: 30px; | ||||
| 
 | ||||
|           > .item { | ||||
|             aspect-ratio: 1 / 1; | ||||
|             width: auto; | ||||
|             height: auto; | ||||
|             min-width: 0; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 					> .item { | ||||
| 						aspect-ratio: 1 / 1; | ||||
| 						width: auto; | ||||
| 						height: auto; | ||||
| 						min-width: 0; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|   > .search { | ||||
|     width: 100%; | ||||
|     padding: 12px; | ||||
|     box-sizing: border-box; | ||||
|     font-size: 1em; | ||||
|     outline: none; | ||||
|     border: none; | ||||
|     background: transparent; | ||||
|     color: var(--fg); | ||||
| 	> .search { | ||||
| 		width: 100%; | ||||
| 		padding: 12px; | ||||
| 		box-sizing: border-box; | ||||
| 		font-size: 1em; | ||||
| 		outline: none; | ||||
| 		border: none; | ||||
| 		background: transparent; | ||||
| 		color: var(--fg); | ||||
| 
 | ||||
|     &:not(:focus):not(.filled) { | ||||
|       margin-bottom: env(safe-area-inset-bottom, 0px); | ||||
|     } | ||||
| 		&:not(:focus):not(.filled) { | ||||
| 			margin-bottom: env(safe-area-inset-bottom, 0px); | ||||
| 		} | ||||
| 
 | ||||
|     &:not(.filled) { | ||||
|       order: 1; | ||||
|       z-index: 2; | ||||
|       box-shadow: 0px -1px 0 0px var(--divider); | ||||
|     } | ||||
|   } | ||||
| 		&:not(.filled) { | ||||
| 			order: 1; | ||||
| 			z-index: 2; | ||||
| 			box-shadow: 0px -1px 0 0px var(--divider); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|   > .tabs { | ||||
|     display: flex; | ||||
|     display: none; | ||||
| 	> .tabs { | ||||
| 		display: flex; | ||||
| 		display: none; | ||||
| 
 | ||||
|     > .tab { | ||||
|       flex: 1; | ||||
|       height: 38px; | ||||
|       border-top: solid 0.5px var(--divider); | ||||
| 		> .tab { | ||||
| 			flex: 1; | ||||
| 			height: 38px; | ||||
| 			border-top: solid 0.5px var(--divider); | ||||
| 
 | ||||
|       &.active { | ||||
|         border-top: solid 1px var(--accent); | ||||
|         color: var(--accent); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 			&.active { | ||||
| 				border-top: solid 1px var(--accent); | ||||
| 				color: var(--accent); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|   > .emojis { | ||||
|     height: 100%; | ||||
|     overflow-y: auto; | ||||
|     overflow-x: hidden; | ||||
| 	> .emojis { | ||||
| 		height: 100%; | ||||
| 		overflow-y: auto; | ||||
| 		overflow-x: hidden; | ||||
| 
 | ||||
|     scrollbar-width: none; | ||||
| 		scrollbar-width: none; | ||||
| 
 | ||||
|     &::-webkit-scrollbar { | ||||
|       display: none; | ||||
|     } | ||||
| 		&::-webkit-scrollbar { | ||||
| 			display: none; | ||||
| 		} | ||||
| 
 | ||||
|     > .group { | ||||
|       &:not(.index) { | ||||
|         padding: 4px 0 8px 0; | ||||
|         border-top: solid 0.5px var(--divider); | ||||
|       } | ||||
| 		> .group { | ||||
| 			&:not(.index) { | ||||
| 				padding: 4px 0 8px 0; | ||||
| 				border-top: solid 0.5px var(--divider); | ||||
| 			} | ||||
| 
 | ||||
|       > header { | ||||
|         /*position: sticky; | ||||
| 			> header { | ||||
| 				/*position: sticky; | ||||
| top: 0; | ||||
| left: 0;*/ | ||||
|         height: 32px; | ||||
|         line-height: 32px; | ||||
|         z-index: 2; | ||||
|         padding: 0 8px; | ||||
|         font-size: 12px; | ||||
|       } | ||||
|     } | ||||
| 				height: 32px; | ||||
| 				line-height: 32px; | ||||
| 				z-index: 2; | ||||
| 				padding: 0 8px; | ||||
| 				font-size: 12px; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|     ::v-deep(section) { | ||||
|       > header { | ||||
|         position: sticky; | ||||
|         top: 0; | ||||
|         left: 0; | ||||
|         height: 32px; | ||||
|         line-height: 32px; | ||||
|         z-index: 1; | ||||
|         padding: 0 8px; | ||||
|         font-size: 12px; | ||||
|         cursor: pointer; | ||||
| 		::v-deep(section) { | ||||
| 			> header { | ||||
| 				position: sticky; | ||||
| 				top: 0; | ||||
| 				left: 0; | ||||
| 				height: 32px; | ||||
| 				line-height: 32px; | ||||
| 				z-index: 1; | ||||
| 				padding: 0 8px; | ||||
| 				font-size: 12px; | ||||
| 				cursor: pointer; | ||||
| 
 | ||||
|         &:hover { | ||||
|           color: var(--accent); | ||||
|         } | ||||
|       } | ||||
| 				&:hover { | ||||
| 					color: var(--accent); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
|       > .body { | ||||
|         position: relative; | ||||
|         padding: $pad; | ||||
| 			> .body { | ||||
| 				position: relative; | ||||
| 				padding: $pad; | ||||
| 
 | ||||
|         > .item { | ||||
|           position: relative; | ||||
|           padding: 0; | ||||
|           width: var(--eachSize); | ||||
|           height: var(--eachSize); | ||||
|           contain: strict; | ||||
|           border-radius: 4px; | ||||
|           font-size: 24px; | ||||
| 				> .item { | ||||
| 					position: relative; | ||||
| 					padding: 0; | ||||
| 					width: var(--eachSize); | ||||
| 					height: var(--eachSize); | ||||
| 					contain: strict; | ||||
| 					border-radius: 4px; | ||||
| 					font-size: 24px; | ||||
| 
 | ||||
|           &:focus-visible { | ||||
|             outline: solid 2px var(--focus); | ||||
|             z-index: 1; | ||||
|           } | ||||
| 					&:focus-visible { | ||||
| 						outline: solid 2px var(--focus); | ||||
| 						z-index: 1; | ||||
| 					} | ||||
| 
 | ||||
|           &:hover { | ||||
|             background: rgba(0, 0, 0, 0.05); | ||||
|           } | ||||
| 					&:hover { | ||||
| 						background: rgba(0, 0, 0, 0.05); | ||||
| 					} | ||||
| 
 | ||||
|           &:active { | ||||
|             background: var(--accent); | ||||
|             box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15); | ||||
|           } | ||||
| 					&:active { | ||||
| 						background: var(--accent); | ||||
| 						box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15); | ||||
| 					} | ||||
| 
 | ||||
|           > .emoji { | ||||
|             height: 1.25em; | ||||
|             vertical-align: -.25em; | ||||
|             pointer-events: none; | ||||
|             width: 100%; | ||||
|             object-fit: contain; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
| 					> .emoji { | ||||
| 						height: 1.25em; | ||||
| 						vertical-align: -.25em; | ||||
| 						pointer-events: none; | ||||
| 						width: 100%; | ||||
| 						object-fit: contain; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
|       &.result { | ||||
|         border-bottom: solid 0.5px var(--divider); | ||||
| 			&.result { | ||||
| 				border-bottom: solid 0.5px var(--divider); | ||||
| 
 | ||||
|         &:empty { | ||||
|           display: none; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 				&:empty { | ||||
| 					display: none; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| .sllfktkhgl{ | ||||
|   display: inline-block; | ||||
|   padding: 0 4px; | ||||
|   font-size: 12px; | ||||
|   line-height: 32px; | ||||
|   text-align: center; | ||||
|   color: var(--fg); | ||||
|   cursor: pointer; | ||||
|   width: 100%; | ||||
|   transition: transform 0.3s ease; | ||||
|   box-shadow: 0 1.5px 0 var(--divider); | ||||
|   height: 32px; | ||||
|   overflow: hidden; | ||||
|   &:hover { | ||||
|     transform: translateY(1.5px); | ||||
|   } | ||||
|   &.active { | ||||
|     transform: translateY(5px); | ||||
|   } | ||||
| 	display: inline-block; | ||||
| 	padding: 0 4px; | ||||
| 	font-size: 12px; | ||||
| 	line-height: 32px; | ||||
| 	text-align: center; | ||||
| 	color: var(--fg); | ||||
| 	cursor: pointer; | ||||
| 	width: 100%; | ||||
| 	transition: transform 0.3s ease; | ||||
| 	box-shadow: 0 1.5px 0 var(--divider); | ||||
| 	height: 32px; | ||||
| 	overflow: hidden; | ||||
| 	&:hover { | ||||
| 		transform: translateY(1.5px); | ||||
| 	} | ||||
| 	&.active { | ||||
| 		transform: translateY(5px); | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue