38 lines
937 B
Vue
38 lines
937 B
Vue
<template>
|
|
<span class="text-amber-700 font-semibold tabular-nums">
|
|
{{ display }}
|
|
</span>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, onMounted, onUnmounted } from "vue";
|
|
|
|
const props = defineProps<{
|
|
until: string;
|
|
}>();
|
|
|
|
const now = ref(Date.now());
|
|
let timer: ReturnType<typeof setInterval> | null = null;
|
|
|
|
const remainingMs = computed(() => Math.max(0, new Date(props.until).getTime() - now.value));
|
|
|
|
const display = computed(() => {
|
|
const totalSec = Math.floor(remainingMs.value / 1000);
|
|
const h = Math.floor(totalSec / 3600);
|
|
const m = Math.floor((totalSec % 3600) / 60);
|
|
const s = totalSec % 60;
|
|
if (h > 0) return `${h}h ${String(m).padStart(2, "0")}m`;
|
|
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
});
|
|
|
|
onMounted(() => {
|
|
timer = setInterval(() => {
|
|
now.value = Date.now();
|
|
}, 1000);
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
if (timer) clearInterval(timer);
|
|
});
|
|
</script>
|