ghostguild-org/app/components/AppFooter.vue

288 lines
No EOL
9 KiB
Vue

<template>
<footer
class="py-16 border-t"
:class="[
backgroundClass,
borderClass
]"
>
<UContainer>
<!-- Main Footer Content -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-12">
<!-- Brand Section -->
<div class="lg:col-span-1">
<div class="flex items-center gap-2 mb-4">
<div class="w-8 h-8 rounded-full flex items-center justify-center" :class="logoBackgroundClass">
<div class="w-4 h-4 bg-white rounded-sm" />
</div>
<div class="w-6 h-6" :class="logoBackgroundClass" style="clip-path: polygon(50% 0%, 0% 100%, 100% 100%)" />
<span class="text-2xl font-bold ml-2" :class="brandTextClass">{{ brandName }}</span>
</div>
<p :class="textColorClass" class="text-sm leading-relaxed">
{{ description }}
</p>
</div>
<!-- Navigation Links -->
<div class="lg:col-span-1">
<h3 class="font-semibold mb-4" :class="headingColorClass">Navigation</h3>
<ul class="space-y-2">
<li v-for="link in navigationLinks" :key="link.path">
<NuxtLink
:to="link.path"
:class="linkColorClass"
class="text-sm hover:underline transition-colors"
>
{{ link.label }}
</NuxtLink>
</li>
</ul>
</div>
<!-- Community Links -->
<div class="lg:col-span-1">
<h3 class="font-semibold mb-4" :class="headingColorClass">Community</h3>
<ul class="space-y-2">
<li v-for="link in communityLinks" :key="link.path">
<NuxtLink
:to="link.path"
:class="linkColorClass"
class="text-sm hover:underline transition-colors"
>
{{ link.label }}
</NuxtLink>
</li>
</ul>
</div>
<!-- Contact/Social -->
<div class="lg:col-span-1">
<h3 class="font-semibold mb-4" :class="headingColorClass">Connect</h3>
<ul class="space-y-2">
<li v-for="link in socialLinks" :key="link.href">
<a
:href="link.href"
:class="linkColorClass"
class="text-sm hover:underline transition-colors"
target="_blank"
rel="noopener noreferrer"
>
{{ link.label }}
</a>
</li>
</ul>
</div>
</div>
<!-- Decorative Elements (matching wireframe) -->
<div class="flex items-center justify-between mb-8">
<div class="flex items-center gap-2">
<div class="w-8 h-8 rounded-full flex items-center justify-center" :class="logoBackgroundClass">
<div class="w-4 h-4 bg-white rounded-sm" />
</div>
<div class="w-6 h-6" :class="logoBackgroundClass" style="clip-path: polygon(50% 0%, 0% 100%, 100% 100%)" />
</div>
<div class="hidden md:flex items-center gap-8">
<div class="space-y-2">
<div class="h-1 w-16 rounded-full" :class="decorativeBarClass" />
<div class="h-1 w-12 rounded-full" :class="decorativeBarSecondaryClass" />
<div class="h-1 w-14 rounded-full" :class="decorativeBarTertiaryClass" />
</div>
<div class="space-y-2">
<div class="h-1 w-12 rounded-full" :class="decorativeBarClass" />
<div class="h-1 w-16 rounded-full" :class="decorativeBarSecondaryClass" />
<div class="h-1 w-10 rounded-full" :class="decorativeBarTertiaryClass" />
</div>
<div class="space-y-2">
<div class="h-1 w-14 rounded-full" :class="decorativeBarClass" />
<div class="h-1 w-10 rounded-full" :class="decorativeBarSecondaryClass" />
<div class="h-1 w-16 rounded-full" :class="decorativeBarTertiaryClass" />
</div>
</div>
</div>
<!-- Copyright -->
<div class="pt-8 text-center" :class="borderClass">
<p :class="textColorClass" class="text-sm">
© {{ currentYear }} {{ brandName }}. {{ copyrightText }}
</p>
</div>
</UContainer>
</footer>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
theme: {
type: String,
default: 'purple',
validator: (value) => ['purple', 'blue', 'emerald', 'gray'].includes(value)
},
brandName: {
type: String,
default: 'Ghost Guild'
},
description: {
type: String,
default: 'A community for game developers exploring cooperative models and building sustainable studios together.'
},
copyrightText: {
type: String,
default: 'All rights reserved.'
},
customNavigationLinks: {
type: Array,
default: () => []
},
customCommunityLinks: {
type: Array,
default: () => []
},
customSocialLinks: {
type: Array,
default: () => []
}
})
const currentYear = new Date().getFullYear()
const navigationLinks = computed(() => {
if (props.customNavigationLinks.length > 0) {
return props.customNavigationLinks
}
return [
{ label: 'Home', path: '/' },
{ label: 'About', path: '/about' },
{ label: 'Events', path: '/events' },
{ label: 'Join', path: '/join' },
{ label: 'Contact', path: '/contact' }
]
})
const communityLinks = computed(() => {
if (props.customCommunityLinks.length > 0) {
return props.customCommunityLinks
}
return [
{ label: 'Upcoming Events', path: '/events' },
{ label: 'Past Events', path: '/events/past' },
{ label: 'Event Calendar', path: '/events/calendar' },
{ label: 'Members Directory', path: '/members' }
]
})
const socialLinks = computed(() => {
if (props.customSocialLinks.length > 0) {
return props.customSocialLinks
}
return [
{ label: 'Discord Community', href: 'https://discord.gg/ghostguild' },
{ label: 'Twitter', href: 'https://twitter.com/ghostguild' },
{ label: 'GitHub', href: 'https://github.com/ghostguild' },
{ label: 'Contact Us', href: 'mailto:hello@ghostguild.org' }
]
})
const backgroundClass = computed(() => {
const themes = {
purple: 'bg-purple-50 dark:bg-purple-900/20',
blue: 'bg-blue-50 dark:bg-blue-900/20',
emerald: 'bg-emerald-50 dark:bg-emerald-900/20',
gray: 'bg-gray-50 dark:bg-gray-900'
}
return themes[props.theme] || themes.purple
})
const borderClass = computed(() => {
const themes = {
purple: 'border-purple-200 dark:border-purple-800',
blue: 'border-blue-200 dark:border-blue-800',
emerald: 'border-emerald-200 dark:border-emerald-800',
gray: 'border-gray-200 dark:border-gray-700'
}
return themes[props.theme] || themes.purple
})
const logoBackgroundClass = computed(() => {
const themes = {
purple: 'bg-purple-500',
blue: 'bg-blue-500',
emerald: 'bg-emerald-500',
gray: 'bg-gray-500'
}
return themes[props.theme] || themes.purple
})
const brandTextClass = computed(() => {
const themes = {
purple: 'text-purple-600 dark:text-purple-400',
blue: 'text-blue-600 dark:text-blue-400',
emerald: 'text-emerald-600 dark:text-emerald-400',
gray: 'text-gray-900 dark:text-white'
}
return themes[props.theme] || themes.purple
})
const headingColorClass = computed(() => {
const themes = {
purple: 'text-purple-900 dark:text-purple-100',
blue: 'text-blue-900 dark:text-blue-100',
emerald: 'text-emerald-900 dark:text-emerald-100',
gray: 'text-gray-900 dark:text-white'
}
return themes[props.theme] || themes.purple
})
const textColorClass = computed(() => {
const themes = {
purple: 'text-purple-600 dark:text-purple-400',
blue: 'text-blue-600 dark:text-blue-400',
emerald: 'text-emerald-600 dark:text-emerald-400',
gray: 'text-gray-600 dark:text-gray-400'
}
return themes[props.theme] || themes.purple
})
const linkColorClass = computed(() => {
const themes = {
purple: 'text-purple-700 dark:text-purple-300 hover:text-purple-900 dark:hover:text-purple-100',
blue: 'text-blue-700 dark:text-blue-300 hover:text-blue-900 dark:hover:text-blue-100',
emerald: 'text-emerald-700 dark:text-emerald-300 hover:text-emerald-900 dark:hover:text-emerald-100',
gray: 'text-gray-700 dark:text-gray-300 hover:text-gray-900 dark:hover:text-gray-100'
}
return themes[props.theme] || themes.purple
})
const decorativeBarClass = computed(() => {
const themes = {
purple: 'bg-purple-500',
blue: 'bg-blue-500',
emerald: 'bg-emerald-500',
gray: 'bg-gray-500'
}
return themes[props.theme] || themes.purple
})
const decorativeBarSecondaryClass = computed(() => {
const themes = {
purple: 'bg-purple-400',
blue: 'bg-blue-400',
emerald: 'bg-emerald-400',
gray: 'bg-gray-400'
}
return themes[props.theme] || themes.purple
})
const decorativeBarTertiaryClass = computed(() => {
const themes = {
purple: 'bg-purple-300',
blue: 'bg-blue-300',
emerald: 'bg-emerald-300',
gray: 'bg-gray-300'
}
return themes[props.theme] || themes.purple
})
</script>