feat: countdown on server panel

This commit is contained in:
Calum H. committed 2025-08-05 13:08:18 +01:00
1 parent e010e617c1
commit 5b46f521b7
2 files changed
+132

No files matched your search

@@ -0,0 +1,129 @@
<template>
<div
class="medal-promotion flex w-full flex-row items-center justify-between rounded-2xl p-4 shadow-xl"
>
<div class="overlay"></div>
<MedalPromoBackground class="background-pattern" />
<div class="z-10 flex flex-col gap-1">
<div class="flex items-center gap-2 text-lg font-semibold text-contrast">
<ClockIcon class="clock-glow size-5 text-orange" />
<span>
Your <span class="text-orange">Medal</span> powered Modrinth Server will expire in
<span class="font-bold text-orange">{{ timeLeftCountdown.days }}</span> days
<span class="font-bold text-orange">{{ timeLeftCountdown.hours }}</span> hours
<span class="font-bold text-orange">{{ timeLeftCountdown.minutes }}</span> minutes
<span class="font-bold text-orange">{{ timeLeftCountdown.seconds }}</span> seconds.
</span>
</div>
</div>
<ButtonStyled color="orange" type="outlined" size="large">
<button class="z-10 my-auto" @click="handleUpgrade"><RocketIcon /> Upgrade</button>
</ButtonStyled>
</div>
</template>
<script setup lang="ts">
import { ClockIcon, RocketIcon } from "@modrinth/assets";
import { ButtonStyled } from "@modrinth/ui";
import dayjs from "dayjs";
import dayjsDuration from "dayjs/plugin/duration";
import MedalPromoBackground from "~/assets/images/illustrations/medal_promo_background.svg?component";
// eslint-disable-next-line import/no-named-as-default-member
dayjs.extend(dayjsDuration);
const props = defineProps<{
expiryDate?: string | Date;
}>();
const expiryDate = computed(() => {
if (props.expiryDate) {
return dayjs(props.expiryDate);
}
return dayjs().add(5, "day");
});
const timeLeftCountdown = ref({ days: 0, hours: 0, minutes: 0, seconds: 0 });
function handleUpgrade(event: Event) {
event.stopPropagation();
// TODO: Upgrade logic
}
function updateCountdown() {
const now = dayjs();
const diff = expiryDate.value.diff(now);
if (diff <= 0) {
timeLeftCountdown.value = { days: 0, hours: 0, minutes: 0, seconds: 0 };
return;
}
const duration = dayjs.duration(diff);
timeLeftCountdown.value = {
days: duration.days(),
hours: duration.hours(),
minutes: duration.minutes(),
seconds: duration.seconds(),
};
}
updateCountdown();
const intervalId = ref<NodeJS.Timeout | null>(null);
onMounted(() => {
intervalId.value = setInterval(updateCountdown, 1000);
});
onUnmounted(() => {
if (intervalId.value) clearInterval(intervalId.value);
});
</script>
<style scoped lang="scss">
.medal-promotion {
position: relative;
border: 1px solid var(--medal-promotion-bg-orange);
background: inherit;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
var(--medal-promotion-bg) 10%,
transparent 30%,
var(--medal-promotion-bg) 100%
);
z-index: 1;
border-radius: inherit;
}
.background-pattern {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
background-color: var(--medal-promotion-bg);
border-radius: inherit;
color: var(--medal-promotion-text-orange);
}
.clock-glow {
filter: drop-shadow(0 0 72px var(--color-orange)) drop-shadow(0 0 36px var(--color-orange))
drop-shadow(0 0 18px var(--color-orange));
}
.text-orange {
color: var(--medal-promotion-text-orange);
font-weight: bold;
}
</style>
@@ -290,6 +290,8 @@
</div>
</div>
<MedalServerCountdown class="mb-4" />
<div
v-if="!isConnected && !isReconnecting && !isLoading"
data-pyro-server-ws-error
@@ -380,6 +382,7 @@ import { useServersFetch } from "~/composables/servers/servers-fetch.ts";
import { ModrinthServer, useModrinthServers } from "~/composables/servers/modrinth-servers.ts";
import ServerInstallation from "~/components/ui/servers/ServerInstallation.vue";
import PanelErrorIcon from "~/components/ui/servers/icons/PanelErrorIcon.vue";
import MedalServerCountdown from "~/components/ui/servers/marketing/MedalServerCountdown.vue";
const app = useNuxtApp() as unknown as { $notify: any };