mirror of
				https://codeberg.org/yeentown/barkey.git
				synced 2025-11-04 07:24:13 +00:00 
			
		
		
		
	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
		
		Reference in a new issue