feat(hytale): implement Hytale plugin development page and related components
- Added a new `/hytale` page with sections for hero, services, and pricing. - Updated existing components to support Hytale-specific content and i18n. - Modified site configuration and state to reflect the new focus on Hytale plugin development. - Enhanced testimonials section to feature relevant client feedback. - Adjusted navigation to include a link to the new Hytale page.
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
<script setup lang="ts">
|
||||
import { siteConfig } from '~/data/site'
|
||||
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
||||
const discordUrl = siteConfig.social.find(s => s.name === 'Discord')?.url ?? '#'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -27,16 +31,14 @@ const localePath = useLocalePath()
|
||||
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-brand-400 opacity-75" />
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-brand-500" />
|
||||
</span>
|
||||
<span class="text-sm font-medium text-brand-700 dark:text-brand-400">Available for projects</span>
|
||||
<span class="text-sm font-medium text-brand-700 dark:text-brand-400">{{ t('home.badge.available') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h1 class="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-extrabold tracking-tight leading-[1.1]">
|
||||
<span class="text-gray-900 dark:text-white">{{ t('home.title').split(' ').slice(0, -2).join(' ') }}
|
||||
</span>
|
||||
<span
|
||||
class="bg-gradient-to-r from-brand-500 via-brand-400 to-emerald-400 bg-clip-text text-transparent">{{
|
||||
t('home.title').split(' ').slice(-2).join(' ') }}</span>
|
||||
t('home.title') }}</span>
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-gray-600 dark:text-gray-400 max-w-xl leading-relaxed">
|
||||
{{ t('home.subtitle') }}
|
||||
@@ -45,27 +47,23 @@ const localePath = useLocalePath()
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
<div class="flex flex-col sm:flex-row gap-3">
|
||||
<NuxtLink
|
||||
:to="localePath('/projects')"
|
||||
class="inline-flex items-center justify-center gap-2 px-6 py-3 rounded-xl bg-brand-500 hover:bg-brand-600 text-white font-semibold text-sm transition-all duration-200 shadow-lg shadow-brand-500/25 hover:shadow-brand-500/40"
|
||||
<UButton
|
||||
:to="discordUrl"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
color="primary"
|
||||
icon="i-simple-icons-discord"
|
||||
size="lg"
|
||||
>
|
||||
{{ t('home.cta.viewProjects') }}
|
||||
<UIcon name="i-lucide-arrow-right" class="w-4 h-4" />
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
:to="localePath('/fiverr')"
|
||||
class="inline-flex items-center justify-center gap-2 px-6 py-3 rounded-xl border border-gray-300 dark:border-gray-700 text-gray-700 dark:text-gray-300 hover:border-brand-500/50 hover:text-brand-500 font-semibold text-sm transition-all duration-200"
|
||||
>
|
||||
{{ t('nav.fiverr') }}
|
||||
<UIcon name="i-lucide-external-link" class="w-4 h-4" />
|
||||
</NuxtLink>
|
||||
<NuxtLink
|
||||
{{ t('home.cta.discord') }}
|
||||
</UButton>
|
||||
<UButton
|
||||
:to="localePath('/contact')"
|
||||
class="inline-flex items-center justify-center gap-2 px-6 py-3 rounded-xl text-gray-600 dark:text-gray-400 hover:text-brand-500 font-semibold text-sm transition-all duration-200"
|
||||
variant="outline"
|
||||
size="lg"
|
||||
>
|
||||
{{ t('home.cta.contactMe') }}
|
||||
<UIcon name="i-lucide-message-circle" class="w-4 h-4" />
|
||||
</NuxtLink>
|
||||
{{ t('home.cta.contact') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -101,7 +99,7 @@ const localePath = useLocalePath()
|
||||
</div>
|
||||
<div class="pl-6">
|
||||
<span class="text-purple-500 dark:text-purple-400">role</span><span class="text-gray-500">: </span>
|
||||
<span class="text-amber-600 dark:text-amber-400">'Full Stack Dev'</span><span
|
||||
<span class="text-amber-600 dark:text-amber-400">'{{ t('home.terminal.role') }}'</span><span
|
||||
class="text-gray-500">,</span>
|
||||
</div>
|
||||
<div class="pl-6">
|
||||
@@ -144,12 +142,12 @@ const localePath = useLocalePath()
|
||||
<div
|
||||
class="absolute -top-4 -right-4 px-3 py-2 rounded-lg bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-lg text-xs font-medium flex items-center gap-2">
|
||||
<span class="w-2 h-2 rounded-full bg-brand-500" />
|
||||
<span class="text-gray-700 dark:text-gray-300">50+ projects</span>
|
||||
<span class="text-gray-700 dark:text-gray-300">{{ t('home.stats.projects') }}</span>
|
||||
</div>
|
||||
<div
|
||||
class="absolute -bottom-3 -left-3 px-3 py-2 rounded-lg bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 shadow-lg text-xs font-medium flex items-center gap-2">
|
||||
<UIcon name="i-lucide-star" class="text-yellow-400 w-3.5 h-3.5" />
|
||||
<span class="text-gray-700 dark:text-gray-300">5.0 rating</span>
|
||||
<span class="text-gray-700 dark:text-gray-300">{{ t('home.stats.rating') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { testimonials, testimonialsStats } from '~/data/testimonials'
|
||||
|
||||
const props = defineProps<{
|
||||
featured?: boolean
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const displayed = computed(() => props.featured ? testimonials.filter(t => t.featured) : testimonials)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -34,7 +40,7 @@ const { t } = useI18n()
|
||||
<!-- Horizontal scrolling testimonials -->
|
||||
<div class="flex gap-5 overflow-x-auto overflow-y-visible pb-8 -mx-4 px-4 pt-2 snap-x snap-mandatory scrollbar-hide">
|
||||
<div
|
||||
v-for="(testimonial, index) in testimonials"
|
||||
v-for="(testimonial, index) in displayed"
|
||||
:key="index"
|
||||
class="flex-none w-[340px] sm:w-[400px] snap-start"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
const { t } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="py-16 md:py-24 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-4xl mx-auto text-center">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">{{ t('hytale.hero.label') }}</span>
|
||||
<h1 class="text-4xl sm:text-5xl md:text-6xl font-extrabold tracking-tight leading-[1.1] mt-4">
|
||||
<span class="bg-gradient-to-r from-brand-500 via-brand-400 to-emerald-400 bg-clip-text text-transparent">{{ t('hytale.hero.title') }}</span>
|
||||
</h1>
|
||||
<p class="text-lg sm:text-xl text-gray-500 dark:text-gray-400 mt-6 max-w-2xl mx-auto leading-relaxed">
|
||||
{{ t('hytale.hero.subtitle') }}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { hytalePricing } from '~/data/pricing'
|
||||
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="py-16 md:py-24 px-4 sm:px-6 lg:px-8">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">{{ t('hytale.pricing.label') }}</span>
|
||||
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold mt-3 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('hytale.pricing.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-4 max-w-2xl mx-auto leading-relaxed">{{ t('hytale.pricing.subtitle') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<UCard
|
||||
v-for="tier in hytalePricing"
|
||||
:key="tier.id"
|
||||
class="hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1 transition-all duration-200"
|
||||
:class="{ 'ring-2 ring-brand-500': tier.featured }"
|
||||
>
|
||||
<div class="flex flex-col gap-4 p-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="text-xl font-bold text-gray-900 dark:text-white">{{ t(`hytale.pricing.${tier.id}.name`) }}</h3>
|
||||
<UBadge v-if="tier.featured" color="primary" variant="subtle">{{ t('hytale.pricing.popular') }}</UBadge>
|
||||
</div>
|
||||
|
||||
<div class="text-3xl font-extrabold text-gray-900 dark:text-white">
|
||||
<template v-if="tier.priceFixed">
|
||||
<span class="text-sm font-normal text-gray-500 dark:text-gray-400">{{ t('hytale.pricing.from') }} </span>
|
||||
{{ tier.priceFixed }}
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="text-lg">{{ t('hytale.pricing.onQuote') }}</span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">{{ t(`hytale.pricing.${tier.id}.description`) }}</p>
|
||||
|
||||
<ul class="space-y-2 flex-1">
|
||||
<li v-for="i in 4" :key="i" class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-300">
|
||||
<UIcon name="i-lucide-check" class="w-4 h-4 text-brand-500 shrink-0" />
|
||||
{{ t(`hytale.pricing.${tier.id}.features.${i - 1}`) }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<UButton
|
||||
:to="localePath('/contact')"
|
||||
:color="tier.featured ? 'primary' : 'neutral'"
|
||||
:variant="tier.featured ? 'solid' : 'outline'"
|
||||
block
|
||||
class="mt-4"
|
||||
>
|
||||
{{ t('hytale.pricing.cta') }}
|
||||
</UButton>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,33 @@
|
||||
<script setup lang="ts">
|
||||
const { t } = useI18n()
|
||||
|
||||
const services = [
|
||||
{ id: 'plugin', icon: 'i-lucide-puzzle' },
|
||||
{ id: 'config', icon: 'i-lucide-settings' },
|
||||
{ id: 'support', icon: 'i-lucide-shield-check' },
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="py-16 md:py-24 px-4 sm:px-6 lg:px-8 bg-gray-50/50 dark:bg-gray-900/20">
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="text-center mb-16">
|
||||
<span class="font-mono text-sm text-brand-500 dark:text-brand-400 tracking-wider">{{ t('hytale.services.label') }}</span>
|
||||
<h2 class="text-3xl sm:text-4xl lg:text-5xl font-bold mt-3 bg-gradient-to-r from-gray-900 via-gray-800 to-gray-600 dark:from-white dark:via-gray-200 dark:to-gray-500 bg-clip-text text-transparent">{{ t('hytale.services.title') }}</h2>
|
||||
<p class="text-lg text-gray-500 dark:text-gray-400 mt-4 max-w-2xl mx-auto leading-relaxed">{{ t('hytale.services.subtitle') }}</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<UCard v-for="service in services" :key="service.id" class="hover:border-brand-500/40 hover:shadow-xl hover:shadow-brand-500/10 hover:-translate-y-1 transition-all duration-200">
|
||||
<div class="flex flex-col items-center text-center gap-4 p-2">
|
||||
<div class="w-12 h-12 rounded-xl bg-brand-500/10 dark:bg-brand-500/15 flex items-center justify-center">
|
||||
<UIcon :name="service.icon" class="w-6 h-6 text-brand-500" />
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">{{ t(`hytale.services.items.${service.id}.title`) }}</h3>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400 leading-relaxed">{{ t(`hytale.services.items.${service.id}.description`) }}</p>
|
||||
</div>
|
||||
</UCard>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
Reference in New Issue
Block a user