Footer

Customize the footer content and links

The main footer (app/components/footer/MainFooter.vue) includes copyright text, legal links, and interactive feedback buttons for authenticated users.

The footer is used in most layouts: default.vue, auth.vue, public.vue, and wide.vue. The ai.vue layout doesn't include a footer.

What's included

The footer (app/components/footer/MainFooter.vue) contains:

  • Copyright text - "© Year Site Name. All rights reserved." (auto-updates with current year and $config.public.siteName)
  • Legal links - Privacy Policy (/legal/privacy) and Terms & Conditions (/legal/terms).
  • Feedback buttons - Three action buttons for authenticated users (desktop only):
    • "Report a bug" - Opens bug report dialog.
    • "Request a feature" - Opens feature request dialog.
    • "Get support" - Links to /support page.
  • Feedback dialogs - ReportBugForm and RequestFeatureForm components that submit to the database.

Layout:

  • Mobile: Stacked vertically (copyright and legal links centered)
  • Desktop: Horizontal layout with feedback buttons on the right
  • Uses base-container class for consistent max-width and horizontal padding
The base-container class ensures consistent spacing across your site. It's defined in your Tailwind configuration and used in headers, sections, and footers.

i18n ready: All text uses translation keys ($t('common.privacyPolicy'), $t('reportBug.button'), etc.)

Quick tweaks

These customizations modify the existing footer structure.

Removing the feedback buttons

If you don't need the feedback system, edit MainFooter.vue:

  1. Remove the import statements:
// Remove these lines
import ReportBugForm from '@/components/feedback/ReportBugForm.vue'
import RequestFeatureForm from '@/components/feedback/RequestFeatureForm.vue'
  1. Remove the state and handlers:
// Remove these lines
const showRequestFeatureForm = ref(false)
const showReportBugForm = ref(false)

const handleClickRequestFeature = () => { ... }
const handleClickReportBug = () => { ... }
  1. Remove the conditional buttons section:
<!-- Remove this entire block -->
<div v-if="isAuthenticated" class="hidden lg:flex gap-2">
  <!-- ... feedback buttons ... -->
</div>
  1. Remove the dialog components at the bottom:
<!-- Remove these lines -->
<RequestFeatureForm v-if="showRequestFeatureForm" v-model="showRequestFeatureForm" />
<ReportBugForm v-if="showReportBugForm" v-model="showReportBugForm" />
  1. Simplify the flex layout class by removing the conditional justification:
<!-- Change this -->
:class="{ 'justify-between': isAuthenticated }"

<!-- To this -->
class="... justify-center ..."

Edit MainFooter.vue to add more links alongside the existing privacy/terms links:

<NuxtLink to="/legal/cookies">
  <span>{{ $t('common.cookies') }}</span>
</NuxtLink>
<span class="opacity-50"> | </span>
<NuxtLink to="/sitemap">
  <span>{{ $t('common.sitemap') }}</span>
</NuxtLink>
Remember to add corresponding translation keys to i18n/locales/en.json and other locale files:
{
  "common": {
    "cookies": "Cookie policy",
    "sitemap": "Sitemap"
  }
}

Edit MainFooter.vue to change the copyright text format:

<!-- With founding year -->
<span>© 2024-{{ new Date().getFullYear() }} {{ $config.public.siteName }}</span>

<!-- i18n version with parameters -->
<span>{{ $t('footer.copyright', { year: new Date().getFullYear(), company: $config.public.siteName }) }}</span>

Changing colors and styling

The footer inherits theme colors from Tailwind. Customize styling in MainFooter.vue:

<!-- Dark background footer -->
<footer class="bg-muted/50 border-t">
  <div class="base-container py-8">
    <!-- Footer content -->
  </div>
</footer>

<!-- Accent border top -->
<footer class="border-t-2 border-primary">
  <div class="base-container py-8">
    <!-- Footer content -->
  </div>
</footer>

Create a custom layout without a footer (e.g., app/layouts/minimal.vue):

<script setup lang="ts">
import MainHeader from '@/components/header/MainHeader.vue'
</script>

<template>
  <div>
    <MainHeader />
    <div class="base-container min-h-[calc(100vh-10rem)]">
      <slot />
    </div>
  </div>
</template>

Then use it on your page:

<script setup lang="ts">
definePageMeta({
  layout: 'minimal'
})
</script>