wip
This commit is contained in:
parent
02701d852d
commit
cd79314f69
|
@ -376,7 +376,7 @@ export default defineComponent({
|
|||
|
||||
chooseUser() {
|
||||
this.close();
|
||||
const vm = os.popup(MkUserSelect, {});
|
||||
const vm = os.modal(MkUserSelect, {});
|
||||
vm.$once('selected', user => {
|
||||
this.complete('user', user);
|
||||
});
|
||||
|
|
|
@ -43,7 +43,7 @@ export default defineComponent({
|
|||
icon: faCog,
|
||||
text: this.$t('notificationSetting'),
|
||||
action: async () => {
|
||||
os.popup(await import('../notification-setting-window.vue'), {
|
||||
os.modal(await import('../notification-setting-window.vue'), {
|
||||
includingTypes: this.column.includingTypes,
|
||||
}).$on('ok', async ({ includingTypes }) => {
|
||||
this.$set(this.column, 'includingTypes', includingTypes);
|
||||
|
|
|
@ -1,46 +1,44 @@
|
|||
<template>
|
||||
<x-modal @closed="$emit('closed')" @click="onBgClick" :showing="showing">
|
||||
<div class="mk-dialog" :class="{ iconOnly }">
|
||||
<template v-if="type == 'signin'">
|
||||
<mk-signin/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="icon" v-if="icon">
|
||||
<fa :icon="icon"/>
|
||||
</div>
|
||||
<div class="icon" v-else-if="!input && !select && !user" :class="type">
|
||||
<fa :icon="faCheck" v-if="type === 'success'"/>
|
||||
<fa :icon="faTimesCircle" v-if="type === 'error'"/>
|
||||
<fa :icon="faExclamationTriangle" v-if="type === 'warning'"/>
|
||||
<fa :icon="faInfoCircle" v-if="type === 'info'"/>
|
||||
<fa :icon="faQuestionCircle" v-if="type === 'question'"/>
|
||||
<fa :icon="faSpinner" pulse v-if="type === 'waiting'"/>
|
||||
</div>
|
||||
<header v-if="title" v-html="title"></header>
|
||||
<header v-if="title == null && user">{{ $t('enterUsername') }}</header>
|
||||
<div class="body" v-if="text" v-html="text"></div>
|
||||
<mk-input v-if="input" v-model:value="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></mk-input>
|
||||
<mk-input v-if="user" v-model:value="userInputValue" autofocus @keydown="onInputKeydown"><template #prefix>@</template></mk-input>
|
||||
<mk-select v-if="select" v-model:value="selectedValue" autofocus>
|
||||
<template v-if="select.items">
|
||||
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
|
||||
</template>
|
||||
<template v-else>
|
||||
<optgroup v-for="groupedItem in select.groupedItems" :label="groupedItem.label">
|
||||
<option v-for="item in groupedItem.items" :value="item.value">{{ item.text }}</option>
|
||||
</optgroup>
|
||||
</template>
|
||||
</mk-select>
|
||||
<div class="buttons" v-if="!iconOnly && (showOkButton || showCancelButton) && !actions">
|
||||
<mk-button inline @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user" :disabled="!canOk">{{ (showCancelButton || input || select || user) ? $t('ok') : $t('gotIt') }}</mk-button>
|
||||
<mk-button inline @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('cancel') }}</mk-button>
|
||||
</div>
|
||||
<div class="buttons" v-if="actions">
|
||||
<mk-button v-for="action in actions" inline @click="() => { action.callback(); close(); }" :primary="action.primary" :key="action.text">{{ action.text }}</mk-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</x-modal>
|
||||
<div class="mk-dialog" :class="{ iconOnly }">
|
||||
<template v-if="type == 'signin'">
|
||||
<mk-signin/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="icon" v-if="icon">
|
||||
<fa :icon="icon"/>
|
||||
</div>
|
||||
<div class="icon" v-else-if="!input && !select && !user" :class="type">
|
||||
<fa :icon="faCheck" v-if="type === 'success'"/>
|
||||
<fa :icon="faTimesCircle" v-if="type === 'error'"/>
|
||||
<fa :icon="faExclamationTriangle" v-if="type === 'warning'"/>
|
||||
<fa :icon="faInfoCircle" v-if="type === 'info'"/>
|
||||
<fa :icon="faQuestionCircle" v-if="type === 'question'"/>
|
||||
<fa :icon="faSpinner" pulse v-if="type === 'waiting'"/>
|
||||
</div>
|
||||
<header v-if="title" v-html="title"></header>
|
||||
<header v-if="title == null && user">{{ $t('enterUsername') }}</header>
|
||||
<div class="body" v-if="text" v-html="text"></div>
|
||||
<mk-input v-if="input" v-model:value="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></mk-input>
|
||||
<mk-input v-if="user" v-model:value="userInputValue" autofocus @keydown="onInputKeydown"><template #prefix>@</template></mk-input>
|
||||
<mk-select v-if="select" v-model:value="selectedValue" autofocus>
|
||||
<template v-if="select.items">
|
||||
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
|
||||
</template>
|
||||
<template v-else>
|
||||
<optgroup v-for="groupedItem in select.groupedItems" :label="groupedItem.label">
|
||||
<option v-for="item in groupedItem.items" :value="item.value">{{ item.text }}</option>
|
||||
</optgroup>
|
||||
</template>
|
||||
</mk-select>
|
||||
<div class="buttons" v-if="!iconOnly && (showOkButton || showCancelButton) && !actions">
|
||||
<mk-button inline @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user" :disabled="!canOk">{{ (showCancelButton || input || select || user) ? $t('ok') : $t('gotIt') }}</mk-button>
|
||||
<mk-button inline @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('cancel') }}</mk-button>
|
||||
</div>
|
||||
<div class="buttons" v-if="actions">
|
||||
<mk-button v-for="action in actions" inline @click="() => { action.callback(); close(); }" :primary="action.primary" :key="action.text">{{ action.text }}</mk-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -52,12 +50,10 @@ import MkInput from './ui/input.vue';
|
|||
import MkSelect from './ui/select.vue';
|
||||
import MkSignin from './signin.vue';
|
||||
import parseAcct from '../../misc/acct/parse';
|
||||
import XModal from './modal.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XModal,
|
||||
MkButton,
|
||||
MkInput,
|
||||
MkSelect,
|
||||
|
@ -65,9 +61,6 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
props: {
|
||||
showing: {
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
@ -118,7 +111,7 @@ export default defineComponent({
|
|||
},
|
||||
},
|
||||
|
||||
emits: ['done', 'closed'],
|
||||
emits: ['done'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
|
|
|
@ -72,7 +72,7 @@ export default defineComponent({
|
|||
if (this.$store.state.device.imageNewTab) {
|
||||
window.open(this.image.url, '_blank');
|
||||
} else {
|
||||
const viewer = os.popup(ImageViewer, {
|
||||
const viewer = os.modal(ImageViewer, {
|
||||
image: this.image
|
||||
});
|
||||
this.$once('hook:beforeDestroy', () => {
|
||||
|
|
|
@ -1,55 +1,43 @@
|
|||
<template>
|
||||
<x-modal :source="source" :no-center="noCenter" @click="close()" @closed="$emit('closed')" :showing="showing">
|
||||
<div class="rrevdjwt" :class="{ left: align === 'left' }" ref="items" :style="{ width: width + 'px' }">
|
||||
<template v-for="(item, i) in items.filter(item => item !== undefined)">
|
||||
<div v-if="item === null" class="divider" :key="i"></div>
|
||||
<span v-else-if="item.type === 'label'" class="label item" :key="i">
|
||||
<span>{{ item.text }}</span>
|
||||
</span>
|
||||
<router-link v-else-if="item.type === 'link'" :to="item.to" @click.native="close()" :tabindex="i" class="_button item" :key="i">
|
||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||
<span>{{ item.text }}</span>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</router-link>
|
||||
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item" :key="i">
|
||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||
<span>{{ item.text }}</span>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</a>
|
||||
<button v-else-if="item.type === 'user'" @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i">
|
||||
<mk-avatar :user="item.user" class="avatar"/><mk-user-name :user="item.user"/>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
<button v-else @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i">
|
||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||
<span>{{ item.text }}</span>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</x-modal>
|
||||
<div class="rrevdjwt" :class="{ left: align === 'left' }" ref="items" :style="{ width: width + 'px' }">
|
||||
<template v-for="(item, i) in items.filter(item => item !== undefined)">
|
||||
<div v-if="item === null" class="divider" :key="i"></div>
|
||||
<span v-else-if="item.type === 'label'" class="label item" :key="i">
|
||||
<span>{{ item.text }}</span>
|
||||
</span>
|
||||
<router-link v-else-if="item.type === 'link'" :to="item.to" @click.native="close()" :tabindex="i" class="_button item" :key="i">
|
||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||
<span>{{ item.text }}</span>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</router-link>
|
||||
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item" :key="i">
|
||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||
<span>{{ item.text }}</span>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</a>
|
||||
<button v-else-if="item.type === 'user'" @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i">
|
||||
<mk-avatar :user="item.user" class="avatar"/><mk-user-name :user="item.user"/>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
<button v-else @click="clicked(item.action)" :tabindex="i" class="_button item" :key="i">
|
||||
<fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||
<mk-avatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||
<span>{{ item.text }}</span>
|
||||
<i v-if="item.indicate"><fa :icon="faCircle"/></i>
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { faCircle } from '@fortawesome/free-solid-svg-icons';
|
||||
import XModal from './modal.vue';
|
||||
import { focusPrev, focusNext } from '@/scripts/focus';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XModal
|
||||
},
|
||||
props: {
|
||||
showing: {
|
||||
required: true
|
||||
},
|
||||
source: {
|
||||
required: true
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
required: true
|
||||
|
|
|
@ -18,6 +18,9 @@ import * as os from '@/os';
|
|||
// memo: 旧popup.vueのfixedプロパティに相当するものはsource要素の祖先を辿るなどして自動で判定できるのでは
|
||||
|
||||
export default defineComponent({
|
||||
provide: {
|
||||
modal: true
|
||||
},
|
||||
props: {
|
||||
showing: {
|
||||
type: Boolean,
|
||||
|
@ -59,58 +62,60 @@ export default defineComponent({
|
|||
|
||||
const popover = this.$refs.content as any;
|
||||
|
||||
const rect = this.source.getBoundingClientRect();
|
||||
const width = popover.offsetWidth;
|
||||
const height = popover.offsetHeight;
|
||||
new ResizeObserver((entries, observer) => {
|
||||
const rect = this.source.getBoundingClientRect();
|
||||
const width = popover.offsetWidth;
|
||||
const height = popover.offsetHeight;
|
||||
|
||||
let left;
|
||||
let top;
|
||||
let left;
|
||||
let top;
|
||||
|
||||
if (os.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;
|
||||
if (os.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 (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 (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 + height - window.pageYOffset > window.innerHeight) {
|
||||
top = window.innerHeight - height + window.pageYOffset;
|
||||
popover.style.transformOrigin = 'center';
|
||||
if (top < 0) {
|
||||
top = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (top < 0) {
|
||||
top = 0;
|
||||
}
|
||||
if (left < 0) {
|
||||
left = 0;
|
||||
}
|
||||
|
||||
if (left < 0) {
|
||||
left = 0;
|
||||
}
|
||||
|
||||
popover.style.left = left + 'px';
|
||||
popover.style.top = top + 'px';
|
||||
popover.style.left = left + 'px';
|
||||
popover.style.top = top + 'px';
|
||||
}).observe(popover);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||
import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||
import { parse } from '../../mfm/parse';
|
||||
|
@ -108,8 +108,6 @@ import XReactionsViewer from './reactions-viewer.vue';
|
|||
import XMediaList from './media-list.vue';
|
||||
import XCwButton from './cw-button.vue';
|
||||
import XPoll from './poll.vue';
|
||||
import MkUrlPreview from './url-preview.vue';
|
||||
import MkReactionPicker from './reaction-picker.vue';
|
||||
import { pleaseLogin } from '@/scripts/please-login';
|
||||
import { focusPrev, focusNext } from '@/scripts/focus';
|
||||
import { url } from '@/config';
|
||||
|
@ -133,7 +131,7 @@ export default defineComponent({
|
|||
XMediaList,
|
||||
XCwButton,
|
||||
XPoll,
|
||||
MkUrlPreview,
|
||||
MkUrlPreview: defineAsyncComponent(() => import('@/components/url-preview.vue')),
|
||||
},
|
||||
|
||||
inject: {
|
||||
|
@ -485,17 +483,17 @@ export default defineComponent({
|
|||
react(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
this.blur();
|
||||
const close = os.popup(MkReactionPicker, {
|
||||
source: this.$refs.reactButton,
|
||||
os.modal(defineAsyncComponent(() => import('@/components/reaction-picker.vue')), {
|
||||
showFocus: viaKeyboard,
|
||||
}, reaction => {
|
||||
os.api('notes/reactions/create', {
|
||||
noteId: this.appearNote.id,
|
||||
reaction: reaction
|
||||
}).then(() => {
|
||||
close();
|
||||
});
|
||||
}, this.focus);
|
||||
this.focus();
|
||||
}, {
|
||||
source: this.$refs.reactButton
|
||||
});
|
||||
},
|
||||
|
||||
reactDirectly(reaction) {
|
||||
|
|
|
@ -32,12 +32,11 @@ import { defineComponent } from 'vue';
|
|||
import paging from '@/scripts/paging';
|
||||
import XNote from './note.vue';
|
||||
import XList from './date-separated-list.vue';
|
||||
import MkButton from './ui/button.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XNote, XList, MkButton
|
||||
XNote, XList,
|
||||
},
|
||||
|
||||
mixins: [
|
||||
|
@ -83,9 +82,9 @@ export default defineComponent({
|
|||
updated(oldValue, newValue) {
|
||||
const i = this.notes.findIndex(n => n === oldValue);
|
||||
if (this.prop) {
|
||||
Vue.set(this.items[i], this.prop, newValue);
|
||||
this.items[i][this.prop] = newValue;
|
||||
} else {
|
||||
Vue.set(this.items, i, newValue);
|
||||
this.items[i] = newValue;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -57,9 +57,6 @@ import * as os from '@/os';
|
|||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
destroy: {
|
||||
required: true
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
required: true
|
||||
|
@ -94,7 +91,7 @@ export default defineComponent({
|
|||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.destroy();
|
||||
this.$emit('closed');
|
||||
}, 1100);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
<template>
|
||||
<x-modal @closed="$emit('closed')" @click="onBgClick" :showing="showing">
|
||||
<x-post-form ref="form" class="ulveipgl"
|
||||
:reply="reply"
|
||||
:renote="renote"
|
||||
:mention="mention"
|
||||
:specified="specified"
|
||||
:initial-text="initialText"
|
||||
:initial-note="initialNote"
|
||||
:instant="instant"
|
||||
@posted="onPosted"
|
||||
@cancel="onCanceled"
|
||||
/>
|
||||
</x-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import XModal from './modal.vue';
|
||||
import XPostForm from './post-form.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XModal,
|
||||
XPostForm,
|
||||
},
|
||||
|
||||
props: {
|
||||
showing: {
|
||||
required: true
|
||||
},
|
||||
reply: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
renote: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
mention: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
specified: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
initialText: {
|
||||
type: String,
|
||||
required: false
|
||||
},
|
||||
initialNote: {
|
||||
type: Object,
|
||||
required: false
|
||||
},
|
||||
instant: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
focus() {
|
||||
this.$refs.form.focus();
|
||||
},
|
||||
|
||||
onPosted() {
|
||||
this.$emit('done', 'posted');
|
||||
},
|
||||
|
||||
onCanceled() {
|
||||
this.$emit('done', 'canceled');
|
||||
},
|
||||
|
||||
onKeydown(e) {
|
||||
if (e.which === 27) { // Esc
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.$emit('done', 'canceled');
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.ulveipgl {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="gafaadew"
|
||||
<div class="gafaadew" :class="{ modal }"
|
||||
@dragover.stop="onDragover"
|
||||
@dragenter="onDragenter"
|
||||
@dragleave="onDragleave"
|
||||
|
@ -80,6 +80,8 @@ export default defineComponent({
|
|||
XPollEditor: defineAsyncComponent(() => import('./poll-editor.vue'))
|
||||
},
|
||||
|
||||
inject: ['modal'],
|
||||
|
||||
props: {
|
||||
reply: {
|
||||
type: Object,
|
||||
|
@ -417,7 +419,7 @@ export default defineComponent({
|
|||
// TODO: information dialog
|
||||
return;
|
||||
}
|
||||
const w = os.popup(MkVisibilityChooser, {
|
||||
const w = os.modal(MkVisibilityChooser, {
|
||||
source: this.$refs.visibilityButton,
|
||||
currentVisibility: this.visibility,
|
||||
currentLocalOnly: this.localOnly
|
||||
|
@ -433,7 +435,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
addVisibleUser() {
|
||||
const vm = os.popup(MkUserSelect, {});
|
||||
const vm = os.modal(MkUserSelect, {});
|
||||
vm.$once('selected', user => {
|
||||
this.visibleUsers.push(user);
|
||||
});
|
||||
|
@ -593,18 +595,18 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
cancel() {
|
||||
this.$emit('cancel');
|
||||
this.$emit('done');
|
||||
},
|
||||
|
||||
insertMention() {
|
||||
const vm = os.popup(MkUserSelect, {});
|
||||
const vm = os.modal(MkUserSelect, {});
|
||||
vm.$once('selected', user => {
|
||||
insertTextAtCursor(this.$refs.text, getAcct(user) + ' ');
|
||||
});
|
||||
},
|
||||
|
||||
async insertEmoji(ev) {
|
||||
const vm = os.popup(await import('./emoji-picker.vue'), {
|
||||
const vm = os.modal(await import('./emoji-picker.vue'), {
|
||||
source: ev.currentTarget || ev.target
|
||||
}).$once('chosen', emoji => {
|
||||
insertTextAtCursor(this.$refs.text, emoji);
|
||||
|
@ -636,6 +638,12 @@ export default defineComponent({
|
|||
position: relative;
|
||||
background: var(--panel);
|
||||
|
||||
&.modal {
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
> header {
|
||||
z-index: 1000;
|
||||
height: 66px;
|
||||
|
|
|
@ -1,36 +1,24 @@
|
|||
<template>
|
||||
<XModal :source="source" @closed="$emit('closed')" :showing="showing" @click="close" v-hotkey.global="keymap">
|
||||
<div class="rdfaahpb">
|
||||
<div class="buttons" ref="buttons" :class="{ showFocus }">
|
||||
<button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :tabindex="i + 1" :title="reaction" v-particle><x-reaction-icon :reaction="reaction"/></button>
|
||||
</div>
|
||||
<input class="text" v-model.trim="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
||||
<div class="rdfaahpb">
|
||||
<div class="buttons" ref="buttons" :class="{ showFocus }">
|
||||
<button class="_button" v-for="(reaction, i) in rs" :key="reaction" @click="react(reaction)" :tabindex="i + 1" :title="reaction" v-particle><x-reaction-icon :reaction="reaction"/></button>
|
||||
</div>
|
||||
</XModal>
|
||||
<input class="text" v-model.trim="text" :placeholder="$t('enterEmoji')" @keyup.enter="reactText" @input="tryReactText" v-autocomplete="{ model: 'text' }">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { emojiRegex } from '../../misc/emoji-regex';
|
||||
import XReactionIcon from './reaction-icon.vue';
|
||||
import XModal from './modal.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XModal,
|
||||
XReactionIcon,
|
||||
},
|
||||
|
||||
props: {
|
||||
showing: {
|
||||
required: true
|
||||
},
|
||||
|
||||
source: {
|
||||
required: true
|
||||
},
|
||||
|
||||
reactions: {
|
||||
required: false
|
||||
},
|
||||
|
|
|
@ -111,7 +111,7 @@ export default defineComponent({
|
|||
|
||||
this.closeDetails();
|
||||
if (!this.isHovering) return;
|
||||
this.details = os.popup(XDetails, {
|
||||
this.details = os.modal(XDetails, {
|
||||
reaction: this.reaction,
|
||||
users,
|
||||
count: this.count,
|
||||
|
|
|
@ -276,7 +276,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
async addAcount() {
|
||||
os.popup(await import('./signin-dialog.vue')).$once('login', res => {
|
||||
os.modal(await import('./signin-dialog.vue')).$once('login', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
os.dialog({
|
||||
type: 'success',
|
||||
|
@ -286,7 +286,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
async createAccount() {
|
||||
os.popup(await import('./signup-dialog.vue')).$once('signup', res => {
|
||||
os.modal(await import('./signup-dialog.vue')).$once('signup', res => {
|
||||
this.$store.dispatch('addAcount', res);
|
||||
this.switchAccountWithToken(res.i);
|
||||
});
|
||||
|
|
|
@ -166,7 +166,7 @@ export default defineComponent({
|
|||
id: notification.id
|
||||
});
|
||||
|
||||
os.popup(await import('@/components/toast.vue'), {
|
||||
os.modal(await import('@/components/toast.vue'), {
|
||||
notification
|
||||
});
|
||||
}
|
||||
|
|
|
@ -335,7 +335,7 @@ export default defineComponent({
|
|||
id: notification.id
|
||||
});
|
||||
|
||||
os.popup(await import('@/components/toast.vue'), {
|
||||
os.modal(await import('@/components/toast.vue'), {
|
||||
notification
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Component, defineAsyncComponent, ref } from 'vue';
|
||||
import { Component, defineAsyncComponent, markRaw, ref } from 'vue';
|
||||
import Stream from '@/scripts/stream';
|
||||
import { store } from '@/store';
|
||||
import { apiUrl } from '@/config';
|
||||
|
@ -44,46 +44,81 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
|
|||
return promise;
|
||||
}
|
||||
|
||||
export function popup(component: Component, props: Record<string, any>, callback?: Function) {
|
||||
export function popup(component: Component, props: Record<string, any>, callback?: Function, option?) {
|
||||
markRaw(component);
|
||||
const id = Math.random().toString(); // TODO: uuidとか使う
|
||||
const showing = ref(true);
|
||||
const popup = {
|
||||
const close = (...args) => {
|
||||
if (callback) callback(...args);
|
||||
showing.value = false;
|
||||
};
|
||||
const modal = {
|
||||
type: 'popup',
|
||||
component,
|
||||
props: {
|
||||
...props,
|
||||
showing
|
||||
},
|
||||
props,
|
||||
showing,
|
||||
done: (...args) => {
|
||||
if (callback) callback(...args);
|
||||
showing.value = false;
|
||||
},
|
||||
source: option?.source,
|
||||
done: close,
|
||||
bgClick: () => close(),
|
||||
closed: () => {
|
||||
store.commit('removePopup', id);
|
||||
},
|
||||
id,
|
||||
};
|
||||
store.commit('addPopup', popup);
|
||||
return () => {
|
||||
store.commit('addPopup', modal);
|
||||
return close;
|
||||
}
|
||||
|
||||
export function modal(component: Component, props: Record<string, any>, callback?: Function, option?) {
|
||||
markRaw(component);
|
||||
const id = Math.random().toString(); // TODO: uuidとか使う
|
||||
const showing = ref(true);
|
||||
const close = (...args) => {
|
||||
if (callback) callback(...args);
|
||||
showing.value = false;
|
||||
};
|
||||
const modal = {
|
||||
type: 'modal',
|
||||
component,
|
||||
props,
|
||||
showing,
|
||||
source: option?.source,
|
||||
done: close,
|
||||
bgClick: () => close(),
|
||||
closed: () => {
|
||||
store.commit('removePopup', id);
|
||||
},
|
||||
id,
|
||||
};
|
||||
store.commit('addPopup', modal);
|
||||
return close;
|
||||
}
|
||||
|
||||
export function dialog(props: Record<string, any>) {
|
||||
return new Promise((res, rej) => {
|
||||
popup(defineAsyncComponent(() => import('@/components/dialog.vue')), props, res);
|
||||
modal(defineAsyncComponent(() => import('@/components/dialog.vue')), props, result => {
|
||||
if (result) {
|
||||
res(result);
|
||||
} else {
|
||||
res({ canceled: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function menu(props: Record<string, any>) {
|
||||
const source = props.source; // TODO: sourceはpropsの外に出して追加の引数として受け取るようにする
|
||||
return new Promise((res, rej) => {
|
||||
popup(defineAsyncComponent(() => import('@/components/menu.vue')), props, res);
|
||||
modal(defineAsyncComponent(() => import('@/components/menu.vue')), props, res, {
|
||||
position: 'source',
|
||||
source
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function post(props: Record<string, any>) {
|
||||
return new Promise((res, rej) => {
|
||||
popup(defineAsyncComponent(() => import('@/components/post-form-dialog.vue')), props, res);
|
||||
modal(defineAsyncComponent(() => import('@/components/post-form.vue')), props, res);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -54,13 +54,13 @@ export default defineComponent({
|
|||
|
||||
methods: {
|
||||
signin() {
|
||||
os.popup(XSigninDialog, {
|
||||
os.modal(XSigninDialog, {
|
||||
autoSet: true
|
||||
});
|
||||
},
|
||||
|
||||
signup() {
|
||||
os.popup(XSignupDialog, {
|
||||
os.modal(XSignupDialog, {
|
||||
autoSet: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
info(instance) {
|
||||
os.popup(MkInstanceInfo, {
|
||||
os.modal(MkInstanceInfo, {
|
||||
instance: instance
|
||||
});
|
||||
}
|
||||
|
|
|
@ -550,7 +550,7 @@ export default defineComponent({
|
|||
host: q
|
||||
});
|
||||
}
|
||||
os.popup(MkInstanceInfo, {
|
||||
os.modal(MkInstanceInfo, {
|
||||
instance: instance
|
||||
});
|
||||
},
|
||||
|
|
|
@ -439,7 +439,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
showFollowing() {
|
||||
os.popup(MkUsersDialog, {
|
||||
os.modal(MkUsersDialog, {
|
||||
title: this.$t('instanceFollowing'),
|
||||
pagination: {
|
||||
endpoint: 'federation/following',
|
||||
|
@ -453,7 +453,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
showFollowers() {
|
||||
os.popup(MkUsersDialog, {
|
||||
os.modal(MkUsersDialog, {
|
||||
title: this.$t('instanceFollowers'),
|
||||
pagination: {
|
||||
endpoint: 'federation/followers',
|
||||
|
@ -467,7 +467,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
showUsers() {
|
||||
os.popup(MkUsersDialog, {
|
||||
os.modal(MkUsersDialog, {
|
||||
title: this.$t('instanceUsers'),
|
||||
pagination: {
|
||||
endpoint: 'federation/users',
|
||||
|
|
|
@ -452,7 +452,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
addPinUser() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
this.pinnedUsers = this.pinnedUsers.trim();
|
||||
this.pinnedUsers += '\n@' + getAcct(user);
|
||||
this.pinnedUsers = this.pinnedUsers.trim();
|
||||
|
@ -460,7 +460,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
chooseProxyAccount() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
this.proxyAccount = user;
|
||||
this.proxyAccountId = user.id;
|
||||
this.save(true);
|
||||
|
|
|
@ -180,7 +180,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
searchUser() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
this.show(user);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -132,7 +132,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
async startUser() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
this.$router.push(`/my/messaging/${getAcct(user)}`);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -220,7 +220,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
async insertEmoji(ev) {
|
||||
const vm = os.popup(await import('@/components/emoji-picker.vue'), {
|
||||
const vm = os.modal(await import('@/components/emoji-picker.vue'), {
|
||||
source: ev.currentTarget || ev.target
|
||||
}).$once('chosen', emoji => {
|
||||
insertTextAtCursor(this.$refs.text, emoji);
|
||||
|
|
|
@ -177,7 +177,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
addUser() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
this.users = this.users.trim();
|
||||
this.users += '\n@' + getAcct(user);
|
||||
this.users = this.users.trim();
|
||||
|
|
|
@ -89,7 +89,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
invite() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
os.api('users/groups/invite', {
|
||||
groupId: this.group.id,
|
||||
userId: user.id
|
||||
|
@ -134,7 +134,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
transfer() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
os.api('users/groups/transfer', {
|
||||
groupId: this.group.id,
|
||||
userId: user.id
|
||||
|
|
|
@ -88,7 +88,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
addUser() {
|
||||
os.popup(MkUserSelect, {}).$once('selected', user => {
|
||||
os.modal(MkUserSelect, {}).$once('selected', user => {
|
||||
os.api('users/lists/push', {
|
||||
listId: this.list.id,
|
||||
userId: user.id
|
||||
|
|
|
@ -26,7 +26,7 @@ export default defineComponent({
|
|||
},
|
||||
methods: {
|
||||
async generateToken() {
|
||||
os.popup(await import('@/components/token-generate-window.vue'), {
|
||||
os.modal(await import('@/components/token-generate-window.vue'), {
|
||||
}).$on('ok', async ({ name, permissions }) => {
|
||||
const { token } = await os.api('miauth/gen-token', {
|
||||
session: null,
|
||||
|
|
|
@ -114,7 +114,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
async configure() {
|
||||
os.popup(await import('@/components/notification-setting-window.vue'), {
|
||||
os.modal(await import('@/components/notification-setting-window.vue'), {
|
||||
includingTypes: this.$store.state.i.includingNotificationTypes,
|
||||
showGlobalToggle: false,
|
||||
}).$on('ok', async ({ includingTypes: value }: any) => {
|
||||
|
|
|
@ -58,7 +58,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
preview(ev) {
|
||||
const picker = os.popup(MkReactionPicker, {
|
||||
const picker = os.modal(MkReactionPicker, {
|
||||
source: ev.currentTarget || ev.target,
|
||||
reactions: this.splited,
|
||||
showFocus: false,
|
||||
|
@ -73,7 +73,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
async chooseEmoji(ev) {
|
||||
const vm = os.popup(await import('@/components/emoji-picker.vue'), {
|
||||
const vm = os.modal(await import('@/components/emoji-picker.vue'), {
|
||||
source: ev.currentTarget || ev.target
|
||||
}).$once('chosen', emoji => {
|
||||
this.reactions += emoji;
|
||||
|
|
|
@ -118,7 +118,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const token = permissions == null || permissions.length === 0 ? null : await new Promise(async (res, rej) => {
|
||||
os.popup(await import('@/components/token-generate-window.vue'), {
|
||||
os.modal(await import('@/components/token-generate-window.vue'), {
|
||||
title: this.$t('tokenRequested'),
|
||||
information: this.$t('pluginTokenRequestedDescription'),
|
||||
initialName: name,
|
||||
|
|
|
@ -60,7 +60,7 @@ export default defineComponent({
|
|||
if (this.title) text += `【${this.title}】\n`;
|
||||
if (this.text) text += `${this.text}\n`;
|
||||
if (this.url) text += `${this.url}`;
|
||||
os.popup(PostFormDialog, {
|
||||
os.modal(PostFormDialog, {
|
||||
instant: true,
|
||||
initialText: text.trim()
|
||||
}).$once('posted', () => {
|
||||
|
|
|
@ -189,7 +189,7 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
menu() {
|
||||
os.popup(XUserMenu, {
|
||||
os.modal(XUserMenu, {
|
||||
source: this.$refs.menu,
|
||||
user: this.user
|
||||
});
|
||||
|
|
|
@ -2,13 +2,17 @@
|
|||
<DeckUI v-if="deckmode"/>
|
||||
<DefaultUI v-else/>
|
||||
|
||||
<component v-for="popup in $store.state.popups" :is="popup.component" v-bind="popup.props" :key="popup.id" @done="popup.done" @closed="popup.closed"/>
|
||||
<XModal v-for="modal in $store.state.popups.filter(x => x.type === 'modal')" :key="modal.id" @closed="modal.closed" @click="modal.bgClick" :showing="modal.showing" :source="modal.source">
|
||||
<component :is="modal.component" v-bind="modal.props" @done="modal.done"/>
|
||||
</XModal>
|
||||
|
||||
<component v-for="popup in $store.state.popups.filter(x => x.type === 'popup')" :key="popup.id" :is="popup.component" v-bind="popup.props" @done="popup.done" @closed="popup.closed"/>
|
||||
|
||||
<div id="wait" v-if="$store.state.pendingApiRequestsCount > 0"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||
import DefaultUI from './default.vue';
|
||||
import DeckUI from './deck.vue';
|
||||
import { instanceName, deckmode } from '@/config';
|
||||
|
@ -17,6 +21,7 @@ export default defineComponent({
|
|||
components: {
|
||||
DefaultUI,
|
||||
DeckUI,
|
||||
XModal: defineAsyncComponent(() => import('@/components/modal.vue'))
|
||||
},
|
||||
|
||||
metaInfo: {
|
||||
|
|
|
@ -111,6 +111,7 @@ export const store = createStore({
|
|||
popups: [] as {
|
||||
id: any;
|
||||
component: any;
|
||||
type: 'popup' | 'modal',
|
||||
props: Record<string, any>;
|
||||
}[],
|
||||
fullView: false,
|
||||
|
|
|
@ -51,7 +51,7 @@ export default defineComponent({
|
|||
|
||||
methods: {
|
||||
async configure() {
|
||||
os.popup(await import('@/components/notification-setting-window.vue'), {
|
||||
os.modal(await import('@/components/notification-setting-window.vue'), {
|
||||
includingTypes: this.props.includingTypes,
|
||||
}).$on('ok', async ({ includingTypes }) => {
|
||||
this.props.includingTypes = includingTypes;
|
||||
|
|
|
@ -52,13 +52,13 @@ export default defineComponent({
|
|||
|
||||
methods: {
|
||||
signin() {
|
||||
os.popup(XSigninDialog, {
|
||||
os.modal(XSigninDialog, {
|
||||
autoSet: true
|
||||
});
|
||||
},
|
||||
|
||||
signup() {
|
||||
os.popup(XSignupDialog, {
|
||||
os.modal(XSignupDialog, {
|
||||
autoSet: true
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue