Update Servers marketing page (#3535)
* Update Servers marketing page * Add burst FAQ * Updated phrasing again * Fix servers page when not logged in * Update changelog
This commit is contained in:
parent
84a28e045b
commit
1903980b71
@ -0,0 +1,187 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ButtonStyled } from "@modrinth/ui";
|
||||||
|
import { RightArrowIcon, SparklesIcon, UnknownIcon } from "@modrinth/assets";
|
||||||
|
import type { MessageDescriptor } from "@vintl/vintl";
|
||||||
|
|
||||||
|
const { formatMessage } = useVIntl();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "select" | "scroll-to-faq"): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
type Plan = "small" | "medium" | "large";
|
||||||
|
|
||||||
|
const plans: Record<
|
||||||
|
Plan,
|
||||||
|
{
|
||||||
|
buttonColor: "blue" | "green" | "purple";
|
||||||
|
accentText: string;
|
||||||
|
accentBg: string;
|
||||||
|
name: MessageDescriptor;
|
||||||
|
symbol: MessageDescriptor;
|
||||||
|
description: MessageDescriptor;
|
||||||
|
}
|
||||||
|
> = {
|
||||||
|
small: {
|
||||||
|
buttonColor: "blue",
|
||||||
|
accentText: "text-blue",
|
||||||
|
accentBg: "bg-bg-blue",
|
||||||
|
name: defineMessage({
|
||||||
|
id: "servers.plan.small.name",
|
||||||
|
defaultMessage: "Small",
|
||||||
|
}),
|
||||||
|
symbol: defineMessage({
|
||||||
|
id: "servers.plan.small.symbol",
|
||||||
|
defaultMessage: "S",
|
||||||
|
}),
|
||||||
|
description: defineMessage({
|
||||||
|
id: "servers.plan.small.description",
|
||||||
|
defaultMessage:
|
||||||
|
"Perfect for vanilla multiplayer, small friend groups, SMPs, and light modding.",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
medium: {
|
||||||
|
buttonColor: "green",
|
||||||
|
accentText: "text-green",
|
||||||
|
accentBg: "bg-bg-green",
|
||||||
|
name: defineMessage({
|
||||||
|
id: "servers.plan.medium.name",
|
||||||
|
defaultMessage: "Medium",
|
||||||
|
}),
|
||||||
|
symbol: defineMessage({
|
||||||
|
id: "servers.plan.medium.symbol",
|
||||||
|
defaultMessage: "M",
|
||||||
|
}),
|
||||||
|
description: defineMessage({
|
||||||
|
id: "servers.plan.medium.description",
|
||||||
|
defaultMessage: "Great for modded multiplayer and small communities.",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
large: {
|
||||||
|
buttonColor: "purple",
|
||||||
|
accentText: "text-purple",
|
||||||
|
accentBg: "bg-bg-purple",
|
||||||
|
name: defineMessage({
|
||||||
|
id: "servers.plan.large.name",
|
||||||
|
defaultMessage: "Large",
|
||||||
|
}),
|
||||||
|
symbol: defineMessage({
|
||||||
|
id: "servers.plan.large.symbol",
|
||||||
|
defaultMessage: "L",
|
||||||
|
}),
|
||||||
|
description: defineMessage({
|
||||||
|
id: "servers.plan.large.description",
|
||||||
|
defaultMessage: "Ideal for larger communities, modpacks, and heavy modding.",
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
capacity?: number;
|
||||||
|
plan: Plan;
|
||||||
|
ram: number;
|
||||||
|
storage: number;
|
||||||
|
cpus: number;
|
||||||
|
price: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const outOfStock = computed(() => {
|
||||||
|
return !props.capacity || props.capacity === 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const lowStock = computed(() => {
|
||||||
|
return !props.capacity || props.capacity < 8;
|
||||||
|
});
|
||||||
|
|
||||||
|
const formattedRam = computed(() => {
|
||||||
|
return props.ram / 1024;
|
||||||
|
});
|
||||||
|
|
||||||
|
const formattedStorage = computed(() => {
|
||||||
|
return props.storage / 1024;
|
||||||
|
});
|
||||||
|
|
||||||
|
const sharedCpus = computed(() => {
|
||||||
|
return props.cpus / 2;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<li class="relative flex w-full flex-col justify-between pt-12 lg:w-1/3">
|
||||||
|
<div
|
||||||
|
v-if="lowStock"
|
||||||
|
class="absolute left-0 right-0 top-[-2px] rounded-t-2xl p-4 text-center font-bold"
|
||||||
|
:class="outOfStock ? 'bg-bg-red' : 'bg-bg-orange'"
|
||||||
|
>
|
||||||
|
<template v-if="outOfStock"> Out of stock! </template>
|
||||||
|
<template v-else> Only {{ capacity }} left in stock! </template>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
:style="
|
||||||
|
plan === 'medium'
|
||||||
|
? {
|
||||||
|
background: `radial-gradient(
|
||||||
|
86.12% 101.64% at 95.97% 94.07%,
|
||||||
|
rgba(27, 217, 106, 0.23) 0%,
|
||||||
|
rgba(14, 115, 56, 0.2) 100%
|
||||||
|
)`,
|
||||||
|
border: `1px solid rgba(12, 107, 52, 0.55)`,
|
||||||
|
'box-shadow': `0px 12px 38.1px rgba(27, 217, 106, 0.13)`,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
"
|
||||||
|
class="flex w-full flex-col justify-between gap-4 rounded-2xl bg-bg p-8 text-left"
|
||||||
|
:class="{ '!rounded-t-none': lowStock }"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-row items-center justify-between">
|
||||||
|
<h1 class="m-0">{{ formatMessage(plans[plan].name) }}</h1>
|
||||||
|
<div
|
||||||
|
class="grid size-8 place-content-center rounded-full text-xs font-bold"
|
||||||
|
:class="`${plans[plan].accentBg} ${plans[plan].accentText}`"
|
||||||
|
>
|
||||||
|
{{ formatMessage(plans[plan].symbol) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="m-0">{{ formatMessage(plans[plan].description) }}</p>
|
||||||
|
<div
|
||||||
|
class="flex flex-row flex-wrap items-center gap-2 text-nowrap text-secondary xl:justify-between"
|
||||||
|
>
|
||||||
|
<p class="m-0">{{ formattedRam }} GB RAM</p>
|
||||||
|
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
||||||
|
<p class="m-0">{{ formattedStorage }} GB SSD</p>
|
||||||
|
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
||||||
|
<p class="m-0">{{ sharedCpus }} Shared CPUs</p>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-secondary">
|
||||||
|
<SparklesIcon /> Bursts up to {{ cpus }} CPUs
|
||||||
|
<nuxt-link
|
||||||
|
v-tooltip="
|
||||||
|
`CPU bursting allows your server to temporarily use additional threads to help mitigate TPS spikes. Click for more info.`
|
||||||
|
"
|
||||||
|
to="/servers#cpu-burst"
|
||||||
|
@click="() => emit('scroll-to-faq')"
|
||||||
|
>
|
||||||
|
<UnknownIcon class="h-4 w-4 text-secondary opacity-80" />
|
||||||
|
</nuxt-link>
|
||||||
|
</div>
|
||||||
|
<span class="m-0 text-2xl font-bold text-contrast">
|
||||||
|
${{ price / 100 }}<span class="text-lg font-semibold text-secondary">/month</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ButtonStyled
|
||||||
|
:color="plans[plan].buttonColor"
|
||||||
|
:type="plan === 'medium' ? 'standard' : 'highlight-colored-text'"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
<span v-if="outOfStock" class="button-like disabled"> Out of Stock </span>
|
||||||
|
<button v-else @click="() => emit('select')">
|
||||||
|
Get Started
|
||||||
|
<RightArrowIcon class="shrink-0" />
|
||||||
|
</button>
|
||||||
|
</ButtonStyled>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
||||||
@ -10,6 +10,7 @@ interface PyroFetchOptions {
|
|||||||
token?: string;
|
token?: string;
|
||||||
};
|
};
|
||||||
retry?: boolean;
|
retry?: boolean;
|
||||||
|
bypassAuth?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PyroFetchError extends Error {
|
export class PyroFetchError extends Error {
|
||||||
@ -28,7 +29,7 @@ export async function usePyroFetch<T>(path: string, options: PyroFetchOptions =
|
|||||||
const auth = await useAuth();
|
const auth = await useAuth();
|
||||||
const authToken = auth.value?.token;
|
const authToken = auth.value?.token;
|
||||||
|
|
||||||
if (!authToken) {
|
if (!authToken && !options.bypassAuth) {
|
||||||
throw new PyroFetchError("Cannot pyrofetch without auth", 10000);
|
throw new PyroFetchError("Cannot pyrofetch without auth", 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,9 +53,15 @@ export async function usePyroFetch<T>(path: string, options: PyroFetchOptions =
|
|||||||
|
|
||||||
type HeadersRecord = Record<string, string>;
|
type HeadersRecord = Record<string, string>;
|
||||||
|
|
||||||
const headers: HeadersRecord = {
|
const authHeader: HeadersRecord = options.bypassAuth
|
||||||
|
? {}
|
||||||
|
: {
|
||||||
Authorization: `Bearer ${override?.token ?? authToken}`,
|
Authorization: `Bearer ${override?.token ?? authToken}`,
|
||||||
"Access-Control-Allow-Headers": "Authorization",
|
"Access-Control-Allow-Headers": "Authorization",
|
||||||
|
};
|
||||||
|
|
||||||
|
const headers: HeadersRecord = {
|
||||||
|
...authHeader,
|
||||||
"User-Agent": "Pyro/1.0 (https://pyro.host)",
|
"User-Agent": "Pyro/1.0 (https://pyro.host)",
|
||||||
Vary: "Accept, Origin",
|
Vary: "Accept, Origin",
|
||||||
"Content-Type": contentType,
|
"Content-Type": contentType,
|
||||||
|
|||||||
@ -1043,6 +1043,33 @@
|
|||||||
"servers.notices.no-notices": {
|
"servers.notices.no-notices": {
|
||||||
"message": "No notices"
|
"message": "No notices"
|
||||||
},
|
},
|
||||||
|
"servers.plan.large.description": {
|
||||||
|
"message": "Ideal for larger communities, modpacks, and heavy modding."
|
||||||
|
},
|
||||||
|
"servers.plan.large.name": {
|
||||||
|
"message": "Large"
|
||||||
|
},
|
||||||
|
"servers.plan.large.symbol": {
|
||||||
|
"message": "L"
|
||||||
|
},
|
||||||
|
"servers.plan.medium.description": {
|
||||||
|
"message": "Great for modded multiplayer and small communities."
|
||||||
|
},
|
||||||
|
"servers.plan.medium.name": {
|
||||||
|
"message": "Medium"
|
||||||
|
},
|
||||||
|
"servers.plan.medium.symbol": {
|
||||||
|
"message": "M"
|
||||||
|
},
|
||||||
|
"servers.plan.small.description": {
|
||||||
|
"message": "Perfect for vanilla multiplayer, small friend groups, SMPs, and light modding."
|
||||||
|
},
|
||||||
|
"servers.plan.small.name": {
|
||||||
|
"message": "Small"
|
||||||
|
},
|
||||||
|
"servers.plan.small.symbol": {
|
||||||
|
"message": "S"
|
||||||
|
},
|
||||||
"settings.billing.modal.cancel.action": {
|
"settings.billing.modal.cancel.action": {
|
||||||
"message": "Cancel subscription"
|
"message": "Cancel subscription"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -211,7 +211,7 @@
|
|||||||
<h2 class="m-0 text-lg font-bold">Experience modern, reliable hosting</h2>
|
<h2 class="m-0 text-lg font-bold">Experience modern, reliable hosting</h2>
|
||||||
<h3 class="m-0 text-base font-normal text-secondary">
|
<h3 class="m-0 text-base font-normal text-secondary">
|
||||||
Modrinth Servers are hosted on
|
Modrinth Servers are hosted on
|
||||||
<span class="text-contrast">2023 Ryzen 7/9 CPUs with DDR5 RAM</span>, running on
|
<span class="text-contrast">high-performance AMD CPUs with DDR5 RAM</span>, running on
|
||||||
custom-built software to ensure your server performs smoothly.
|
custom-built software to ensure your server performs smoothly.
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
@ -329,27 +329,6 @@
|
|||||||
alt=""
|
alt=""
|
||||||
class="absolute -bottom-12 -right-[15%] hidden max-w-2xl rounded-2xl bg-brand p-4 lg:block"
|
class="absolute -bottom-12 -right-[15%] hidden max-w-2xl rounded-2xl bg-brand p-4 lg:block"
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-row items-center gap-3">
|
|
||||||
<div
|
|
||||||
aria-hidden="true"
|
|
||||||
class="max-w-fit rounded-full bg-brand p-4 text-sm font-bold text-[var(--color-accent-contrast)] lg:absolute lg:bottom-8 lg:right-8 lg:block"
|
|
||||||
>
|
|
||||||
8.49 GB used
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
aria-hidden="true"
|
|
||||||
class="flex w-fit items-center gap-2 rounded-full bg-button-bg p-3 lg:hidden"
|
|
||||||
>
|
|
||||||
<SortAscendingIcon class="h-6 w-6" />
|
|
||||||
Sort
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
aria-hidden="true"
|
|
||||||
class="flex w-fit items-center rounded-full bg-button-bg p-3 lg:hidden"
|
|
||||||
>
|
|
||||||
<SearchIcon class="h-6 w-6" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid w-full grid-cols-1 gap-8 lg:grid-cols-2">
|
<div class="grid w-full grid-cols-1 gap-8 lg:grid-cols-2">
|
||||||
@ -418,9 +397,24 @@
|
|||||||
</span>
|
</span>
|
||||||
What kind of CPUs do Modrinth Servers run on?
|
What kind of CPUs do Modrinth Servers run on?
|
||||||
</summary>
|
</summary>
|
||||||
<p class="m-0 !leading-[190%]">
|
<p class="m-0 ml-6 leading-[160%]">
|
||||||
Modrinth Servers use 2023 Ryzen 7 and Ryzen 9 CPUs at 4+ GHz, paired with DDR5
|
Modrinth Servers are powered by AMD Ryzen 7900 and 7950X3D equivalent CPUs at 5+
|
||||||
memory.
|
GHz, paired with with DDR5 memory.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
<details pyro-hash="cpu-burst" class="group" :open="$route.hash === '#cpu-burst'">
|
||||||
|
<summary class="flex cursor-pointer items-center py-3 font-medium text-contrast">
|
||||||
|
<span class="mr-2 transition-transform duration-200 group-open:rotate-90">
|
||||||
|
<RightArrowIcon />
|
||||||
|
</span>
|
||||||
|
How do CPU burst threads work?
|
||||||
|
</summary>
|
||||||
|
<p class="m-0 ml-6 leading-[160%]">
|
||||||
|
When your server is under heavy load, we temporarily give it access to additional
|
||||||
|
CPU threads to help mitigate lag spikes and instability. This helps prevent the TPS
|
||||||
|
from going below 20, ensuring the smoothest experience possible. Since those extra
|
||||||
|
CPU threads are only shortly available during high load periods, they might not show
|
||||||
|
up in Spark reports or other profiling tools.
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -431,10 +425,12 @@
|
|||||||
</span>
|
</span>
|
||||||
Do Modrinth Servers have DDoS protection?
|
Do Modrinth Servers have DDoS protection?
|
||||||
</summary>
|
</summary>
|
||||||
<p class="m-0 !leading-[190%]">
|
<p class="m-0 ml-6 leading-[160%]">
|
||||||
Yes. All Modrinth Servers come with DDoS protection. Protection is powered by a
|
Yes. All Modrinth Servers come with DDoS protection powered by
|
||||||
combination of in-house network filtering as well as with our data center provider.
|
<a href="https://us.ovhcloud.com/security/anti-ddos/" target="_blank"
|
||||||
Your server is safe on Modrinth.
|
>OVHcloud® Anti-DDoS infrastructure</a
|
||||||
|
>
|
||||||
|
which has over 17Tbps capacity. Your server is safe on Modrinth.
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -445,11 +441,9 @@
|
|||||||
</span>
|
</span>
|
||||||
Where are Modrinth Servers located? Can I choose a region?
|
Where are Modrinth Servers located? Can I choose a region?
|
||||||
</summary>
|
</summary>
|
||||||
<p class="m-0 !leading-[190%]">
|
<p class="m-0 ml-6 leading-[160%]">
|
||||||
Currently, Modrinth Servers are located throughout the United States in New York,
|
Currently, Modrinth Servers are located on the east coast of the United States in
|
||||||
Los Angelas, Dallas, Miami, and Spokane. More regions are coming soon! Your server's
|
Vint Hill, Virginia. More regions to come in the future!
|
||||||
location is currently chosen algorithmically, but you will be able to choose a
|
|
||||||
region in the future.
|
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -460,7 +454,7 @@
|
|||||||
</span>
|
</span>
|
||||||
Can I increase the storage on my server?
|
Can I increase the storage on my server?
|
||||||
</summary>
|
</summary>
|
||||||
<p class="m-0 !leading-[190%]">
|
<p class="m-0 ml-6 leading-[160%]">
|
||||||
Yes, storage can be increased on your server at no additional cost. If you need more
|
Yes, storage can be increased on your server at no additional cost. If you need more
|
||||||
storage, reach out to Modrinth Support.
|
storage, reach out to Modrinth Support.
|
||||||
</p>
|
</p>
|
||||||
@ -471,13 +465,19 @@
|
|||||||
<span class="mr-2 transition-transform duration-200 group-open:rotate-90">
|
<span class="mr-2 transition-transform duration-200 group-open:rotate-90">
|
||||||
<RightArrowIcon />
|
<RightArrowIcon />
|
||||||
</span>
|
</span>
|
||||||
How fast are Modrinth Servers? How many players can they handle?
|
How fast are Modrinth Servers?
|
||||||
</summary>
|
</summary>
|
||||||
<p class="m-0 !leading-[190%]">
|
<p class="m-0 ml-6 leading-[160%]">
|
||||||
During the Modrinth "Emergency SMP" test, we had over 80 players on a server running
|
Modrinth Servers are hosted on very modern high-performance hardware, but it's tough
|
||||||
on the Large plan. The server ran smoothly and was only limited by RAM. We're
|
to say how exactly that will translate into how fast your server will run because
|
||||||
confident that Modrinth Servers can handle a large number of players, with any kind
|
there are so many factors that affect it, such as the mods, data packs, or plugins
|
||||||
of modpack.
|
you're running on your server, and even user behavior.
|
||||||
|
</p>
|
||||||
|
<p class="mb-0 ml-6 mt-3 leading-[160%]">
|
||||||
|
Most performance issues that arise tend to be the fault of an unoptimized modpack,
|
||||||
|
mod, data pack, or plugin that causes the server to lag. Since our servers are very
|
||||||
|
high-end, you shouldn't run into much trouble as long as you pick an appropriate
|
||||||
|
plan for the content you're running on the server.
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
@ -486,6 +486,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section
|
<section
|
||||||
|
v-if="false"
|
||||||
class="relative mt-24 flex flex-col bg-[radial-gradient(65%_50%_at_50%_-10%,var(--color-brand-highlight)_0%,var(--color-accent-contrast)_100%)] px-3 pt-24 md:mt-48 md:pt-48"
|
class="relative mt-24 flex flex-col bg-[radial-gradient(65%_50%_at_50%_-10%,var(--color-brand-highlight)_0%,var(--color-accent-contrast)_100%)] px-3 pt-24 md:mt-48 md:pt-48"
|
||||||
>
|
>
|
||||||
<div class="faded-brand-line absolute left-0 top-0 h-[1px] w-full"></div>
|
<div class="faded-brand-line absolute left-0 top-0 h-[1px] w-full"></div>
|
||||||
@ -596,182 +597,49 @@
|
|||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<ul class="m-0 mt-8 flex w-full flex-col gap-8 p-0 lg:flex-row">
|
<ul class="m-0 mt-8 flex w-full flex-col gap-8 p-0 lg:flex-row">
|
||||||
<li class="relative flex w-full flex-col justify-between pt-12 lg:w-1/3">
|
<ServerPlanSelector
|
||||||
<div
|
:capacity="capacityStatuses?.small?.available"
|
||||||
v-if="isSmallLowStock"
|
plan="small"
|
||||||
class="absolute left-0 right-0 top-[-2px] rounded-t-2xl bg-yellow-500/20 p-4 text-center font-bold"
|
:ram="plans.small.metadata.ram"
|
||||||
>
|
:storage="plans.small.metadata.storage"
|
||||||
Only {{ capacityStatuses?.small?.available }} left in stock!
|
:cpus="plans.small.metadata.cpu"
|
||||||
</div>
|
:price="
|
||||||
<div
|
plans.small?.prices?.find((x) => x.currency_code === 'USD')?.prices?.intervals
|
||||||
class="flex w-full flex-col justify-between gap-4 rounded-2xl bg-bg p-8 text-left"
|
?.monthly
|
||||||
:class="{ '!rounded-t-none': isSmallLowStock }"
|
|
||||||
>
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<div class="flex flex-row items-center justify-between">
|
|
||||||
<h1 class="m-0">Small</h1>
|
|
||||||
<div
|
|
||||||
class="grid size-8 place-content-center rounded-full bg-highlight-blue text-xs font-bold text-blue"
|
|
||||||
>
|
|
||||||
S
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="m-0">
|
|
||||||
Perfect for vanilla multiplayer, small friend groups, SMPs, and light modding.
|
|
||||||
</p>
|
|
||||||
<div class="flex flex-row flex-wrap items-center gap-3 text-nowrap">
|
|
||||||
<p class="m-0">4 GB RAM</p>
|
|
||||||
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
|
||||||
<p class="m-0">4 vCPUs</p>
|
|
||||||
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
|
||||||
<p class="m-0">32 GB Storage</p>
|
|
||||||
</div>
|
|
||||||
<h2 class="m-0 text-3xl text-contrast">
|
|
||||||
$12<span class="text-sm font-normal text-secondary">/month</span>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<ButtonStyled color="blue" size="large">
|
|
||||||
<a
|
|
||||||
v-if="!loggedOut && isSmallAtCapacity"
|
|
||||||
:href="outOfStockUrl"
|
|
||||||
target="_blank"
|
|
||||||
class="flex items-center gap-2 !bg-highlight-blue !font-medium !text-blue"
|
|
||||||
>
|
|
||||||
Out of Stock
|
|
||||||
<ExternalIcon class="!min-h-4 !min-w-4 !text-blue" />
|
|
||||||
</a>
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
class="!bg-highlight-blue !font-medium !text-blue"
|
|
||||||
@click="selectProduct('small')"
|
|
||||||
>
|
|
||||||
Get Started
|
|
||||||
<RightArrowIcon class="!min-h-4 !min-w-4 !text-blue" />
|
|
||||||
</button>
|
|
||||||
</ButtonStyled>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="relative flex w-full flex-col justify-between pt-12 lg:w-1/3">
|
|
||||||
<div
|
|
||||||
v-if="isMediumLowStock"
|
|
||||||
class="absolute left-0 right-0 top-[-2px] rounded-t-2xl bg-yellow-500/20 p-4 text-center font-bold"
|
|
||||||
>
|
|
||||||
Only {{ capacityStatuses?.medium?.available }} left in stock!
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style="
|
|
||||||
background: radial-gradient(
|
|
||||||
86.12% 101.64% at 95.97% 94.07%,
|
|
||||||
rgba(27, 217, 106, 0.23) 0%,
|
|
||||||
rgba(14, 115, 56, 0.2) 100%
|
|
||||||
);
|
|
||||||
border: 1px solid rgba(12, 107, 52, 0.55);
|
|
||||||
box-shadow: 0px 12px 38.1px rgba(27, 217, 106, 0.13);
|
|
||||||
"
|
"
|
||||||
class="flex w-full flex-col justify-between gap-4 rounded-2xl p-8 text-left"
|
@select="selectProduct('small')"
|
||||||
:class="{ '!rounded-t-none': isMediumLowStock }"
|
@scroll-to-faq="scrollToFaq()"
|
||||||
>
|
/>
|
||||||
<div class="flex flex-col gap-4">
|
<ServerPlanSelector
|
||||||
<div class="flex flex-row items-center justify-between">
|
:capacity="capacityStatuses?.medium?.available"
|
||||||
<h1 class="m-0">Medium</h1>
|
plan="medium"
|
||||||
<div
|
:ram="plans.medium.metadata.ram"
|
||||||
class="grid size-8 place-content-center rounded-full bg-highlight-green text-xs font-bold text-brand"
|
:storage="plans.medium.metadata.storage"
|
||||||
>
|
:cpus="plans.medium.metadata.cpu"
|
||||||
M
|
:price="
|
||||||
</div>
|
plans.medium?.prices?.find((x) => x.currency_code === 'USD')?.prices?.intervals
|
||||||
</div>
|
?.monthly
|
||||||
<p class="m-0">Great for modded multiplayer and small communities.</p>
|
"
|
||||||
<div class="flex flex-row flex-wrap items-center gap-3 text-nowrap">
|
@select="selectProduct('medium')"
|
||||||
<p class="m-0">6 GB RAM</p>
|
@scroll-to-faq="scrollToFaq()"
|
||||||
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
/>
|
||||||
<p class="m-0">6 vCPUs</p>
|
<ServerPlanSelector
|
||||||
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
:capacity="capacityStatuses?.large?.available"
|
||||||
<p class="m-0">48 GB Storage</p>
|
:ram="plans.large.metadata.ram"
|
||||||
</div>
|
:storage="plans.large.metadata.storage"
|
||||||
<h2 class="m-0 text-3xl text-contrast">
|
:cpus="plans.large.metadata.cpu"
|
||||||
$18<span class="text-sm font-normal text-secondary">/month</span>
|
:price="
|
||||||
</h2>
|
plans.large?.prices?.find((x) => x.currency_code === 'USD')?.prices?.intervals
|
||||||
</div>
|
?.monthly
|
||||||
<ButtonStyled color="brand" size="large">
|
"
|
||||||
<a
|
plan="large"
|
||||||
v-if="!loggedOut && isMediumAtCapacity"
|
@select="selectProduct('large')"
|
||||||
:href="outOfStockUrl"
|
@scroll-to-faq="scrollToFaq()"
|
||||||
target="_blank"
|
/>
|
||||||
class="flex items-center gap-2 !bg-highlight-green !font-medium !text-green"
|
|
||||||
>
|
|
||||||
Out of Stock
|
|
||||||
<ExternalIcon class="!min-h-4 !min-w-4 !text-green" />
|
|
||||||
</a>
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
class="!bg-highlight-green !font-medium !text-green"
|
|
||||||
@click="selectProduct('medium')"
|
|
||||||
>
|
|
||||||
Get Started
|
|
||||||
<RightArrowIcon class="!min-h-4 !min-w-4 !text-green" />
|
|
||||||
</button>
|
|
||||||
</ButtonStyled>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li class="relative flex w-full flex-col justify-between pt-12 lg:w-1/3">
|
|
||||||
<div
|
|
||||||
v-if="isLargeLowStock"
|
|
||||||
class="absolute left-0 right-0 top-[-2px] rounded-t-2xl bg-yellow-500/20 p-4 text-center font-bold"
|
|
||||||
>
|
|
||||||
Only {{ capacityStatuses?.large?.available }} left in stock!
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="flex w-full flex-col justify-between gap-4 rounded-2xl bg-bg p-8 text-left"
|
|
||||||
:class="{ '!rounded-t-none': isLargeLowStock }"
|
|
||||||
>
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<div class="flex flex-row items-center justify-between">
|
|
||||||
<h1 class="m-0">Large</h1>
|
|
||||||
<div
|
|
||||||
class="grid size-8 place-content-center rounded-full bg-highlight-purple text-xs font-bold text-purple"
|
|
||||||
>
|
|
||||||
L
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p class="m-0">Ideal for larger communities, modpacks, and heavy modding.</p>
|
|
||||||
<div class="flex flex-row flex-wrap items-center gap-3 text-nowrap">
|
|
||||||
<p class="m-0">8 GB RAM</p>
|
|
||||||
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
|
||||||
<p class="m-0">8 vCPUs</p>
|
|
||||||
<div class="size-1.5 rounded-full bg-secondary opacity-25"></div>
|
|
||||||
<p class="m-0">64 GB Storage</p>
|
|
||||||
</div>
|
|
||||||
<h2 class="m-0 text-3xl text-contrast">
|
|
||||||
$24<span class="text-sm font-normal text-secondary">/month</span>
|
|
||||||
</h2>
|
|
||||||
</div>
|
|
||||||
<ButtonStyled color="brand" size="large">
|
|
||||||
<a
|
|
||||||
v-if="!loggedOut && isLargeAtCapacity"
|
|
||||||
:href="outOfStockUrl"
|
|
||||||
target="_blank"
|
|
||||||
class="flex items-center gap-2 !bg-highlight-purple !font-medium !text-purple"
|
|
||||||
>
|
|
||||||
Out of Stock
|
|
||||||
<ExternalIcon class="!min-h-4 !min-w-4 !text-purple" />
|
|
||||||
</a>
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
class="!bg-highlight-purple !font-medium !text-purple"
|
|
||||||
@click="selectProduct('large')"
|
|
||||||
>
|
|
||||||
Get Started
|
|
||||||
<RightArrowIcon class="!min-h-4 !min-w-4 !text-purple" />
|
|
||||||
</button>
|
|
||||||
</ButtonStyled>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="mb-4 flex w-full flex-col items-start justify-between gap-4 rounded-2xl bg-bg p-8 text-left lg:flex-row lg:gap-0"
|
class="mb-24 flex w-full flex-col items-start justify-between gap-4 rounded-2xl bg-bg p-8 text-left lg:flex-row lg:gap-0"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<h1 class="m-0">Build your own</h1>
|
<h1 class="m-0">Build your own</h1>
|
||||||
@ -781,11 +649,13 @@
|
|||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex w-full flex-col-reverse gap-2 md:w-auto md:flex-col md:items-center">
|
<div
|
||||||
|
class="experimental-styles-within flex w-full flex-col-reverse gap-2 md:w-auto md:flex-col md:items-center"
|
||||||
|
>
|
||||||
<ButtonStyled color="standard" size="large">
|
<ButtonStyled color="standard" size="large">
|
||||||
<button class="w-full md:w-fit" @click="selectProduct('custom')">
|
<button class="w-full md:w-fit" @click="selectProduct('custom')">
|
||||||
Build your own
|
Build your own
|
||||||
<RightArrowIcon class="!min-h-4 !min-w-4" />
|
<RightArrowIcon class="shrink-0" />
|
||||||
</button>
|
</button>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
<p class="m-0 text-sm">Starting at $3/GB RAM</p>
|
<p class="m-0 text-sm">Starting at $3/GB RAM</p>
|
||||||
@ -802,9 +672,6 @@ import {
|
|||||||
BoxIcon,
|
BoxIcon,
|
||||||
GameIcon,
|
GameIcon,
|
||||||
RightArrowIcon,
|
RightArrowIcon,
|
||||||
SearchIcon,
|
|
||||||
SortAscendingIcon,
|
|
||||||
ExternalIcon,
|
|
||||||
TerminalSquareIcon,
|
TerminalSquareIcon,
|
||||||
TransferIcon,
|
TransferIcon,
|
||||||
VersionIcon,
|
VersionIcon,
|
||||||
@ -813,6 +680,7 @@ import {
|
|||||||
import { products } from "~/generated/state.json";
|
import { products } from "~/generated/state.json";
|
||||||
import LoaderIcon from "~/components/ui/servers/icons/LoaderIcon.vue";
|
import LoaderIcon from "~/components/ui/servers/icons/LoaderIcon.vue";
|
||||||
import Globe from "~/components/ui/servers/Globe.vue";
|
import Globe from "~/components/ui/servers/Globe.vue";
|
||||||
|
import ServerPlanSelector from "~/components/ui/servers/marketing/ServerPlanSelector.vue";
|
||||||
|
|
||||||
const pyroProducts = products.filter((p) => p.metadata.type === "pyro");
|
const pyroProducts = products.filter((p) => p.metadata.type === "pyro");
|
||||||
const pyroPlanProducts = pyroProducts.filter(
|
const pyroPlanProducts = pyroProducts.filter(
|
||||||
@ -893,6 +761,7 @@ async function fetchCapacityStatuses(customProduct = null) {
|
|||||||
swap_mb: product.metadata.swap,
|
swap_mb: product.metadata.swap,
|
||||||
storage_mb: product.metadata.storage,
|
storage_mb: product.metadata.storage,
|
||||||
},
|
},
|
||||||
|
bypassAuth: true,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -931,21 +800,6 @@ const isMediumAtCapacity = computed(() => capacityStatuses.value?.medium?.availa
|
|||||||
const isLargeAtCapacity = computed(() => capacityStatuses.value?.large?.available === 0);
|
const isLargeAtCapacity = computed(() => capacityStatuses.value?.large?.available === 0);
|
||||||
const isCustomAtCapacity = computed(() => capacityStatuses.value?.custom?.available === 0);
|
const isCustomAtCapacity = computed(() => capacityStatuses.value?.custom?.available === 0);
|
||||||
|
|
||||||
const isSmallLowStock = computed(() => {
|
|
||||||
const available = capacityStatuses.value?.small?.available;
|
|
||||||
return available !== undefined && available > 0 && available < 8;
|
|
||||||
});
|
|
||||||
|
|
||||||
const isMediumLowStock = computed(() => {
|
|
||||||
const available = capacityStatuses.value?.medium?.available;
|
|
||||||
return available !== undefined && available > 0 && available < 8;
|
|
||||||
});
|
|
||||||
|
|
||||||
const isLargeLowStock = computed(() => {
|
|
||||||
const available = capacityStatuses.value?.large?.available;
|
|
||||||
return available !== undefined && available > 0 && available < 8;
|
|
||||||
});
|
|
||||||
|
|
||||||
const startTyping = () => {
|
const startTyping = () => {
|
||||||
const currentWord = words[currentWordIndex.value];
|
const currentWord = words[currentWordIndex.value];
|
||||||
if (isDeleting.value) {
|
if (isDeleting.value) {
|
||||||
|
|||||||
@ -196,7 +196,10 @@
|
|||||||
<div class="mt-2 flex flex-col gap-2">
|
<div class="mt-2 flex flex-col gap-2">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<CheckCircleIcon class="h-5 w-5 text-brand" />
|
<CheckCircleIcon class="h-5 w-5 text-brand" />
|
||||||
<span> {{ getPyroProduct(subscription)?.metadata?.cpu }} vCores (CPU) </span>
|
<span>
|
||||||
|
{{ getPyroProduct(subscription)?.metadata?.cpu / 2 }} Shared CPUs (Bursts up
|
||||||
|
to {{ getPyroProduct(subscription)?.metadata?.cpu }} CPUs)
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<CheckCircleIcon class="h-5 w-5 text-brand" />
|
<CheckCircleIcon class="h-5 w-5 text-brand" />
|
||||||
|
|||||||
@ -6,7 +6,7 @@ const props = withDefaults(
|
|||||||
color?: 'standard' | 'brand' | 'red' | 'orange' | 'green' | 'blue' | 'purple'
|
color?: 'standard' | 'brand' | 'red' | 'orange' | 'green' | 'blue' | 'purple'
|
||||||
size?: 'standard' | 'large'
|
size?: 'standard' | 'large'
|
||||||
circular?: boolean
|
circular?: boolean
|
||||||
type?: 'standard' | 'outlined' | 'transparent' | 'highlight'
|
type?: 'standard' | 'outlined' | 'transparent' | 'highlight' | 'highlight-colored-text'
|
||||||
colorFill?: 'auto' | 'background' | 'text' | 'none'
|
colorFill?: 'auto' | 'background' | 'text' | 'none'
|
||||||
hoverColorFill?: 'auto' | 'background' | 'text' | 'none'
|
hoverColorFill?: 'auto' | 'background' | 'text' | 'none'
|
||||||
highlightedStyle?: 'main-nav-primary' | 'main-nav-secondary'
|
highlightedStyle?: 'main-nav-primary' | 'main-nav-secondary'
|
||||||
@ -24,20 +24,40 @@ const props = withDefaults(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const highlightedColorVar = computed(() => {
|
||||||
|
switch (props.color) {
|
||||||
|
case 'brand':
|
||||||
|
return 'var(--color-brand-highlight)'
|
||||||
|
case 'red':
|
||||||
|
return 'var(--color-red-highlight)'
|
||||||
|
case 'orange':
|
||||||
|
return 'var(--color-orange-highlight)'
|
||||||
|
case 'green':
|
||||||
|
return 'var(--color-green-highlight)'
|
||||||
|
case 'blue':
|
||||||
|
return 'var(--color-blue-highlight)'
|
||||||
|
case 'purple':
|
||||||
|
return 'var(--color-purple-highlight)'
|
||||||
|
case 'standard':
|
||||||
|
default:
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const colorVar = computed(() => {
|
const colorVar = computed(() => {
|
||||||
switch (props.color) {
|
switch (props.color) {
|
||||||
case 'brand':
|
case 'brand':
|
||||||
return props.type === 'highlight' ? 'var(--color-brand-highlight)' : 'var(--color-brand)'
|
return 'var(--color-brand)'
|
||||||
case 'red':
|
case 'red':
|
||||||
return props.type === 'highlight' ? 'var(--color-red-highlight)' : 'var(--color-red)'
|
return 'var(--color-red)'
|
||||||
case 'orange':
|
case 'orange':
|
||||||
return props.type === 'highlight' ? 'var(--color-orange-highlight)' : 'var(--color-orange)'
|
return 'var(--color-orange)'
|
||||||
case 'green':
|
case 'green':
|
||||||
return props.type === 'highlight' ? 'var(--color-green-highlight)' : 'var(--color-green)'
|
return 'var(--color-green)'
|
||||||
case 'blue':
|
case 'blue':
|
||||||
return props.type === 'highlight' ? 'var(--color-blue-highlight)' : 'var(--color-blue)'
|
return 'var(--color-blue)'
|
||||||
case 'purple':
|
case 'purple':
|
||||||
return props.type === 'highlight' ? 'var(--color-purple-highlight)' : 'var(--color-purple)'
|
return 'var(--color-purple)'
|
||||||
case 'standard':
|
case 'standard':
|
||||||
default:
|
default:
|
||||||
return null
|
return null
|
||||||
@ -111,10 +131,14 @@ function setColorFill(
|
|||||||
): { bg: string; text: string } {
|
): { bg: string; text: string } {
|
||||||
if (colorVar.value) {
|
if (colorVar.value) {
|
||||||
if (fill === 'background') {
|
if (fill === 'background') {
|
||||||
colors.bg = colorVar.value
|
if (props.type === 'highlight' && highlightedColorVar.value) {
|
||||||
if (props.type === 'highlight') {
|
colors.bg = highlightedColorVar.value
|
||||||
colors.text = 'var(--color-contrast)'
|
colors.text = 'var(--color-contrast)'
|
||||||
|
} else if (props.type === 'highlight-colored-text' && highlightedColorVar.value) {
|
||||||
|
colors.bg = highlightedColorVar.value
|
||||||
|
colors.text = colorVar.value
|
||||||
} else {
|
} else {
|
||||||
|
colors.bg = colorVar.value
|
||||||
colors.text = 'var(--color-accent-contrast)'
|
colors.text = 'var(--color-accent-contrast)'
|
||||||
}
|
}
|
||||||
} else if (fill === 'text') {
|
} else if (fill === 'text') {
|
||||||
|
|||||||
@ -106,13 +106,16 @@
|
|||||||
</p>
|
</p>
|
||||||
<IssuesIcon
|
<IssuesIcon
|
||||||
v-if="customServerConfig.ramInGb < 4"
|
v-if="customServerConfig.ramInGb < 4"
|
||||||
v-tooltip="'This might not be enough resources for your Minecraft server.'"
|
v-tooltip="'This might not be powerful enough for your Minecraft server.'"
|
||||||
class="h-6 w-6 text-orange"
|
class="h-6 w-6 text-orange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="existingPlan" class="mt-1 mb-2 text-secondary">
|
<p v-if="existingPlan" class="mt-1 mb-2 text-secondary">
|
||||||
Your current plan has <strong>{{ existingPlan.metadata.ram / 1024 }} GB RAM</strong> and
|
Your current plan has <strong>{{ existingPlan.metadata.ram / 1024 }} GB RAM</strong> and
|
||||||
<strong>{{ existingPlan.metadata.cpu }} vCPUs</strong>.
|
<strong
|
||||||
|
>{{ existingPlan.metadata.cpu / 2 }} shared CPUs (bursts up to
|
||||||
|
{{ existingPlan.metadata.cpu }} CPUs)</strong
|
||||||
|
>.
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<div class="flex w-full gap-2 items-center">
|
<div class="flex w-full gap-2 items-center">
|
||||||
@ -131,12 +134,28 @@
|
|||||||
class="flex sm:flex-row flex-col gap-4 w-full"
|
class="flex sm:flex-row flex-col gap-4 w-full"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col w-full gap-2">
|
<div class="flex flex-col w-full gap-2">
|
||||||
<div class="font-semibold">vCPUs</div>
|
<div class="font-semibold">Shared CPUs</div>
|
||||||
<input v-model="mutatedProduct.metadata.cpu" disabled class="input" />
|
<input :value="sharedCpus" disabled class="input w-full" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col w-full gap-2">
|
||||||
|
<div class="font-semibold flex items-center gap-1">
|
||||||
|
Max Burst CPUs
|
||||||
|
<UnknownIcon
|
||||||
|
v-tooltip="
|
||||||
|
'CPU bursting allows your server to temporarily use additional threads to help mitigate TPS spikes. See Modrinth Servers FAQ for more info.'
|
||||||
|
"
|
||||||
|
class="h-4 w-4text-secondary opacity-60"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<input :value="mutatedProduct.metadata.cpu" disabled class="input w-full" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col w-full gap-2">
|
<div class="flex flex-col w-full gap-2">
|
||||||
<div class="font-semibold">Storage</div>
|
<div class="font-semibold">Storage</div>
|
||||||
<input v-model="customServerConfig.storageGbFormatted" disabled class="input" />
|
<input
|
||||||
|
v-model="customServerConfig.storageGbFormatted"
|
||||||
|
disabled
|
||||||
|
class="input w-full"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Admonition
|
<Admonition
|
||||||
@ -153,10 +172,11 @@
|
|||||||
later, or try a different amount.
|
later, or try a different amount.
|
||||||
</Admonition>
|
</Admonition>
|
||||||
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex gap-2">
|
||||||
<InfoIcon class="hidden sm:block" />
|
<InfoIcon class="hidden sm:block shrink-0 mt-1" />
|
||||||
<span class="text-sm text-secondary">
|
<span class="text-sm text-secondary">
|
||||||
Storage and vCPUs are currently not configurable.
|
Storage and shared CPU count are currently not configurable independently, and are
|
||||||
|
based on the amount of RAM you select.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -500,6 +520,7 @@
|
|||||||
import { ref, computed, nextTick, reactive, watch } from 'vue'
|
import { ref, computed, nextTick, reactive, watch } from 'vue'
|
||||||
import NewModal from '../modal/NewModal.vue'
|
import NewModal from '../modal/NewModal.vue'
|
||||||
import {
|
import {
|
||||||
|
UnknownIcon,
|
||||||
SpinnerIcon,
|
SpinnerIcon,
|
||||||
CardIcon,
|
CardIcon,
|
||||||
CheckCircleIcon,
|
CheckCircleIcon,
|
||||||
@ -765,7 +786,11 @@ function updateRamValues() {
|
|||||||
customMinRam.value = Math.min(...ramValues)
|
customMinRam.value = Math.min(...ramValues)
|
||||||
customMaxRam.value = Math.max(...ramValues)
|
customMaxRam.value = Math.max(...ramValues)
|
||||||
|
|
||||||
|
if (props.product.some((product) => product.metadata.ram / 1024 === 4)) {
|
||||||
|
customServerConfig.ramInGb = 4
|
||||||
|
} else {
|
||||||
customServerConfig.ramInGb = customMinRam.value
|
customServerConfig.ramInGb = customMinRam.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.customServer) {
|
if (props.customServer) {
|
||||||
@ -832,6 +857,10 @@ const metadata = computed(() => {
|
|||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const sharedCpus = computed(() => {
|
||||||
|
return (mutatedProduct.value?.metadata?.cpu ?? 0) / 2
|
||||||
|
})
|
||||||
|
|
||||||
function nextStep() {
|
function nextStep() {
|
||||||
if (
|
if (
|
||||||
mutatedProduct.value.metadata.type === 'pyro' &&
|
mutatedProduct.value.metadata.type === 'pyro' &&
|
||||||
|
|||||||
@ -10,6 +10,12 @@ export type VersionEntry = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const VERSIONS: VersionEntry[] = [
|
const VERSIONS: VersionEntry[] = [
|
||||||
|
{
|
||||||
|
date: `2025-04-18T22:30:00-07:00`,
|
||||||
|
product: 'web',
|
||||||
|
body: `### Improvements
|
||||||
|
- Updated Modrinth Servers marketing page to be accurate to post-Pyro infrastructure.`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
date: `2025-04-17T02:25:00-07:00`,
|
date: `2025-04-17T02:25:00-07:00`,
|
||||||
product: 'servers',
|
product: 'servers',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user