summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/components/emoji-picker-dialog.vue9
-rw-r--r--src/client/components/emoji-picker.vue35
-rw-r--r--src/client/components/note-detailed.vue22
-rw-r--r--src/client/components/note.vue22
-rw-r--r--src/client/components/ui/modal.vue26
-rw-r--r--src/client/os.ts37
-rw-r--r--src/client/ui/chat/note.vue25
7 files changed, 101 insertions, 75 deletions
diff --git a/src/client/components/emoji-picker-dialog.vue b/src/client/components/emoji-picker-dialog.vue
index 177b5db44d..3450d219c3 100644
--- a/src/client/components/emoji-picker-dialog.vue
+++ b/src/client/components/emoji-picker-dialog.vue
@@ -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
},
diff --git a/src/client/components/emoji-picker.vue b/src/client/components/emoji-picker.vue
index b11f0a62fa..41e667dd98 100644
--- a/src/client/components/emoji-picker.vue
+++ b/src/client/components/emoji-picker.vue
@@ -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>
+ <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>
</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>
+ <XSection v-for="category in categories" :emojis="emojilist.filter(e => e.category === category).map(e => e.char)">{{ category }}</XSection>
</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>
+ <XSection v-for="tag in emojiTags" :emojis="customEmojis.filter(e => e.aliases.includes(tag)).map(e => ':' + e.name + ':')">{{ tag }}</XSection>
</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,14 +270,18 @@ export default defineComponent({
},
mounted() {
- if (!isMobile && !isDeviceTouch) {
- this.$refs.search.focus({
- preventScroll: true
- });
- }
+ this.focus();
},
methods: {
+ focus() {
+ if (!isMobile && !isDeviceTouch) {
+ this.$refs.search.focus({
+ preventScroll: true
+ });
+ }
+ },
+
getKey(emoji: any) {
return typeof emoji === 'string' ? emoji : (emoji.char || `:${emoji.name}:`);
},
diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue
index e1927133ae..7df87c6b01 100644
--- a/src/client/components/note-detailed.vue
+++ b/src/client/components/note-detailed.vue
@@ -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.api('notes/reactions/create', {
- noteId: this.appearNote.id,
- reaction: reaction
- });
- }
- this.focus();
- },
- }, 'closed');
+ os.pickReaction(this.$refs.reactButton, reaction => {
+ os.api('notes/reactions/create', {
+ noteId: this.appearNote.id,
+ reaction: reaction
+ });
+ }, () => {
+ this.focus();
+ });
},
reactDirectly(reaction) {
diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index 6af0668e2e..dab7643762 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -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.api('notes/reactions/create', {
- noteId: this.appearNote.id,
- reaction: reaction
- });
- }
- this.focus();
- },
- }, 'closed');
+ os.pickReaction(this.$refs.reactButton, reaction => {
+ os.api('notes/reactions/create', {
+ noteId: this.appearNote.id,
+ reaction: reaction
+ });
+ }, () => {
+ this.focus();
+ });
},
reactDirectly(reaction) {
diff --git a/src/client/components/ui/modal.vue b/src/client/components/ui/modal.vue
index 405fa4aaa5..1c8ae63907 100644
--- a/src/client/components/ui/modal.vue
+++ b/src/client/components/ui/modal.vue
@@ -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.fixed = getFixedContainer(this.src) != null;
+ 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() {
diff --git a/src/client/os.ts b/src/client/os.ts
index a971eebd45..9fafb6db43 100644
--- a/src/client/os.ts
+++ b/src/client/os.ts
@@ -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;
diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue
index d80978e182..75b92a32f2 100644
--- a/src/client/ui/chat/note.vue
+++ b/src/client/ui/chat/note.vue
@@ -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.api('notes/reactions/create', {
- noteId: this.appearNote.id,
- reaction: reaction
- });
- }
- },
- closed: () => {
- this.operating = false;
- this.focus();
- dispose();
- }
+ os.pickReaction(this.$refs.reactButton, reaction => {
+ os.api('notes/reactions/create', {
+ noteId: this.appearNote.id,
+ reaction: reaction
+ });
+ }, () => {
+ this.operating = false;
+ this.focus();
});
},