This commit is contained in:
syuilo 2020-09-06 00:20:06 +09:00
parent e441ee9d8a
commit 4d68baca0d
17 changed files with 117 additions and 27 deletions

View File

@ -207,7 +207,7 @@ export default defineComponent({
}, },
showMenu() { showMenu() {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: this.getMenu(), items: this.getMenu(),
source: this.$refs.menu, source: this.$refs.menu,
}); });

View File

@ -82,7 +82,7 @@ export default defineComponent({
if (this.selectMode) { if (this.selectMode) {
this.$emit('chosen', this.file); this.$emit('chosen', this.file);
} else { } else {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('rename'), text: this.$t('rename'),
icon: faICursor, icon: faICursor,

View File

@ -1,6 +1,6 @@
<template> <template>
<x-popup :source="source" :no-center="noCenter" :fixed="fixed" :width="width" ref="popup" @closed="() => { $emit('closed'); destroyDom(); }" v-hotkey.global="keymap"> <x-modal :source="source" :no-center="noCenter" ref="popup" @click="" @closed="$store.commit('removeMenu', id)" :showing="showing">
<div class="rrevdjwt" :class="{ left: align === 'left' }" ref="items"> <div class="rrevdjwt" :class="{ left: align === 'left' }" ref="items" :style="{ width: width + 'px' }">
<template v-for="(item, i) in items.filter(item => item !== undefined)"> <template v-for="(item, i) in items.filter(item => item !== undefined)">
<div v-if="item === null" class="divider" :key="i"></div> <div v-if="item === null" class="divider" :key="i"></div>
<span v-else-if="item.type === 'label'" class="label item" :key="i"> <span v-else-if="item.type === 'label'" class="label item" :key="i">
@ -29,18 +29,18 @@
</button> </button>
</template> </template>
</div> </div>
</x-popup> </x-modal>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { faCircle } from '@fortawesome/free-solid-svg-icons'; import { faCircle } from '@fortawesome/free-solid-svg-icons';
import XPopup from './popup.vue'; import XModal from './modal.vue';
import { focusPrev, focusNext } from '../scripts/focus'; import { focusPrev, focusNext } from '../scripts/focus';
export default defineComponent({ export default defineComponent({
components: { components: {
XPopup XModal
}, },
props: { props: {
source: { source: {
@ -58,10 +58,6 @@ export default defineComponent({
type: Boolean, type: Boolean,
required: false required: false
}, },
fixed: {
type: Boolean,
required: false
},
width: { width: {
type: Number, type: Number,
required: false required: false

View File

@ -14,6 +14,8 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
// memo: popup.vuefixedsource辿
export default defineComponent({ export default defineComponent({
emits: ['click', 'esc', 'closed'], emits: ['click', 'esc', 'closed'],
props: { props: {
@ -26,6 +28,9 @@ export default defineComponent({
required: false, required: false,
default: true, default: true,
}, },
sourceEl: {
required: false,
}
}, },
computed: { computed: {
keymap(): any { keymap(): any {
@ -34,6 +39,64 @@ export default defineComponent({
}; };
}, },
}, },
mounted() {
this.$nextTick(() => {
const popover = this.$refs.content as any;
const rect = this.source.getBoundingClientRect();
const width = popover.offsetWidth;
const height = popover.offsetHeight;
let left;
let top;
if (this.$root.isMobile && !this.noCenter) {
const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.source.offsetWidth / 2);
const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + (this.source.offsetHeight / 2);
left = (x - (width / 2));
top = (y - (height / 2));
popover.style.transformOrigin = 'center';
} else {
const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.source.offsetWidth / 2);
const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + this.source.offsetHeight;
left = (x - (width / 2));
top = y;
}
if (this.fixed) {
if (left + width > window.innerWidth) {
left = window.innerWidth - width;
popover.style.transformOrigin = 'center';
}
if (top + height > window.innerHeight) {
top = window.innerHeight - height;
popover.style.transformOrigin = 'center';
}
} else {
if (left + width - window.pageXOffset > window.innerWidth) {
left = window.innerWidth - width + window.pageXOffset;
popover.style.transformOrigin = 'center';
}
if (top + height - window.pageYOffset > window.innerHeight) {
top = window.innerHeight - height + window.pageYOffset;
popover.style.transformOrigin = 'center';
}
}
if (top < 0) {
top = 0;
}
if (left < 0) {
left = 0;
}
popover.style.left = left + 'px';
popover.style.top = top + 'px';
});
},
}); });
</script> </script>

View File

@ -452,7 +452,7 @@ export default defineComponent({
renote(viaKeyboard = false) { renote(viaKeyboard = false) {
pleaseLogin(this.$root); pleaseLogin(this.$root);
this.blur(); this.blur();
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('renote'), text: this.$t('renote'),
icon: faRetweet, icon: faRetweet,
@ -685,7 +685,7 @@ export default defineComponent({
}))]); }))]);
} }
this.$root.menu({ this.$store.dispatch('showMenu', {
items: menu, items: menu,
source: this.$refs.menuButton, source: this.$refs.menuButton,
viaKeyboard viaKeyboard
@ -694,7 +694,7 @@ export default defineComponent({
showRenoteMenu(viaKeyboard = false) { showRenoteMenu(viaKeyboard = false) {
if (!this.isMyRenote) return; if (!this.isMyRenote) return;
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('unrenote'), text: this.$t('unrenote'),
icon: faTrashAlt, icon: faTrashAlt,

View File

@ -1,3 +1,5 @@
// popupmodal
<template> <template>
<div class="mk-popup" v-hotkey.global="keymap"> <div class="mk-popup" v-hotkey.global="keymap">
<transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear> <transition :name="$store.state.device.animation ? 'bg-fade' : ''" appear>

View File

@ -80,7 +80,7 @@ export default defineComponent({
}, },
showFileMenu(file, ev: MouseEvent) { showFileMenu(file, ev: MouseEvent) {
if (this.menu) return; if (this.menu) return;
this.menu = this.$root.menu({ this.menu = this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('renameFile'), text: this.$t('renameFile'),
icon: faICursor, icon: faICursor,

View File

@ -346,7 +346,7 @@ export default defineComponent({
}, },
chooseFileFrom(ev) { chooseFileFrom(ev) {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
type: 'label', type: 'label',
text: this.$t('attachFile'), text: this.$t('attachFile'),
@ -612,7 +612,7 @@ export default defineComponent({
}, },
showActions(ev) { showActions(ev) {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: this.$store.state.postFormActions.map(action => ({ items: this.$store.state.postFormActions.map(action => ({
text: action.title, text: action.title,
action: () => { action: () => {

View File

@ -149,7 +149,7 @@ export default defineComponent({
action: () => { this.switchAccount(account); } action: () => { this.switchAccount(account); }
})); }));
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [...[{ items: [...[{
type: 'link', type: 'link',
text: this.$t('profile'), text: this.$t('profile'),
@ -164,7 +164,7 @@ export default defineComponent({
icon: faPlus, icon: faPlus,
text: this.$t('addAcount'), text: this.$t('addAcount'),
action: () => { action: () => {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('existingAcount'), text: this.$t('existingAcount'),
action: () => { this.addAcount(); }, action: () => { this.addAcount(); },
@ -187,7 +187,7 @@ export default defineComponent({
}, },
oepnInstanceMenu(ev) { oepnInstanceMenu(ev) {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
type: 'link', type: 'link',
text: this.$t('dashboard'), text: this.$t('dashboard'),
@ -250,7 +250,7 @@ export default defineComponent({
action: def.action, action: def.action,
indicate: def.indicated, indicate: def.indicated,
})); }));
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [...items, null, { items: [...items, null, {
type: 'link', type: 'link',
text: this.$t('help'), text: this.$t('help'),

View File

@ -39,7 +39,7 @@ export default defineComponent({
methods: { methods: {
menu(ev) { menu(ev) {
this.menuOpened = true; this.menuOpened = true;
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('addFile'), text: this.$t('addFile'),
type: 'label' type: 'label'

View File

@ -171,7 +171,7 @@ export default defineComponent({
this.$router.push(`/channels/${channel.id}`); this.$router.push(`/channels/${channel.id}`);
} }
})); }));
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('_timelines.home'), text: this.$t('_timelines.home'),
icon: faHome, icon: faHome,

View File

@ -115,7 +115,7 @@ export default defineComponent({
}, },
start(ev) { start(ev) {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('messagingWithUser'), text: this.$t('messagingWithUser'),
icon: faUser, icon: faUser,

View File

@ -255,7 +255,7 @@ export default defineComponent({
showTypeMenu(e: MouseEvent) { showTypeMenu(e: MouseEvent) {
return new Promise<ThemeValue>((resolve) => { return new Promise<ThemeValue>((resolve) => {
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('_theme.defaultValue'), text: this.$t('_theme.defaultValue'),
action: () => resolve(null), action: () => resolve(null),

View File

@ -4,6 +4,8 @@
<XPostFormDialog v-if="$store.state.postForm" v-bind="$store.state.postForm"/> <XPostFormDialog v-if="$store.state.postForm" v-bind="$store.state.postForm"/>
<XMenu v-if="menu" v-bind="menu" :key="menu.id"/>
<XDialog v-if="dialog" v-bind="dialog" :key="dialog.id"/> <XDialog v-if="dialog" v-bind="dialog" :key="dialog.id"/>
</template> </template>
@ -18,6 +20,7 @@ export default defineComponent({
DefaultUI, DefaultUI,
DeckUI, DeckUI,
XDialog: defineAsyncComponent(() => import('./components/dialog.vue')), XDialog: defineAsyncComponent(() => import('./components/dialog.vue')),
XMenu: defineAsyncComponent(() => import('./components/menu.vue')),
XPostFormDialog: defineAsyncComponent(() => import('./components/post-form-dialog.vue')), XPostFormDialog: defineAsyncComponent(() => import('./components/post-form-dialog.vue')),
}, },
@ -51,6 +54,12 @@ export default defineComponent({
// what: // what:
// why: // why:
return this.$store.state.dialogs[this.$store.state.dialogs.length - 1]; return this.$store.state.dialogs[this.$store.state.dialogs.length - 1];
},
menu() {
if (this.$store.state.menus.length === 0) return null;
return this.$store.state.menus[this.$store.state.menus.length - 1];
} }
}, },

View File

@ -65,7 +65,7 @@ export function selectFile(component: any, src: any, label: string | null, multi
}; };
component.$root.menu({ component.$store.dispatch('showMenu', {
items: [label ? { items: [label ? {
text: label, text: label,
type: 'label' type: 'label'

View File

@ -115,6 +115,7 @@ export const store = createStore({
text: string; text: string;
result: any; result: any;
}[], }[],
menus: [],
postForm: null, postForm: null,
fullView: false, fullView: false,
@ -277,6 +278,10 @@ export const store = createStore({
state.dialogs = state.dialogs.filter(d => d.id !== dialogId); state.dialogs = state.dialogs.filter(d => d.id !== dialogId);
}, },
addMenu(state, menu) {
state.menus.push(menu);
},
setPostForm(state, postForm) { setPostForm(state, postForm) {
if (state.postForm != null && postForm != null) return; if (state.postForm != null && postForm != null) return;
state.postForm = postForm; state.postForm = postForm;
@ -392,6 +397,21 @@ export const store = createStore({
}); });
}, },
showMenu(ctx, opts) {
return new Promise((res, rej) => {
const menu = reactive({
...opts,
result: null,
id: Math.random().toString() // TODO: uuidとか使う
});
ctx.commit('addMenu', menu);
const unwatch = watch(() => menu.result, result => {
unwatch();
res(result);
});
});
},
api(ctx, { endpoint, data, token }) { api(ctx, { endpoint, data, token }) {
if (++ctx.state.pendingApiRequestsCount === 1) { if (++ctx.state.pendingApiRequestsCount === 1) {
// TODO: spinnerの表示はstoreでやらない // TODO: spinnerの表示はstoreでやらない

View File

@ -88,7 +88,7 @@ export default defineComponent({
this.setSrc('list'); this.setSrc('list');
} }
})); }));
this.$root.menu({ this.$store.dispatch('showMenu', {
items: [{ items: [{
text: this.$t('_timelines.home'), text: this.$t('_timelines.home'),
icon: faHome, icon: faHome,