diff options
| author | syuilo <Syuilotan@yahoo.co.jp> | 2023-01-26 11:40:46 +0900 |
|---|---|---|
| committer | syuilo <Syuilotan@yahoo.co.jp> | 2023-01-26 11:40:46 +0900 |
| commit | 34f5d81d1fa82abc985fafc1d83f1c8e7c48703c (patch) | |
| tree | ea24fd52c46127da9c5ea5031cc706e7ff5e2c3b /packages/frontend/src/components | |
| parent | Merge branch 'develop' (diff) | |
| parent | 13.2.3 (diff) | |
| download | misskey-34f5d81d1fa82abc985fafc1d83f1c8e7c48703c.tar.gz misskey-34f5d81d1fa82abc985fafc1d83f1c8e7c48703c.tar.bz2 misskey-34f5d81d1fa82abc985fafc1d83f1c8e7c48703c.zip | |
Merge branch 'develop'
Diffstat (limited to 'packages/frontend/src/components')
6 files changed, 74 insertions, 63 deletions
diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 702fba9796..2cb3aeb3d8 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -33,7 +33,7 @@ </template> <script lang="ts"> -import { markRaw, ref, shallowRef, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'; +import { markRaw, ref, shallowRef, computed, onUpdated, onMounted, onBeforeUnmount, nextTick, watch } from 'vue'; import sanitizeHtml from 'sanitize-html'; import contains from '@/scripts/contains'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base'; @@ -61,59 +61,62 @@ type EmojiDef = { const lib = emojilist.filter(x => x.category !== 'flags'); -const char2path = defaultStore.state.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath; +const emojiDb = computed(() => { + //#region Unicode Emoji + const char2path = defaultStore.reactiveState.emojiStyle.value === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath; -const emjdb: EmojiDef[] = lib.map(x => ({ - emoji: x.char, - name: x.name, - url: char2path(x.char), -})); + const unicodeEmojiDB: EmojiDef[] = lib.map(x => ({ + emoji: x.char, + name: x.name, + url: char2path(x.char), + })); -for (const x of lib) { - if (x.keywords) { - for (const k of x.keywords) { - emjdb.push({ - emoji: x.char, - name: k, - aliasOf: x.name, - url: char2path(x.char), - }); + for (const x of lib) { + if (x.keywords) { + for (const k of x.keywords) { + unicodeEmojiDB.push({ + emoji: x.char, + name: k, + aliasOf: x.name, + url: char2path(x.char), + }); + } } } -} -emjdb.sort((a, b) => a.name.length - b.name.length); + unicodeEmojiDB.sort((a, b) => a.name.length - b.name.length); + //#endregion -//#region Construct Emoji DB -const emojiDefinitions: EmojiDef[] = []; + //#region Custom Emoji + const customEmojiDB: EmojiDef[] = []; -for (const x of customEmojis) { - emojiDefinitions.push({ - name: x.name, - emoji: `:${x.name}:`, - isCustomEmoji: true, - }); + for (const x of customEmojis.value) { + customEmojiDB.push({ + name: x.name, + emoji: `:${x.name}:`, + isCustomEmoji: true, + }); - if (x.aliases) { - for (const alias of x.aliases) { - emojiDefinitions.push({ - name: alias, - aliasOf: x.name, - emoji: `:${x.name}:`, - isCustomEmoji: true, - }); + if (x.aliases) { + for (const alias of x.aliases) { + customEmojiDB.push({ + name: alias, + aliasOf: x.name, + emoji: `:${x.name}:`, + isCustomEmoji: true, + }); + } } } -} -emojiDefinitions.sort((a, b) => a.name.length - b.name.length); + customEmojiDB.sort((a, b) => a.name.length - b.name.length); + //#endregion -const emojiDb = markRaw(emojiDefinitions.concat(emjdb)); -//#endregion + return markRaw([ ...customEmojiDB, ...unicodeEmojiDB ]); +}); export default { emojiDb, - emojiDefinitions, emojilist, }; </script> @@ -230,27 +233,27 @@ function exec() { } else if (props.type === 'emoji') { if (!props.q || props.q === '') { // 最近使った絵文字をサジェスト - emojis.value = defaultStore.state.recentlyUsedEmojis.map(emoji => emojiDb.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[]; + emojis.value = defaultStore.state.recentlyUsedEmojis.map(emoji => emojiDb.value.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[]; return; } const matched: EmojiDef[] = []; const max = 30; - emojiDb.some(x => { + emojiDb.value.some(x => { if (x.name.startsWith(props.q ?? '') && !x.aliasOf && !matched.some(y => y.emoji === x.emoji)) matched.push(x); return matched.length === max; }); if (matched.length < max) { - emojiDb.some(x => { + emojiDb.value.some(x => { if (x.name.startsWith(props.q ?? '') && !matched.some(y => y.emoji === x.emoji)) matched.push(x); return matched.length === max; }); } if (matched.length < max) { - emojiDb.some(x => { + emojiDb.value.some(x => { if (x.name.includes(props.q ?? '') && !matched.some(y => y.emoji === x.emoji)) matched.push(x); return matched.length === max; }); diff --git a/packages/frontend/src/components/MkEmojiPicker.section.vue b/packages/frontend/src/components/MkEmojiPicker.section.vue index 8b0b7cf29a..acced44793 100644 --- a/packages/frontend/src/components/MkEmojiPicker.section.vue +++ b/packages/frontend/src/components/MkEmojiPicker.section.vue @@ -18,10 +18,10 @@ </template> <script lang="ts" setup> -import { ref } from 'vue'; +import { ref, computed, Ref } from 'vue'; const props = defineProps<{ - emojis: string[]; + emojis: string[] | Ref<string[]>; initialShown?: boolean; }>(); @@ -29,5 +29,7 @@ const emit = defineEmits<{ (ev: 'chosen', v: string, event: MouseEvent): void; }>(); +const emojis = computed(() => Array.isArray(props.emojis) ? props.emojis : props.emojis.value); + const shown = ref(!!props.initialShown); </script> diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index 9c6d62ce8b..f64cc6e9aa 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -60,7 +60,15 @@ </div> <div v-once class="group"> <header class="_acrylic">{{ i18n.ts.customEmojis }}</header> - <XSection v-for="category in customEmojiCategories" :key="'custom:' + category" :initial-shown="false" :emojis="customEmojis.filter(e => e.category === category).map(e => ':' + e.name + ':')" @chosen="chosen">{{ category || i18n.ts.other }}</XSection> + <XSection + v-for="category in customEmojiCategories" + :key="`custom:${category}`" + :initial-shown="false" + :emojis="computed(() => customEmojis.filter(e => category === null ? (e.category === 'null' || !e.category) : e.category === category).map(e => `:${e.name}:`))" + @chosen="chosen" + > + {{ category || i18n.ts.other }} + </XSection> </div> <div v-once class="group"> <header class="_acrylic">{{ i18n.ts.emoji }}</header> @@ -88,7 +96,7 @@ import { deviceKind } from '@/scripts/device-kind'; import { instance } from '@/instance'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; -import { getCustomEmojiCategories, customEmojis } from '@/custom-emojis'; +import { customEmojiCategories, customEmojis } from '@/custom-emojis'; const props = withDefaults(defineProps<{ showPinned?: boolean; @@ -104,7 +112,6 @@ const emit = defineEmits<{ (ev: 'chosen', v: string): void; }>(); -const customEmojiCategories = getCustomEmojiCategories(); const searchEl = shallowRef<HTMLInputElement>(); const emojisEl = shallowRef<HTMLDivElement>(); @@ -138,7 +145,7 @@ watch(q, () => { const searchCustom = () => { const max = 8; - const emojis = customEmojis; + const emojis = customEmojis.value; const matches = new Set<Misskey.entities.CustomEmoji>(); const exactMatch = emojis.find(emoji => emoji.name === newQ); @@ -323,7 +330,7 @@ function done(query?: string): boolean | void { if (query == null || typeof query !== 'string') return; const q2 = query.replace(/:/g, ''); - const exactMatchCustom = customEmojis.find(emoji => emoji.name === q2); + const exactMatchCustom = customEmojis.value.find(emoji => emoji.name === q2); if (exactMatchCustom) { chosen(exactMatchCustom); return true; diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index 94dabcac90..eee77a9475 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -335,8 +335,7 @@ onBeforeUnmount(() => { } .icon { - margin-right: 5px; - width: 20px; + margin-right: 8px; } .caret { diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue index bb2a789b3f..5d33ad0ad3 100644 --- a/packages/frontend/src/components/MkSuperMenu.vue +++ b/packages/frontend/src/components/MkSuperMenu.vue @@ -6,15 +6,15 @@ <div class="items"> <template v-for="(item, i) in group.items"> <a v-if="item.type === 'a'" :href="item.href" :target="item.target" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }"> - <i v-if="item.icon" class="icon ti-fw" :class="item.icon"></i> + <span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span> <span class="text">{{ item.text }}</span> </a> <button v-else-if="item.type === 'button'" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }" :disabled="item.active" @click="ev => item.action(ev)"> - <i v-if="item.icon" class="icon ti-fw" :class="item.icon"></i> + <span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span> <span class="text">{{ item.text }}</span> </button> <MkA v-else :to="item.to" :tabindex="i" class="_button item" :class="{ danger: item.danger, active: item.active }"> - <i v-if="item.icon" class="icon ti-fw" :class="item.icon"></i> + <span v-if="item.icon" class="icon"><i :class="item.icon" class="ti-fw"></i></span> <span class="text">{{ item.text }}</span> </MkA> </template> diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue index 93f50da20e..b554d5e47c 100644 --- a/packages/frontend/src/components/global/MkEmoji.vue +++ b/packages/frontend/src/components/global/MkEmoji.vue @@ -1,6 +1,6 @@ <template> <span v-if="isCustom && errored">:{{ customEmojiName }}:</span> -<img v-else-if="isCustom" :class="[$style.root, $style.custom, { [$style.normal]: normal, [$style.noStyle]: noStyle }]" :src="url" :alt="alt" :title="alt" decoding="async" @error="errored = true"/> +<img v-else-if="isCustom" :class="[$style.root, $style.custom, { [$style.normal]: normal, [$style.noStyle]: noStyle }]" :src="url" :alt="alt" :title="alt" decoding="async" @error="errored = true" @load="errored = false"/> <img v-else-if="char && !useOsNativeEmojis" :class="$style.root" :src="url" :alt="alt" decoding="async" @pointerenter="computeTitle"/> <span v-else-if="char && useOsNativeEmojis" :alt="alt" @pointerenter="computeTitle">{{ char }}</span> <span v-else>{{ emoji }}</span> @@ -25,29 +25,29 @@ const props = defineProps<{ const char2path = defaultStore.state.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath; const isCustom = computed(() => props.emoji.startsWith(':')); -const customEmojiName = props.emoji.substr(1, props.emoji.length - 2).replace('@.', ''); +const customEmojiName = computed(() => props.emoji.substr(1, props.emoji.length - 2).replace('@.', '')); const char = computed(() => isCustom.value ? undefined : props.emoji); const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'native' && !props.isReaction); const url = computed(() => { if (char.value) { return char2path(char.value); - } else if (props.host == null && !customEmojiName.includes('@')) { - const found = customEmojis.find(x => x.name === customEmojiName); - return found ? found.url : null; + } else if (props.host == null && !customEmojiName.value.includes('@')) { + const found = customEmojis.value.find(x => x.name === customEmojiName.value); + return found ? defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(found.url) : found.url : null; } else { - const rawUrl = props.host ? `/emoji/${customEmojiName}@${props.host}.webp` : `/emoji/${customEmojiName}.webp`; + const rawUrl = props.host ? `/emoji/${customEmojiName.value}@${props.host}.webp` : `/emoji/${customEmojiName.value}.webp`; return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(rawUrl) : rawUrl; } }); -const alt = computed(() => isCustom.value ? `:${customEmojiName}:` : char.value); +const alt = computed(() => isCustom.value ? `:${customEmojiName.value}:` : char.value); let errored = $ref(isCustom.value && url.value == null); // Searching from an array with 2000 items for every emoji felt like too energy-consuming, so I decided to do it lazily on pointerenter function computeTitle(event: PointerEvent): void { const title = isCustom.value - ? `:${customEmojiName}:` + ? `:${customEmojiName.value}:` : (getEmojiName(char.value as string) ?? char.value as string); (event.target as HTMLElement).title = title; } |