feat(marketing): miami, overallocation card, misc fixes (#2926)
* fix(marketing): make faq headings medium * feat(marketing): add card for overallocation * feat(marketing): add miami location * fix(marketing): 'login' -> 'sign in' consistency * feat: plan query string support + simplify buttons
This commit is contained in:
parent
f5208a85b0
commit
24e90f0a54
@ -167,7 +167,7 @@
|
||||
class="hidden w-full rounded-2xl sm:block"
|
||||
/>
|
||||
</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-3">
|
||||
<div class="flex flex-col gap-4 rounded-2xl bg-bg p-6 text-left md:p-12">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -218,6 +218,22 @@
|
||||
custom-built software to ensure your server performs smoothly.
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="relative flex flex-col gap-4 rounded-2xl bg-bg p-6 text-left md:p-12">
|
||||
<ServerIcon class="size-8 text-brand" />
|
||||
<h2 class="m-0 text-lg font-bold">Consistently fast</h2>
|
||||
<h3 class="m-0 text-base font-normal text-secondary">
|
||||
Under Pyro, infrastructure is never overloaded, meaning each Modrinth server always
|
||||
runs at its full performance.
|
||||
<a
|
||||
class="mt-2 flex items-center gap-2 font-medium text-contrast transition-all hover:gap-3"
|
||||
href="https://status.pyro.host/"
|
||||
target="_blank"
|
||||
>
|
||||
See the infrastructure <RightArrowIcon class="flex-none" />
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -406,7 +422,7 @@
|
||||
<h1 class="m-0 text-lg font-bold">Frequently Asked Questions</h1>
|
||||
<div class="details-hide flex flex-col gap-1">
|
||||
<details pyro-hash="cpus" class="group" :open="$route.hash === '#cpus'">
|
||||
<summary class="flex cursor-pointer items-center py-3 font-bold text-contrast">
|
||||
<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>
|
||||
@ -419,7 +435,7 @@
|
||||
</details>
|
||||
|
||||
<details pyro-hash="ddos" class="group" :open="$route.hash === '#ddos'">
|
||||
<summary class="flex cursor-pointer items-center py-3 font-bold text-contrast">
|
||||
<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>
|
||||
@ -433,21 +449,21 @@
|
||||
</details>
|
||||
|
||||
<details pyro-hash="region" class="group" :open="$route.hash === '#region'">
|
||||
<summary class="flex cursor-pointer items-center py-3 font-bold text-contrast">
|
||||
<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>
|
||||
Where are Modrinth Servers located? Can I choose a region?
|
||||
</summary>
|
||||
<p class="m-0 !leading-[190%]">
|
||||
Currently, Modrinth Servers are located in New York and Los Angeles. More regions
|
||||
are coming soon! Your server's location is currently chosen algorithmically, but you
|
||||
will be able to choose a region in the future.
|
||||
Currently, Modrinth Servers are located in New York, Los Angeles, and Miami. More
|
||||
regions are coming soon! Your server's location is currently chosen algorithmically,
|
||||
but you will be able to choose a region in the future.
|
||||
</p>
|
||||
</details>
|
||||
|
||||
<details pyro-hash="storage" class="group" :open="$route.hash === '#storage'">
|
||||
<summary class="flex cursor-pointer items-center py-3 font-bold text-contrast">
|
||||
<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>
|
||||
@ -460,7 +476,7 @@
|
||||
</details>
|
||||
|
||||
<details pyro-hash="players" class="group" :open="$route.hash === '#players'">
|
||||
<summary class="flex cursor-pointer items-center py-3 font-bold text-contrast">
|
||||
<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>
|
||||
@ -496,7 +512,7 @@
|
||||
: "There's a plan for everyone! Choose the one that fits your needs."
|
||||
}}
|
||||
<span class="font-bold">
|
||||
Servers are currently US only, in New York and Los Angeles. More regions coming
|
||||
Servers are currently US only, in New York, Los Angeles, and Miami. More regions coming
|
||||
soon!</span
|
||||
>
|
||||
</h2>
|
||||
@ -526,17 +542,7 @@
|
||||
</h2>
|
||||
<ButtonStyled color="blue" size="large">
|
||||
<NuxtLink
|
||||
v-if="loggedOut"
|
||||
:to="loginUrl"
|
||||
target="_self"
|
||||
class="!bg-highlight-blue !font-medium !text-blue"
|
||||
>
|
||||
Login
|
||||
<UserIcon class="!min-h-4 !min-w-4 !text-blue" />
|
||||
</NuxtLink>
|
||||
<template v-else>
|
||||
<NuxtLink
|
||||
v-if="isSmallAtCapacity"
|
||||
v-if="!loggedOut && isSmallAtCapacity"
|
||||
:to="outOfStockUrl"
|
||||
target="_blank"
|
||||
class="!bg-highlight-blue !font-medium !text-blue"
|
||||
@ -547,12 +553,11 @@
|
||||
<button
|
||||
v-else
|
||||
class="!bg-highlight-blue !font-medium !text-blue"
|
||||
@click="selectProduct(pyroPlanProducts[0])"
|
||||
@click="selectProduct('small')"
|
||||
>
|
||||
Get Started
|
||||
<RightArrowIcon class="!min-h-4 !min-w-4 !text-blue" />
|
||||
</button>
|
||||
</template>
|
||||
</ButtonStyled>
|
||||
</li>
|
||||
|
||||
@ -589,17 +594,7 @@
|
||||
</h2>
|
||||
<ButtonStyled color="brand" size="large">
|
||||
<NuxtLink
|
||||
v-if="loggedOut"
|
||||
:to="loginUrl"
|
||||
target="_self"
|
||||
class="!bg-highlight-green !font-medium !text-green"
|
||||
>
|
||||
Login
|
||||
<UserIcon class="!min-h-4 !min-w-4 !text-green" />
|
||||
</NuxtLink>
|
||||
<template v-else>
|
||||
<NuxtLink
|
||||
v-if="isMediumAtCapacity"
|
||||
v-if="!loggedOut && isMediumAtCapacity"
|
||||
:to="outOfStockUrl"
|
||||
target="_blank"
|
||||
class="!bg-highlight-green !font-medium !text-green"
|
||||
@ -610,12 +605,11 @@
|
||||
<button
|
||||
v-else
|
||||
class="!bg-highlight-green !font-medium !text-green"
|
||||
@click="selectProduct(pyroPlanProducts[1])"
|
||||
@click="selectProduct('medium')"
|
||||
>
|
||||
Get Started
|
||||
<RightArrowIcon class="!min-h-4 !min-w-4 !text-green" />
|
||||
</button>
|
||||
</template>
|
||||
</ButtonStyled>
|
||||
</li>
|
||||
|
||||
@ -639,19 +633,9 @@
|
||||
<h2 class="m-0 text-3xl text-contrast">
|
||||
$24<span class="text-sm font-normal text-secondary">/month</span>
|
||||
</h2>
|
||||
<ButtonStyled color="purple" size="large">
|
||||
<ButtonStyled color="brand" size="large">
|
||||
<NuxtLink
|
||||
v-if="loggedOut"
|
||||
:to="loginUrl"
|
||||
target="_self"
|
||||
class="!bg-highlight-purple !font-medium !text-purple"
|
||||
>
|
||||
Login
|
||||
<UserIcon class="!min-h-4 !min-w-4 !text-purple" />
|
||||
</NuxtLink>
|
||||
<template v-else>
|
||||
<NuxtLink
|
||||
v-if="isLargeAtCapacity"
|
||||
v-if="!loggedOut && isLargeAtCapacity"
|
||||
:to="outOfStockUrl"
|
||||
target="_blank"
|
||||
class="!bg-highlight-purple !font-medium !text-purple"
|
||||
@ -662,12 +646,11 @@
|
||||
<button
|
||||
v-else
|
||||
class="!bg-highlight-purple !font-medium !text-purple"
|
||||
@click="selectProduct(pyroPlanProducts[2])"
|
||||
@click="selectProduct('large')"
|
||||
>
|
||||
Get Started
|
||||
<RightArrowIcon class="!min-h-4 !min-w-4 !text-purple" />
|
||||
</button>
|
||||
</template>
|
||||
</ButtonStyled>
|
||||
</li>
|
||||
</ul>
|
||||
@ -685,11 +668,7 @@
|
||||
|
||||
<div class="flex w-full flex-col-reverse gap-2 md:w-auto md:flex-col md:items-center">
|
||||
<ButtonStyled color="standard" size="large">
|
||||
<NuxtLink v-if="loggedOut" :to="loginUrl" target="_self" class="w-full md:w-fit">
|
||||
Login
|
||||
<UserIcon class="!min-h-4 !min-w-4" />
|
||||
</NuxtLink>
|
||||
<button v-else class="w-full md:w-fit" @click="selectProduct(pyroProducts, true)">
|
||||
<button class="w-full md:w-fit" @click="selectProduct('custom')">
|
||||
Build your own
|
||||
<RightArrowIcon class="!min-h-4 !min-w-4" />
|
||||
</button>
|
||||
@ -712,9 +691,9 @@ import {
|
||||
SortAscendingIcon,
|
||||
ExternalIcon,
|
||||
TerminalSquareIcon,
|
||||
UserIcon,
|
||||
TransferIcon,
|
||||
VersionIcon,
|
||||
ServerIcon,
|
||||
} from "@modrinth/assets";
|
||||
import { products } from "~/generated/state.json";
|
||||
import LoaderIcon from "~/components/ui/servers/icons/LoaderIcon.vue";
|
||||
@ -724,11 +703,6 @@ const pyroPlanProducts = pyroProducts.filter(
|
||||
(p) => p.metadata.ram === 4096 || p.metadata.ram === 6144 || p.metadata.ram === 8192,
|
||||
);
|
||||
pyroPlanProducts.sort((a, b) => a.metadata.ram - b.metadata.ram);
|
||||
// yep. this is a thing.
|
||||
if (!pyroProducts.metadata) {
|
||||
pyroProducts.metadata = {};
|
||||
}
|
||||
pyroProducts.metadata.type = "pyro";
|
||||
|
||||
const title = "Modrinth Servers";
|
||||
const description =
|
||||
@ -772,7 +746,6 @@ const deletingSpeed = 25;
|
||||
const pauseTime = 2000;
|
||||
|
||||
const loggedOut = computed(() => !auth.value.user);
|
||||
const loginUrl = `/auth/sign-in?redirect=${encodeURIComponent("/servers#plan")}`;
|
||||
const outOfStockUrl = "https://support.modrinth.com";
|
||||
|
||||
const { data: hasServers } = await useAsyncData("ServerListCountCheck", async () => {
|
||||
@ -920,19 +893,20 @@ onMounted(scrollToFaq);
|
||||
|
||||
watch(() => route.hash, scrollToFaq);
|
||||
|
||||
const selectProduct = async (product, custom) => {
|
||||
if (isAtCapacity.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Server Capacity Full",
|
||||
type: "error",
|
||||
text: "We are currently at capacity. Please try again later.",
|
||||
});
|
||||
const plans = {
|
||||
small: pyroPlanProducts?.[0],
|
||||
medium: pyroPlanProducts?.[1],
|
||||
large: pyroPlanProducts?.[2],
|
||||
custom: pyroProducts || [],
|
||||
};
|
||||
|
||||
const selectProduct = async (product) => {
|
||||
if (loggedOut.value) {
|
||||
data.$router.push(`/auth/sign-in?redirect=${encodeURIComponent("/servers?plan=" + product)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
await refreshCapacity();
|
||||
|
||||
if (isAtCapacity.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
@ -943,68 +917,53 @@ const selectProduct = async (product, custom) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!auth.value.user) {
|
||||
data.$router.push(loginUrl);
|
||||
const selectedPlan = plans[product];
|
||||
if (!selectedPlan) return;
|
||||
|
||||
if (
|
||||
(product === "custom" && !selectedPlan.length) ||
|
||||
(product !== "custom" && !selectedPlan.metadata)
|
||||
) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Invalid product",
|
||||
type: "error",
|
||||
text: "The selected product was found but lacks necessary data. Please contact support.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
customServer.value = !!custom;
|
||||
selectedProduct.value = product;
|
||||
// required for the purchase modal
|
||||
if (!pyroProducts.metadata) {
|
||||
pyroProducts.metadata = {};
|
||||
}
|
||||
pyroProducts.metadata.type = "pyro";
|
||||
|
||||
customServer.value = product === "custom";
|
||||
selectedProduct.value = selectedPlan;
|
||||
showModal.value = true;
|
||||
modalKey.value++;
|
||||
await nextTick();
|
||||
|
||||
if (purchaseModal.value && purchaseModal.value.show) {
|
||||
purchaseModal.value.show();
|
||||
}
|
||||
};
|
||||
|
||||
const openPurchaseModal = () => {
|
||||
if (isAtCapacity.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Server Capacity Full",
|
||||
type: "error",
|
||||
text: "We are currently at capacity. Please try again later.",
|
||||
});
|
||||
return;
|
||||
const planQuery = () => {
|
||||
if (route.query.plan) {
|
||||
document.getElementById("plan").scrollIntoView();
|
||||
selectProduct(route.query.plan);
|
||||
}
|
||||
|
||||
refreshCapacity();
|
||||
|
||||
if (isAtCapacity.value) {
|
||||
addNotification({
|
||||
group: "main",
|
||||
title: "Server Capacity Full",
|
||||
type: "error",
|
||||
text: "We are currently at capacity. Please try again later.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
customServer.value = false;
|
||||
selectedProduct.value = pyroPlanProducts[0];
|
||||
showModal.value = true;
|
||||
modalKey.value++;
|
||||
nextTick(() => {
|
||||
if (purchaseModal.value && purchaseModal.value.show) {
|
||||
purchaseModal.value.show();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
startTyping();
|
||||
if (route.query.showModal) {
|
||||
openPurchaseModal();
|
||||
}
|
||||
planQuery();
|
||||
});
|
||||
|
||||
watch(customer, (newCustomer) => {
|
||||
if (newCustomer) {
|
||||
if (route.query.showModal) {
|
||||
openPurchaseModal();
|
||||
}
|
||||
}
|
||||
if (newCustomer) planQuery();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user