From d6e85ffb596632892347b93661b7ddb9f66db6c6 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Sat, 18 Dec 2021 14:55:53 +0900 Subject: [PATCH] feat(client): improve toast component and show welcome message --- locales/ja-JP.yml | 1 + .../src/components/notification-toast.vue | 74 +++++++++++++++++++ packages/client/src/components/toast.vue | 71 +++++++++--------- packages/client/src/init.ts | 14 +++- packages/client/src/os.ts | 4 +- packages/client/src/ui/_common_/common.vue | 2 +- 6 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 packages/client/src/components/notification-toast.vue diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index daac05c66c..084fd6448e 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -816,6 +816,7 @@ hide: "隠す" leaveGroup: "グループから抜ける" leaveGroupConfirm: "「{name}」から抜けますか?" useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示" +welcomeBackWithName: "おかえりなさい、{name}さん" _emailUnavailable: used: "既に使用されています" diff --git a/packages/client/src/components/notification-toast.vue b/packages/client/src/components/notification-toast.vue new file mode 100644 index 0000000000..5449409ccc --- /dev/null +++ b/packages/client/src/components/notification-toast.vue @@ -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> diff --git a/packages/client/src/components/toast.vue b/packages/client/src/components/toast.vue index 02b61e5bef..d9f0aa5eaa 100644 --- a/packages/client/src/components/toast.vue +++ b/packages/client/src/components/toast.vue @@ -1,25 +1,25 @@ <template> -<div class="mk-toast" :style="{ zIndex }"> - <transition name="notification-slide" appear @after-leave="$emit('closed')"> - <XNotification v-if="showing" :notification="notification" class="notification _acrylic"/> +<div class="mk-toast"> + <transition name="toast" appear @after-leave="$emit('closed')"> + <div v-if="showing" class="body _acrylic" :style="{ zIndex }"> + <div class="message"> + {{ message }} + </div> + </div> </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 - } + message: { + type: String, + required: true, + }, }, emits: ['closed'], data() { @@ -31,44 +31,41 @@ export default defineComponent({ mounted() { setTimeout(() => { this.showing = false; - }, 6000); + }, 4000); } }); </script> <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; } -.notification-slide-enter-from, .notification-slide-leave-to { +.toast-enter-from, .toast-leave-to { opacity: 0; - transform: translateX(-250px); + transform: translateY(calc(0px - (100% - 32px))); } .mk-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%; + > .body { + position: fixed; + left: 0; + right: 0; + top: 0; + margin: 0 auto; + padding-top: 32px; + margin-top: -32px; + min-width: 300px; + max-width: calc(100% - 32px); + width: min-content; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); - border-radius: 8px; - overflow: hidden; + border-radius: 0 0 8px 8px; + overflow: clip; + text-align: center; + pointer-events: none; + + > .message { + padding: 16px 24px; + } } } </style> diff --git a/packages/client/src/init.ts b/packages/client/src/init.ts index f0368cc1d7..82a1e169ce 100644 --- a/packages/client/src/init.ts +++ b/packages/client/src/init.ts @@ -26,7 +26,7 @@ import { router } from '@/router'; import { applyTheme } from '@/scripts/theme'; import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; 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 { $i, refreshAccount, login, updateAccount, signout } from '@/account'; 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.permission === 'default') { diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts index 665151b017..4ed69e0ec0 100644 --- a/packages/client/src/os.ts +++ b/packages/client/src/os.ts @@ -221,7 +221,9 @@ export function modalPageWindow(path: string) { } export function toast(message: string) { - // TODO + popup(import('@/components/toast.vue'), { + message + }, {}, 'closed'); } export function alert(props: { diff --git a/packages/client/src/ui/_common_/common.vue b/packages/client/src/ui/_common_/common.vue index 68f5f779ff..956ec556c1 100644 --- a/packages/client/src/ui/_common_/common.vue +++ b/packages/client/src/ui/_common_/common.vue @@ -34,7 +34,7 @@ export default defineComponent({ id: notification.id }); - popup(import('@/components/toast.vue'), { + popup(import('@/components/notification-toast.vue'), { notification }, {}, 'closed'); }