Feat:emoji folder
This commit is contained in:
		
							parent
							
								
									120efff6c1
								
							
						
					
					
						commit
						a3743a0622
					
				|  | @ -323,6 +323,7 @@ export interface Locale { | |||
|     "createFolder": string; | ||||
|     "renameFolder": string; | ||||
|     "deleteFolder": string; | ||||
|     "Folder": string; | ||||
|     "addFile": string; | ||||
|     "emptyDrive": string; | ||||
|     "emptyFolder": string; | ||||
|  |  | |||
|  | @ -320,6 +320,7 @@ folderName: "フォルダー名" | |||
| createFolder: "フォルダーを作成" | ||||
| renameFolder: "フォルダー名を変更" | ||||
| deleteFolder: "フォルダーを削除" | ||||
| Folder: "フォルダー" | ||||
| addFile: "ファイルを追加" | ||||
| emptyDrive: "ドライブは空です" | ||||
| emptyFolder: "フォルダーは空です" | ||||
|  |  | |||
|  | @ -4,49 +4,129 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| --> | ||||
| 
 | ||||
| <template> | ||||
| <!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと --> | ||||
| <section> | ||||
| 	<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> | ||||
|     <!-- このコンポーネントの要素のclassは親から利用されるのでむやみに弄らないこと --> | ||||
|     <section> | ||||
| 
 | ||||
| 
 | ||||
|         <header v-if="!category" 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> | ||||
|         <header v-else-if="category.length === 1" class="_acrylic" @click="shown = !shown"> | ||||
|             <i class="toggle ti-fw" :class="shown ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> | ||||
|             {{ category[0] }} | ||||
|             ({{ | ||||
|                 emojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category[0]).length | ||||
|             }}) | ||||
|         </header> | ||||
|         <header v-else class="_acrylic" style="top:unset;" @click="toggleShown_fol"> | ||||
|             <i class="toggle ti-fw" :class="shown_fol? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> | ||||
|             {{ category[0] || i18n.ts.other }} | ||||
|             <template v-if="category.length !== 1"> | ||||
|                 ({{ i18n.ts.Folder }}) | ||||
|             </template> | ||||
|             <template v-else> | ||||
|                 ({{ | ||||
|                     emojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category[0]).length | ||||
|                 }}) 2 | ||||
|             </template> | ||||
|         </header> | ||||
|         <template v-for="(n, index) in category" v-if="shown_fol"> | ||||
|             <header | ||||
|                     v-if="emojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category[0]).length !== 0 || index!==0" | ||||
|                     style="top:unset;padding-left: 18px;" | ||||
|                     class="_acrylic" | ||||
|                     @click="toggleShown(index)" | ||||
|             > | ||||
|                 <i class="toggle ti-fw" :class="shown_fold[index] ? 'ti ti-chevron-down' : 'ti ti-chevron-up'"></i> | ||||
|                 {{ n || i18n.ts.other }} | ||||
|                 ({{ | ||||
|                     emojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === (index === 0 && category !== undefined ? category[0] : `${category[0]}/${n}`)).length | ||||
|                 }}) | ||||
|             </header> | ||||
|                 <div v-if="shown_fold[index]" class="body"> | ||||
|                     <button | ||||
|                             v-for="emoji in emojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category ===( index === 0 && category !== undefined ? category[0] : `${category[0]}/${n}`)).map(e => `:${e.name}:`)" | ||||
|                             :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> | ||||
|         </template> | ||||
| 
 | ||||
|         <div v-if="shown && category" class="body"> | ||||
|             <button | ||||
|                     v-for="emoji in emojis.filter(e => e.category === category[0]).map(e => `:${e.name}:`)" | ||||
|                     :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> | ||||
|         <div v-else-if="shown && !category" 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> | ||||
| import { ref, computed, Ref } from 'vue'; | ||||
| import { getEmojiName } from '@/scripts/emojilist.js'; | ||||
| import {ref, computed, Ref} from 'vue'; | ||||
| import {getEmojiName} from '@/scripts/emojilist.js'; | ||||
| import {i18n} from "../i18n.js"; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
| 	emojis: string[] | Ref<string[]>; | ||||
| 	initialShown?: boolean; | ||||
|     emojis: string[] | Ref<string[]>; | ||||
|     initialShown?: boolean; | ||||
|     category?: string[]; | ||||
| }>(); | ||||
| 
 | ||||
| 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 toggleShown = (index) => { | ||||
|     shown_fold.value[index] = !shown_fold.value[index]; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| const toggleShown_fol = () => { | ||||
|     for (let i = 0; i < shown_fold.value.length; i++) { | ||||
|         shown_fold.value[i] = false; | ||||
|     } | ||||
|     shown_fol.value = !shown_fol.value; | ||||
| }; | ||||
| 
 | ||||
| const emojis = computed(() => Array.isArray(props.emojis) ? props.emojis : props.emojis.value); | ||||
| const shown_fold = ref(Array(props.category === undefined ? 0 : props.category.length).fill(false)); | ||||
| const shown = ref(!!props.initialShown); | ||||
| const shown_fol = 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; | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
|  |  | |||
|  | @ -72,19 +72,26 @@ SPDX-License-Identifier: AGPL-3.0-only | |||
| 		</div> | ||||
| 		<div v-once class="group"> | ||||
| 			<header class="_acrylic">{{ i18n.ts.customEmojis }}</header> | ||||
| 
 | ||||
| 			<XSection | ||||
| 				v-for="category in customEmojiCategories" | ||||
| 				v-for="category in groupedData" | ||||
| 				:key="`custom:${category}`" | ||||
| 				:initialShown="false" | ||||
| 				:emojis="computed(() => customEmojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category).filter(filterAvailable).map(e => `:${e.name}:`))" | ||||
| 				@chosen="chosen" | ||||
| 			> | ||||
| 				{{ category || i18n.ts.other }} | ||||
| 			</XSection> | ||||
| 				:emojis="computed(() => customEmojis.filter(filterAvailable))" | ||||
|                 :category="category" | ||||
|                 @chosen="chosen" | ||||
| 			/> | ||||
| 		</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) ?? []" @chosen="chosen">{{ category }}</XSection> | ||||
| 			<XSection | ||||
| 				v-for="category in categories" | ||||
| 				:key="category" | ||||
| 				:emojis="emojiCharByCategory.get(category) ?? []" | ||||
| 				@chosen="chosen" | ||||
| 			>{{ category }} | ||||
| 			</XSection> | ||||
| 
 | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="tabs"> | ||||
|  | @ -107,7 +114,7 @@ import { isTouchUsing } from '@/scripts/touch.js'; | |||
| import { deviceKind } from '@/scripts/device-kind.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js'; | ||||
| import {customEmojiCategories, customEmojis, customEmojisMap} from '@/custom-emojis.js'; | ||||
| import { $i } from '@/account.js'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
|  | @ -143,6 +150,23 @@ const q = ref<string>(''); | |||
| const searchResultCustom = ref<Misskey.entities.CustomEmoji[]>([]); | ||||
| const searchResultUnicode = ref<UnicodeEmojiDef[]>([]); | ||||
| const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index'); | ||||
| let split_categories = []; | ||||
| customEmojiCategories.value.forEach(e => { | ||||
|     if (e !== null){ | ||||
|         split_categories.push(e.split('/')) | ||||
|     } | ||||
| }); | ||||
| 
 | ||||
| const groupedData = {}; | ||||
| split_categories.forEach((item) => { | ||||
|         if (!groupedData[item[0]]) { | ||||
|             groupedData[item[0]] = []; | ||||
|             groupedData[item[0]].push(item[0]); | ||||
|         }else{ | ||||
|             groupedData[item[0]].push(item[1]); | ||||
|         } | ||||
| }); | ||||
| console.log(groupedData) | ||||
| 
 | ||||
| watch(q, () => { | ||||
| 	if (emojisEl.value) emojisEl.value.scrollTop = 0; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue