This commit is contained in:
syuilo 2020-09-06 18:38:09 +09:00
parent 3762116c17
commit d79a1a4e0e
36 changed files with 135 additions and 130 deletions

View File

@ -376,7 +376,7 @@ export default defineComponent({
chooseUser() {
this.close();
const vm = this.$root.new(MkUserSelect, {});
const vm = os.popup(MkUserSelect, {});
vm.$once('selected', user => {
this.complete('user', user);
});

View File

@ -43,7 +43,7 @@ export default defineComponent({
icon: faCog,
text: this.$t('notificationSetting'),
action: async () => {
this.$root.new(await import('../notification-setting-window.vue'), {
os.popup(await import('../notification-setting-window.vue'), {
includingTypes: this.column.includingTypes,
}).$on('ok', async ({ includingTypes }) => {
this.$set(this.column, 'includingTypes', includingTypes);

View File

@ -1,5 +1,5 @@
<template>
<x-modal ref="modal" @closed="$store.commit('removePopup', id)" @click="onBgClick" :showing="showing">
<x-modal ref="modal" @closed="destroy" @click="onBgClick" :showing="showing">
<div class="mk-dialog" :class="{ iconOnly }">
<template v-if="type == 'signin'">
<mk-signin/>
@ -65,7 +65,10 @@ export default defineComponent({
},
props: {
id: {
destroy: {
required: true
},
emit: {
required: true
},
type: {
@ -160,7 +163,7 @@ export default defineComponent({
methods: {
done(canceled, result?) {
this.showing = false;
os.dialogCallbacks[this.id]({ canceled, result });
this.emit({ canceled, result });
},
async ok() {

View File

@ -72,7 +72,7 @@ export default defineComponent({
if (this.$store.state.device.imageNewTab) {
window.open(this.image.url, '_blank');
} else {
const viewer = this.$root.new(ImageViewer, {
const viewer = os.popup(ImageViewer, {
image: this.image
});
this.$once('hook:beforeDestroy', () => {

View File

@ -1,5 +1,5 @@
<template>
<x-modal :source="source" :no-center="noCenter" ref="popup" @click="close()" @closed="$store.commit('removePopup', id)" :showing="showing">
<x-modal :source="source" :no-center="noCenter" ref="popup" @click="close()" @closed="destroy" :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>
@ -44,7 +44,7 @@ export default defineComponent({
XModal
},
props: {
id: {
destroy: {
required: true
},
source: {

View File

@ -110,7 +110,7 @@ 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 { pleaseLogin } from '@/scripts/please-login';
import { focusPrev, focusNext } from '@/scripts/focus';
import { url } from '@/config';
import copyToClipboard from '@/scripts/copy-to-clipboard';
@ -441,7 +441,7 @@ export default defineComponent({
},
reply(viaKeyboard = false) {
pleaseLogin(this.$root);
pleaseLogin();
this.$root.post({
reply: this.appearNote,
animation: !viaKeyboard,
@ -451,7 +451,7 @@ export default defineComponent({
},
renote(viaKeyboard = false) {
pleaseLogin(this.$root);
pleaseLogin();
this.blur();
os.menu({
items: [{
@ -483,21 +483,19 @@ export default defineComponent({
},
react(viaKeyboard = false) {
pleaseLogin(this.$root);
pleaseLogin();
this.blur();
const picker = this.$root.new(MkReactionPicker, {
const close = os.popup(MkReactionPicker, {
source: this.$refs.reactButton,
showFocus: viaKeyboard,
});
picker.$once('chosen', reaction => {
}, reaction => {
os.api('notes/reactions/create', {
noteId: this.appearNote.id,
reaction: reaction
}).then(() => {
picker.close();
close();
});
});
picker.$once('closed', this.focus);
}, this.focus);
},
reactDirectly(reaction) {
@ -516,7 +514,7 @@ export default defineComponent({
},
favorite() {
pleaseLogin(this.$root);
pleaseLogin();
os.api('notes/favorites/create', {
noteId: this.appearNote.id
}).then(() => {

View File

@ -3,43 +3,48 @@
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<circle fill="none" cx="64" cy="64">
<animate attributeName="r"
begin="0s" dur="0.5s"
values="4; 32"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.165, 0.84, 0.44, 1"
repeatCount="1" />
begin="0s" dur="0.5s"
values="4; 32"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.165, 0.84, 0.44, 1"
repeatCount="1"
/>
<animate attributeName="stroke-width"
begin="0s" dur="0.5s"
values="16; 0"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="1" />
begin="0s" dur="0.5s"
values="16; 0"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="1"
/>
</circle>
<g fill="none" fill-rule="evenodd">
<circle v-for="(particle, i) in particles" :key="i" :fill="particle.color">
<animate attributeName="r"
begin="0s" dur="0.8s"
:values="`${particle.size}; 0`"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.165, 0.84, 0.44, 1"
repeatCount="1" />
begin="0s" dur="0.8s"
:values="`${particle.size}; 0`"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.165, 0.84, 0.44, 1"
repeatCount="1"
/>
<animate attributeName="cx"
begin="0s" dur="0.8s"
:values="`${particle.xA}; ${particle.xB}`"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="1" />
begin="0s" dur="0.8s"
:values="`${particle.xA}; ${particle.xB}`"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="1"
/>
<animate attributeName="cy"
begin="0s" dur="0.8s"
:values="`${particle.yA}; ${particle.yB}`"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="1" />
begin="0s" dur="0.8s"
:values="`${particle.yA}; ${particle.yB}`"
calcMode="spline"
keyTimes="0; 1"
keySplines="0.3, 0.61, 0.355, 1"
repeatCount="1"
/>
</circle>
</g>
</svg>
@ -52,6 +57,9 @@ import * as os from '@/os';
export default defineComponent({
props: {
destroy: {
required: true
},
x: {
type: Number,
required: true
@ -86,7 +94,7 @@ export default defineComponent({
},
mounted() {
setTimeout(() => {
this.destroyDom();
this.destroy();
}, 1100);
}
});

View File

@ -417,7 +417,7 @@ export default defineComponent({
// TODO: information dialog
return;
}
const w = this.$root.new(MkVisibilityChooser, {
const w = os.popup(MkVisibilityChooser, {
source: this.$refs.visibilityButton,
currentVisibility: this.visibility,
currentLocalOnly: this.localOnly
@ -433,7 +433,7 @@ export default defineComponent({
},
addVisibleUser() {
const vm = this.$root.new(MkUserSelect, {});
const vm = os.popup(MkUserSelect, {});
vm.$once('selected', user => {
this.visibleUsers.push(user);
});
@ -597,14 +597,14 @@ export default defineComponent({
},
insertMention() {
const vm = this.$root.new(MkUserSelect, {});
const vm = os.popup(MkUserSelect, {});
vm.$once('selected', user => {
insertTextAtCursor(this.$refs.text, getAcct(user) + ' ');
});
},
async insertEmoji(ev) {
const vm = this.$root.new(await import('./emoji-picker.vue'), {
const vm = os.popup(await import('./emoji-picker.vue'), {
source: ev.currentTarget || ev.target
}).$once('chosen', emoji => {
insertTextAtCursor(this.$refs.text, emoji);

View File

@ -111,7 +111,7 @@ export default defineComponent({
this.closeDetails();
if (!this.isHovering) return;
this.details = this.$root.new(XDetails, {
this.details = os.popup(XDetails, {
reaction: this.reaction,
users,
count: this.count,

View File

@ -276,7 +276,7 @@ export default defineComponent({
},
async addAcount() {
this.$root.new(await import('./signin-dialog.vue')).$once('login', res => {
os.popup(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() {
this.$root.new(await import('./signup-dialog.vue')).$once('signup', res => {
os.popup(await import('./signup-dialog.vue')).$once('signup', res => {
this.$store.dispatch('addAcount', res);
this.switchAccountWithToken(res.i);
});

View File

@ -166,7 +166,7 @@ export default defineComponent({
id: notification.id
});
this.$root.new(await import('@/components/toast.vue'), {
os.popup(await import('@/components/toast.vue'), {
notification
});
}

View File

@ -335,7 +335,7 @@ export default defineComponent({
id: notification.id
});
this.$root.new(await import('@/components/toast.vue'), {
os.popup(await import('@/components/toast.vue'), {
notification
});
}

View File

@ -11,6 +11,6 @@ export default function(app: App) {
app.directive('userPreview', userPreview);
app.directive('user-preview', userPreview);
app.directive('size', size);
//app.directive('particle', particle);
app.directive('particle', particle);
app.directive('tooltip', tooltip);
}

View File

@ -1,24 +1,18 @@
import Particle from '@/components/particle.vue';
import { popup } from '@/os';
export default {
bind(el, binding, vn) {
mounted(el, binding, vn) {
// 明示的に false であればバインドしない
if (binding.value === false) return;
el.addEventListener('click', () => {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.clientWidth / 2);
const y = rect.top + (el.clientHeight / 2);
const particle = new Particle({
parent: vn.context,
propsData: {
x,
y
}
}).$mount();
document.body.appendChild(particle.$el);
popup(Particle, { x, y });
});
}
};

View File

@ -1,4 +1,4 @@
import { defineAsyncComponent } from 'vue';
import { Component, defineAsyncComponent } from 'vue';
import Stream from '@/scripts/stream';
import { store } from '@/store';
import { apiUrl } from '@/config';
@ -8,8 +8,6 @@ export const isMobile = /mobile|iphone|ipad|android/.test(ua);
export const stream = new Stream();
export const dialogCallbacks = {};
export function api(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) {
store.commit('beginApiRequest');
@ -46,17 +44,36 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
return promise;
}
export function popup(component: Component, props: Record<string, any>, eventHandler?: Function, closedCallback?: Function) {
const id = Math.random().toString(); // TODO: uuidとか使う
const destroy = () => {
store.commit('removePopup', id);
if (closedCallback) closedCallback();
};
const popup = {
component,
props: {
...props,
destroy,
emit: (...args) => {
if (eventHandler) eventHandler(...args);
}
},
id,
};
store.commit('addPopup', popup);
return destroy;
}
export function dialog(props: Record<string, any>) {
return store.dispatch('popup', {
component: defineAsyncComponent(() => import('@/components/dialog.vue')),
props
return new Promise((res, rej) => {
popup(defineAsyncComponent(() => import('@/components/dialog.vue')), props, res);
});
}
export function menu(props: Record<string, any>) {
return store.dispatch('popup', {
component: defineAsyncComponent(() => import('@/components/menu.vue')),
props
return new Promise((res, rej) => {
return popup(defineAsyncComponent(() => import('@/components/menu.vue')), props, res);
});
}

View File

@ -54,13 +54,13 @@ export default defineComponent({
methods: {
signin() {
this.$root.new(XSigninDialog, {
os.popup(XSigninDialog, {
autoSet: true
});
},
signup() {
this.$root.new(XSignupDialog, {
os.popup(XSignupDialog, {
autoSet: true
});
}

View File

@ -125,7 +125,7 @@ export default defineComponent({
},
info(instance) {
this.$root.new(MkInstanceInfo, {
os.popup(MkInstanceInfo, {
instance: instance
});
}

View File

@ -550,7 +550,7 @@ export default defineComponent({
host: q
});
}
this.$root.new(MkInstanceInfo, {
os.popup(MkInstanceInfo, {
instance: instance
});
},

View File

@ -439,7 +439,7 @@ export default defineComponent({
},
showFollowing() {
this.$root.new(MkUsersDialog, {
os.popup(MkUsersDialog, {
title: this.$t('instanceFollowing'),
pagination: {
endpoint: 'federation/following',
@ -453,7 +453,7 @@ export default defineComponent({
},
showFollowers() {
this.$root.new(MkUsersDialog, {
os.popup(MkUsersDialog, {
title: this.$t('instanceFollowers'),
pagination: {
endpoint: 'federation/followers',
@ -467,7 +467,7 @@ export default defineComponent({
},
showUsers() {
this.$root.new(MkUsersDialog, {
os.popup(MkUsersDialog, {
title: this.$t('instanceUsers'),
pagination: {
endpoint: 'federation/users',

View File

@ -452,7 +452,7 @@ export default defineComponent({
},
addPinUser() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(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() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
this.proxyAccount = user;
this.proxyAccountId = user.id;
this.save(true);

View File

@ -180,7 +180,7 @@ export default defineComponent({
},
searchUser() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
this.show(user);
});
},

View File

@ -132,7 +132,7 @@ export default defineComponent({
},
async startUser() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
this.$router.push(`/my/messaging/${getAcct(user)}`);
});
},

View File

@ -220,7 +220,7 @@ export default defineComponent({
},
async insertEmoji(ev) {
const vm = this.$root.new(await import('@/components/emoji-picker.vue'), {
const vm = os.popup(await import('@/components/emoji-picker.vue'), {
source: ev.currentTarget || ev.target
}).$once('chosen', emoji => {
insertTextAtCursor(this.$refs.text, emoji);

View File

@ -177,7 +177,7 @@ export default defineComponent({
},
addUser() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
this.users = this.users.trim();
this.users += '\n@' + getAcct(user);
this.users = this.users.trim();

View File

@ -89,7 +89,7 @@ export default defineComponent({
},
invite() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
os.api('users/groups/invite', {
groupId: this.group.id,
userId: user.id
@ -134,7 +134,7 @@ export default defineComponent({
},
transfer() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
os.api('users/groups/transfer', {
groupId: this.group.id,
userId: user.id

View File

@ -88,7 +88,7 @@ export default defineComponent({
},
addUser() {
this.$root.new(MkUserSelect, {}).$once('selected', user => {
os.popup(MkUserSelect, {}).$once('selected', user => {
os.api('users/lists/push', {
listId: this.list.id,
userId: user.id

View File

@ -26,7 +26,7 @@ export default defineComponent({
},
methods: {
async generateToken() {
this.$root.new(await import('@/components/token-generate-window.vue'), {
os.popup(await import('@/components/token-generate-window.vue'), {
}).$on('ok', async ({ name, permissions }) => {
const { token } = await os.api('miauth/gen-token', {
session: null,

View File

@ -114,7 +114,7 @@ export default defineComponent({
},
async configure() {
this.$root.new(await import('@/components/notification-setting-window.vue'), {
os.popup(await import('@/components/notification-setting-window.vue'), {
includingTypes: this.$store.state.i.includingNotificationTypes,
showGlobalToggle: false,
}).$on('ok', async ({ includingTypes: value }: any) => {

View File

@ -58,7 +58,7 @@ export default defineComponent({
},
preview(ev) {
const picker = this.$root.new(MkReactionPicker, {
const picker = os.popup(MkReactionPicker, {
source: ev.currentTarget || ev.target,
reactions: this.splited,
showFocus: false,
@ -73,7 +73,7 @@ export default defineComponent({
},
async chooseEmoji(ev) {
const vm = this.$root.new(await import('@/components/emoji-picker.vue'), {
const vm = os.popup(await import('@/components/emoji-picker.vue'), {
source: ev.currentTarget || ev.target
}).$once('chosen', emoji => {
this.reactions += emoji;

View File

@ -118,7 +118,7 @@ export default defineComponent({
}
const token = permissions == null || permissions.length === 0 ? null : await new Promise(async (res, rej) => {
this.$root.new(await import('@/components/token-generate-window.vue'), {
os.popup(await import('@/components/token-generate-window.vue'), {
title: this.$t('tokenRequested'),
information: this.$t('pluginTokenRequestedDescription'),
initialName: name,

View File

@ -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}`;
this.$root.new(PostFormDialog, {
os.popup(PostFormDialog, {
instant: true,
initialText: text.trim()
}).$once('posted', () => {

View File

@ -189,7 +189,7 @@ export default defineComponent({
},
menu() {
this.$root.new(XUserMenu, {
os.popup(XUserMenu, {
source: this.$refs.menu,
user: this.user
});

View File

@ -1,10 +1,14 @@
export default ($root: any) => {
if ($root.$store.getters.isSignedIn) return;
import { locale } from '@/i18n';
import { dialog } from '@/os';
import { store } from '@/store';
os.dialog({
title: $root.$t('signinRequired'),
export function pleaseLogin() {
if (store.getters.isSignedIn) return;
dialog({
title: locale['signinRequired'],
text: null
});
throw new Error('signin required');
};
}

View File

@ -5,7 +5,7 @@ import { faSatelliteDish, faTerminal, faHashtag, faBroadcastTower, faFireAlt, fa
import { faBell, faEnvelope, faComments } from '@fortawesome/free-regular-svg-icons';
import { AiScript, utils, values } from '@syuilo/aiscript';
import { deckmode } from '@/config';
import { api, dialogCallbacks } from '@/os';
import { api } from '@/os';
import { erase } from '../prelude/array';
export const defaultSettings = {
@ -371,25 +371,6 @@ export const store = createStore({
ctx.commit('settings/init', me.clientData);
}
},
popup(ctx, { component, props }) {
return new Promise((res, rej) => {
const id = Math.random().toString(); // TODO: uuidとか使う
const popup = {
component,
props: {
...props,
id
},
id,
};
dialogCallbacks[id] = result => {
delete dialogCallbacks[id];
res(result);
};
ctx.commit('addPopup', popup);
});
},
},
modules: {

View File

@ -51,7 +51,7 @@ export default defineComponent({
methods: {
async configure() {
this.$root.new(await import('@/components/notification-setting-window.vue'), {
os.popup(await import('@/components/notification-setting-window.vue'), {
includingTypes: this.props.includingTypes,
}).$on('ok', async ({ includingTypes }) => {
this.props.includingTypes = includingTypes;

View File

@ -52,13 +52,13 @@ export default defineComponent({
methods: {
signin() {
this.$root.new(XSigninDialog, {
os.popup(XSigninDialog, {
autoSet: true
});
},
signup() {
this.$root.new(XSignupDialog, {
os.popup(XSignupDialog, {
autoSet: true
});
}