Resolve #7270
This commit is contained in:
parent
cb2a9a29fe
commit
764a158cd7
7 changed files with 101 additions and 75 deletions
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
|
||||
<MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen"/>
|
||||
<MkModal ref="modal" :manual-showing="manualShowing" :src="src" @click="$refs.modal.close()" @opening="$refs.picker.focus()" @close="$emit('close')" @closed="$emit('closed')">
|
||||
<MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen" ref="picker"/>
|
||||
</MkModal>
|
||||
</template>
|
||||
|
||||
|
@ -16,6 +16,11 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
props: {
|
||||
manualShowing: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
src: {
|
||||
required: false
|
||||
},
|
||||
|
|
|
@ -54,23 +54,17 @@
|
|||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div v-appear="() => showingCustomEmojis = true">
|
||||
<div>
|
||||
<header class="_acrylic">{{ $ts.customEmojis }}</header>
|
||||
<template v-if="showingCustomEmojis">
|
||||
<XSection v-for="category in customEmojiCategories" :key="'custom:' + category" :initial-shown="false" :emojis="customEmojis.filter(e => e.category === category).map(e => ':' + e.name + ':')">{{ category || $ts.other }}</XSection>
|
||||
</template>
|
||||
</div>
|
||||
<div v-appear="() => showingEmojis = true">
|
||||
<div>
|
||||
<header class="_acrylic">{{ $ts.emoji }}</header>
|
||||
<template v-if="showingEmojis">
|
||||
<XSection v-for="category in categories" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)">{{ category }}</XSection>
|
||||
</template>
|
||||
</div>
|
||||
<div v-appear="() => showingTags = true">
|
||||
<div>
|
||||
<header class="_acrylic">{{ $ts.tags }}</header>
|
||||
<template v-if="showingTags">
|
||||
<XSection v-for="tag in emojiTags" :emojis="customEmojis.filter(e => e.aliases.includes(tag)).map(e => ':' + e.name + ':')">{{ tag }}</XSection>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs">
|
||||
|
@ -127,9 +121,6 @@ export default defineComponent({
|
|||
searchResultCustom: [],
|
||||
searchResultUnicode: [],
|
||||
tab: 'index',
|
||||
showingCustomEmojis: false,
|
||||
showingEmojis: false,
|
||||
showingTags: false,
|
||||
categories: ['face', 'people', 'animals_and_nature', 'food_and_drink', 'activity', 'travel_and_places', 'objects', 'symbols', 'flags'],
|
||||
faGlobe, faClock, faChevronDown, faAsterisk, faLaugh, faUtensils, faLeaf, faShapes, faBicycle, faHashtag,
|
||||
};
|
||||
|
@ -279,6 +270,11 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.focus();
|
||||
},
|
||||
|
||||
methods: {
|
||||
focus() {
|
||||
if (!isMobile && !isDeviceTouch) {
|
||||
this.$refs.search.focus({
|
||||
preventScroll: true
|
||||
|
@ -286,7 +282,6 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
getKey(emoji: any) {
|
||||
return typeof emoji === 'string' ? emoji : (emoji.char || `:${emoji.name}:`);
|
||||
},
|
||||
|
|
|
@ -523,20 +523,14 @@ export default defineComponent({
|
|||
react(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
this.blur();
|
||||
os.popup(import('@/components/emoji-picker-dialog.vue'), {
|
||||
src: this.$refs.reactButton,
|
||||
asReactionPicker: true
|
||||
}, {
|
||||
done: reaction => {
|
||||
if (reaction) {
|
||||
os.pickReaction(this.$refs.reactButton, reaction => {
|
||||
os.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
});
|
||||
}
|
||||
}, () => {
|
||||
this.focus();
|
||||
},
|
||||
}, 'closed');
|
||||
});
|
||||
},
|
||||
|
||||
reactDirectly(reaction) {
|
||||
|
|
|
@ -498,20 +498,14 @@ export default defineComponent({
|
|||
react(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
this.blur();
|
||||
os.popup(import('@/components/emoji-picker-dialog.vue'), {
|
||||
src: this.$refs.reactButton,
|
||||
asReactionPicker: true
|
||||
}, {
|
||||
done: reaction => {
|
||||
if (reaction) {
|
||||
os.pickReaction(this.$refs.reactButton, reaction => {
|
||||
os.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
});
|
||||
}
|
||||
}, () => {
|
||||
this.focus();
|
||||
},
|
||||
}, 'closed');
|
||||
});
|
||||
},
|
||||
|
||||
reactDirectly(reaction) {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<div class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: showing ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
||||
<div class="mk-modal" v-hotkey.global="keymap" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
||||
<transition :name="$store.state.animation ? 'modal-bg' : ''" appear>
|
||||
<div class="bg _modalBg" v-if="showing" @click="onBgClick"></div>
|
||||
<div class="bg _modalBg" v-if="manualShowing != null ? manualShowing : showing" @click="onBgClick"></div>
|
||||
</transition>
|
||||
<div class="content" :class="{ popup, fixed, top: position === 'top' }" @click.self="onBgClick" ref="content">
|
||||
<transition :name="$store.state.animation ? popup ? 'modal-popup-content' : 'modal-content' : ''" appear @after-leave="$emit('closed')" @after-enter="childRendered">
|
||||
<slot v-if="showing"></slot>
|
||||
<transition :name="$store.state.animation ? popup ? 'modal-popup-content' : 'modal-content' : ''" appear @after-leave="$emit('closed')" @enter="$emit('opening')" @after-enter="childRendered">
|
||||
<div v-show="manualShowing != null ? manualShowing : showing">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,6 +31,11 @@ export default defineComponent({
|
|||
modal: true
|
||||
},
|
||||
props: {
|
||||
manualShowing: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
srcCenter: {
|
||||
type: Boolean,
|
||||
required: false
|
||||
|
@ -40,7 +47,7 @@ export default defineComponent({
|
|||
required: false
|
||||
}
|
||||
},
|
||||
emits: ['click', 'esc', 'closed'],
|
||||
emits: ['opening', 'click', 'esc', 'close', 'closed'],
|
||||
data() {
|
||||
return {
|
||||
showing: true,
|
||||
|
@ -60,15 +67,17 @@ export default defineComponent({
|
|||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$watch('src', () => {
|
||||
this.fixed = getFixedContainer(this.src) != null;
|
||||
}, { immediate: true });
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (!this.popup) return;
|
||||
|
||||
const popover = this.$refs.content as any;
|
||||
|
||||
// TODO: ResizeObserver無くしたい
|
||||
new ResizeObserver((entries, observer) => {
|
||||
if (!this.popup) return;
|
||||
|
||||
const rect = this.src.getBoundingClientRect();
|
||||
|
||||
const width = popover.offsetWidth;
|
||||
|
@ -141,6 +150,7 @@ export default defineComponent({
|
|||
|
||||
close() {
|
||||
this.showing = false;
|
||||
this.$emit('close');
|
||||
},
|
||||
|
||||
onBgClick() {
|
||||
|
|
|
@ -357,6 +357,43 @@ export async function openEmojiPicker(src?: HTMLElement, opts, initialTextarea:
|
|||
});
|
||||
}
|
||||
|
||||
let reactionPicker = null;
|
||||
export async function pickReaction(src: HTMLElement, chosen, closed) {
|
||||
if (reactionPicker) {
|
||||
if (reactionPicker.opening) return;
|
||||
|
||||
reactionPicker.opening = true;
|
||||
reactionPicker.src.value = src;
|
||||
reactionPicker.manualShowing.value = true;
|
||||
reactionPicker.chosen = chosen;
|
||||
reactionPicker.closed = closed;
|
||||
} else {
|
||||
reactionPicker = {
|
||||
opening: true,
|
||||
src: ref(src),
|
||||
manualShowing: ref(true),
|
||||
chosen, closed
|
||||
};
|
||||
popup(import('@/components/emoji-picker-dialog.vue'), {
|
||||
src: reactionPicker.src,
|
||||
asReactionPicker: true,
|
||||
manualShowing: reactionPicker.manualShowing
|
||||
}, {
|
||||
done: reaction => {
|
||||
reactionPicker.chosen(reaction);
|
||||
},
|
||||
close: () => {
|
||||
reactionPicker.manualShowing.value = false;
|
||||
},
|
||||
closed: () => {
|
||||
reactionPicker.src.value = null;
|
||||
reactionPicker.closed();
|
||||
reactionPicker.opening = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let dispose;
|
||||
|
|
|
@ -504,23 +504,14 @@ export default defineComponent({
|
|||
pleaseLogin();
|
||||
this.operating = true;
|
||||
this.blur();
|
||||
const { dispose } = await os.popup(import('@/components/emoji-picker-dialog.vue'), {
|
||||
src: this.$refs.reactButton,
|
||||
asReactionPicker: true
|
||||
}, {
|
||||
done: reaction => {
|
||||
if (reaction) {
|
||||
os.pickReaction(this.$refs.reactButton, reaction => {
|
||||
os.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
});
|
||||
}
|
||||
},
|
||||
closed: () => {
|
||||
}, () => {
|
||||
this.operating = false;
|
||||
this.focus();
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in a new issue