Merge branch 'develop' into swn
This commit is contained in:
@@ -11,6 +11,7 @@ type Account = {
|
||||
token: string;
|
||||
isModerator: boolean;
|
||||
isAdmin: boolean;
|
||||
isDeleted: boolean;
|
||||
};
|
||||
|
||||
const data = localStorage.getItem('account');
|
||||
@@ -29,16 +30,18 @@ export async function signout() {
|
||||
//#endregion
|
||||
|
||||
//#region Remove push notification registration
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
const push = await registration.pushManager.getSubscription();
|
||||
if (!push) return;
|
||||
await fetch(`${apiUrl}/sw/unregister`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
i: $i.token,
|
||||
endpoint: push.endpoint,
|
||||
}),
|
||||
});
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
const push = await registration.pushManager.getSubscription();
|
||||
if (!push) return;
|
||||
await fetch(`${apiUrl}/sw/unregister`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
i: $i.token,
|
||||
endpoint: push.endpoint,
|
||||
}),
|
||||
});
|
||||
} catch (e) {}
|
||||
//#endregion
|
||||
|
||||
document.cookie = `igi=; path=/`;
|
||||
|
||||
@@ -118,6 +118,8 @@ export default defineComponent({
|
||||
|
||||
&:not(.noGap) {
|
||||
> .notes {
|
||||
background: var(--bg);
|
||||
|
||||
.qtqtichx {
|
||||
background: var(--panel);
|
||||
border-radius: var(--radius);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<p class="mfcuwfyp" v-else-if="empty">{{ $ts.noNotifications }}</p>
|
||||
|
||||
<div v-else>
|
||||
<XList class="notifications" :items="items" v-slot="{ item: notification }" :no-gap="true">
|
||||
<XList class="elsfgstc" :items="items" v-slot="{ item: notification }" :no-gap="true">
|
||||
<XNote v-if="['reply', 'quote', 'mention'].includes(notification.type)" :note="notification.note" @update:note="noteUpdated(notification.note, $event)" :key="notification.id"/>
|
||||
<XNotification v-else :notification="notification" :with-time="true" :full="true" class="_panel notification" :key="notification.id"/>
|
||||
</XList>
|
||||
@@ -163,4 +163,8 @@ export default defineComponent({
|
||||
text-align: center;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.elsfgstc {
|
||||
background: var(--panel);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -367,7 +367,12 @@ export default defineComponent({
|
||||
this.cw = init.cw;
|
||||
this.useCw = init.cw != null;
|
||||
if (init.poll) {
|
||||
this.poll = init.poll;
|
||||
this.poll = {
|
||||
choices: init.poll.choices.map(x => x.text),
|
||||
multiple: init.poll.multiple,
|
||||
expiresAt: init.poll.expiresAt,
|
||||
expiredAfter: init.poll.expiredAfter,
|
||||
};
|
||||
}
|
||||
this.visibility = init.visibility;
|
||||
this.localOnly = init.localOnly;
|
||||
|
||||
@@ -330,6 +330,13 @@ for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) {
|
||||
}
|
||||
|
||||
if ($i) {
|
||||
if ($i.isDeleted) {
|
||||
dialog({
|
||||
type: 'warning',
|
||||
text: i18n.locale.accountDeletionInProgress,
|
||||
});
|
||||
}
|
||||
|
||||
if ('Notification' in window) {
|
||||
// 許可を得ていなかったらリクエスト
|
||||
if (Notification.permission === 'default') {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<XNotifications class="_content" @before="before" @after="after" page/>
|
||||
<div class="clupoqwt" v-size="{ min: [800] }">
|
||||
<XNotifications class="notifications" @before="before" @after="after" page/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -43,3 +43,17 @@ export default defineComponent({
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.clupoqwt {
|
||||
&.min-width_800px {
|
||||
background: var(--bg);
|
||||
padding: 32px 0;
|
||||
|
||||
> .notifications {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
67
src/client/pages/settings/delete-account.vue
Normal file
67
src/client/pages/settings/delete-account.vue
Normal file
@@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<FormBase>
|
||||
<FormInfo warn>{{ $ts._accountDelete.mayTakeTime }}</FormInfo>
|
||||
<FormInfo>{{ $ts._accountDelete.sendEmail }}</FormInfo>
|
||||
<FormButton @click="deleteAccount" danger v-if="!$i.isDeleted">{{ $ts._accountDelete.requestAccountDelete }}</FormButton>
|
||||
<FormButton disabled v-else>{{ $ts._accountDelete.inProgress }}</FormButton>
|
||||
</FormBase>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||
import FormInfo from '@client/components/form/info.vue';
|
||||
import FormBase from '@client/components/form/base.vue';
|
||||
import FormGroup from '@client/components/form/group.vue';
|
||||
import FormButton from '@client/components/form/button.vue';
|
||||
import * as os from '@client/os';
|
||||
import { debug } from '@client/config';
|
||||
import { signout } from '@client/account';
|
||||
import * as symbols from '@client/symbols';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
FormBase,
|
||||
FormButton,
|
||||
FormGroup,
|
||||
FormInfo,
|
||||
},
|
||||
|
||||
emits: ['info'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
[symbols.PAGE_INFO]: {
|
||||
title: this.$ts._accountDelete.accountDelete,
|
||||
icon: 'fas fa-exclamation-triangle'
|
||||
},
|
||||
debug,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$emit('info', this[symbols.PAGE_INFO]);
|
||||
},
|
||||
|
||||
methods: {
|
||||
async deleteAccount() {
|
||||
const { canceled, result: password } = await os.dialog({
|
||||
title: this.$ts.password,
|
||||
input: {
|
||||
type: 'password'
|
||||
}
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('i/delete-account', {
|
||||
password: password
|
||||
});
|
||||
|
||||
await os.dialog({
|
||||
title: this.$ts._accountDelete.started,
|
||||
});
|
||||
|
||||
signout();
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -132,6 +132,7 @@ export default defineComponent({
|
||||
case 'account-info': return defineAsyncComponent(() => import('./account-info.vue'));
|
||||
case 'update': return defineAsyncComponent(() => import('./update.vue'));
|
||||
case 'registry': return defineAsyncComponent(() => import('./registry.vue'));
|
||||
case 'delete-account': return defineAsyncComponent(() => import('./delete-account.vue'));
|
||||
case 'experimental-features': return defineAsyncComponent(() => import('./experimental-features.vue'));
|
||||
}
|
||||
if (page.value.startsWith('registry/keys/system/')) {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<FormLink to="/bios" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>BIOS</FormLink>
|
||||
<FormLink to="/cli" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>CLI</FormLink>
|
||||
|
||||
<FormButton @click="closeAccount" danger>{{ $ts.closeAccount }}</FormButton>
|
||||
<FormLink to="./delete-account"><template #icon><i class="fas fa-exclamation-triangle"></i></template>{{ $ts.closeAccount }}</FormLink>
|
||||
</FormBase>
|
||||
</template>
|
||||
|
||||
@@ -41,7 +41,6 @@ import FormButton from '@client/components/form/button.vue';
|
||||
import * as os from '@client/os';
|
||||
import { debug } from '@client/config';
|
||||
import { defaultStore } from '@client/store';
|
||||
import { signout } from '@client/account';
|
||||
import { unisonReload } from '@client/scripts/unison-reload';
|
||||
import * as symbols from '@client/symbols';
|
||||
|
||||
@@ -92,22 +91,6 @@ export default defineComponent({
|
||||
os.popup(import('@client/components/taskmanager.vue'), {
|
||||
}, {}, 'closed');
|
||||
},
|
||||
|
||||
closeAccount() {
|
||||
os.dialog({
|
||||
title: this.$ts.password,
|
||||
input: {
|
||||
type: 'password'
|
||||
}
|
||||
}).then(({ canceled, result: password }) => {
|
||||
if (canceled) return;
|
||||
os.api('i/delete-account', {
|
||||
password: password
|
||||
}).then(() => {
|
||||
signout();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="cmuxhskf" v-hotkey.global="keymap">
|
||||
<div class="cmuxhskf" v-hotkey.global="keymap" v-size="{ min: [800] }">
|
||||
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block _isolated"/>
|
||||
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block _isolated" fixed/>
|
||||
<div class="tabs">
|
||||
@@ -19,17 +19,19 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="new" v-if="queue > 0"><button class="_buttonPrimary" @click="top()">{{ $ts.newNoteRecived }}</button></div>
|
||||
<XTimeline ref="tl" class="tl"
|
||||
:key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src"
|
||||
:src="src"
|
||||
:list="list ? list.id : null"
|
||||
:antenna="antenna ? antenna.id : null"
|
||||
:channel="channel ? channel.id : null"
|
||||
:sound="true"
|
||||
@before="before()"
|
||||
@after="after()"
|
||||
@queue="queueUpdated"
|
||||
/>
|
||||
<div class="tl">
|
||||
<XTimeline ref="tl" class="tl"
|
||||
:key="src === 'list' ? `list:${list.id}` : src === 'antenna' ? `antenna:${antenna.id}` : src === 'channel' ? `channel:${channel.id}` : src"
|
||||
:src="src"
|
||||
:list="list ? list.id : null"
|
||||
:antenna="antenna ? antenna.id : null"
|
||||
:channel="channel ? channel.id : null"
|
||||
:sound="true"
|
||||
@before="before()"
|
||||
@after="after()"
|
||||
@queue="queueUpdated"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -231,6 +233,7 @@ export default defineComponent({
|
||||
padding: 0 8px;
|
||||
white-space: nowrap;
|
||||
overflow: auto;
|
||||
border-bottom: solid 0.5px var(--divider);
|
||||
|
||||
// 影の都合上
|
||||
position: relative;
|
||||
@@ -287,8 +290,16 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
> .tl {
|
||||
border-top: solid 0.5px var(--divider);
|
||||
&.min-width_800px {
|
||||
> .tl {
|
||||
background: var(--bg);
|
||||
padding: 32px 0;
|
||||
|
||||
> .tl {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -65,7 +65,7 @@ export class Autocomplete {
|
||||
*/
|
||||
private onInput() {
|
||||
const caretPos = this.textarea.selectionStart;
|
||||
const text = this.text.substr(0, caretPos).split('\n').pop();
|
||||
const text = this.text.substr(0, caretPos).split('\n').pop()!;
|
||||
|
||||
const mentionIndex = text.lastIndexOf('@');
|
||||
const hashtagIndex = text.lastIndexOf('#');
|
||||
@@ -83,7 +83,7 @@ export class Autocomplete {
|
||||
|
||||
const isMention = mentionIndex != -1;
|
||||
const isHashtag = hashtagIndex != -1;
|
||||
const isEmoji = emojiIndex != -1;
|
||||
const isEmoji = emojiIndex != -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':');
|
||||
|
||||
let opened = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user