288 lines
No EOL
9 KiB
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> |