feat: finish server card layout
This commit is contained in:
parent
0b3cbbd37a
commit
e010e617c1
@ -1,63 +1,92 @@
|
|||||||
<template>
|
<template>
|
||||||
<NuxtLink
|
<div>
|
||||||
class="contents"
|
|
||||||
:to="status === 'suspended' ? '' : `/servers/manage/${props.server_id}`"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="medal-promotion flex flex-row items-center overflow-x-hidden rounded-2xl p-4 shadow-xl transition-transform duration-100"
|
class="medal-promotion flex flex-row items-center overflow-x-hidden rounded-2xl p-4 shadow-xl transition-transform duration-100"
|
||||||
:class="status === 'suspended' ? '!rounded-b-none border-b-0 opacity-75' : 'active:scale-95'"
|
:class="status === 'suspended' ? '!rounded-b-none border-b-0 opacity-75' : ''"
|
||||||
data-pyro-server-listing
|
data-pyro-server-listing
|
||||||
:data-pyro-server-listing-id="server_id"
|
:data-pyro-server-listing-id="server_id"
|
||||||
>
|
>
|
||||||
<div class="overlay"></div>
|
<div class="overlay"></div>
|
||||||
<MedalPromoBackground class="background-pattern" />
|
<MedalPromoBackground class="background-pattern" />
|
||||||
<MedalServerIcon
|
|
||||||
v-if="status !== 'suspended'"
|
<NuxtLink
|
||||||
class="z-10 size-16 rounded-xl bg-bg text-orange"
|
:to="status === 'suspended' ? '' : `/servers/manage/${props.server_id}`"
|
||||||
/>
|
class="z-10 flex flex-grow flex-row items-center overflow-x-hidden"
|
||||||
<div
|
:class="status !== 'suspended' && 'active:scale-95'"
|
||||||
v-else
|
|
||||||
class="bg-bg-secondary z-10 flex size-16 items-center justify-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
|
|
||||||
>
|
>
|
||||||
<LockIcon class="size-12 text-secondary" />
|
<MedalServerIcon
|
||||||
</div>
|
v-if="status !== 'suspended'"
|
||||||
<div class="z-10 ml-4 flex flex-col gap-2.5">
|
class="z-10 size-16 shrink-0 rounded-xl bg-bg text-orange"
|
||||||
<div class="flex flex-row items-center gap-2">
|
|
||||||
<h2 class="m-0 text-xl font-bold text-contrast">{{ name }}</h2>
|
|
||||||
<ChevronRightIcon />
|
|
||||||
|
|
||||||
<span>{{ timeLeftCountdown }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="projectData?.title"
|
|
||||||
class="m-0 flex flex-row items-center gap-2 text-sm font-medium text-secondary"
|
|
||||||
>
|
|
||||||
<Avatar
|
|
||||||
:src="iconUrl"
|
|
||||||
no-shadow
|
|
||||||
style="min-height: 20px; min-width: 20px; height: 20px; width: 20px"
|
|
||||||
alt="Server Icon"
|
|
||||||
/>
|
|
||||||
Using {{ projectData?.title || "Unknown" }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
v-if="isConfiguring"
|
|
||||||
class="flex min-w-0 items-center gap-2 truncate text-sm font-semibold text-brand"
|
|
||||||
>
|
|
||||||
<SparklesIcon class="size-5 shrink-0" /> New server
|
|
||||||
</div>
|
|
||||||
<UiServersServerInfoLabels
|
|
||||||
v-else
|
|
||||||
:server-data="{ game, mc_version, loader, loader_version, net }"
|
|
||||||
:show-game-label="showGameLabel"
|
|
||||||
:show-loader-label="showLoaderLabel"
|
|
||||||
:linked="false"
|
|
||||||
class="pointer-events-none flex w-full flex-row flex-wrap items-center gap-4 text-secondary *:hidden sm:flex-row sm:*:flex"
|
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="bg-bg-secondary z-10 flex size-16 shrink-0 items-center justify-center rounded-xl border-[1px] border-solid border-button-border bg-button-bg shadow-sm"
|
||||||
|
>
|
||||||
|
<LockIcon class="size-12 text-secondary" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="z-10 ml-4 flex min-w-0 flex-col gap-2.5">
|
||||||
|
<div class="flex flex-row items-center gap-2">
|
||||||
|
<h2 class="m-0 truncate text-xl font-bold text-contrast">{{ name }}</h2>
|
||||||
|
<ChevronRightIcon />
|
||||||
|
|
||||||
|
<span class="truncate">
|
||||||
|
<span class="text-medal-orange">
|
||||||
|
{{ timeLeftCountdown.days }}
|
||||||
|
</span>
|
||||||
|
days
|
||||||
|
<span class="text-medal-orange">
|
||||||
|
{{ timeLeftCountdown.hours }}
|
||||||
|
</span>
|
||||||
|
hours
|
||||||
|
<span class="text-medal-orange">
|
||||||
|
{{ timeLeftCountdown.minutes }}
|
||||||
|
</span>
|
||||||
|
minutes
|
||||||
|
<span class="text-medal-orange">
|
||||||
|
{{ timeLeftCountdown.seconds }}
|
||||||
|
</span>
|
||||||
|
seconds remaining...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="projectData?.title"
|
||||||
|
class="m-0 flex flex-row items-center gap-2 text-sm font-medium text-secondary"
|
||||||
|
>
|
||||||
|
<Avatar
|
||||||
|
:src="iconUrl"
|
||||||
|
no-shadow
|
||||||
|
style="min-height: 20px; min-width: 20px; height: 20px; width: 20px"
|
||||||
|
alt="Server Icon"
|
||||||
|
/>
|
||||||
|
Using {{ projectData?.title || "Unknown" }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="isConfiguring"
|
||||||
|
class="flex min-w-0 items-center gap-2 truncate text-sm font-semibold text-brand"
|
||||||
|
>
|
||||||
|
<SparklesIcon class="size-5 shrink-0" /> New server
|
||||||
|
</div>
|
||||||
|
<UiServersServerInfoLabels
|
||||||
|
v-else
|
||||||
|
:server-data="{ game, mc_version, loader, loader_version, net }"
|
||||||
|
:show-game-label="showGameLabel"
|
||||||
|
:show-loader-label="showLoaderLabel"
|
||||||
|
:linked="false"
|
||||||
|
class="pointer-events-none flex w-full flex-row flex-wrap items-center gap-4 text-secondary *:hidden sm:flex-row sm:*:flex"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</NuxtLink>
|
||||||
|
|
||||||
|
<div class="z-10 ml-auto mr-6">
|
||||||
|
<ButtonStyled color="orange" type="outlined" size="large">
|
||||||
|
<button class="my-auto" @click="handleUpgrade"><RocketIcon /> Upgrade</button>
|
||||||
|
</ButtonStyled>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="status === 'suspended' && suspension_reason === 'upgrading'"
|
v-if="status === 'suspended' && suspension_reason === 'upgrading'"
|
||||||
class="relative -mt-4 flex w-full flex-row items-center gap-2 rounded-b-2xl border-[1px] border-t-0 border-solid border-bg-blue bg-bg-blue p-4 text-sm font-bold text-contrast"
|
class="relative -mt-4 flex w-full flex-row items-center gap-2 rounded-b-2xl border-[1px] border-t-0 border-solid border-bg-blue bg-bg-blue p-4 text-sm font-bold text-contrast"
|
||||||
@ -96,17 +125,21 @@
|
|||||||
</div>
|
</div>
|
||||||
<CopyCode :text="`${props.server_id}`" class="ml-auto" />
|
<CopyCode :text="`${props.server_id}`" class="ml-auto" />
|
||||||
</div>
|
</div>
|
||||||
</NuxtLink>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ChevronRightIcon, LockIcon, SparklesIcon } from "@modrinth/assets";
|
import { ChevronRightIcon, LockIcon, SparklesIcon, RocketIcon } from "@modrinth/assets";
|
||||||
import type { Project, Server } from "@modrinth/utils";
|
import type { Project, Server } from "@modrinth/utils";
|
||||||
import { Avatar, CopyCode } from "@modrinth/ui";
|
import { Avatar, CopyCode, ButtonStyled } from "@modrinth/ui";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
|
import dayjsDuration from "dayjs/plugin/duration";
|
||||||
import MedalServerIcon from "~/assets/images/servers/medal_server_icon.svg?component";
|
import MedalServerIcon from "~/assets/images/servers/medal_server_icon.svg?component";
|
||||||
import MedalPromoBackground from "~/assets/images/illustrations/medal_promo_background.svg?component";
|
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<Partial<Server>>();
|
const props = defineProps<Partial<Server>>();
|
||||||
|
|
||||||
const showGameLabel = computed(() => !!props.game);
|
const showGameLabel = computed(() => !!props.game);
|
||||||
@ -130,10 +163,41 @@ const iconUrl = computed(() => projectData.value?.icon_url || undefined);
|
|||||||
const isConfiguring = computed(() => props.flows?.intro);
|
const isConfiguring = computed(() => props.flows?.intro);
|
||||||
|
|
||||||
const expiryDate = dayjs().add(5, "day");
|
const expiryDate = dayjs().add(5, "day");
|
||||||
const timeLeftCountdown = computed(() => {
|
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 now = dayjs();
|
||||||
const diff = expiryDate.diff(now, "day");
|
const diff = expiryDate.diff(now);
|
||||||
return diff > 0 ? `${diff} day${diff > 1 ? "s" : ""} left` : "Expired";
|
|
||||||
|
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>
|
</script>
|
||||||
|
|
||||||
@ -169,4 +233,9 @@ const timeLeftCountdown = computed(() => {
|
|||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
color: var(--medal-promotion-text-orange);
|
color: var(--medal-promotion-text-orange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-medal-orange {
|
||||||
|
color: var(--medal-promotion-text-orange);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -139,6 +139,7 @@ import _ReplyIcon from './icons/reply.svg?component'
|
|||||||
import _ReportIcon from './icons/report.svg?component'
|
import _ReportIcon from './icons/report.svg?component'
|
||||||
import _RestoreIcon from './icons/restore.svg?component'
|
import _RestoreIcon from './icons/restore.svg?component'
|
||||||
import _RightArrowIcon from './icons/right-arrow.svg?component'
|
import _RightArrowIcon from './icons/right-arrow.svg?component'
|
||||||
|
import _RocketIcon from './icons/rocket.svg?component'
|
||||||
import _RotateClockwiseIcon from './icons/rotate-clockwise.svg?component'
|
import _RotateClockwiseIcon from './icons/rotate-clockwise.svg?component'
|
||||||
import _RotateCounterClockwiseIcon from './icons/rotate-counter-clockwise.svg?component'
|
import _RotateCounterClockwiseIcon from './icons/rotate-counter-clockwise.svg?component'
|
||||||
import _RssIcon from './icons/rss.svg?component'
|
import _RssIcon from './icons/rss.svg?component'
|
||||||
@ -333,6 +334,7 @@ export const ReplyIcon = _ReplyIcon
|
|||||||
export const ReportIcon = _ReportIcon
|
export const ReportIcon = _ReportIcon
|
||||||
export const RestoreIcon = _RestoreIcon
|
export const RestoreIcon = _RestoreIcon
|
||||||
export const RightArrowIcon = _RightArrowIcon
|
export const RightArrowIcon = _RightArrowIcon
|
||||||
|
export const RocketIcon = _RocketIcon
|
||||||
export const RotateClockwiseIcon = _RotateClockwiseIcon
|
export const RotateClockwiseIcon = _RotateClockwiseIcon
|
||||||
export const RotateCounterClockwiseIcon = _RotateCounterClockwiseIcon
|
export const RotateCounterClockwiseIcon = _RotateCounterClockwiseIcon
|
||||||
export const RssIcon = _RssIcon
|
export const RssIcon = _RssIcon
|
||||||
|
|||||||
1
packages/assets/icons/rocket.svg
Normal file
1
packages/assets/icons/rocket.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-rocket-icon lucide-rocket"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>
|
||||||
|
After Width: | Height: | Size: 544 B |
Loading…
x
Reference in New Issue
Block a user