enhance(client): improve clock widget
This commit is contained in:
		
							parent
							
								
									3a9da78901
								
							
						
					
					
						commit
						b31f09692a
					
				
					 3 changed files with 110 additions and 68 deletions
				
			
		
							
								
								
									
										77
									
								
								packages/client/src/components/digital-clock.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								packages/client/src/components/digital-clock.vue
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| <template> | ||||
| <span class="zjobosdg"> | ||||
| 	<span v-text="hh"></span> | ||||
| 	<span class="colon" :class="{ showColon }">:</span> | ||||
| 	<span v-text="mm"></span> | ||||
| 	<span v-if="showS" class="colon" :class="{ showColon }">:</span> | ||||
| 	<span v-if="showS" v-text="ss"></span> | ||||
| 	<span v-if="showMs" class="colon" :class="{ showColon }">:</span> | ||||
| 	<span v-if="showMs" v-text="ms"></span> | ||||
| </span> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { onUnmounted, ref, watch } from 'vue'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	showS?: boolean; | ||||
| 	showMs?: boolean; | ||||
| 	offset?: number; | ||||
| }>(), { | ||||
| 	showS: true, | ||||
| 	showMs: false, | ||||
| 	offset: 0 - new Date().getTimezoneOffset(), | ||||
| }); | ||||
| 
 | ||||
| let intervalId; | ||||
| const hh = ref(''); | ||||
| const mm = ref(''); | ||||
| const ss = ref(''); | ||||
| const ms = ref(''); | ||||
| 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(); | ||||
| 	now.setMinutes(now.getMinutes() + (new Date().getTimezoneOffset() + props.offset)); | ||||
| 	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'); | ||||
| 	if (now.getSeconds() !== prevSec) showColon.value = true; | ||||
| 	prevSec = now.getSeconds(); | ||||
| }; | ||||
| 
 | ||||
| tick(); | ||||
| 
 | ||||
| watch(() => props.showMs, () => { | ||||
| 	if (intervalId) window.clearInterval(intervalId); | ||||
| 	intervalId = window.setInterval(tick, props.showMs ? 10 : 1000); | ||||
| }, { immediate: true }); | ||||
| 
 | ||||
| onUnmounted(() => { | ||||
| 	window.clearInterval(intervalId); | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .zjobosdg { | ||||
| 	> .colon { | ||||
| 		opacity: 0; | ||||
| 		transition: opacity 1s ease; | ||||
| 
 | ||||
| 		&.showColon { | ||||
| 			opacity: 1; | ||||
| 			transition: opacity 0s; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  | @ -1,7 +1,7 @@ | |||
| <template> | ||||
| <MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-clock"> | ||||
| 	<div class="vubelbmv" :class="widgetProps.size"> | ||||
| 		<div v-if="widgetProps.showLabel" class="label abbrev">{{ tzAbbrev }}</div> | ||||
| 		<div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label a abbrev">{{ tzAbbrev }}</div> | ||||
| 		<MkAnalogClock | ||||
| 			class="clock" | ||||
| 			:thickness="widgetProps.thickness" | ||||
|  | @ -10,7 +10,8 @@ | |||
| 			:fade-graduations="widgetProps.fadeGraduations" | ||||
| 			:twentyfour="widgetProps.twentyFour" | ||||
| 		/> | ||||
| 		<div v-if="widgetProps.showLabel" class="label offset">{{ tzOffsetLabel }}</div> | ||||
| 		<MkDigitalClock v-if="widgetProps.label === 'time' || widgetProps.label === 'timeAndTz'" class="_monospace label c time" :show-s="false" :offset="tzOffset"/> | ||||
| 		<div v-if="widgetProps.label === 'tz' || widgetProps.label === 'timeAndTz'" class="_monospace label d offset">{{ tzOffsetLabel }}</div> | ||||
| 	</div> | ||||
| </MkContainer> | ||||
| </template> | ||||
|  | @ -21,6 +22,7 @@ import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExp | |||
| import { GetFormResultType } from '@/scripts/form'; | ||||
| import MkContainer from '@/components/ui/container.vue'; | ||||
| import MkAnalogClock from '@/components/analog-clock.vue'; | ||||
| import MkDigitalClock from '@/components/digital-clock.vue'; | ||||
| import { timezones } from '@/scripts/timezones'; | ||||
| import { i18n } from '@/i18n'; | ||||
| 
 | ||||
|  | @ -72,9 +74,18 @@ const widgetPropsDef = { | |||
| 		type: 'boolean' as const, | ||||
| 		default: false, | ||||
| 	}, | ||||
| 	showLabel: { | ||||
| 		type: 'boolean' as const, | ||||
| 		default: true, | ||||
| 	label: { | ||||
| 		type: 'radio' as const, | ||||
| 		default: 'none', | ||||
| 		options: [{ | ||||
| 			value: 'none', label: 'None', | ||||
| 		}, { | ||||
| 			value: 'time', label: 'Time', | ||||
| 		}, { | ||||
| 			value: 'tz', label: 'TZ', | ||||
| 		}, { | ||||
| 			value: 'timeAndTz', label: 'Time + TZ', | ||||
| 		}], | ||||
| 	}, | ||||
| 	timezone: { | ||||
| 		type: 'enum' as const, | ||||
|  | @ -125,16 +136,25 @@ defineExpose<WidgetComponentExpose>({ | |||
| 	position: relative; | ||||
| 
 | ||||
| 	> .label { | ||||
| 		position: absolute; | ||||
| 		opacity: 0.7; | ||||
| 
 | ||||
| 		&.abbrev { | ||||
| 			position: absolute; | ||||
| 		&.a { | ||||
| 			top: 14px; | ||||
| 			left: 14px; | ||||
| 		} | ||||
| 
 | ||||
| 		&.offset { | ||||
| 			position: absolute; | ||||
| 		&.b { | ||||
| 			top: 14px; | ||||
| 			right: 14px; | ||||
| 		} | ||||
| 
 | ||||
| 		&.c { | ||||
| 			bottom: 14px; | ||||
| 			left: 14px; | ||||
| 		} | ||||
| 
 | ||||
| 		&.d { | ||||
| 			bottom: 14px; | ||||
| 			right: 14px; | ||||
| 		} | ||||
|  | @ -145,7 +165,7 @@ defineExpose<WidgetComponentExpose>({ | |||
| 	} | ||||
| 
 | ||||
| 	&.small { | ||||
| 		padding: 8px; | ||||
| 		padding: 12px; | ||||
| 
 | ||||
| 		> .clock { | ||||
| 			height: 100px; | ||||
|  | @ -153,7 +173,7 @@ defineExpose<WidgetComponentExpose>({ | |||
| 	} | ||||
| 
 | ||||
| 	&.medium { | ||||
| 		padding: 8px; | ||||
| 		padding: 14px; | ||||
| 
 | ||||
| 		> .clock { | ||||
| 			height: 150px; | ||||
|  |  | |||
|  | @ -2,13 +2,7 @@ | |||
| <div class="mkw-digitalClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> | ||||
| 	<div v-if="widgetProps.showLabel" class="label">{{ tzAbbrev }}</div> | ||||
| 	<div class="time"> | ||||
| 		<span v-text="hh"></span> | ||||
| 		<span class="colon" :class="{ showColon }">:</span> | ||||
| 		<span v-text="mm"></span> | ||||
| 		<span class="colon" :class="{ showColon }">:</span> | ||||
| 		<span v-text="ss"></span> | ||||
| 		<span v-if="widgetProps.showMs" class="colon" :class="{ showColon }">:</span> | ||||
| 		<span v-if="widgetProps.showMs" v-text="ms"></span> | ||||
| 		<MkDigitalClock :show-ms="widgetProps.showMs" :offset="tzOffset"/> | ||||
| 	</div> | ||||
| 	<div v-if="widgetProps.showLabel" class="label">{{ tzOffsetLabel }}</div> | ||||
| </div> | ||||
|  | @ -19,6 +13,7 @@ import { onUnmounted, ref, watch } from 'vue'; | |||
| import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; | ||||
| import { GetFormResultType } from '@/scripts/form'; | ||||
| import { timezones } from '@/scripts/timezones'; | ||||
| import MkDigitalClock from '@/components/digital-clock.vue'; | ||||
| 
 | ||||
| const name = 'digitalClock'; | ||||
| 
 | ||||
|  | @ -77,44 +72,6 @@ const tzOffset = $computed(() => widgetProps.timezone === null | |||
| 
 | ||||
| const tzOffsetLabel = $computed(() => (tzOffset >= 0 ? '+' : '-') + Math.floor(tzOffset / 60).toString().padStart(2, '0') + ':' + (tzOffset % 60).toString().padStart(2, '0')); | ||||
| 
 | ||||
| let intervalId; | ||||
| const hh = ref(''); | ||||
| const mm = ref(''); | ||||
| const ss = ref(''); | ||||
| const ms = ref(''); | ||||
| 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(); | ||||
| 	now.setMinutes(now.getMinutes() + (new Date().getTimezoneOffset() + tzOffset)); | ||||
| 	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'); | ||||
| 	if (now.getSeconds() !== prevSec) showColon.value = true; | ||||
| 	prevSec = now.getSeconds(); | ||||
| }; | ||||
| 
 | ||||
| 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, | ||||
|  | @ -131,17 +88,5 @@ defineExpose<WidgetComponentExpose>({ | |||
| 		font-size: 65%; | ||||
| 		opacity: 0.7; | ||||
| 	} | ||||
| 
 | ||||
| 	> .time { | ||||
| 		> .colon { | ||||
| 			opacity: 0; | ||||
| 			transition: opacity 1s ease; | ||||
| 
 | ||||
| 			&.showColon { | ||||
| 				opacity: 1; | ||||
| 				transition: opacity 0s; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| </style> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue