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