Dynamic product pages + Battlefield ACP marketing page
- Web Hosting & Game Servers now pull plans from database (same pattern as VPS/Dedicated) - Add 6 game server plans to PlanSeeder (Minecraft, Rust, ARK, Valheim, CS2, Palworld) - Create Battlefield ACP marketing page with ProCon replacement hero, 6 feature cards, ML analytics, ban appeals, PunkBuster screenshots, Discord integration sections - Add Battlefield ACP to Products dropdown navigation - Marketing pages use SectionHeader component, fade-in animations, Vuexy design patterns Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -443,6 +443,110 @@ class PlanSeeder extends Seeder
|
|||||||
'sort_order' => 23,
|
'sort_order' => 23,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// ─── Game Server Plans ──────────────────────────────────────
|
||||||
|
[
|
||||||
|
'name' => 'Minecraft',
|
||||||
|
'slug' => 'game-minecraft',
|
||||||
|
'description' => 'Java & Bedrock Minecraft server with full mod support.',
|
||||||
|
'service_type' => 'game',
|
||||||
|
'price' => 7.99,
|
||||||
|
'billing_cycle' => 'monthly',
|
||||||
|
'features' => [
|
||||||
|
'ram' => '2 GB',
|
||||||
|
'slots' => '20 Players',
|
||||||
|
'storage' => '10 GB SSD',
|
||||||
|
'cpu' => '2 Threads',
|
||||||
|
'mods' => 'Full Mod Support',
|
||||||
|
'ddos' => 'DDoS Protection',
|
||||||
|
],
|
||||||
|
'sort_order' => 40,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Rust',
|
||||||
|
'slug' => 'game-rust',
|
||||||
|
'description' => 'High-performance Rust server with Oxide/uMod support.',
|
||||||
|
'service_type' => 'game',
|
||||||
|
'price' => 14.99,
|
||||||
|
'billing_cycle' => 'monthly',
|
||||||
|
'features' => [
|
||||||
|
'ram' => '4 GB',
|
||||||
|
'slots' => '50 Players',
|
||||||
|
'storage' => '25 GB SSD',
|
||||||
|
'cpu' => '3 Threads',
|
||||||
|
'mods' => 'Oxide/uMod Support',
|
||||||
|
'ddos' => 'DDoS Protection',
|
||||||
|
],
|
||||||
|
'sort_order' => 41,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'ARK: Survival Evolved',
|
||||||
|
'slug' => 'game-ark',
|
||||||
|
'description' => 'ARK servers with cluster support and full mod compatibility.',
|
||||||
|
'service_type' => 'game',
|
||||||
|
'price' => 19.99,
|
||||||
|
'billing_cycle' => 'monthly',
|
||||||
|
'features' => [
|
||||||
|
'ram' => '8 GB',
|
||||||
|
'slots' => '30 Players',
|
||||||
|
'storage' => '50 GB SSD',
|
||||||
|
'cpu' => '4 Threads',
|
||||||
|
'mods' => 'Full Mod Support',
|
||||||
|
'ddos' => 'DDoS Protection',
|
||||||
|
],
|
||||||
|
'sort_order' => 42,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Valheim',
|
||||||
|
'slug' => 'game-valheim',
|
||||||
|
'description' => 'Dedicated Valheim server with BepInEx mod support.',
|
||||||
|
'service_type' => 'game',
|
||||||
|
'price' => 9.99,
|
||||||
|
'billing_cycle' => 'monthly',
|
||||||
|
'features' => [
|
||||||
|
'ram' => '4 GB',
|
||||||
|
'slots' => '10 Players',
|
||||||
|
'storage' => '10 GB SSD',
|
||||||
|
'cpu' => '2 Threads',
|
||||||
|
'mods' => 'BepInEx Support',
|
||||||
|
'ddos' => 'DDoS Protection',
|
||||||
|
],
|
||||||
|
'sort_order' => 43,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'CS2',
|
||||||
|
'slug' => 'game-cs2',
|
||||||
|
'description' => 'Counter-Strike 2 competitive and casual servers.',
|
||||||
|
'service_type' => 'game',
|
||||||
|
'price' => 12.99,
|
||||||
|
'billing_cycle' => 'monthly',
|
||||||
|
'features' => [
|
||||||
|
'ram' => '4 GB',
|
||||||
|
'slots' => '32 Players',
|
||||||
|
'storage' => '15 GB SSD',
|
||||||
|
'cpu' => '3 Threads',
|
||||||
|
'mods' => 'Workshop Support',
|
||||||
|
'ddos' => 'DDoS Protection',
|
||||||
|
],
|
||||||
|
'sort_order' => 44,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Palworld',
|
||||||
|
'slug' => 'game-palworld',
|
||||||
|
'description' => 'Palworld dedicated server with full configuration.',
|
||||||
|
'service_type' => 'game',
|
||||||
|
'price' => 14.99,
|
||||||
|
'billing_cycle' => 'monthly',
|
||||||
|
'features' => [
|
||||||
|
'ram' => '8 GB',
|
||||||
|
'slots' => '32 Players',
|
||||||
|
'storage' => '20 GB SSD',
|
||||||
|
'cpu' => '4 Threads',
|
||||||
|
'mods' => 'Community Mods',
|
||||||
|
'ddos' => 'DDoS Protection',
|
||||||
|
],
|
||||||
|
'sort_order' => 45,
|
||||||
|
],
|
||||||
|
|
||||||
// ─── MySQL Hosting Plans ─────────────────────────────────────
|
// ─── MySQL Hosting Plans ─────────────────────────────────────
|
||||||
[
|
[
|
||||||
'name' => 'Bronze',
|
'name' => 'Bronze',
|
||||||
|
|||||||
68
website/resources/styles/_marketing.scss
Normal file
68
website/resources/styles/_marketing.scss
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// ━━━ Marketing Page Styles ━━━
|
||||||
|
|
||||||
|
// Standard section spacing (matches Vuexy convention)
|
||||||
|
.marketing-section {
|
||||||
|
padding-block: 5.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animated gradient text effect
|
||||||
|
.hero-gradient-text {
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
rgb(var(--v-theme-primary)) 0%,
|
||||||
|
#9f8fff 50%,
|
||||||
|
rgb(var(--v-theme-primary)) 100%
|
||||||
|
);
|
||||||
|
background-size: 200% auto;
|
||||||
|
background-clip: text;
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
animation: gradient-shine 3s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes gradient-shine {
|
||||||
|
0% { background-position: 0% center; }
|
||||||
|
50% { background-position: 100% center; }
|
||||||
|
100% { background-position: 0% center; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Card hover effect - lift up with shadow
|
||||||
|
.feature-card-hover {
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 4px 25px 0 rgba(var(--v-shadow-key-umbra-color), 0.16) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fade-in-up animation
|
||||||
|
.fade-in-up {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(20px);
|
||||||
|
animation: fadeInUp 0.6s ease forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Staggered animation delays (for card grids)
|
||||||
|
@for $i from 1 through 8 {
|
||||||
|
.stagger-delay-#{$i} {
|
||||||
|
animation-delay: #{$i * 0.1}s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alternating section background
|
||||||
|
.section-alt-bg {
|
||||||
|
background-color: rgba(var(--v-theme-on-surface), var(--v-hover-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hero section with rounded bottom
|
||||||
|
.hero-section {
|
||||||
|
border-radius: 0 0 50px 50px;
|
||||||
|
}
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
// Vertical sidebar navigation layout
|
// Vertical sidebar navigation layout
|
||||||
@use "@layouts/styles/vertical-nav";
|
@use "@layouts/styles/vertical-nav";
|
||||||
|
|
||||||
|
// Marketing page shared styles
|
||||||
|
@use "marketing";
|
||||||
|
|
||||||
// ━━━ Project-specific overrides ━━━
|
// ━━━ Project-specific overrides ━━━
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
|||||||
46
website/resources/ts/Components/Marketing/SectionHeader.vue
Normal file
46
website/resources/ts/Components/Marketing/SectionHeader.vue
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
interface Props {
|
||||||
|
label?: string
|
||||||
|
labelColor?: string
|
||||||
|
title: string
|
||||||
|
highlightWord?: string
|
||||||
|
subtitle?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
withDefaults(defineProps<Props>(), {
|
||||||
|
label: undefined,
|
||||||
|
labelColor: 'primary',
|
||||||
|
highlightWord: undefined,
|
||||||
|
subtitle: undefined,
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="text-center mb-12">
|
||||||
|
<VChip
|
||||||
|
v-if="label"
|
||||||
|
:color="labelColor"
|
||||||
|
variant="tonal"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</VChip>
|
||||||
|
|
||||||
|
<h2 class="text-h3 font-weight-bold mb-3">
|
||||||
|
<template v-if="highlightWord && title.includes(highlightWord)">
|
||||||
|
{{ title.split(highlightWord)[0] }}<span class="hero-gradient-text">{{ highlightWord }}</span>{{ title.split(highlightWord)[1] }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
{{ title }}
|
||||||
|
</template>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p
|
||||||
|
v-if="subtitle"
|
||||||
|
class="text-body-1 text-medium-emphasis mx-auto"
|
||||||
|
style="max-inline-size: 600px;"
|
||||||
|
>
|
||||||
|
{{ subtitle }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { usePage } from '@inertiajs/vue3'
|
import { useForm, usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { useTheme } from 'vuetify'
|
import { useTheme } from 'vuetify'
|
||||||
import { marketingNavItems } from '@/navigation/marketing'
|
import { marketingNavItems } from '@/navigation/marketing'
|
||||||
import ThemeSwitcher from '@/Components/ThemeSwitcher.vue'
|
import ThemeSwitcher from '@/Components/ThemeSwitcher.vue'
|
||||||
@@ -9,6 +9,45 @@ import logoWhite from '@images/ezscale_logo_white.png'
|
|||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const isDark = computed(() => theme.global.current.value.dark)
|
const isDark = computed(() => theme.global.current.value.dark)
|
||||||
|
|
||||||
|
const isScrolled = ref(false)
|
||||||
|
|
||||||
|
function handleScroll(): void {
|
||||||
|
isScrolled.value = window.scrollY > 50
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('scroll', handleScroll)
|
||||||
|
handleScroll()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener('scroll', handleScroll)
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentPath = computed<string>(() => {
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
return window.location.pathname
|
||||||
|
}
|
||||||
|
return '/'
|
||||||
|
})
|
||||||
|
|
||||||
|
const newsletterForm = useForm({
|
||||||
|
email: '',
|
||||||
|
})
|
||||||
|
|
||||||
|
const newsletterSuccess = ref(false)
|
||||||
|
|
||||||
|
function subscribeNewsletter(): void {
|
||||||
|
// For now, just show success state (no backend endpoint yet)
|
||||||
|
if (newsletterForm.email) {
|
||||||
|
newsletterSuccess.value = true
|
||||||
|
setTimeout(() => {
|
||||||
|
newsletterSuccess.value = false
|
||||||
|
newsletterForm.email = ''
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
domains: { marketing: string; account: string; admin: string }
|
domains: { marketing: string; account: string; admin: string }
|
||||||
}
|
}
|
||||||
@@ -53,7 +92,11 @@ const socialLinks = [
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VApp>
|
<VApp>
|
||||||
<VAppBar flat>
|
<VAppBar
|
||||||
|
:elevation="isScrolled ? 4 : 0"
|
||||||
|
:class="isScrolled ? 'navbar-scrolled' : 'navbar-transparent'"
|
||||||
|
class="marketing-navbar"
|
||||||
|
>
|
||||||
<VContainer class="d-flex align-center">
|
<VContainer class="d-flex align-center">
|
||||||
<a href="/" class="d-inline-flex align-center">
|
<a href="/" class="d-inline-flex align-center">
|
||||||
<img
|
<img
|
||||||
@@ -94,7 +137,11 @@ const socialLinks = [
|
|||||||
</VMenu>
|
</VMenu>
|
||||||
|
|
||||||
<a v-else :href="item.href" class="text-decoration-none">
|
<a v-else :href="item.href" class="text-decoration-none">
|
||||||
<VBtn variant="text" size="small">
|
<VBtn
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
:color="item.href === currentPath ? 'primary' : undefined"
|
||||||
|
>
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</a>
|
</a>
|
||||||
@@ -148,16 +195,23 @@ const socialLinks = [
|
|||||||
High-performance VPS, dedicated servers, and hosting solutions with 24/7 support and enterprise-grade infrastructure.
|
High-performance VPS, dedicated servers, and hosting solutions with 24/7 support and enterprise-grade infrastructure.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<VForm class="subscribe-form d-flex align-center">
|
<VForm class="subscribe-form d-flex align-center" @submit.prevent="subscribeNewsletter">
|
||||||
<VTextField
|
<VTextField
|
||||||
label="Subscribe to newsletter"
|
v-model="newsletterForm.email"
|
||||||
|
:label="newsletterSuccess ? 'Subscribed!' : 'Subscribe to newsletter'"
|
||||||
placeholder="john@email.com"
|
placeholder="john@email.com"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
hide-details
|
hide-details
|
||||||
|
type="email"
|
||||||
|
:color="newsletterSuccess ? 'success' : undefined"
|
||||||
/>
|
/>
|
||||||
<VBtn class="align-self-end rounded-s-0">
|
<VBtn
|
||||||
Subscribe
|
type="submit"
|
||||||
|
class="align-self-end rounded-s-0"
|
||||||
|
:color="newsletterSuccess ? 'success' : undefined"
|
||||||
|
>
|
||||||
|
{{ newsletterSuccess ? 'Done!' : 'Subscribe' }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</VForm>
|
</VForm>
|
||||||
</div>
|
</div>
|
||||||
@@ -291,6 +345,14 @@ const socialLinks = [
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.marketing-navbar {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-scrolled {
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
.footer-title {
|
.footer-title {
|
||||||
color: rgba(255, 255, 255, 92%);
|
color: rgba(255, 255, 255, 92%);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
@@ -11,10 +12,17 @@ const values = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const milestones = [
|
const milestones = [
|
||||||
{ year: '2024', event: 'EZSCALE founded with a mission to simplify cloud hosting.' },
|
{ year: '2024', event: 'EZSCALE founded with a mission to simplify cloud hosting.', color: 'primary' },
|
||||||
{ year: '2024', event: 'Launched VPS and Dedicated Server product lines.' },
|
{ year: '2024', event: 'Launched VPS and Dedicated Server product lines.', color: 'success' },
|
||||||
{ year: '2025', event: 'Expanded to 50+ data center locations worldwide.' },
|
{ year: '2025', event: 'Expanded to 50+ data center locations worldwide.', color: 'warning' },
|
||||||
{ year: '2025', event: 'Surpassed 10,000 active customers.' },
|
{ year: '2025', event: 'Surpassed 10,000 active customers.', color: 'error' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ value: '10K+', label: 'Customers', color: 'primary' },
|
||||||
|
{ value: '99.99%', label: 'Uptime', color: 'success' },
|
||||||
|
{ value: '50+', label: 'Locations', color: 'warning' },
|
||||||
|
{ value: '24/7', label: 'Support', color: 'error' },
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -24,7 +32,9 @@ const milestones = [
|
|||||||
<VContainer class="py-16">
|
<VContainer class="py-16">
|
||||||
<VRow align="center">
|
<VRow align="center">
|
||||||
<VCol cols="12" md="8" class="mx-auto text-center">
|
<VCol cols="12" md="8" class="mx-auto text-center">
|
||||||
<h1 class="text-h2 font-weight-bold mb-4">About EZSCALE</h1>
|
<h1 class="text-h2 font-weight-bold mb-4">
|
||||||
|
About <span class="hero-gradient-text">EZSCALE</span>
|
||||||
|
</h1>
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular">
|
<p class="text-h6 text-medium-emphasis font-weight-regular">
|
||||||
We're on a mission to make cloud hosting simple, affordable, and accessible to everyone.
|
We're on a mission to make cloud hosting simple, affordable, and accessible to everyone.
|
||||||
From individual developers to growing businesses, EZSCALE provides the infrastructure you need to succeed.
|
From individual developers to growing businesses, EZSCALE provides the infrastructure you need to succeed.
|
||||||
@@ -36,13 +46,17 @@ const milestones = [
|
|||||||
<!-- Values -->
|
<!-- Values -->
|
||||||
<div class="bg-surface-variant py-16">
|
<div class="bg-surface-variant py-16">
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Our Values</h2>
|
label="Our Values"
|
||||||
</div>
|
title="What We Stand For"
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="value in values" :key="value.title" cols="12" sm="6" md="3">
|
<VCol v-for="(value, index) in values" :key="value.title" cols="12" sm="6" md="3">
|
||||||
<VCard variant="flat" class="text-center pa-6 h-100 bg-transparent">
|
<VCard
|
||||||
|
variant="flat"
|
||||||
|
:class="`text-center pa-6 h-100 bg-transparent feature-card-hover fade-in-up stagger-delay-${index + 1}`"
|
||||||
|
>
|
||||||
<VAvatar :color="value.color" variant="tonal" size="64" class="mb-4">
|
<VAvatar :color="value.color" variant="tonal" size="64" class="mb-4">
|
||||||
<VIcon :icon="value.icon" size="32" />
|
<VIcon :icon="value.icon" size="32" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
@@ -56,9 +70,10 @@ const milestones = [
|
|||||||
|
|
||||||
<!-- Timeline -->
|
<!-- Timeline -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="py-16">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Our Journey</h2>
|
label="Our Journey"
|
||||||
</div>
|
title="Milestones Along the Way"
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow justify="center">
|
<VRow justify="center">
|
||||||
<VCol cols="12" md="8">
|
<VCol cols="12" md="8">
|
||||||
@@ -66,12 +81,12 @@ const milestones = [
|
|||||||
<VTimelineItem
|
<VTimelineItem
|
||||||
v-for="(milestone, index) in milestones"
|
v-for="(milestone, index) in milestones"
|
||||||
:key="index"
|
:key="index"
|
||||||
dot-color="primary"
|
:dot-color="milestone.color"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<VCard variant="outlined">
|
<VCard variant="outlined">
|
||||||
<VCardText>
|
<VCardText>
|
||||||
<div class="text-caption text-primary font-weight-bold mb-1">{{ milestone.year }}</div>
|
<div :class="`text-caption text-${milestone.color} font-weight-bold mb-1`">{{ milestone.year }}</div>
|
||||||
<div class="text-body-1">{{ milestone.event }}</div>
|
<div class="text-body-1">{{ milestone.event }}</div>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
@@ -85,21 +100,11 @@ const milestones = [
|
|||||||
<div class="bg-surface-variant py-16">
|
<div class="bg-surface-variant py-16">
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol cols="6" md="3" class="text-center">
|
<VCol v-for="stat in stats" :key="stat.label" cols="6" md="3">
|
||||||
<div class="text-h3 font-weight-bold text-primary">10K+</div>
|
<VCard flat class="pa-4" :style="`border-inline-start: 4px solid rgb(var(--v-theme-${stat.color}));`">
|
||||||
<div class="text-body-1 text-medium-emphasis mt-1">Customers</div>
|
<div :class="`text-h3 font-weight-bold text-${stat.color}`">{{ stat.value }}</div>
|
||||||
</VCol>
|
<div class="text-body-1 text-medium-emphasis mt-1">{{ stat.label }}</div>
|
||||||
<VCol cols="6" md="3" class="text-center">
|
</VCard>
|
||||||
<div class="text-h3 font-weight-bold text-primary">99.99%</div>
|
|
||||||
<div class="text-body-1 text-medium-emphasis mt-1">Uptime</div>
|
|
||||||
</VCol>
|
|
||||||
<VCol cols="6" md="3" class="text-center">
|
|
||||||
<div class="text-h3 font-weight-bold text-primary">50+</div>
|
|
||||||
<div class="text-body-1 text-medium-emphasis mt-1">Locations</div>
|
|
||||||
</VCol>
|
|
||||||
<VCol cols="6" md="3" class="text-center">
|
|
||||||
<div class="text-h3 font-weight-bold text-primary">24/7</div>
|
|
||||||
<div class="text-body-1 text-medium-emphasis mt-1">Support</div>
|
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ const sections: Section[] = [
|
|||||||
<p class="text-body-1 mb-6">
|
<p class="text-body-1 mb-6">
|
||||||
This Acceptable Use Policy ("AUP") governs the use of all services provided by {{ companyName }}
|
This Acceptable Use Policy ("AUP") governs the use of all services provided by {{ companyName }}
|
||||||
("EZSCALE," "we," "us," or "our"). This AUP is incorporated into and forms part of our
|
("EZSCALE," "we," "us," or "our"). This AUP is incorporated into and forms part of our
|
||||||
<Link :href="route('terms')" class="text-primary text-decoration-none font-weight-medium">Terms of Service</Link>.
|
<Link href="/terms-of-service" class="text-primary text-decoration-none font-weight-medium">Terms of Service</Link>.
|
||||||
By using our Services, you agree to comply with this policy. Violations may result in suspension
|
By using our Services, you agree to comply with this policy. Violations may result in suspension
|
||||||
or termination of your account.
|
or termination of your account.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
256
website/resources/ts/Pages/Marketing/BattlefieldAcp.vue
Normal file
256
website/resources/ts/Pages/Marketing/BattlefieldAcp.vue
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
|
interface Feature {
|
||||||
|
icon: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExtraFeature {
|
||||||
|
icon: string
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Game {
|
||||||
|
name: string
|
||||||
|
icon: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyFeatures: Feature[] = [
|
||||||
|
{
|
||||||
|
icon: 'tabler-terminal',
|
||||||
|
title: 'RCON Management',
|
||||||
|
description: 'Live scoreboard with admin actions — kill, kick, ban, yell, say, nuke, team switch, punish, forgive, and mute players in real-time.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler-brain',
|
||||||
|
title: 'ML Analytics',
|
||||||
|
description: 'Cheat detection, chat toxicity scoring, player risk assessments, server health monitoring, and intelligent slot recommendations.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler-gavel',
|
||||||
|
title: 'Ban Appeal System',
|
||||||
|
description: 'Public portal — no account needed. Battlelog verification, tracking codes, threaded discussions, file attachments up to 2 GB, and Discord notifications.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler-camera',
|
||||||
|
title: 'PunkBuster Screenshots',
|
||||||
|
description: 'S3 storage with automatic FTP sync, OCR metadata extraction, thumbnail grid viewer, pagination, and search.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler-world',
|
||||||
|
title: 'Public Pages',
|
||||||
|
description: 'Server browser with population graphs, leaderboards (score, kills, K/D, HSR%, SPM, KPM, playtime, wins), and detailed player profiles.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'tabler-brand-discord',
|
||||||
|
title: 'Discord Integration',
|
||||||
|
description: 'Real-time webhooks for all ban appeal events with rich embeds — player avatars, server names, ban types, and tracking codes.',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const moreFeatures: ExtraFeature[] = [
|
||||||
|
{ icon: 'tabler-fingerprint', title: 'Passkey Authentication' },
|
||||||
|
{ icon: 'tabler-activity-heartbeat', title: 'System Health Dashboard' },
|
||||||
|
{ icon: 'tabler-moon-stars', title: 'Dark & Light Themes' },
|
||||||
|
{ icon: 'tabler-device-mobile', title: 'Mobile Support' },
|
||||||
|
{ icon: 'tabler-search', title: 'Player Search' },
|
||||||
|
{ icon: 'tabler-list-details', title: 'Event Logger' },
|
||||||
|
{ icon: 'tabler-message-dots', title: 'Chat Log Viewer' },
|
||||||
|
{ icon: 'tabler-star', title: 'Reputation System' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const supportedGames: Game[] = [
|
||||||
|
{ name: 'Battlefield 3', icon: 'tabler-military-rank', description: 'Full support for BF3 servers including all RCON plugins and leaderboards.' },
|
||||||
|
{ name: 'Battlefield 4', icon: 'tabler-military-award', description: 'Complete BF4 server management with real-time scoreboard and ML analytics.' },
|
||||||
|
{ name: 'Battlefield Hardline', icon: 'tabler-badge', description: 'Hardline server support with all admin tools and ban appeal system.' },
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- Hero -->
|
||||||
|
<div class="hero-section" style="padding-block: 5.25rem; background: linear-gradient(135deg, rgb(var(--v-theme-info), 0.12), rgb(var(--v-theme-surface)));">
|
||||||
|
<VContainer class="text-center">
|
||||||
|
<VChip color="info" variant="tonal" class="mb-4">Game Server Management</VChip>
|
||||||
|
<h1 class="text-h2 font-weight-bold mb-3">
|
||||||
|
Battlefield Admin <span class="hero-gradient-text">Control Panel</span>
|
||||||
|
</h1>
|
||||||
|
<p class="text-h6 text-medium-emphasis font-weight-regular mb-4 mx-auto" style="max-width: 700px;">
|
||||||
|
A ground-up rebuild in Laravel 12 + Vue 3. Manage your BF3, BF4, and Hardline servers with a modern web panel — no more ProCon.
|
||||||
|
</p>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-8 mx-auto" style="max-width: 600px;">
|
||||||
|
ACP v5.0 replaces the ProCon dependency entirely. Configure all 24 RCON plugins directly from the panel with real-time auto-save.
|
||||||
|
</p>
|
||||||
|
<a href="/contact" class="text-decoration-none">
|
||||||
|
<VBtn color="info" size="x-large" rounded="lg">
|
||||||
|
Order Now
|
||||||
|
<VIcon icon="tabler-arrow-right" end />
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- No More ProCon -->
|
||||||
|
<VContainer class="marketing-section">
|
||||||
|
<VRow align="center">
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VChip color="success" variant="tonal" class="mb-3">Headline Feature</VChip>
|
||||||
|
<h2 class="text-h4 font-weight-bold mb-3">
|
||||||
|
No More <span class="text-info">ProCon</span>
|
||||||
|
</h2>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-4">
|
||||||
|
ACP v5.0 eliminates the need for ProCon entirely. All 24 RCON plugins can now be configured directly from the server edit page in your browser.
|
||||||
|
</p>
|
||||||
|
<VList density="compact" class="pa-0 bg-transparent">
|
||||||
|
<VListItem class="px-0">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="tabler-circle-check" color="success" size="20" class="me-2" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle class="text-body-1">Toggle plugins on/off from the web panel</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem class="px-0">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="tabler-circle-check" color="success" size="20" class="me-2" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle class="text-body-1">Adjust settings in real-time with auto-save</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem class="px-0">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="tabler-circle-check" color="success" size="20" class="me-2" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle class="text-body-1">24 RCON plugins configurable without external tools</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem class="px-0">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="tabler-circle-check" color="success" size="20" class="me-2" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle class="text-body-1">Modern Vue 3 UI with dark/light theme and mobile support</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VCard variant="outlined" class="pa-6 text-center">
|
||||||
|
<VAvatar color="info" variant="tonal" size="80" class="mb-4">
|
||||||
|
<VIcon icon="tabler-plug-connected-x" size="40" />
|
||||||
|
</VAvatar>
|
||||||
|
<h3 class="text-h5 font-weight-bold mb-2">ProCon Replacement</h3>
|
||||||
|
<p class="text-body-2 text-medium-emphasis mb-4">
|
||||||
|
No downloads. No .NET runtime. No port forwarding. Just log in and manage your server from any browser.
|
||||||
|
</p>
|
||||||
|
<div class="d-flex flex-wrap justify-center ga-2">
|
||||||
|
<VChip size="small" variant="tonal" color="info">Web-Based</VChip>
|
||||||
|
<VChip size="small" variant="tonal" color="info">Real-Time</VChip>
|
||||||
|
<VChip size="small" variant="tonal" color="info">Auto-Save</VChip>
|
||||||
|
<VChip size="small" variant="tonal" color="info">24 Plugins</VChip>
|
||||||
|
</div>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VContainer>
|
||||||
|
|
||||||
|
<!-- Key Features -->
|
||||||
|
<div class="section-alt-bg marketing-section">
|
||||||
|
<VContainer>
|
||||||
|
<SectionHeader
|
||||||
|
label="Features"
|
||||||
|
label-color="info"
|
||||||
|
title="Powerful Server Management"
|
||||||
|
highlight-word="Management"
|
||||||
|
subtitle="Everything you need to run, monitor, and moderate your Battlefield servers."
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VRow>
|
||||||
|
<VCol v-for="(feature, index) in keyFeatures" :key="feature.title" cols="12" sm="6" md="4">
|
||||||
|
<VCard variant="outlined" :class="['h-100 feature-card-hover', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
|
<VCardText class="pa-5">
|
||||||
|
<VAvatar color="info" variant="tonal" size="48" class="mb-3">
|
||||||
|
<VIcon :icon="feature.icon" size="24" />
|
||||||
|
</VAvatar>
|
||||||
|
<h3 class="text-subtitle-1 font-weight-bold mb-2">{{ feature.title }}</h3>
|
||||||
|
<p class="text-body-2 text-medium-emphasis mb-0">{{ feature.description }}</p>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- More Features -->
|
||||||
|
<VContainer class="marketing-section">
|
||||||
|
<SectionHeader
|
||||||
|
label="And More"
|
||||||
|
label-color="info"
|
||||||
|
title="Built for Admins"
|
||||||
|
highlight-word="Admins"
|
||||||
|
subtitle="Additional capabilities that make ACP the most complete Battlefield admin tool."
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VRow>
|
||||||
|
<VCol v-for="(feat, index) in moreFeatures" :key="feat.title" cols="6" sm="4" md="3">
|
||||||
|
<div :class="['text-center pa-4 feature-card-hover rounded-lg', `fade-in-up stagger-delay-${(index % 4) + 1}`]">
|
||||||
|
<VAvatar color="info" variant="tonal" size="48" class="mb-2">
|
||||||
|
<VIcon :icon="feat.icon" size="24" />
|
||||||
|
</VAvatar>
|
||||||
|
<h4 class="text-body-1 font-weight-bold">{{ feat.title }}</h4>
|
||||||
|
</div>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VContainer>
|
||||||
|
|
||||||
|
<!-- Supported Games -->
|
||||||
|
<div class="section-alt-bg marketing-section">
|
||||||
|
<VContainer>
|
||||||
|
<SectionHeader
|
||||||
|
label="Compatibility"
|
||||||
|
label-color="info"
|
||||||
|
title="Supported Games"
|
||||||
|
highlight-word="Games"
|
||||||
|
subtitle="Full support for the Battlefield franchise."
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VRow justify="center">
|
||||||
|
<VCol v-for="(game, index) in supportedGames" :key="game.name" cols="12" sm="6" md="4">
|
||||||
|
<VCard variant="outlined" :class="['h-100 feature-card-hover', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
|
<VCardText class="text-center pa-6">
|
||||||
|
<VAvatar color="info" variant="tonal" size="56" class="mb-3">
|
||||||
|
<VIcon :icon="game.icon" size="28" />
|
||||||
|
</VAvatar>
|
||||||
|
<h3 class="text-h6 font-weight-bold mb-2">{{ game.name }}</h3>
|
||||||
|
<p class="text-body-2 text-medium-emphasis mb-0">{{ game.description }}</p>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<div class="marketing-section" style="background: linear-gradient(135deg, rgb(var(--v-theme-info), 0.08), rgb(var(--v-theme-surface)));">
|
||||||
|
<VContainer class="text-center">
|
||||||
|
<h2 class="text-h4 font-weight-bold mb-3">Ready to Take Control of Your Battlefield Servers?</h2>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-6">
|
||||||
|
Get ACP v5.0 — the most powerful Battlefield admin panel available. No ProCon required.
|
||||||
|
</p>
|
||||||
|
<div class="d-flex ga-3 justify-center flex-wrap">
|
||||||
|
<a href="/contact" class="text-decoration-none">
|
||||||
|
<VBtn color="info" size="large" rounded="lg">
|
||||||
|
Order Now
|
||||||
|
<VIcon icon="tabler-arrow-right" end />
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
<a href="/contact" class="text-decoration-none">
|
||||||
|
<VBtn color="info" variant="outlined" size="large" rounded="lg">
|
||||||
|
Contact Sales
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useForm } from '@inertiajs/vue3'
|
import { useForm } from '@inertiajs/vue3'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
import AppTextField from '@/Components/app-form-elements/AppTextField.vue'
|
import AppTextField from '@/Components/app-form-elements/AppTextField.vue'
|
||||||
import AppSelect from '@/Components/app-form-elements/AppSelect.vue'
|
import AppSelect from '@/Components/app-form-elements/AppSelect.vue'
|
||||||
import AppTextarea from '@/Components/app-form-elements/AppTextarea.vue'
|
import AppTextarea from '@/Components/app-form-elements/AppTextarea.vue'
|
||||||
@@ -39,13 +40,12 @@ const contactInfo = [
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h1 class="text-h2 font-weight-bold mb-3">Contact Us</h1>
|
label="Get in Touch"
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular">
|
title="Contact Us"
|
||||||
Have a question? We'd love to hear from you.
|
subtitle="Have a question? We'd love to hear from you."
|
||||||
</p>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<!-- Contact Form -->
|
<!-- Contact Form -->
|
||||||
@@ -115,7 +115,7 @@ const contactInfo = [
|
|||||||
<!-- Contact Info -->
|
<!-- Contact Info -->
|
||||||
<VCol cols="12" md="5">
|
<VCol cols="12" md="5">
|
||||||
<div class="d-flex flex-column ga-4">
|
<div class="d-flex flex-column ga-4">
|
||||||
<VCard v-for="info in contactInfo" :key="info.title" variant="outlined">
|
<VCard v-for="info in contactInfo" :key="info.title" variant="outlined" class="feature-card-hover">
|
||||||
<VCardText class="d-flex align-center ga-4">
|
<VCardText class="d-flex align-center ga-4">
|
||||||
<VAvatar color="primary" variant="tonal" size="48">
|
<VAvatar color="primary" variant="tonal" size="48">
|
||||||
<VIcon :icon="info.icon" size="24" />
|
<VIcon :icon="info.icon" size="24" />
|
||||||
@@ -140,8 +140,9 @@ const contactInfo = [
|
|||||||
<p class="text-body-2 mb-3">
|
<p class="text-body-2 mb-3">
|
||||||
Our support team is available 24/7 through your account dashboard.
|
Our support team is available 24/7 through your account dashboard.
|
||||||
</p>
|
</p>
|
||||||
<VBtn variant="outlined" size="small">
|
<VBtn variant="outlined" size="small" href="https://ezscale.support/en/knowledgebase" target="_blank">
|
||||||
Visit Knowledge Base
|
Visit Knowledge Base
|
||||||
|
<VIcon icon="tabler-external-link" end size="16" />
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
|||||||
@@ -2,28 +2,28 @@
|
|||||||
import { usePage } from '@inertiajs/vue3'
|
import { usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
|
interface Plan {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
slug: string
|
||||||
|
price: string
|
||||||
|
features: Record<string, string | number> | null
|
||||||
|
stock_quantity: number | null
|
||||||
|
}
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
|
plans: Plan[]
|
||||||
domains: { marketing: string; account: string; admin: string }
|
domains: { marketing: string; account: string; admin: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = usePage()
|
const page = usePage()
|
||||||
const props = computed(() => page.props as unknown as PageProps)
|
const props = computed(() => page.props as unknown as PageProps)
|
||||||
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
||||||
|
const plans = computed(() => props.value.plans || [])
|
||||||
interface ServerConfig {
|
|
||||||
model: string
|
|
||||||
formFactor: string
|
|
||||||
cpu: string
|
|
||||||
coresThreads: string
|
|
||||||
clockSpeed: string
|
|
||||||
ram: string
|
|
||||||
bays: string
|
|
||||||
price: string
|
|
||||||
inStock: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const features = [
|
const features = [
|
||||||
{ icon: 'tabler-cpu', title: 'Dedicated Hardware', description: 'No shared resources — all CPU, RAM, and storage are exclusively yours.' },
|
{ icon: 'tabler-cpu', title: 'Dedicated Hardware', description: 'No shared resources — all CPU, RAM, and storage are exclusively yours.' },
|
||||||
@@ -34,97 +34,6 @@ const features = [
|
|||||||
{ icon: 'tabler-headset', title: '24/7 Support', description: 'Expert engineers available around the clock for hardware and network issues.' },
|
{ icon: 'tabler-headset', title: '24/7 Support', description: 'Expert engineers available around the clock for hardware and network issues.' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const servers: ServerConfig[] = [
|
|
||||||
{
|
|
||||||
model: 'Dell R330 LFF',
|
|
||||||
formFactor: '4-Bay',
|
|
||||||
cpu: '1x Intel Xeon E3-1220 v5',
|
|
||||||
coresThreads: '4C/4T',
|
|
||||||
clockSpeed: '3.0/3.5 GHz',
|
|
||||||
ram: '16 GB',
|
|
||||||
bays: '4x 3.5"',
|
|
||||||
price: '$44.39',
|
|
||||||
inStock: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R420 LFF',
|
|
||||||
formFactor: '4-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2430v2',
|
|
||||||
coresThreads: '12C/24T',
|
|
||||||
clockSpeed: '2.5/3.0 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '4x 3.5"',
|
|
||||||
price: '$58.79',
|
|
||||||
inStock: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R620 SFF',
|
|
||||||
formFactor: '10-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2667v2',
|
|
||||||
coresThreads: '16C/32T',
|
|
||||||
clockSpeed: '3.3/4.0 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '10x 2.5"',
|
|
||||||
price: '$61.19',
|
|
||||||
inStock: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R620 SFF',
|
|
||||||
formFactor: '8-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2667v2',
|
|
||||||
coresThreads: '16C/32T',
|
|
||||||
clockSpeed: '3.3/4.0 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '8x 2.5"',
|
|
||||||
price: '$61.19',
|
|
||||||
inStock: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R520 LFF',
|
|
||||||
formFactor: '8-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2420v2',
|
|
||||||
coresThreads: '12C/24T',
|
|
||||||
clockSpeed: '2.2/2.7 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '8x 3.5"',
|
|
||||||
price: '$64.79',
|
|
||||||
inStock: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R430 LFF',
|
|
||||||
formFactor: '4-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2667v4',
|
|
||||||
coresThreads: '16C/32T',
|
|
||||||
clockSpeed: '3.2/3.6 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '4x 3.5"',
|
|
||||||
price: '$87.59',
|
|
||||||
inStock: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R630 SFF',
|
|
||||||
formFactor: '8-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2697A v4',
|
|
||||||
coresThreads: '32C/64T',
|
|
||||||
clockSpeed: '2.6/3.6 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '8x 2.5"',
|
|
||||||
price: '$93.59',
|
|
||||||
inStock: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
model: 'Dell R730 LFF',
|
|
||||||
formFactor: '8-Bay',
|
|
||||||
cpu: '2x Intel Xeon E5-2680v4',
|
|
||||||
coresThreads: '28C/56T',
|
|
||||||
clockSpeed: '2.4/3.3 GHz',
|
|
||||||
ram: '32 GB',
|
|
||||||
bays: '8x 3.5"',
|
|
||||||
price: '$107.99',
|
|
||||||
inStock: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const included = [
|
const included = [
|
||||||
{ icon: 'tabler-world', label: '10 TB Bandwidth' },
|
{ icon: 'tabler-world', label: '10 TB Bandwidth' },
|
||||||
{ icon: 'tabler-network', label: '1 Gbps Port' },
|
{ icon: 'tabler-network', label: '1 Gbps Port' },
|
||||||
@@ -133,15 +42,30 @@ const included = [
|
|||||||
{ icon: 'tabler-hexagons', label: '1x /64 IPv6 Subnet' },
|
{ icon: 'tabler-hexagons', label: '1x /64 IPv6 Subnet' },
|
||||||
{ icon: 'tabler-dashboard', label: 'SynergyCP Panel' },
|
{ icon: 'tabler-dashboard', label: 'SynergyCP Panel' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function isInStock(plan: Plan): boolean {
|
||||||
|
return plan.stock_quantity === null || plan.stock_quantity > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFeature(plan: Plan, key: string): string {
|
||||||
|
return String(plan.features?.[key] ?? '-')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPrice(plan: Plan): string {
|
||||||
|
const price = parseFloat(plan.price) || 0
|
||||||
|
return price % 1 === 0 ? `$${price}` : `$${price.toFixed(2)}`
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Hero -->
|
<!-- Hero -->
|
||||||
<div class="py-16" style="background: linear-gradient(135deg, rgb(var(--v-theme-success), 0.1), rgb(var(--v-theme-surface)));">
|
<div class="hero-section" style="padding-block: 5.25rem; background: linear-gradient(135deg, rgb(var(--v-theme-success), 0.1), rgb(var(--v-theme-surface)));">
|
||||||
<VContainer class="text-center">
|
<VContainer class="text-center">
|
||||||
<VChip color="success" variant="tonal" class="mb-4">Dedicated Servers</VChip>
|
<VChip color="success" variant="tonal" class="mb-4">Dedicated Servers</VChip>
|
||||||
<h1 class="text-h2 font-weight-bold mb-3">Bare Metal Power</h1>
|
<h1 class="text-h2 font-weight-bold mb-3">
|
||||||
|
Bare Metal <span class="hero-gradient-text">Power</span>
|
||||||
|
</h1>
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular mb-8 mx-auto" style="max-width: 600px;">
|
<p class="text-h6 text-medium-emphasis font-weight-regular mb-8 mx-auto" style="max-width: 600px;">
|
||||||
Enterprise-grade Dell PowerEdge servers with full root access, SynergyCP management, and same-day deployment from our Atlanta datacenter.
|
Enterprise-grade Dell PowerEdge servers with full root access, SynergyCP management, and same-day deployment from our Atlanta datacenter.
|
||||||
</p>
|
</p>
|
||||||
@@ -155,14 +79,17 @@ const included = [
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Features -->
|
<!-- Features -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Enterprise Hardware</h2>
|
label="Features"
|
||||||
<p class="text-body-1 text-medium-emphasis">Every dedicated server comes with these features included.</p>
|
label-color="success"
|
||||||
</div>
|
title="Enterprise Hardware"
|
||||||
|
highlight-word="Hardware"
|
||||||
|
subtitle="Every dedicated server comes with these features included."
|
||||||
|
/>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="feature in features" :key="feature.title" cols="12" sm="6" md="4">
|
<VCol v-for="(feature, index) in features" :key="feature.title" cols="12" sm="6" md="4">
|
||||||
<div class="d-flex ga-3 mb-4">
|
<div :class="['d-flex ga-3 mb-4 feature-card-hover pa-3 rounded-lg', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
<VAvatar color="success" variant="tonal" size="44">
|
<VAvatar color="success" variant="tonal" size="44">
|
||||||
<VIcon :icon="feature.icon" size="22" />
|
<VIcon :icon="feature.icon" size="22" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
@@ -176,39 +103,40 @@ const included = [
|
|||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- Server Configurations -->
|
<!-- Server Configurations -->
|
||||||
<div class="bg-surface-variant py-16">
|
<div class="section-alt-bg marketing-section">
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<div class="text-center mb-8">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Server Configurations</h2>
|
label="Servers"
|
||||||
<p class="text-body-1 text-medium-emphasis">Real Dell PowerEdge servers. Storage sold separately -- configure your drives at checkout.</p>
|
label-color="success"
|
||||||
</div>
|
title="Server Configurations"
|
||||||
|
highlight-word="Configurations"
|
||||||
|
subtitle="Real Dell PowerEdge servers. Storage sold separately -- configure your drives at checkout."
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="(server, index) in servers" :key="index" cols="12" sm="6" lg="3">
|
<VCol v-for="(plan, index) in plans" :key="plan.id" cols="12" sm="6" lg="3">
|
||||||
<VCard
|
<VCard
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
class="h-100"
|
:class="['h-100 feature-card-hover', `fade-in-up stagger-delay-${Math.min(index + 1, 8)}`, { 'server-card-unavailable': !isInStock(plan) }]"
|
||||||
:class="{ 'server-card-unavailable': !server.inStock }"
|
|
||||||
:style="server.inStock ? {} : { opacity: 0.7 }"
|
|
||||||
>
|
>
|
||||||
<VCardText class="pa-5">
|
<VCardText class="pa-5">
|
||||||
<!-- Header with model and stock status -->
|
<!-- Header with model and stock status -->
|
||||||
<div class="d-flex align-center justify-space-between mb-1">
|
<div class="d-flex align-center justify-space-between mb-1">
|
||||||
<h3 class="text-subtitle-1 font-weight-bold">{{ server.model }}</h3>
|
<h3 class="text-subtitle-1 font-weight-bold">{{ plan.name }}</h3>
|
||||||
<VChip
|
<VChip
|
||||||
:color="server.inStock ? 'success' : 'error'"
|
:color="isInStock(plan) ? 'success' : 'error'"
|
||||||
size="small"
|
size="small"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
{{ server.inStock ? 'In Stock' : 'Sold Out' }}
|
{{ isInStock(plan) ? 'In Stock' : 'Sold Out' }}
|
||||||
</VChip>
|
</VChip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="text-caption text-medium-emphasis mb-3">{{ server.formFactor }}</p>
|
<p class="text-caption text-medium-emphasis mb-3">{{ getFeature(plan, 'storage_bays') }}</p>
|
||||||
|
|
||||||
<!-- Price -->
|
<!-- Price -->
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<span class="text-h4 font-weight-bold" :class="server.inStock ? 'text-success' : 'text-medium-emphasis'">{{ server.price }}</span>
|
<span class="text-h4 font-weight-bold" :class="isInStock(plan) ? 'text-success' : 'text-medium-emphasis'">{{ formatPrice(plan) }}</span>
|
||||||
<span class="text-body-2 text-medium-emphasis">/mo</span>
|
<span class="text-body-2 text-medium-emphasis">/mo</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -218,25 +146,25 @@ const included = [
|
|||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<div class="d-flex align-center ga-2 py-1">
|
<div class="d-flex align-center ga-2 py-1">
|
||||||
<VIcon icon="tabler-cpu" size="16" color="medium-emphasis" />
|
<VIcon icon="tabler-cpu" size="16" color="medium-emphasis" />
|
||||||
<span class="text-body-2">{{ server.cpu }}</span>
|
<span class="text-body-2">{{ getFeature(plan, 'cpu') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center ga-2 py-1">
|
<div class="d-flex align-center ga-2 py-1">
|
||||||
<VIcon icon="tabler-topology-star-3" size="16" color="medium-emphasis" />
|
<VIcon icon="tabler-topology-star-3" size="16" color="medium-emphasis" />
|
||||||
<span class="text-body-2">{{ server.coresThreads }} @ {{ server.clockSpeed }}</span>
|
<span class="text-body-2">{{ getFeature(plan, 'cores') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center ga-2 py-1">
|
<div class="d-flex align-center ga-2 py-1">
|
||||||
<VIcon icon="tabler-database" size="16" color="medium-emphasis" />
|
<VIcon icon="tabler-database" size="16" color="medium-emphasis" />
|
||||||
<span class="text-body-2">{{ server.ram }} RAM</span>
|
<span class="text-body-2">{{ getFeature(plan, 'ram') }} RAM</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center ga-2 py-1">
|
<div class="d-flex align-center ga-2 py-1">
|
||||||
<VIcon icon="tabler-server" size="16" color="medium-emphasis" />
|
<VIcon icon="tabler-server" size="16" color="medium-emphasis" />
|
||||||
<span class="text-body-2">{{ server.bays }} drive bays</span>
|
<span class="text-body-2">{{ getFeature(plan, 'storage_bays') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Order Button -->
|
<!-- Order Button -->
|
||||||
<a
|
<a
|
||||||
v-if="server.inStock"
|
v-if="isInStock(plan)"
|
||||||
:href="accountUrl + '/register'"
|
:href="accountUrl + '/register'"
|
||||||
class="text-decoration-none d-block"
|
class="text-decoration-none d-block"
|
||||||
>
|
>
|
||||||
@@ -261,11 +189,14 @@ const included = [
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Included With Every Server -->
|
<!-- Included With Every Server -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-8">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Included With Every Server</h2>
|
label="Included"
|
||||||
<p class="text-body-1 text-medium-emphasis">No hidden fees. All servers come with these essentials.</p>
|
label-color="success"
|
||||||
</div>
|
title="Included With Every Server"
|
||||||
|
highlight-word="Every"
|
||||||
|
subtitle="No hidden fees. All servers come with these essentials."
|
||||||
|
/>
|
||||||
<VRow justify="center">
|
<VRow justify="center">
|
||||||
<VCol v-for="item in included" :key="item.label" cols="6" sm="4" md="2">
|
<VCol v-for="item in included" :key="item.label" cols="6" sm="4" md="2">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
@@ -279,7 +210,7 @@ const included = [
|
|||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- CTA -->
|
<!-- CTA -->
|
||||||
<div class="py-12" style="background: linear-gradient(135deg, rgb(var(--v-theme-success), 0.08), rgb(var(--v-theme-surface)));">
|
<div class="marketing-section" style="background: linear-gradient(135deg, rgb(var(--v-theme-success), 0.08), rgb(var(--v-theme-surface)));">
|
||||||
<VContainer class="text-center">
|
<VContainer class="text-center">
|
||||||
<h2 class="text-h4 font-weight-bold mb-3">Need a Custom Configuration?</h2>
|
<h2 class="text-h4 font-weight-bold mb-3">Need a Custom Configuration?</h2>
|
||||||
<p class="text-body-1 text-medium-emphasis mb-6">
|
<p class="text-body-1 text-medium-emphasis mb-6">
|
||||||
@@ -302,3 +233,9 @@ const included = [
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.server-card-unavailable {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -2,27 +2,57 @@
|
|||||||
import { usePage } from '@inertiajs/vue3'
|
import { usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
|
interface Plan {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
slug: string
|
||||||
|
description: string | null
|
||||||
|
price: string
|
||||||
|
features: Record<string, string | number> | null
|
||||||
|
}
|
||||||
|
|
||||||
interface PageProps {
|
interface PageProps {
|
||||||
|
plans: Plan[]
|
||||||
domains: { marketing: string; account: string; admin: string }
|
domains: { marketing: string; account: string; admin: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Feature {
|
||||||
|
icon: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const gameIcons: Record<string, string> = {
|
||||||
|
'Minecraft': 'tabler-cube',
|
||||||
|
'Rust': 'tabler-shield',
|
||||||
|
'ARK: Survival Evolved': 'tabler-dinosaur',
|
||||||
|
'Valheim': 'tabler-sword',
|
||||||
|
'CS2': 'tabler-crosshair',
|
||||||
|
'Palworld': 'tabler-paw',
|
||||||
|
}
|
||||||
|
|
||||||
const page = usePage()
|
const page = usePage()
|
||||||
const props = computed(() => page.props as unknown as PageProps)
|
const props = computed(() => page.props as unknown as PageProps)
|
||||||
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
const plans = computed(() => props.value.plans || [])
|
||||||
|
|
||||||
const games = [
|
function formatPrice(plan: Plan): string {
|
||||||
{ name: 'Minecraft', icon: 'tabler-cube', description: 'Java & Bedrock editions with mod support.', startingAt: '$7.99/mo' },
|
const price = parseFloat(plan.price) || 0
|
||||||
{ name: 'Rust', icon: 'tabler-shield', description: 'High-performance Rust servers with Oxide support.', startingAt: '$14.99/mo' },
|
return price % 1 === 0 ? `$${price}` : `$${price.toFixed(2)}`
|
||||||
{ name: 'ARK: Survival Evolved', icon: 'tabler-dinosaur', description: 'ARK servers with cluster support.', startingAt: '$19.99/mo' },
|
}
|
||||||
{ name: 'Valheim', icon: 'tabler-sword', description: 'Dedicated Valheim servers with mod support.', startingAt: '$9.99/mo' },
|
|
||||||
{ name: 'CS2', icon: 'tabler-crosshair', description: 'Counter-Strike 2 competitive and casual servers.', startingAt: '$12.99/mo' },
|
|
||||||
{ name: 'Palworld', icon: 'tabler-paw', description: 'Palworld dedicated servers with full configuration.', startingAt: '$14.99/mo' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const features = [
|
function getIcon(plan: Plan): string {
|
||||||
|
return gameIcons[plan.name] || 'tabler-device-gamepad-2'
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFeature(plan: Plan, key: string): string {
|
||||||
|
return String(plan.features?.[key] ?? '-')
|
||||||
|
}
|
||||||
|
|
||||||
|
const features: Feature[] = [
|
||||||
{ icon: 'tabler-bolt', title: 'Low Latency', description: 'Optimized network routing for minimal ping.' },
|
{ icon: 'tabler-bolt', title: 'Low Latency', description: 'Optimized network routing for minimal ping.' },
|
||||||
{ icon: 'tabler-puzzle', title: 'Mod Support', description: 'Easy plugin and mod installation with one-click tools.' },
|
{ icon: 'tabler-puzzle', title: 'Mod Support', description: 'Easy plugin and mod installation with one-click tools.' },
|
||||||
{ icon: 'tabler-shield-check', title: 'DDoS Protection', description: 'Always-on protection to keep your server online.' },
|
{ icon: 'tabler-shield-check', title: 'DDoS Protection', description: 'Always-on protection to keep your server online.' },
|
||||||
@@ -33,40 +63,64 @@ const features = [
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Hero -->
|
<!-- Hero -->
|
||||||
<div class="py-16" style="background: linear-gradient(135deg, rgb(var(--v-theme-error), 0.1), rgb(var(--v-theme-surface)));">
|
<div class="hero-section" style="padding-block: 5.25rem; background: linear-gradient(135deg, rgb(var(--v-theme-error), 0.1), rgb(var(--v-theme-surface)));">
|
||||||
<VContainer class="text-center">
|
<VContainer class="text-center">
|
||||||
<VChip color="error" variant="tonal" class="mb-4">Game Servers</VChip>
|
<VChip color="error" variant="tonal" class="mb-4">Game Servers</VChip>
|
||||||
<h1 class="text-h2 font-weight-bold mb-3">Game Server Hosting</h1>
|
<h1 class="text-h2 font-weight-bold mb-3">
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular mb-8 mx-auto" style="max-width: 600px;">
|
Game Server <span class="hero-gradient-text">Hosting</span>
|
||||||
|
</h1>
|
||||||
|
<p class="text-h6 text-medium-emphasis font-weight-regular mb-4 mx-auto" style="max-width: 600px;">
|
||||||
Low-latency game server hosting with instant setup, mod support, and DDoS protection.
|
Low-latency game server hosting with instant setup, mod support, and DDoS protection.
|
||||||
</p>
|
</p>
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
<VChip color="warning" variant="flat" class="mb-8">
|
||||||
|
<VIcon icon="tabler-clock" start size="16" />
|
||||||
|
Coming Soon
|
||||||
|
</VChip>
|
||||||
|
<div>
|
||||||
<VBtn color="error" size="x-large" rounded="lg">
|
<VBtn color="error" size="x-large" rounded="lg">
|
||||||
Get Your Server
|
Notify Me
|
||||||
<VIcon icon="tabler-arrow-right" end />
|
<VIcon icon="tabler-bell" end />
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</a>
|
</div>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Supported Games -->
|
<!-- Supported Games -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Supported Games</h2>
|
label="Games"
|
||||||
<p class="text-body-1 text-medium-emphasis">Popular titles with more being added regularly.</p>
|
label-color="error"
|
||||||
</div>
|
title="Supported Games"
|
||||||
|
highlight-word="Games"
|
||||||
|
subtitle="Popular titles with more being added regularly."
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="game in games" :key="game.name" cols="12" sm="6" md="4">
|
<VCol v-for="(plan, index) in plans" :key="plan.id" cols="12" sm="6" md="4">
|
||||||
<VCard variant="outlined" class="h-100">
|
<VCard variant="outlined" :class="['h-100 feature-card-hover', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
<VCardText class="d-flex align-center ga-4">
|
<VCardText class="pa-5">
|
||||||
|
<div class="d-flex align-center ga-4 mb-3">
|
||||||
<VAvatar color="error" variant="tonal" size="48">
|
<VAvatar color="error" variant="tonal" size="48">
|
||||||
<VIcon :icon="game.icon" size="24" />
|
<VIcon :icon="getIcon(plan)" size="24" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-subtitle-1 font-weight-bold">{{ game.name }}</h3>
|
<h3 class="text-subtitle-1 font-weight-bold">{{ plan.name }}</h3>
|
||||||
<p class="text-body-2 text-medium-emphasis mb-1">{{ game.description }}</p>
|
<p class="text-body-2 text-medium-emphasis mb-0">{{ plan.description }}</p>
|
||||||
<span class="text-body-2 text-error font-weight-medium">From {{ game.startingAt }}</span>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<VDivider class="mb-3" />
|
||||||
|
|
||||||
|
<div class="d-flex flex-wrap ga-2 mb-3">
|
||||||
|
<VChip size="x-small" variant="tonal" color="error">{{ getFeature(plan, 'ram') }} RAM</VChip>
|
||||||
|
<VChip size="x-small" variant="tonal" color="error">{{ getFeature(plan, 'slots') }}</VChip>
|
||||||
|
<VChip size="x-small" variant="tonal" color="error">{{ getFeature(plan, 'storage') }}</VChip>
|
||||||
|
<VChip size="x-small" variant="tonal" color="error">{{ getFeature(plan, 'mods') }}</VChip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex align-center justify-space-between">
|
||||||
|
<span class="text-h6 text-error font-weight-bold">{{ formatPrice(plan) }}<span class="text-body-2 text-medium-emphasis font-weight-regular">/mo</span></span>
|
||||||
|
<VChip color="warning" size="x-small" variant="flat">Coming Soon</VChip>
|
||||||
</div>
|
</div>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
@@ -75,14 +129,17 @@ const features = [
|
|||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- Features -->
|
<!-- Features -->
|
||||||
<div class="bg-surface-variant py-16">
|
<div class="section-alt-bg marketing-section">
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Why Gamers Choose EZSCALE</h2>
|
label="Features"
|
||||||
</div>
|
label-color="error"
|
||||||
|
title="Why Gamers Choose EZSCALE"
|
||||||
|
highlight-word="EZSCALE"
|
||||||
|
/>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="feature in features" :key="feature.title" cols="12" sm="6" md="3">
|
<VCol v-for="(feature, index) in features" :key="feature.title" cols="12" sm="6" md="3">
|
||||||
<VCard variant="flat" class="text-center pa-4 h-100 bg-transparent">
|
<VCard variant="flat" :class="['text-center pa-4 h-100 bg-transparent feature-card-hover', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
<VAvatar color="error" variant="tonal" size="56" class="mb-3">
|
<VAvatar color="error" variant="tonal" size="56" class="mb-3">
|
||||||
<VIcon :icon="feature.icon" size="28" />
|
<VIcon :icon="feature.icon" size="28" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
@@ -93,5 +150,26 @@ const features = [
|
|||||||
</VRow>
|
</VRow>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<div class="marketing-section" style="background: linear-gradient(135deg, rgb(var(--v-theme-error), 0.08), rgb(var(--v-theme-surface)));">
|
||||||
|
<VContainer class="text-center">
|
||||||
|
<h2 class="text-h4 font-weight-bold mb-3">Be the First to Know</h2>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-6">
|
||||||
|
Game server hosting is coming soon. Sign up to get notified when we launch.
|
||||||
|
</p>
|
||||||
|
<div class="d-flex ga-3 justify-center flex-wrap">
|
||||||
|
<VBtn color="error" size="large" rounded="lg">
|
||||||
|
Notify Me
|
||||||
|
<VIcon icon="tabler-bell" end />
|
||||||
|
</VBtn>
|
||||||
|
<a href="/contact" class="text-decoration-none">
|
||||||
|
<VBtn color="error" variant="outlined" size="large" rounded="lg">
|
||||||
|
Contact Us
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { usePage } from '@inertiajs/vue3'
|
import { usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
@@ -13,101 +14,442 @@ const page = usePage()
|
|||||||
const props = computed(() => page.props as unknown as PageProps)
|
const props = computed(() => page.props as unknown as PageProps)
|
||||||
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
||||||
|
|
||||||
const features = [
|
interface Product {
|
||||||
|
icon: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
href: string
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const products: Product[] = [
|
||||||
{ icon: 'tabler-server', title: 'VPS Hosting', description: 'SSD VPS with VirtFusion panel, instant provisioning, and full root access. Starting at $4.20/mo.', href: '/vps-hosting', color: 'primary' },
|
{ icon: 'tabler-server', title: 'VPS Hosting', description: 'SSD VPS with VirtFusion panel, instant provisioning, and full root access. Starting at $4.20/mo.', href: '/vps-hosting', color: 'primary' },
|
||||||
{ icon: 'tabler-server-2', title: 'Dedicated Servers', description: 'Dell PowerEdge servers with SynergyCP management and 1Gbps connectivity. Starting at $44.39/mo.', href: '/dedicated-servers', color: 'success' },
|
{ icon: 'tabler-server-2', title: 'Dedicated Servers', description: 'Dell PowerEdge servers with SynergyCP management and 1Gbps connectivity. Starting at $44.39/mo.', href: '/dedicated-servers', color: 'success' },
|
||||||
{ icon: 'tabler-world', title: 'Web Hosting', description: 'Web hosting with Enhance panel, free SSL, Cloudflare DNS, and Redis cache. Starting at $2.39/mo.', href: '/web-hosting', color: 'warning' },
|
{ icon: 'tabler-world', title: 'Web Hosting', description: 'Web hosting with Enhance panel, free SSL, Cloudflare DNS, and Redis cache. Starting at $2.39/mo.', href: '/web-hosting', color: 'warning' },
|
||||||
{ icon: 'tabler-device-gamepad-2', title: 'Game Servers', description: 'Low-latency game hosting for Minecraft, Rust, ARK, and more. Coming soon.', href: '/game-servers', color: 'error' },
|
{ icon: 'tabler-device-gamepad-2', title: 'Game Servers', description: 'Low-latency game hosting for Minecraft, Rust, ARK, and more. Coming soon.', href: '/game-servers', color: 'error' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const stats = [
|
interface ValueProp {
|
||||||
{ value: '10,000+', label: 'Active Customers' },
|
icon: string
|
||||||
{ value: '99.99%', label: 'Uptime SLA' },
|
title: string
|
||||||
{ value: '50+', label: 'Server Locations' },
|
description: string
|
||||||
{ value: '24/7', label: 'Expert Support' },
|
color: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const valueProps: ValueProp[] = [
|
||||||
|
{ icon: 'tabler-shield-check', title: '99.99% Uptime', description: 'Enterprise-grade infrastructure with redundant power, cooling, and networking ensures your services stay online around the clock.', color: 'success' },
|
||||||
|
{ icon: 'tabler-headset', title: '24/7 Expert Support', description: 'Our team of experienced engineers is available day and night to help you resolve issues and optimize your infrastructure.', color: 'primary' },
|
||||||
|
{ icon: 'tabler-server', title: 'Enterprise Hardware', description: 'Dell PowerEdge and HP ProLiant servers with NVMe SSDs, ECC RAM, and RAID storage for maximum performance and reliability.', color: 'warning' },
|
||||||
|
]
|
||||||
|
|
||||||
|
interface Stat {
|
||||||
|
value: string
|
||||||
|
label: string
|
||||||
|
icon: string
|
||||||
|
color: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const stats: Stat[] = [
|
||||||
|
{ value: '10,000+', label: 'Active Customers', icon: 'tabler-users', color: 'primary' },
|
||||||
|
{ value: '99.99%', label: 'Uptime SLA', icon: 'tabler-arrow-up', color: 'success' },
|
||||||
|
{ value: '50+', label: 'Server Locations', icon: 'tabler-map-pin', color: 'warning' },
|
||||||
|
{ value: '24/7', label: 'Expert Support', icon: 'tabler-headset', color: 'error' },
|
||||||
|
]
|
||||||
|
|
||||||
|
interface Testimonial {
|
||||||
|
quote: string
|
||||||
|
name: string
|
||||||
|
company: string
|
||||||
|
rating: number
|
||||||
|
avatarColor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const testimonials: Testimonial[] = [
|
||||||
|
{
|
||||||
|
quote: 'EZSCALE\'s VPS hosting is incredibly fast and reliable. Migration was seamless.',
|
||||||
|
name: 'Alex Turner',
|
||||||
|
company: 'DevOps Lead',
|
||||||
|
rating: 5,
|
||||||
|
avatarColor: 'primary',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote: 'Best dedicated server hosting we\'ve used. The SynergyCP panel is fantastic.',
|
||||||
|
name: 'Sarah Chen',
|
||||||
|
company: 'CTO at TechVentures',
|
||||||
|
rating: 5,
|
||||||
|
avatarColor: 'success',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
quote: 'Their support team resolved our issue in minutes, not hours. Impressive!',
|
||||||
|
name: 'Marcus Rodriguez',
|
||||||
|
company: 'Founder at LaunchPad',
|
||||||
|
rating: 5,
|
||||||
|
avatarColor: 'warning',
|
||||||
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Hero Section -->
|
<!-- Hero Section -->
|
||||||
<div class="py-16" style="background: linear-gradient(135deg, rgb(var(--v-theme-primary), 0.1), rgb(var(--v-theme-surface)));">
|
<div
|
||||||
|
class="hero-section"
|
||||||
|
style="padding-block: 6rem 4rem; background: linear-gradient(135deg, rgb(var(--v-theme-primary), 0.1), rgb(var(--v-theme-surface)));"
|
||||||
|
>
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<VRow align="center" justify="center">
|
<VRow
|
||||||
<VCol cols="12" md="8" class="text-center">
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<VCol
|
||||||
|
cols="12"
|
||||||
|
md="8"
|
||||||
|
class="text-center"
|
||||||
|
>
|
||||||
<h1 class="text-h2 text-md-h1 font-weight-bold mb-4">
|
<h1 class="text-h2 text-md-h1 font-weight-bold mb-4">
|
||||||
Cloud Hosting
|
Cloud Hosting
|
||||||
<span class="text-primary">Made Simple</span>
|
<span class="hero-gradient-text">Made Simple</span>
|
||||||
</h1>
|
</h1>
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular mb-8 mx-auto" style="max-width: 600px;">
|
|
||||||
|
<p
|
||||||
|
class="text-h6 text-medium-emphasis font-weight-regular mb-8 mx-auto"
|
||||||
|
style="max-inline-size: 600px;"
|
||||||
|
>
|
||||||
VPS, Dedicated Servers, Web Hosting, and Game Servers. Deploy in minutes with enterprise-grade infrastructure.
|
VPS, Dedicated Servers, Web Hosting, and Game Servers. Deploy in minutes with enterprise-grade infrastructure.
|
||||||
</p>
|
</p>
|
||||||
<div class="d-flex justify-center ga-4 flex-wrap">
|
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
<div class="d-flex justify-center ga-4 flex-wrap mb-4">
|
||||||
<VBtn color="primary" size="x-large" rounded="lg">
|
<a
|
||||||
|
:href="accountUrl + '/register'"
|
||||||
|
class="text-decoration-none"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
color="primary"
|
||||||
|
size="x-large"
|
||||||
|
rounded="lg"
|
||||||
|
>
|
||||||
Start Free Trial
|
Start Free Trial
|
||||||
<VIcon icon="tabler-arrow-right" end />
|
<VIcon
|
||||||
|
icon="tabler-arrow-right"
|
||||||
|
end
|
||||||
|
/>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</a>
|
</a>
|
||||||
<a href="/pricing" class="text-decoration-none">
|
|
||||||
<VBtn variant="outlined" size="x-large" rounded="lg">
|
<a
|
||||||
|
href="/pricing"
|
||||||
|
class="text-decoration-none"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
variant="outlined"
|
||||||
|
size="x-large"
|
||||||
|
rounded="lg"
|
||||||
|
>
|
||||||
View Pricing
|
View Pricing
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p class="text-body-2 text-disabled">
|
||||||
|
No credit card required. Deploy in 60 seconds.
|
||||||
|
</p>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Features Section -->
|
<!-- Products Section -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Our Products</h2>
|
label="Our Products"
|
||||||
<p class="text-body-1 text-medium-emphasis">Everything you need to build, deploy, and scale.</p>
|
title="Everything You Need to Build, Deploy, and Scale"
|
||||||
</div>
|
highlight-word="Scale"
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="feature in features" :key="feature.title" cols="12" sm="6" md="3">
|
<VCol
|
||||||
<VCard variant="outlined" class="h-100" :href="feature.href">
|
v-for="(product, index) in products"
|
||||||
|
:key="product.title"
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
md="3"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
variant="outlined"
|
||||||
|
class="h-100 feature-card-hover fade-in-up"
|
||||||
|
:class="`stagger-delay-${index + 1}`"
|
||||||
|
:href="product.href"
|
||||||
|
>
|
||||||
<VCardText class="text-center pa-6">
|
<VCardText class="text-center pa-6">
|
||||||
<VAvatar :color="feature.color" variant="tonal" size="64" class="mb-4">
|
<VAvatar
|
||||||
<VIcon :icon="feature.icon" size="32" />
|
:color="product.color"
|
||||||
|
variant="tonal"
|
||||||
|
size="64"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="product.icon"
|
||||||
|
size="32"
|
||||||
|
/>
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
<h3 class="text-h6 font-weight-bold mb-2">{{ feature.title }}</h3>
|
|
||||||
<p class="text-body-2 text-medium-emphasis mb-0">{{ feature.description }}</p>
|
<h3 class="text-h6 font-weight-bold mb-2">
|
||||||
|
{{ product.title }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p class="text-body-2 text-medium-emphasis mb-0">
|
||||||
|
{{ product.description }}
|
||||||
|
</p>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- Stats Section -->
|
<!-- Why Choose EZSCALE Section -->
|
||||||
<div class="bg-surface-variant py-16">
|
<div class="section-alt-bg">
|
||||||
<VContainer>
|
<VContainer class="marketing-section">
|
||||||
|
<SectionHeader
|
||||||
|
label="Why EZSCALE"
|
||||||
|
title="Built for Performance and Reliability"
|
||||||
|
highlight-word="Reliability"
|
||||||
|
subtitle="We invest in enterprise hardware, redundant networks, and expert staff so you can focus on building your business."
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="stat in stats" :key="stat.label" cols="6" md="3" class="text-center">
|
<VCol
|
||||||
<div class="text-h3 font-weight-bold text-primary">{{ stat.value }}</div>
|
v-for="(prop, index) in valueProps"
|
||||||
<div class="text-body-1 text-medium-emphasis mt-1">{{ stat.label }}</div>
|
:key="prop.title"
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
class="h-100 feature-card-hover fade-in-up"
|
||||||
|
:class="`stagger-delay-${index + 1}`"
|
||||||
|
>
|
||||||
|
<VCardText class="text-center pa-8">
|
||||||
|
<VAvatar
|
||||||
|
:color="prop.color"
|
||||||
|
variant="tonal"
|
||||||
|
size="64"
|
||||||
|
class="mb-5"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="prop.icon"
|
||||||
|
size="32"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<h3 class="text-h6 font-weight-bold mb-3">
|
||||||
|
{{ prop.title }}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-0">
|
||||||
|
{{ prop.description }}
|
||||||
|
</p>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
</VCol>
|
</VCol>
|
||||||
</VRow>
|
</VRow>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- CTA Section -->
|
<!-- Stats Section -->
|
||||||
<VContainer class="py-16">
|
<div class="section-alt-bg">
|
||||||
<VCard color="primary" class="text-center pa-12">
|
<VContainer class="marketing-section">
|
||||||
<h2 class="text-h3 font-weight-bold text-white mb-3">Ready to get started?</h2>
|
<VRow>
|
||||||
<p class="text-h6 font-weight-regular mb-6" style="opacity: 0.9;">
|
<VCol
|
||||||
Deploy your first server in under 60 seconds.
|
v-for="stat in stats"
|
||||||
|
:key="stat.label"
|
||||||
|
cols="6"
|
||||||
|
md="3"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
flat
|
||||||
|
class="h-100"
|
||||||
|
:style="`border-inline-start: 4px solid rgb(var(--v-theme-${stat.color}))`"
|
||||||
|
>
|
||||||
|
<VCardText class="pa-5">
|
||||||
|
<div class="d-flex align-center ga-3 mb-2">
|
||||||
|
<VAvatar
|
||||||
|
:color="stat.color"
|
||||||
|
variant="tonal"
|
||||||
|
size="40"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
:icon="stat.icon"
|
||||||
|
size="22"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<span class="text-h3 font-weight-bold">{{ stat.value }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-body-1 text-medium-emphasis">
|
||||||
|
{{ stat.label }}
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Testimonials Section -->
|
||||||
|
<VContainer class="marketing-section">
|
||||||
|
<SectionHeader
|
||||||
|
label="Testimonials"
|
||||||
|
title="Trusted by Thousands of Customers"
|
||||||
|
highlight-word="Thousands"
|
||||||
|
subtitle="See what our customers have to say about their experience with EZSCALE."
|
||||||
|
/>
|
||||||
|
|
||||||
|
<VRow>
|
||||||
|
<VCol
|
||||||
|
v-for="(testimonial, index) in testimonials"
|
||||||
|
:key="testimonial.name"
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
class="h-100 feature-card-hover fade-in-up"
|
||||||
|
:class="`stagger-delay-${index + 1}`"
|
||||||
|
>
|
||||||
|
<VCardText class="pa-6 d-flex flex-column h-100">
|
||||||
|
<VRating
|
||||||
|
:model-value="testimonial.rating"
|
||||||
|
readonly
|
||||||
|
color="warning"
|
||||||
|
density="compact"
|
||||||
|
class="mb-4"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p class="text-body-1 font-italic text-medium-emphasis flex-grow-1 mb-4">
|
||||||
|
"{{ testimonial.quote }}"
|
||||||
</p>
|
</p>
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
|
||||||
<VBtn color="white" size="x-large" rounded="lg">
|
<VDivider class="mb-4" />
|
||||||
|
|
||||||
|
<div class="d-flex align-center ga-3">
|
||||||
|
<VAvatar
|
||||||
|
:color="testimonial.avatarColor"
|
||||||
|
variant="tonal"
|
||||||
|
size="40"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
icon="tabler-user"
|
||||||
|
size="22"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="font-weight-bold text-body-1">
|
||||||
|
{{ testimonial.name }}
|
||||||
|
</div>
|
||||||
|
<div class="text-body-2 text-medium-emphasis">
|
||||||
|
{{ testimonial.company }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VContainer>
|
||||||
|
|
||||||
|
<!-- CTA Section -->
|
||||||
|
<VContainer class="marketing-section">
|
||||||
|
<VCard
|
||||||
|
color="primary"
|
||||||
|
class="overflow-hidden"
|
||||||
|
>
|
||||||
|
<VRow
|
||||||
|
no-gutters
|
||||||
|
align="center"
|
||||||
|
>
|
||||||
|
<VCol
|
||||||
|
cols="12"
|
||||||
|
md="7"
|
||||||
|
>
|
||||||
|
<VCardText class="pa-12">
|
||||||
|
<h2 class="text-h3 font-weight-bold text-white mb-3">
|
||||||
|
Ready to Get Started?
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<p
|
||||||
|
class="text-h6 font-weight-regular mb-6"
|
||||||
|
style="opacity: 0.85;"
|
||||||
|
>
|
||||||
|
Deploy your first server in under 60 seconds. No credit card required, cancel anytime.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a
|
||||||
|
:href="accountUrl + '/register'"
|
||||||
|
class="text-decoration-none"
|
||||||
|
>
|
||||||
|
<VBtn
|
||||||
|
color="white"
|
||||||
|
size="x-large"
|
||||||
|
rounded="lg"
|
||||||
|
>
|
||||||
Create Free Account
|
Create Free Account
|
||||||
<VIcon icon="tabler-arrow-right" end />
|
<VIcon
|
||||||
|
icon="tabler-arrow-right"
|
||||||
|
end
|
||||||
|
/>
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</a>
|
</a>
|
||||||
|
</VCardText>
|
||||||
|
</VCol>
|
||||||
|
|
||||||
|
<VCol
|
||||||
|
cols="12"
|
||||||
|
md="5"
|
||||||
|
class="d-none d-md-flex align-center justify-center"
|
||||||
|
>
|
||||||
|
<div class="cta-decoration">
|
||||||
|
<VAvatar
|
||||||
|
color="rgba(255, 255, 255, 0.15)"
|
||||||
|
size="140"
|
||||||
|
>
|
||||||
|
<VIcon
|
||||||
|
icon="tabler-rocket"
|
||||||
|
size="72"
|
||||||
|
color="white"
|
||||||
|
/>
|
||||||
|
</VAvatar>
|
||||||
|
</div>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cta-decoration {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 2rem;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
position: absolute;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 10%);
|
||||||
|
border-radius: 50%;
|
||||||
|
block-size: 200px;
|
||||||
|
content: "";
|
||||||
|
inline-size: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 5%);
|
||||||
|
border-radius: 50%;
|
||||||
|
block-size: 260px;
|
||||||
|
content: "";
|
||||||
|
inline-size: 260px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { usePage } from '@inertiajs/vue3'
|
import { usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
@@ -30,6 +31,47 @@ const props = computed(() => page.props as unknown as PageProps)
|
|||||||
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
||||||
const plans = computed(() => props.value.plans || [])
|
const plans = computed(() => props.value.plans || [])
|
||||||
|
|
||||||
|
// Internal provisioning keys that should never be shown to visitors
|
||||||
|
const internalKeys = new Set([
|
||||||
|
'virtfusion_package_id',
|
||||||
|
'synergy_package_id',
|
||||||
|
'enhance_package_id',
|
||||||
|
'pterodactyl_package_id',
|
||||||
|
'virtfusion_server_id',
|
||||||
|
'synergy_server_id',
|
||||||
|
])
|
||||||
|
|
||||||
|
function isDisplayableFeature(key: string): boolean {
|
||||||
|
return !internalKeys.has(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
const featureLabels: Record<string, string> = {
|
||||||
|
vcpu: 'vCPU',
|
||||||
|
cpu: 'CPU',
|
||||||
|
ram: 'RAM',
|
||||||
|
storage: 'Storage',
|
||||||
|
bandwidth: 'Bandwidth',
|
||||||
|
ip_addresses: 'IP Addresses',
|
||||||
|
backups: 'Backups',
|
||||||
|
ddos_protection: 'DDoS Protection',
|
||||||
|
support: 'Support',
|
||||||
|
uptime_sla: 'Uptime SLA',
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanizeFeatureKey(key: string): string {
|
||||||
|
if (featureLabels[key]) return featureLabels[key]
|
||||||
|
return key
|
||||||
|
.replace(/_/g, ' ')
|
||||||
|
.replace(/\b\w/g, c => c.toUpperCase())
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDisplayFeatures(plan: Plan): Array<{ key: string; value: string }> {
|
||||||
|
if (!plan.features) return []
|
||||||
|
return Object.entries(plan.features)
|
||||||
|
.filter(([key]) => isDisplayableFeature(key))
|
||||||
|
.map(([key, value]) => ({ key, value }))
|
||||||
|
}
|
||||||
|
|
||||||
function getMonthlyPrice(plan: Plan): string {
|
function getMonthlyPrice(plan: Plan): string {
|
||||||
const price = parseFloat(plan.price ?? '0') || 0
|
const price = parseFloat(plan.price ?? '0') || 0
|
||||||
return price % 1 === 0 ? price.toString() : price.toFixed(2)
|
return price % 1 === 0 ? price.toString() : price.toFixed(2)
|
||||||
@@ -44,17 +86,19 @@ function isPopular(index: number): boolean {
|
|||||||
return plans.value.length > 1 && index === 1
|
return plans.value.length > 1 && index === 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Feature comparison data
|
// Feature comparison data — excluding internal keys
|
||||||
const featureComparison = computed(() => {
|
const featureComparison = computed(() => {
|
||||||
if (plans.value.length === 0) return []
|
if (plans.value.length === 0) return []
|
||||||
const allFeatures = new Set<string>()
|
const allFeatures = new Set<string>()
|
||||||
plans.value.forEach(plan => {
|
plans.value.forEach(plan => {
|
||||||
if (plan.features) {
|
if (plan.features) {
|
||||||
Object.keys(plan.features).forEach(f => allFeatures.add(f))
|
Object.keys(plan.features)
|
||||||
|
.filter(isDisplayableFeature)
|
||||||
|
.forEach(f => allFeatures.add(f))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return Array.from(allFeatures).map(feature => ({
|
return Array.from(allFeatures).map(feature => ({
|
||||||
feature,
|
feature: humanizeFeatureKey(feature),
|
||||||
plans: plans.value.map(plan => ({
|
plans: plans.value.map(plan => ({
|
||||||
value: plan.features?.[feature] ?? null,
|
value: plan.features?.[feature] ?? null,
|
||||||
})),
|
})),
|
||||||
@@ -86,17 +130,11 @@ const faqs = [
|
|||||||
<VCard class="pricing-card" flat>
|
<VCard class="pricing-card" flat>
|
||||||
<!-- Plan Cards Section -->
|
<!-- Plan Cards Section -->
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<div class="text-center">
|
<SectionHeader
|
||||||
<h3 class="text-h3 pricing-title mb-2">
|
label="Pricing"
|
||||||
Pricing Plans
|
title="Pricing Plans"
|
||||||
</h3>
|
subtitle="All plans include 24/7 monitoring and enterprise-grade infrastructure. Choose the best plan to fit your needs."
|
||||||
<p class="mb-0 text-body-1">
|
/>
|
||||||
All plans include 24/7 monitoring and enterprise-grade infrastructure.
|
|
||||||
</p>
|
|
||||||
<p class="mb-2 text-body-1">
|
|
||||||
Choose the best plan to fit your needs.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Plan Cards -->
|
<!-- Plan Cards -->
|
||||||
<VRow v-if="plans.length">
|
<VRow v-if="plans.length">
|
||||||
@@ -109,6 +147,7 @@ const faqs = [
|
|||||||
<VCard
|
<VCard
|
||||||
flat
|
flat
|
||||||
border
|
border
|
||||||
|
class="feature-card-hover"
|
||||||
:class="isPopular(index) ? 'border-primary border-opacity-100' : ''"
|
:class="isPopular(index) ? 'border-primary border-opacity-100' : ''"
|
||||||
>
|
>
|
||||||
<VCardText
|
<VCardText
|
||||||
@@ -167,8 +206,8 @@ const faqs = [
|
|||||||
<!-- Plan Features -->
|
<!-- Plan Features -->
|
||||||
<VList class="card-list mb-4">
|
<VList class="card-list mb-4">
|
||||||
<VListItem
|
<VListItem
|
||||||
v-for="(value, feature) in plan.features"
|
v-for="feat in getDisplayFeatures(plan)"
|
||||||
:key="String(feature)"
|
:key="feat.key"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon
|
<VIcon
|
||||||
@@ -179,7 +218,7 @@ const faqs = [
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<VListItemTitle class="text-body-1">
|
<VListItemTitle class="text-body-1">
|
||||||
{{ value }}
|
{{ feat.value }}
|
||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
@@ -209,17 +248,26 @@ const faqs = [
|
|||||||
We're finalizing our plans. Check back soon or sign up to be notified.
|
We're finalizing our plans. Check back soon or sign up to be notified.
|
||||||
</p>
|
</p>
|
||||||
</VCard>
|
</VCard>
|
||||||
|
|
||||||
|
<!-- Money-back guarantee banner -->
|
||||||
|
<VCard v-if="plans.length" variant="tonal" color="primary" class="my-8">
|
||||||
|
<VCardText class="text-center py-4">
|
||||||
|
<div class="d-flex align-center justify-center ga-2">
|
||||||
|
<VIcon icon="tabler-sparkles" />
|
||||||
|
<span class="text-body-1 font-weight-medium">All plans include a 30-day money-back guarantee</span>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- Feature Comparison Table -->
|
<!-- Feature Comparison Table -->
|
||||||
<VContainer v-if="plans.length && featureComparison.length">
|
<VContainer v-if="plans.length && featureComparison.length">
|
||||||
<VCardText class="text-center py-16 pricing-section">
|
<VCardText class="text-center py-16 pricing-section">
|
||||||
<h3 class="text-h3 mb-2">
|
<SectionHeader
|
||||||
Pick a plan that works best for you
|
label="Compare Plans"
|
||||||
</h3>
|
title="Pick a Plan That Works Best for You"
|
||||||
<p class="text-body-1">
|
subtitle="Stay cool, we have a 30-day money back guarantee!"
|
||||||
Stay cool, we have a 30-day money back guarantee!
|
/>
|
||||||
</p>
|
|
||||||
|
|
||||||
<VTable class="text-no-wrap border rounded pricing-table">
|
<VTable class="text-no-wrap border rounded pricing-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ const products = [
|
|||||||
</VAvatar>
|
</VAvatar>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="text-h5 font-weight-bold">{{ product.title }}</h2>
|
<h2 class="text-h5 font-weight-bold">{{ product.title }}</h2>
|
||||||
<span class="text-body-2 text-medium-emphasis">Starting at {{ product.startingAt }}</span>
|
<span v-if="product.startingAt.startsWith('$')" class="text-body-2 text-medium-emphasis">Starting at {{ product.startingAt }}</span>
|
||||||
|
<VChip v-else color="info" size="small" variant="tonal">{{ product.startingAt }}</VChip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const creditTiers: CreditTier[] = [
|
|||||||
<!-- Introduction -->
|
<!-- Introduction -->
|
||||||
<p class="text-body-1 mb-6">
|
<p class="text-body-1 mb-6">
|
||||||
This Service Level Agreement ("SLA") is part of the
|
This Service Level Agreement ("SLA") is part of the
|
||||||
<Link :href="route('terms')" class="text-primary text-decoration-none font-weight-medium">Terms of Service</Link>
|
<Link href="/terms-of-service" class="text-primary text-decoration-none font-weight-medium">Terms of Service</Link>
|
||||||
between you and {{ companyName }} ("EZSCALE," "we," "us," or "our"). This SLA describes our
|
between you and {{ companyName }} ("EZSCALE," "we," "us," or "our"). This SLA describes our
|
||||||
uptime commitments and the remedies available to you if we fail to meet them.
|
uptime commitments and the remedies available to you if we fail to meet them.
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ const sections: Section[] = [
|
|||||||
<p class="text-body-1 mb-3">
|
<p class="text-body-1 mb-3">
|
||||||
By creating an account, placing an order, or otherwise using any of our Services, you acknowledge
|
By creating an account, placing an order, or otherwise using any of our Services, you acknowledge
|
||||||
that you have read, understood, and agree to be bound by these Terms, as well as our
|
that you have read, understood, and agree to be bound by these Terms, as well as our
|
||||||
<Link :href="route('privacy')" class="text-primary text-decoration-none font-weight-medium">Privacy Policy</Link>,
|
<Link href="/privacy-policy" class="text-primary text-decoration-none font-weight-medium">Privacy Policy</Link>,
|
||||||
<Link :href="route('aup')" class="text-primary text-decoration-none font-weight-medium">Acceptable Use Policy</Link>, and
|
<Link href="/acceptable-use" class="text-primary text-decoration-none font-weight-medium">Acceptable Use Policy</Link>, and
|
||||||
<Link :href="route('sla')" class="text-primary text-decoration-none font-weight-medium">Service Level Agreement</Link>.
|
<Link href="/sla" class="text-primary text-decoration-none font-weight-medium">Service Level Agreement</Link>.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-body-1 mb-3">
|
<p class="text-body-1 mb-3">
|
||||||
If you are using the Services on behalf of an organization, you represent and warrant that you have
|
If you are using the Services on behalf of an organization, you represent and warrant that you have
|
||||||
@@ -174,7 +174,7 @@ const sections: Section[] = [
|
|||||||
<h2 class="text-h5 font-weight-bold mb-4">6. Acceptable Use</h2>
|
<h2 class="text-h5 font-weight-bold mb-4">6. Acceptable Use</h2>
|
||||||
<p class="text-body-1 mb-3">
|
<p class="text-body-1 mb-3">
|
||||||
Your use of the Services is subject to our
|
Your use of the Services is subject to our
|
||||||
<Link :href="route('aup')" class="text-primary text-decoration-none font-weight-medium">Acceptable Use Policy</Link>.
|
<Link href="/acceptable-use" class="text-primary text-decoration-none font-weight-medium">Acceptable Use Policy</Link>.
|
||||||
You agree not to use our Services for any purpose that is unlawful or prohibited by these Terms. Prohibited uses include, but are not limited to:
|
You agree not to use our Services for any purpose that is unlawful or prohibited by these Terms. Prohibited uses include, but are not limited to:
|
||||||
</p>
|
</p>
|
||||||
<ul class="text-body-1 mb-3 ml-6">
|
<ul class="text-body-1 mb-3 ml-6">
|
||||||
@@ -195,7 +195,7 @@ const sections: Section[] = [
|
|||||||
<h2 class="text-h5 font-weight-bold mb-4">7. Service Level Agreement</h2>
|
<h2 class="text-h5 font-weight-bold mb-4">7. Service Level Agreement</h2>
|
||||||
<p class="text-body-1 mb-3">
|
<p class="text-body-1 mb-3">
|
||||||
Our commitment to uptime and service reliability is detailed in our
|
Our commitment to uptime and service reliability is detailed in our
|
||||||
<Link :href="route('sla')" class="text-primary text-decoration-none font-weight-medium">Service Level Agreement (SLA)</Link>.
|
<Link href="/sla" class="text-primary text-decoration-none font-weight-medium">Service Level Agreement (SLA)</Link>.
|
||||||
The SLA outlines our uptime guarantees, credit policies, and the process for reporting and claiming service disruptions.
|
The SLA outlines our uptime guarantees, credit policies, and the process for reporting and claiming service disruptions.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-body-1">
|
<p class="text-body-1">
|
||||||
|
|||||||
@@ -2,20 +2,22 @@
|
|||||||
import { usePage } from '@inertiajs/vue3'
|
import { usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
interface PageProps {
|
interface Plan {
|
||||||
domains: { marketing: string; account: string; admin: string }
|
id: number
|
||||||
|
name: string
|
||||||
|
slug: string
|
||||||
|
price: string
|
||||||
|
features: Record<string, string | number> | null
|
||||||
|
stock_quantity: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VpsPlan {
|
interface PageProps {
|
||||||
name: string
|
plans: Plan[]
|
||||||
cpu: string
|
domains: { marketing: string; account: string; admin: string }
|
||||||
ram: string
|
|
||||||
storage: string
|
|
||||||
bandwidth: string
|
|
||||||
price: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Feature {
|
interface Feature {
|
||||||
@@ -27,6 +29,13 @@ interface Feature {
|
|||||||
const page = usePage()
|
const page = usePage()
|
||||||
const props = computed(() => page.props as unknown as PageProps)
|
const props = computed(() => page.props as unknown as PageProps)
|
||||||
const accountUrl = computed<string>(() => `https://${props.value.domains?.account}`)
|
const accountUrl = computed<string>(() => `https://${props.value.domains?.account}`)
|
||||||
|
const plans = computed(() => props.value.plans || [])
|
||||||
|
|
||||||
|
const startingPrice = computed<string>(() => {
|
||||||
|
if (plans.value.length === 0) return '3.50'
|
||||||
|
const lowest = Math.min(...plans.value.map(p => parseFloat(p.price)))
|
||||||
|
return lowest % 1 === 0 ? lowest.toString() : lowest.toFixed(2)
|
||||||
|
})
|
||||||
|
|
||||||
const features: Feature[] = [
|
const features: Feature[] = [
|
||||||
{ icon: 'tabler-database', title: 'RAID 10 SSD Storage', description: 'Redundant SSD arrays for fast read/write speeds and data protection.' },
|
{ icon: 'tabler-database', title: 'RAID 10 SSD Storage', description: 'Redundant SSD arrays for fast read/write speeds and data protection.' },
|
||||||
@@ -37,43 +46,51 @@ const features: Feature[] = [
|
|||||||
{ icon: 'tabler-server', title: 'VirtFusion Panel', description: 'Powerful control panel for managing your VPS with ease.' },
|
{ icon: 'tabler-server', title: 'VirtFusion Panel', description: 'Powerful control panel for managing your VPS with ease.' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const plans: VpsPlan[] = [
|
|
||||||
{ name: 'Micro VPS', cpu: '1 vCPU', ram: '1 GB', storage: '25 GB SSD', bandwidth: '2 TB', price: '$4.20' },
|
|
||||||
{ name: 'Mini VPS', cpu: '1 vCPU', ram: '2 GB', storage: '50 GB SSD', bandwidth: '4 TB', price: '$6.00' },
|
|
||||||
{ name: 'Dev Starter', cpu: '2 vCPU', ram: '2 GB', storage: '60 GB SSD', bandwidth: '4 TB', price: '$8.00' },
|
|
||||||
{ name: 'Basic VPS', cpu: '2 vCPU', ram: '4 GB', storage: '80 GB SSD', bandwidth: '6 TB', price: '$12.00' },
|
|
||||||
{ name: 'Storage Box', cpu: '2 vCPU', ram: '2 GB', storage: '500 GB SSD', bandwidth: '8 TB', price: '$15.00' },
|
|
||||||
{ name: 'Standard VPS', cpu: '4 vCPU', ram: '8 GB', storage: '160 GB SSD', bandwidth: '8 TB', price: '$15.60' },
|
|
||||||
{ name: 'RAM Optimized', cpu: '4 vCPU', ram: '16 GB', storage: '240 GB SSD', bandwidth: '10 TB', price: '$19.00' },
|
|
||||||
{ name: 'Advanced VPS', cpu: '6 vCPU', ram: '16 GB', storage: '320 GB SSD', bandwidth: '10 TB', price: '$21.60' },
|
|
||||||
{ name: 'Pro VPS', cpu: '8 vCPU', ram: '32 GB', storage: '640 GB SSD', bandwidth: '16 TB', price: '$30.00' },
|
|
||||||
]
|
|
||||||
|
|
||||||
const includedFeatures: string[] = [
|
const includedFeatures: string[] = [
|
||||||
'1 IPv4 & 1 /64 IPv6',
|
'1 IPv4 & 1 /64 IPv6',
|
||||||
'Near instant provisioning',
|
'Near instant provisioning',
|
||||||
'VM backups',
|
'VM backups',
|
||||||
'Windows (BYOL) & Linux support',
|
'Windows (BYOL) & Linux support',
|
||||||
'Intel E5-2680 v4 processors',
|
|
||||||
'Full root access',
|
'Full root access',
|
||||||
'VirtFusion control panel',
|
'VirtFusion control panel',
|
||||||
'RAID 10 backed storage',
|
'RAID 10 backed storage',
|
||||||
'14-day money back guarantee',
|
'14-day money back guarantee',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// Keys from features JSON that should not be shown as table columns
|
||||||
|
const internalKeys = new Set([
|
||||||
|
'virtfusion_package_id',
|
||||||
|
'virtfusion_server_id',
|
||||||
|
'control_panel',
|
||||||
|
'os',
|
||||||
|
'ipv4',
|
||||||
|
'ipv6',
|
||||||
|
])
|
||||||
|
|
||||||
|
function getFeature(plan: Plan, key: string): string {
|
||||||
|
return String(plan.features?.[key] ?? '-')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPrice(plan: Plan): string {
|
||||||
|
const price = parseFloat(plan.price) || 0
|
||||||
|
return price % 1 === 0 ? `$${price}` : `$${price.toFixed(2)}`
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Hero -->
|
<!-- Hero -->
|
||||||
<div class="py-16" style="background: linear-gradient(135deg, rgb(var(--v-theme-primary), 0.1), rgb(var(--v-theme-surface)));">
|
<div class="hero-section" style="padding-block: 5.25rem; background: linear-gradient(135deg, rgb(var(--v-theme-primary), 0.1), rgb(var(--v-theme-surface)));">
|
||||||
<VContainer class="text-center">
|
<VContainer class="text-center">
|
||||||
<VChip color="primary" variant="tonal" class="mb-4">VPS Hosting</VChip>
|
<VChip color="primary" variant="tonal" class="mb-4">VPS Hosting</VChip>
|
||||||
<h1 class="text-h2 font-weight-bold mb-3">Virtual Private Servers</h1>
|
<h1 class="text-h2 font-weight-bold mb-3">
|
||||||
|
Virtual Private <span class="hero-gradient-text">Servers</span>
|
||||||
|
</h1>
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular mb-4 mx-auto" style="max-width: 600px;">
|
<p class="text-h6 text-medium-emphasis font-weight-regular mb-4 mx-auto" style="max-width: 600px;">
|
||||||
High-performance VPS hosting with RAID 10 SSD storage, dedicated resources, and full root access from our Atlanta, GA datacenter.
|
High-performance VPS hosting with RAID 10 SSD storage, dedicated resources, and full root access from our Atlanta, GA datacenter.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-body-1 text-medium-emphasis mb-8">
|
<p class="text-body-1 text-medium-emphasis mb-8">
|
||||||
Starting at just <span class="text-primary font-weight-bold">$4.20/mo</span>
|
Starting at just <span class="text-primary font-weight-bold">${{ startingPrice }}/mo</span>
|
||||||
</p>
|
</p>
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
||||||
<VBtn color="primary" size="x-large" rounded="lg">
|
<VBtn color="primary" size="x-large" rounded="lg">
|
||||||
@@ -85,13 +102,16 @@ const includedFeatures: string[] = [
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Features -->
|
<!-- Features -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Why Choose EZSCALE VPS?</h2>
|
label="Features"
|
||||||
</div>
|
title="Why Choose EZSCALE VPS?"
|
||||||
|
highlight-word="EZSCALE"
|
||||||
|
subtitle="Enterprise-grade infrastructure with the simplicity you deserve."
|
||||||
|
/>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="feature in features" :key="feature.title" cols="12" sm="6" md="4">
|
<VCol v-for="(feature, index) in features" :key="feature.title" cols="12" sm="6" md="4">
|
||||||
<div class="d-flex ga-3 mb-4">
|
<div :class="['d-flex ga-3 mb-4 feature-card-hover pa-3 rounded-lg', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
<VAvatar color="primary" variant="tonal" size="44">
|
<VAvatar color="primary" variant="tonal" size="44">
|
||||||
<VIcon :icon="feature.icon" size="22" />
|
<VIcon :icon="feature.icon" size="22" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
@@ -105,16 +125,16 @@ const includedFeatures: string[] = [
|
|||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- Plans Table -->
|
<!-- Plans Table -->
|
||||||
<div class="bg-surface-variant py-16">
|
<div class="section-alt-bg marketing-section">
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<div class="text-center mb-8">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">VPS Plans</h2>
|
label="Pricing"
|
||||||
<p class="text-body-1 text-medium-emphasis">
|
title="VPS Plans"
|
||||||
All plans hosted in our Atlanta, GA datacenter. DDoS protection, full root access, and VirtFusion panel included.
|
highlight-word="Plans"
|
||||||
</p>
|
subtitle="All plans hosted in our Atlanta, GA datacenter. DDoS protection, full root access, and VirtFusion panel included."
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
<VCard>
|
<VCard class="feature-card-hover">
|
||||||
<VTable>
|
<VTable>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -128,13 +148,13 @@ const includedFeatures: string[] = [
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="plan in plans" :key="plan.name">
|
<tr v-for="plan in plans" :key="plan.id">
|
||||||
<td class="font-weight-bold">{{ plan.name }}</td>
|
<td class="font-weight-bold">{{ plan.name }}</td>
|
||||||
<td>{{ plan.cpu }}</td>
|
<td>{{ getFeature(plan, 'cpu') }}</td>
|
||||||
<td>{{ plan.ram }}</td>
|
<td>{{ getFeature(plan, 'ram') }}</td>
|
||||||
<td>{{ plan.storage }}</td>
|
<td>{{ getFeature(plan, 'storage') }}</td>
|
||||||
<td>{{ plan.bandwidth }}</td>
|
<td>{{ getFeature(plan, 'bandwidth') }}</td>
|
||||||
<td class="text-primary font-weight-bold">{{ plan.price }}/mo</td>
|
<td class="text-primary font-weight-bold">{{ formatPrice(plan) }}/mo</td>
|
||||||
<td>
|
<td>
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
||||||
<VBtn color="primary" size="small" variant="tonal">Order Now</VBtn>
|
<VBtn color="primary" size="small" variant="tonal">Order Now</VBtn>
|
||||||
@@ -146,7 +166,7 @@ const includedFeatures: string[] = [
|
|||||||
</VCard>
|
</VCard>
|
||||||
|
|
||||||
<!-- Included with all plans -->
|
<!-- Included with all plans -->
|
||||||
<VCard class="mt-8 pa-6">
|
<VCard class="mt-8 pa-6 feature-card-hover">
|
||||||
<h3 class="text-h5 font-weight-bold mb-4 text-center">Included With All Plans</h3>
|
<h3 class="text-h5 font-weight-bold mb-4 text-center">Included With All Plans</h3>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol
|
<VCol
|
||||||
@@ -165,5 +185,28 @@ const includedFeatures: string[] = [
|
|||||||
</VCard>
|
</VCard>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<div class="marketing-section" style="background: linear-gradient(135deg, rgb(var(--v-theme-primary), 0.08), rgb(var(--v-theme-surface)));">
|
||||||
|
<VContainer class="text-center">
|
||||||
|
<h2 class="text-h4 font-weight-bold mb-3">Ready to Get Started?</h2>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-6">
|
||||||
|
Deploy your VPS in seconds with full root access, DDoS protection, and 24/7 support.
|
||||||
|
</p>
|
||||||
|
<div class="d-flex ga-3 justify-center flex-wrap">
|
||||||
|
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
||||||
|
<VBtn color="primary" size="large" rounded="lg">
|
||||||
|
Get Started
|
||||||
|
<VIcon icon="tabler-arrow-right" end />
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
<a href="/contact" class="text-decoration-none">
|
||||||
|
<VBtn color="primary" variant="outlined" size="large" rounded="lg">
|
||||||
|
Contact Sales
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,16 +2,22 @@
|
|||||||
import { usePage } from '@inertiajs/vue3'
|
import { usePage } from '@inertiajs/vue3'
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
import MarketingLayout from '@/Layouts/MarketingLayout.vue'
|
||||||
|
import SectionHeader from '@/Components/Marketing/SectionHeader.vue'
|
||||||
|
|
||||||
defineOptions({ layout: MarketingLayout })
|
defineOptions({ layout: MarketingLayout })
|
||||||
|
|
||||||
interface PageProps {
|
interface Plan {
|
||||||
domains: { marketing: string; account: string; admin: string }
|
id: number
|
||||||
|
name: string
|
||||||
|
slug: string
|
||||||
|
price: string
|
||||||
|
features: Record<string, string | number> | null
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = usePage()
|
interface PageProps {
|
||||||
const props = computed(() => page.props as unknown as PageProps)
|
plans: Plan[]
|
||||||
const accountUrl = computed(() => `https://${props.value.domains?.account}`)
|
domains: { marketing: string; account: string; admin: string }
|
||||||
|
}
|
||||||
|
|
||||||
interface Feature {
|
interface Feature {
|
||||||
icon: string
|
icon: string
|
||||||
@@ -19,18 +25,16 @@ interface Feature {
|
|||||||
description: string
|
description: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Plan {
|
const page = usePage()
|
||||||
name: string
|
const props = computed(() => page.props as unknown as PageProps)
|
||||||
storage: string
|
const accountUrl = computed<string>(() => `https://${props.value.domains?.account}`)
|
||||||
databases: string
|
const plans = computed(() => props.value.plans || [])
|
||||||
email: string
|
|
||||||
domains: string
|
const startingPrice = computed<string>(() => {
|
||||||
bandwidth: string
|
if (plans.value.length === 0) return '2.39'
|
||||||
ram: string
|
const lowest = Math.min(...plans.value.map(p => parseFloat(p.price)))
|
||||||
cores: string
|
return lowest % 1 === 0 ? lowest.toString() : lowest.toFixed(2)
|
||||||
price: string
|
})
|
||||||
popular?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
const features: Feature[] = [
|
const features: Feature[] = [
|
||||||
{ icon: 'tabler-layout-dashboard', title: 'Enhance Control Panel', description: 'Modern, intuitive control panel for effortless website and server management.' },
|
{ icon: 'tabler-layout-dashboard', title: 'Enhance Control Panel', description: 'Modern, intuitive control panel for effortless website and server management.' },
|
||||||
@@ -41,54 +45,6 @@ const features: Feature[] = [
|
|||||||
{ icon: 'tabler-terminal-2', title: 'SSH Access', description: 'Full SSH access for advanced users who need command-line control.' },
|
{ icon: 'tabler-terminal-2', title: 'SSH Access', description: 'Full SSH access for advanced users who need command-line control.' },
|
||||||
]
|
]
|
||||||
|
|
||||||
const plans: Plan[] = [
|
|
||||||
{
|
|
||||||
name: 'Small',
|
|
||||||
storage: '10 GB SSD',
|
|
||||||
databases: '2 MySQL DBs',
|
|
||||||
email: '5 Email Accounts',
|
|
||||||
domains: '1 Domain',
|
|
||||||
bandwidth: '1 TB BW',
|
|
||||||
ram: '512 MB RAM',
|
|
||||||
cores: '1 Core',
|
|
||||||
price: '$2.39',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Medium',
|
|
||||||
storage: '25 GB SSD',
|
|
||||||
databases: '6 MySQL DBs',
|
|
||||||
email: '20 Email Accounts',
|
|
||||||
domains: '4 Domains',
|
|
||||||
bandwidth: '1 TB BW',
|
|
||||||
ram: '1 GB RAM',
|
|
||||||
cores: '1 Core',
|
|
||||||
price: '$3.99',
|
|
||||||
popular: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Large',
|
|
||||||
storage: '100 GB SSD',
|
|
||||||
databases: 'Unlimited MySQL DBs',
|
|
||||||
email: 'Unlimited Email',
|
|
||||||
domains: '30 Domains',
|
|
||||||
bandwidth: '2 TB BW',
|
|
||||||
ram: '4 GB RAM',
|
|
||||||
cores: '4 Cores',
|
|
||||||
price: '$7.19',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Dedicated',
|
|
||||||
storage: '160 GB SSD',
|
|
||||||
databases: 'Unlimited MySQL DBs',
|
|
||||||
email: 'Unlimited Email',
|
|
||||||
domains: '100 Domains',
|
|
||||||
bandwidth: '4 TB BW',
|
|
||||||
ram: '8 GB RAM',
|
|
||||||
cores: '4 Cores',
|
|
||||||
price: '$15.99',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const includedFeatures: string[] = [
|
const includedFeatures: string[] = [
|
||||||
'Free SSL',
|
'Free SSL',
|
||||||
'Cloudflare DNS',
|
'Cloudflare DNS',
|
||||||
@@ -97,18 +53,50 @@ const includedFeatures: string[] = [
|
|||||||
'SSH Access',
|
'SSH Access',
|
||||||
'Enhance Panel',
|
'Enhance Panel',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const internalKeys = new Set(['enhance_package_id', 'ssl', 'panel'])
|
||||||
|
|
||||||
|
function getFeature(plan: Plan, key: string): string {
|
||||||
|
return String(plan.features?.[key] ?? '-')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPrice(plan: Plan): string {
|
||||||
|
const price = parseFloat(plan.price) || 0
|
||||||
|
return price % 1 === 0 ? `$${price}` : `$${price.toFixed(2)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlanFeatureRow {
|
||||||
|
key: string
|
||||||
|
icon: string
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const featureRows: PlanFeatureRow[] = [
|
||||||
|
{ key: 'storage', icon: 'tabler-database', label: 'Storage' },
|
||||||
|
{ key: 'databases', icon: 'tabler-stack-2', label: 'Databases' },
|
||||||
|
{ key: 'email', icon: 'tabler-mail', label: 'Email' },
|
||||||
|
{ key: 'domains', icon: 'tabler-world', label: 'Domains' },
|
||||||
|
{ key: 'bandwidth', icon: 'tabler-arrows-transfer-up', label: 'Bandwidth' },
|
||||||
|
{ key: 'ram', icon: 'tabler-device-desktop-analytics', label: 'RAM' },
|
||||||
|
{ key: 'cpu', icon: 'tabler-cpu', label: 'CPU' },
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- Hero -->
|
<!-- Hero -->
|
||||||
<div class="py-16" style="background: linear-gradient(135deg, rgb(var(--v-theme-warning), 0.1), rgb(var(--v-theme-surface)));">
|
<div class="hero-section" style="padding-block: 5.25rem; background: linear-gradient(135deg, rgb(var(--v-theme-warning), 0.1), rgb(var(--v-theme-surface)));">
|
||||||
<VContainer class="text-center">
|
<VContainer class="text-center">
|
||||||
<VChip color="warning" variant="tonal" class="mb-4">Web Hosting</VChip>
|
<VChip color="warning" variant="tonal" class="mb-4">Web Hosting</VChip>
|
||||||
<h1 class="text-h2 font-weight-bold mb-3">Managed Web Hosting</h1>
|
<h1 class="text-h2 font-weight-bold mb-3">
|
||||||
<p class="text-h6 text-medium-emphasis font-weight-regular mb-8 mx-auto" style="max-width: 600px;">
|
Managed Web <span class="hero-gradient-text">Hosting</span>
|
||||||
|
</h1>
|
||||||
|
<p class="text-h6 text-medium-emphasis font-weight-regular mb-4 mx-auto" style="max-width: 600px;">
|
||||||
Fast, secure, and reliable web hosting powered by Enhance with free SSL, Cloudflare DNS, and Redis caching.
|
Fast, secure, and reliable web hosting powered by Enhance with free SSL, Cloudflare DNS, and Redis caching.
|
||||||
</p>
|
</p>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-8">
|
||||||
|
Starting at just <span class="text-warning font-weight-bold">${{ startingPrice }}/mo</span>
|
||||||
|
</p>
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
||||||
<VBtn color="warning" size="x-large" rounded="lg">
|
<VBtn color="warning" size="x-large" rounded="lg">
|
||||||
Get Started
|
Get Started
|
||||||
@@ -119,16 +107,17 @@ const includedFeatures: string[] = [
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Features -->
|
<!-- Features -->
|
||||||
<VContainer class="py-16">
|
<VContainer class="marketing-section">
|
||||||
<div class="text-center mb-12">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Everything You Need</h2>
|
label="Features"
|
||||||
<p class="text-body-1 text-medium-emphasis mx-auto" style="max-width: 550px;">
|
label-color="warning"
|
||||||
Every plan comes loaded with the tools and features you need to build and grow your website.
|
title="Everything You Need"
|
||||||
</p>
|
highlight-word="Need"
|
||||||
</div>
|
subtitle="Every plan comes loaded with the tools and features you need to build and grow your website."
|
||||||
|
/>
|
||||||
<VRow>
|
<VRow>
|
||||||
<VCol v-for="feature in features" :key="feature.title" cols="12" sm="6" md="4">
|
<VCol v-for="(feature, index) in features" :key="feature.title" cols="12" sm="6" md="4">
|
||||||
<div class="d-flex ga-3 mb-4">
|
<div :class="['d-flex ga-3 mb-4 feature-card-hover pa-3 rounded-lg', `fade-in-up stagger-delay-${index + 1}`]">
|
||||||
<VAvatar color="warning" variant="tonal" size="44">
|
<VAvatar color="warning" variant="tonal" size="44">
|
||||||
<VIcon :icon="feature.icon" size="22" />
|
<VIcon :icon="feature.icon" size="22" />
|
||||||
</VAvatar>
|
</VAvatar>
|
||||||
@@ -142,25 +131,26 @@ const includedFeatures: string[] = [
|
|||||||
</VContainer>
|
</VContainer>
|
||||||
|
|
||||||
<!-- Plans -->
|
<!-- Plans -->
|
||||||
<div class="bg-surface-variant py-16">
|
<div class="section-alt-bg marketing-section">
|
||||||
<VContainer>
|
<VContainer>
|
||||||
<div class="text-center mb-8">
|
<SectionHeader
|
||||||
<h2 class="text-h3 font-weight-bold mb-3">Hosting Plans</h2>
|
label="Pricing"
|
||||||
<p class="text-body-1 text-medium-emphasis mx-auto" style="max-width: 550px;">
|
label-color="warning"
|
||||||
Choose the plan that fits your needs. All plans include free SSL, Cloudflare DNS, and the Enhance control panel.
|
title="Hosting Plans"
|
||||||
</p>
|
highlight-word="Plans"
|
||||||
</div>
|
subtitle="Choose the plan that fits your needs. All plans include free SSL, Cloudflare DNS, and the Enhance control panel."
|
||||||
|
/>
|
||||||
|
|
||||||
<VRow justify="center">
|
<VRow justify="center">
|
||||||
<VCol v-for="plan in plans" :key="plan.name" cols="12" sm="6" lg="3">
|
<VCol v-for="(plan, index) in plans" :key="plan.id" cols="12" sm="6" lg="3">
|
||||||
<VCard
|
<VCard
|
||||||
:variant="plan.popular ? 'elevated' : 'outlined'"
|
:variant="index === 1 ? 'elevated' : 'outlined'"
|
||||||
:class="['h-100', { 'border-warning border-opacity-100': plan.popular }]"
|
:class="['h-100 feature-card-hover', `fade-in-up stagger-delay-${index + 1}`, { 'border-warning border-opacity-100': index === 1 }]"
|
||||||
:elevation="plan.popular ? 8 : 0"
|
:elevation="index === 1 ? 8 : 0"
|
||||||
>
|
>
|
||||||
<VCardText class="pa-6 text-center">
|
<VCardText class="pa-6 text-center">
|
||||||
<VChip
|
<VChip
|
||||||
v-if="plan.popular"
|
v-if="index === 1"
|
||||||
color="warning"
|
color="warning"
|
||||||
size="small"
|
size="small"
|
||||||
class="mb-2"
|
class="mb-2"
|
||||||
@@ -170,53 +160,17 @@ const includedFeatures: string[] = [
|
|||||||
|
|
||||||
<h3 class="text-h5 font-weight-bold mb-1">{{ plan.name }}</h3>
|
<h3 class="text-h5 font-weight-bold mb-1">{{ plan.name }}</h3>
|
||||||
<div class="text-h4 font-weight-bold text-warning mb-4">
|
<div class="text-h4 font-weight-bold text-warning mb-4">
|
||||||
{{ plan.price }}<span class="text-body-2 text-medium-emphasis">/mo</span>
|
{{ formatPrice(plan) }}<span class="text-body-2 text-medium-emphasis">/mo</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<VDivider class="mb-4" />
|
<VDivider class="mb-4" />
|
||||||
|
|
||||||
<VList density="compact" class="pa-0">
|
<VList density="compact" class="pa-0">
|
||||||
<VListItem class="px-0">
|
<VListItem v-for="row in featureRows" :key="row.key" class="px-0">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon icon="tabler-database" color="warning" size="18" class="me-2" />
|
<VIcon :icon="row.icon" color="warning" size="18" class="me-2" />
|
||||||
</template>
|
</template>
|
||||||
<VListItemTitle class="text-body-2">{{ plan.storage }}</VListItemTitle>
|
<VListItemTitle class="text-body-2">{{ getFeature(plan, row.key) }}</VListItemTitle>
|
||||||
</VListItem>
|
|
||||||
<VListItem class="px-0">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="tabler-stack-2" color="warning" size="18" class="me-2" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle class="text-body-2">{{ plan.databases }}</VListItemTitle>
|
|
||||||
</VListItem>
|
|
||||||
<VListItem class="px-0">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="tabler-mail" color="warning" size="18" class="me-2" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle class="text-body-2">{{ plan.email }}</VListItemTitle>
|
|
||||||
</VListItem>
|
|
||||||
<VListItem class="px-0">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="tabler-world" color="warning" size="18" class="me-2" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle class="text-body-2">{{ plan.domains }}</VListItemTitle>
|
|
||||||
</VListItem>
|
|
||||||
<VListItem class="px-0">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="tabler-arrows-transfer-up" color="warning" size="18" class="me-2" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle class="text-body-2">{{ plan.bandwidth }}</VListItemTitle>
|
|
||||||
</VListItem>
|
|
||||||
<VListItem class="px-0">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="tabler-device-desktop-analytics" color="warning" size="18" class="me-2" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle class="text-body-2">{{ plan.ram }}</VListItemTitle>
|
|
||||||
</VListItem>
|
|
||||||
<VListItem class="px-0">
|
|
||||||
<template #prepend>
|
|
||||||
<VIcon icon="tabler-cpu" color="warning" size="18" class="me-2" />
|
|
||||||
</template>
|
|
||||||
<VListItemTitle class="text-body-2">{{ plan.cores }}</VListItemTitle>
|
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
|
|
||||||
@@ -236,8 +190,8 @@ const includedFeatures: string[] = [
|
|||||||
|
|
||||||
<a :href="accountUrl + '/register'" class="text-decoration-none d-block">
|
<a :href="accountUrl + '/register'" class="text-decoration-none d-block">
|
||||||
<VBtn
|
<VBtn
|
||||||
:color="plan.popular ? 'warning' : 'warning'"
|
color="warning"
|
||||||
:variant="plan.popular ? 'elevated' : 'tonal'"
|
:variant="index === 1 ? 'elevated' : 'tonal'"
|
||||||
block
|
block
|
||||||
>
|
>
|
||||||
Choose Plan
|
Choose Plan
|
||||||
@@ -249,5 +203,28 @@ const includedFeatures: string[] = [
|
|||||||
</VRow>
|
</VRow>
|
||||||
</VContainer>
|
</VContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<div class="marketing-section" style="background: linear-gradient(135deg, rgb(var(--v-theme-warning), 0.08), rgb(var(--v-theme-surface)));">
|
||||||
|
<VContainer class="text-center">
|
||||||
|
<h2 class="text-h4 font-weight-bold mb-3">Ready to Launch Your Website?</h2>
|
||||||
|
<p class="text-body-1 text-medium-emphasis mb-6">
|
||||||
|
Get started with managed hosting that includes free SSL, Cloudflare DNS, and the Enhance control panel.
|
||||||
|
</p>
|
||||||
|
<div class="d-flex ga-3 justify-center flex-wrap">
|
||||||
|
<a :href="accountUrl + '/register'" class="text-decoration-none">
|
||||||
|
<VBtn color="warning" size="large" rounded="lg">
|
||||||
|
Get Started
|
||||||
|
<VIcon icon="tabler-arrow-right" end />
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
<a href="/contact" class="text-decoration-none">
|
||||||
|
<VBtn color="warning" variant="outlined" size="large" rounded="lg">
|
||||||
|
Contact Sales
|
||||||
|
</VBtn>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</VContainer>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const marketingNavItems: MarketingNavItem[] = [
|
|||||||
{ title: 'Dedicated Servers', href: '/dedicated-servers', description: 'Bare metal power', icon: 'tabler-server-2' },
|
{ title: 'Dedicated Servers', href: '/dedicated-servers', description: 'Bare metal power', icon: 'tabler-server-2' },
|
||||||
{ title: 'Web Hosting', href: '/web-hosting', description: 'Managed web hosting', icon: 'tabler-world' },
|
{ title: 'Web Hosting', href: '/web-hosting', description: 'Managed web hosting', icon: 'tabler-world' },
|
||||||
{ title: 'Game Servers', href: '/game-servers', description: 'Low-latency game hosting', icon: 'tabler-device-gamepad-2' },
|
{ title: 'Game Servers', href: '/game-servers', description: 'Low-latency game hosting', icon: 'tabler-device-gamepad-2' },
|
||||||
|
{ title: 'Battlefield ACP', href: '/battlefield-acp', description: 'BF server admin panel', icon: 'tabler-military-rank' },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ title: 'Pricing', href: '/pricing' },
|
{ title: 'Pricing', href: '/pricing' },
|
||||||
|
|||||||
@@ -9,10 +9,55 @@ use Inertia\Inertia;
|
|||||||
|
|
||||||
Route::get('/', fn () => Inertia::render('Marketing/Home'))->name('home');
|
Route::get('/', fn () => Inertia::render('Marketing/Home'))->name('home');
|
||||||
Route::get('/products', fn () => Inertia::render('Marketing/Products'))->name('products');
|
Route::get('/products', fn () => Inertia::render('Marketing/Products'))->name('products');
|
||||||
Route::get('/vps-hosting', fn () => Inertia::render('Marketing/VpsHosting'))->name('vps-hosting');
|
Route::get('/vps-hosting', function () {
|
||||||
Route::get('/dedicated-servers', fn () => Inertia::render('Marketing/DedicatedServers'))->name('dedicated-servers');
|
$plans = Plan::query()
|
||||||
Route::get('/web-hosting', fn () => Inertia::render('Marketing/WebHosting'))->name('web-hosting');
|
->where('service_type', 'vps')
|
||||||
Route::get('/game-servers', fn () => Inertia::render('Marketing/GameServers'))->name('game-servers');
|
->where('status', 'active')
|
||||||
|
->orderBy('sort_order')
|
||||||
|
->orderBy('price')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return Inertia::render('Marketing/VpsHosting', [
|
||||||
|
'plans' => $plans,
|
||||||
|
]);
|
||||||
|
})->name('vps-hosting');
|
||||||
|
Route::get('/dedicated-servers', function () {
|
||||||
|
$plans = Plan::query()
|
||||||
|
->where('service_type', 'dedicated')
|
||||||
|
->where('status', 'active')
|
||||||
|
->orderBy('sort_order')
|
||||||
|
->orderBy('price')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return Inertia::render('Marketing/DedicatedServers', [
|
||||||
|
'plans' => $plans,
|
||||||
|
]);
|
||||||
|
})->name('dedicated-servers');
|
||||||
|
Route::get('/web-hosting', function () {
|
||||||
|
$plans = Plan::query()
|
||||||
|
->where('service_type', 'hosting')
|
||||||
|
->where('status', 'active')
|
||||||
|
->orderBy('sort_order')
|
||||||
|
->orderBy('price')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return Inertia::render('Marketing/WebHosting', [
|
||||||
|
'plans' => $plans,
|
||||||
|
]);
|
||||||
|
})->name('web-hosting');
|
||||||
|
Route::get('/game-servers', function () {
|
||||||
|
$plans = Plan::query()
|
||||||
|
->where('service_type', 'game')
|
||||||
|
->where('status', 'active')
|
||||||
|
->orderBy('sort_order')
|
||||||
|
->orderBy('price')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return Inertia::render('Marketing/GameServers', [
|
||||||
|
'plans' => $plans,
|
||||||
|
]);
|
||||||
|
})->name('game-servers');
|
||||||
|
Route::get('/battlefield-acp', fn () => Inertia::render('Marketing/BattlefieldAcp'))->name('battlefield-acp');
|
||||||
Route::get('/pricing', function () {
|
Route::get('/pricing', function () {
|
||||||
$plans = Plan::query()
|
$plans = Plan::query()
|
||||||
->where('status', 'active')
|
->where('status', 'active')
|
||||||
|
|||||||
Reference in New Issue
Block a user