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> | <template> | ||||||
| <MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-clock"> | <MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-clock"> | ||||||
| 	<div class="vubelbmv" :class="widgetProps.size"> | 	<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 | 		<MkAnalogClock | ||||||
| 			class="clock" | 			class="clock" | ||||||
| 			:thickness="widgetProps.thickness" | 			:thickness="widgetProps.thickness" | ||||||
|  | @ -10,7 +10,8 @@ | ||||||
| 			:fade-graduations="widgetProps.fadeGraduations" | 			:fade-graduations="widgetProps.fadeGraduations" | ||||||
| 			:twentyfour="widgetProps.twentyFour" | 			: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> | 	</div> | ||||||
| </MkContainer> | </MkContainer> | ||||||
| </template> | </template> | ||||||
|  | @ -21,6 +22,7 @@ import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExp | ||||||
| import { GetFormResultType } from '@/scripts/form'; | import { GetFormResultType } from '@/scripts/form'; | ||||||
| import MkContainer from '@/components/ui/container.vue'; | import MkContainer from '@/components/ui/container.vue'; | ||||||
| import MkAnalogClock from '@/components/analog-clock.vue'; | import MkAnalogClock from '@/components/analog-clock.vue'; | ||||||
|  | import MkDigitalClock from '@/components/digital-clock.vue'; | ||||||
| import { timezones } from '@/scripts/timezones'; | import { timezones } from '@/scripts/timezones'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| 
 | 
 | ||||||
|  | @ -72,9 +74,18 @@ const widgetPropsDef = { | ||||||
| 		type: 'boolean' as const, | 		type: 'boolean' as const, | ||||||
| 		default: false, | 		default: false, | ||||||
| 	}, | 	}, | ||||||
| 	showLabel: { | 	label: { | ||||||
| 		type: 'boolean' as const, | 		type: 'radio' as const, | ||||||
| 		default: true, | 		default: 'none', | ||||||
|  | 		options: [{ | ||||||
|  | 			value: 'none', label: 'None', | ||||||
|  | 		}, { | ||||||
|  | 			value: 'time', label: 'Time', | ||||||
|  | 		}, { | ||||||
|  | 			value: 'tz', label: 'TZ', | ||||||
|  | 		}, { | ||||||
|  | 			value: 'timeAndTz', label: 'Time + TZ', | ||||||
|  | 		}], | ||||||
| 	}, | 	}, | ||||||
| 	timezone: { | 	timezone: { | ||||||
| 		type: 'enum' as const, | 		type: 'enum' as const, | ||||||
|  | @ -125,16 +136,25 @@ defineExpose<WidgetComponentExpose>({ | ||||||
| 	position: relative; | 	position: relative; | ||||||
| 
 | 
 | ||||||
| 	> .label { | 	> .label { | ||||||
|  | 		position: absolute; | ||||||
| 		opacity: 0.7; | 		opacity: 0.7; | ||||||
| 
 | 
 | ||||||
| 		&.abbrev { | 		&.a { | ||||||
| 			position: absolute; |  | ||||||
| 			top: 14px; | 			top: 14px; | ||||||
| 			left: 14px; | 			left: 14px; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		&.offset { | 		&.b { | ||||||
| 			position: absolute; | 			top: 14px; | ||||||
|  | 			right: 14px; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		&.c { | ||||||
|  | 			bottom: 14px; | ||||||
|  | 			left: 14px; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		&.d { | ||||||
| 			bottom: 14px; | 			bottom: 14px; | ||||||
| 			right: 14px; | 			right: 14px; | ||||||
| 		} | 		} | ||||||
|  | @ -145,7 +165,7 @@ defineExpose<WidgetComponentExpose>({ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	&.small { | 	&.small { | ||||||
| 		padding: 8px; | 		padding: 12px; | ||||||
| 
 | 
 | ||||||
| 		> .clock { | 		> .clock { | ||||||
| 			height: 100px; | 			height: 100px; | ||||||
|  | @ -153,7 +173,7 @@ defineExpose<WidgetComponentExpose>({ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	&.medium { | 	&.medium { | ||||||
| 		padding: 8px; | 		padding: 14px; | ||||||
| 
 | 
 | ||||||
| 		> .clock { | 		> .clock { | ||||||
| 			height: 150px; | 			height: 150px; | ||||||
|  |  | ||||||
|  | @ -2,13 +2,7 @@ | ||||||
| <div class="mkw-digitalClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> | <div class="mkw-digitalClock _monospace" :class="{ _panel: !widgetProps.transparent }" :style="{ fontSize: `${widgetProps.fontSize}em` }"> | ||||||
| 	<div v-if="widgetProps.showLabel" class="label">{{ tzAbbrev }}</div> | 	<div v-if="widgetProps.showLabel" class="label">{{ tzAbbrev }}</div> | ||||||
| 	<div class="time"> | 	<div class="time"> | ||||||
| 		<span v-text="hh"></span> | 		<MkDigitalClock :show-ms="widgetProps.showMs" :offset="tzOffset"/> | ||||||
| 		<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> |  | ||||||
| 	</div> | 	</div> | ||||||
| 	<div v-if="widgetProps.showLabel" class="label">{{ tzOffsetLabel }}</div> | 	<div v-if="widgetProps.showLabel" class="label">{{ tzOffsetLabel }}</div> | ||||||
| </div> | </div> | ||||||
|  | @ -19,6 +13,7 @@ import { onUnmounted, ref, watch } from 'vue'; | ||||||
| import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; | import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; | ||||||
| import { GetFormResultType } from '@/scripts/form'; | import { GetFormResultType } from '@/scripts/form'; | ||||||
| import { timezones } from '@/scripts/timezones'; | import { timezones } from '@/scripts/timezones'; | ||||||
|  | import MkDigitalClock from '@/components/digital-clock.vue'; | ||||||
| 
 | 
 | ||||||
| const name = 'digitalClock'; | 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')); | 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>({ | defineExpose<WidgetComponentExpose>({ | ||||||
| 	name, | 	name, | ||||||
| 	configure, | 	configure, | ||||||
|  | @ -131,17 +88,5 @@ defineExpose<WidgetComponentExpose>({ | ||||||
| 		font-size: 65%; | 		font-size: 65%; | ||||||
| 		opacity: 0.7; | 		opacity: 0.7; | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	> .time { |  | ||||||
| 		> .colon { |  | ||||||
| 			opacity: 0; |  | ||||||
| 			transition: opacity 1s ease; |  | ||||||
| 
 |  | ||||||
| 			&.showColon { |  | ||||||
| 				opacity: 1; |  | ||||||
| 				transition: opacity 0s; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| </style> | </style> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue