From bdaa35d11fa1ab08a21c90e6e71adfa3d767cf7e Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Thu, 4 Aug 2022 22:20:00 +0900 Subject: [PATCH] feat(client): improve widget --- CHANGELOG.md | 1 + locales/ja-JP.yml | 1 + packages/client/src/widgets/digital-clock.vue | 39 ++++-- packages/client/src/widgets/index.ts | 2 + packages/client/src/widgets/unix-clock.vue | 116 ++++++++++++++++++ 5 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 packages/client/src/widgets/unix-clock.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 225e2fbae6..5111cce436 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ You should also include the user name that made the change. ### Improvements - Client: Add vi-VN language support +- Client: Add unix time widget @syuilo ### Bugfixes - Server: リモートユーザーを正しくブロックできるように修正する @xianonn diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index f8895bd99c..b10cce9231 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1312,6 +1312,7 @@ _widgets: activity: "アクティビティ" photos: "フォト" digitalClock: "デジタル時計" + unixClock: "UNIX時計" federation: "連合" instanceCloud: "インスタンスクラウド" postForm: "投稿フォーム" diff --git a/packages/client/src/widgets/digital-clock.vue b/packages/client/src/widgets/digital-clock.vue index a17ed040c9..743c5657b4 100644 --- a/packages/client/src/widgets/digital-clock.vue +++ b/packages/client/src/widgets/digital-clock.vue @@ -1,21 +1,21 @@ <template> <div class="mkw-digitalClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> - <span> + <div class="time"> <span v-text="hh"></span> - <span :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> + <span class="colon" :class="{ showColon }">:</span> <span v-text="mm"></span> - <span :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> + <span class="colon" :class="{ showColon }">:</span> <span v-text="ss"></span> - <span v-if="widgetProps.showMs" :style="{ visibility: showColon ? 'visible' : 'hidden' }">:</span> + <span v-if="widgetProps.showMs" class="colon" :class="{ showColon }">:</span> <span v-if="widgetProps.showMs" v-text="ms"></span> - </span> + </div> </div> </template> <script lang="ts" setup> import { onUnmounted, ref, watch } from 'vue'; -import { GetFormResultType } from '@/scripts/form'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; const name = 'digitalClock'; @@ -54,14 +54,25 @@ const hh = ref(''); const mm = ref(''); const ss = ref(''); const ms = ref(''); -const showColon = ref(true); +const showColon = ref(false); +let prevSec: number | null = null; + +watch(showColon, (v) => { + if (v) { + window.setTimeout(() => { + showColon.value = false; + }, 30); + } +}); + const tick = () => { const now = new Date(); hh.value = now.getHours().toString().padStart(2, '0'); mm.value = now.getMinutes().toString().padStart(2, '0'); ss.value = now.getSeconds().toString().padStart(2, '0'); ms.value = Math.floor(now.getMilliseconds() / 10).toString().padStart(2, '0'); - showColon.value = now.getSeconds() % 2 === 0; + if (now.getSeconds() !== prevSec) showColon.value = true; + prevSec = now.getSeconds(); }; tick(); @@ -86,5 +97,17 @@ defineExpose<WidgetComponentExpose>({ .mkw-digitalClock { padding: 16px 0; text-align: center; + + > .time { + > .colon { + opacity: 0; + transition: opacity 1s ease; + + &.showColon { + opacity: 1; + transition: opacity 0s; + } + } + } } </style> diff --git a/packages/client/src/widgets/index.ts b/packages/client/src/widgets/index.ts index baf6acd23d..66bec7c83f 100644 --- a/packages/client/src/widgets/index.ts +++ b/packages/client/src/widgets/index.ts @@ -12,6 +12,7 @@ export default function(app: App) { app.component('MkwActivity', defineAsyncComponent(() => import('./activity.vue'))); app.component('MkwPhotos', defineAsyncComponent(() => import('./photos.vue'))); app.component('MkwDigitalClock', defineAsyncComponent(() => import('./digital-clock.vue'))); + app.component('MkwUnixClock', defineAsyncComponent(() => import('./unix-clock.vue'))); app.component('MkwFederation', defineAsyncComponent(() => import('./federation.vue'))); app.component('MkwPostForm', defineAsyncComponent(() => import('./post-form.vue'))); app.component('MkwSlideshow', defineAsyncComponent(() => import('./slideshow.vue'))); @@ -36,6 +37,7 @@ export const widgets = [ 'activity', 'photos', 'digitalClock', + 'unixClock', 'federation', 'instanceCloud', 'postForm', diff --git a/packages/client/src/widgets/unix-clock.vue b/packages/client/src/widgets/unix-clock.vue new file mode 100644 index 0000000000..c9e2b4b92a --- /dev/null +++ b/packages/client/src/widgets/unix-clock.vue @@ -0,0 +1,116 @@ +<template> +<div class="mkw-unixClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> + <div v-if="widgetProps.showLabel" class="label">UNIX time</div> + <div class="time"> + <span v-text="ss"></span> + <span v-if="widgetProps.showMs" class="colon" :class="{ showColon }">:</span> + <span v-if="widgetProps.showMs" v-text="ms"></span> + </div> + <div v-if="widgetProps.showLabel" class="label">UTC</div> +</div> +</template> + +<script lang="ts" setup> +import { onUnmounted, ref, watch } from 'vue'; +import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; +import { GetFormResultType } from '@/scripts/form'; + +const name = 'unixClock'; + +const widgetPropsDef = { + transparent: { + type: 'boolean' as const, + default: false, + }, + fontSize: { + type: 'number' as const, + default: 1.5, + step: 0.1, + }, + showMs: { + type: 'boolean' as const, + default: true, + }, + showLabel: { + type: 'boolean' as const, + default: true, + }, +}; + +type WidgetProps = GetFormResultType<typeof widgetPropsDef>; + +// 現時点ではvueの制限によりimportしたtypeをジェネリックに渡せない +//const props = defineProps<WidgetComponentProps<WidgetProps>>(); +//const emit = defineEmits<WidgetComponentEmits<WidgetProps>>(); +const props = defineProps<{ widget?: Widget<WidgetProps>; }>(); +const emit = defineEmits<{ (ev: 'updateProps', props: WidgetProps); }>(); + +const { widgetProps, configure } = useWidgetPropsManager(name, + widgetPropsDef, + props, + emit, +); + +let intervalId; +const ss = ref(''); +const ms = ref(''); +const showColon = ref(false); +let prevSec: string | null = null; + +watch(showColon, (v) => { + if (v) { + window.setTimeout(() => { + showColon.value = false; + }, 30); + } +}); + +const tick = () => { + const now = new Date(); + ss.value = Math.floor(now.getTime() / 1000).toString(); + ms.value = Math.floor(now.getTime() % 1000 / 10).toString().padStart(2, '0'); + if (ss.value !== prevSec) showColon.value = true; + prevSec = ss.value; +}; + +tick(); + +watch(() => widgetProps.showMs, () => { + if (intervalId) window.clearInterval(intervalId); + intervalId = window.setInterval(tick, widgetProps.showMs ? 10 : 1000); +}, { immediate: true }); + +onUnmounted(() => { + window.clearInterval(intervalId); +}); + +defineExpose<WidgetComponentExpose>({ + name, + configure, + id: props.widget ? props.widget.id : null, +}); +</script> + +<style lang="scss" scoped> +.mkw-unixClock { + padding: 16px 0; + text-align: center; + + > .label { + font-size: 65%; + opacity: 0.7; + } + + > .time { + > .colon { + opacity: 0; + transition: opacity 1s ease; + + &.showColon { + opacity: 1; + transition: opacity 0s; + } + } + } +} +</style>