wip
This commit is contained in:
parent
e441ee9d8a
commit
4d68baca0d
|
@ -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,
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
// memo: popup.vueのfixedプロパティに相当するものはsource要素の祖先を辿るなどして自動で判定できるのでは
|
||||||
|
|
||||||
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>
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// popupはmodalと統合
|
||||||
|
|
||||||
<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>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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: () => {
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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でやらない
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue