This commit is contained in:
syuilo 2021-02-28 01:09:59 +09:00
parent cb2a9a29fe
commit 764a158cd7
7 changed files with 101 additions and 75 deletions

View file

@ -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
},

View file

@ -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}:`);
},

View file

@ -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) {

View file

@ -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) {

View file

@ -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() {

View file

@ -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;

View file

@ -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();
}
});
},