feat(client): improve toast component and show welcome message

This commit is contained in:
syuilo 2021-12-18 14:55:53 +09:00
parent f9e3fd7001
commit d6e85ffb59
6 changed files with 126 additions and 40 deletions

View file

@ -816,6 +816,7 @@ hide: "隠す"
leaveGroup: "グループから抜ける" leaveGroup: "グループから抜ける"
leaveGroupConfirm: "「{name}」から抜けますか?" leaveGroupConfirm: "「{name}」から抜けますか?"
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示" useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
welcomeBackWithName: "おかえりなさい、{name}さん"
_emailUnavailable: _emailUnavailable:
used: "既に使用されています" used: "既に使用されています"

View file

@ -0,0 +1,74 @@
<template>
<div class="mk-notification-toast" :style="{ zIndex }">
<transition name="notification-toast" appear @after-leave="$emit('closed')">
<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/>
</transition>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XNotification from './notification.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XNotification
},
props: {
notification: {
type: Object,
required: true
}
},
emits: ['closed'],
data() {
return {
showing: true,
zIndex: os.claimZIndex('high'),
};
},
mounted() {
setTimeout(() => {
this.showing = false;
}, 6000);
}
});
</script>
<style lang="scss" scoped>
.notification-toast-enter-active, .notification-toast-leave-active {
transition: opacity 0.3s, transform 0.3s !important;
}
.notification-toast-enter-from, .notification-toast-leave-to {
opacity: 0;
transform: translateX(-250px);
}
.mk-notification-toast {
position: fixed;
left: 0;
width: 250px;
top: 32px;
padding: 0 32px;
pointer-events: none;
@media (max-width: 700px) {
top: initial;
bottom: 112px;
padding: 0 16px;
}
@media (max-width: 500px) {
bottom: 92px;
padding: 0 8px;
}
> .notification {
height: 100%;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
border-radius: 8px;
overflow: hidden;
}
}
</style>

View file

@ -1,25 +1,25 @@
<template> <template>
<div class="mk-toast" :style="{ zIndex }"> <div class="mk-toast">
<transition name="notification-slide" appear @after-leave="$emit('closed')"> <transition name="toast" appear @after-leave="$emit('closed')">
<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/> <div v-if="showing" class="body _acrylic" :style="{ zIndex }">
<div class="message">
{{ message }}
</div>
</div>
</transition> </transition>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import XNotification from './notification.vue';
import * as os from '@/os'; import * as os from '@/os';
export default defineComponent({ export default defineComponent({
components: {
XNotification
},
props: { props: {
notification: { message: {
type: Object, type: String,
required: true required: true,
} },
}, },
emits: ['closed'], emits: ['closed'],
data() { data() {
@ -31,44 +31,41 @@ export default defineComponent({
mounted() { mounted() {
setTimeout(() => { setTimeout(() => {
this.showing = false; this.showing = false;
}, 6000); }, 4000);
} }
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.notification-slide-enter-active, .notification-slide-leave-active { .toast-enter-active, .toast-leave-active {
transition: opacity 0.3s, transform 0.3s !important; transition: opacity 0.3s, transform 0.3s !important;
} }
.notification-slide-enter-from, .notification-slide-leave-to { .toast-enter-from, .toast-leave-to {
opacity: 0; opacity: 0;
transform: translateX(-250px); transform: translateY(calc(0px - (100% - 32px)));
} }
.mk-toast { .mk-toast {
position: fixed; > .body {
left: 0; position: fixed;
width: 250px; left: 0;
top: 32px; right: 0;
padding: 0 32px; top: 0;
pointer-events: none; margin: 0 auto;
padding-top: 32px;
@media (max-width: 700px) { margin-top: -32px;
top: initial; min-width: 300px;
bottom: 112px; max-width: calc(100% - 32px);
padding: 0 16px; width: min-content;
}
@media (max-width: 500px) {
bottom: 92px;
padding: 0 8px;
}
> .notification {
height: 100%;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
border-radius: 8px; border-radius: 0 0 8px 8px;
overflow: hidden; overflow: clip;
text-align: center;
pointer-events: none;
> .message {
padding: 16px 24px;
}
} }
} }
</style> </style>

View file

@ -26,7 +26,7 @@ import { router } from '@/router';
import { applyTheme } from '@/scripts/theme'; import { applyTheme } from '@/scripts/theme';
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { stream, confirm, alert, post, popup } from '@/os'; import { stream, confirm, alert, post, popup, toast } from '@/os';
import * as sound from '@/scripts/sound'; import * as sound from '@/scripts/sound';
import { $i, refreshAccount, login, updateAccount, signout } from '@/account'; import { $i, refreshAccount, login, updateAccount, signout } from '@/account';
import { defaultStore, ColdDeviceStorage } from '@/store'; import { defaultStore, ColdDeviceStorage } from '@/store';
@ -342,6 +342,18 @@ if ($i) {
}); });
} }
const lastUsed = localStorage.getItem('lastUsed');
if (lastUsed) {
const lastUsedDate = parseInt(lastUsed, 10);
// 二時間以上前なら
if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) {
toast(i18n.t('welcomeBackWithName', {
name: $i.name || $i.username,
}));
}
}
localStorage.setItem('lastUsed', Date.now().toString());
if ('Notification' in window) { if ('Notification' in window) {
// 許可を得ていなかったらリクエスト // 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') { if (Notification.permission === 'default') {

View file

@ -221,7 +221,9 @@ export function modalPageWindow(path: string) {
} }
export function toast(message: string) { export function toast(message: string) {
// TODO popup(import('@/components/toast.vue'), {
message
}, {}, 'closed');
} }
export function alert(props: { export function alert(props: {

View file

@ -34,7 +34,7 @@ export default defineComponent({
id: notification.id id: notification.id
}); });
popup(import('@/components/toast.vue'), { popup(import('@/components/notification-toast.vue'), {
notification notification
}, {}, 'closed'); }, {}, 'closed');
} }