[FEAT] Add FAQ

This commit is contained in:
2025-11-26 19:27:33 +01:00
parent 0942ce5d51
commit 75e24eac42
4 changed files with 117 additions and 0 deletions

View File

@@ -36,6 +36,7 @@
<router-link to="/blog" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Read our blog posts" aria-label="Navigate to blog">Blog</router-link> <router-link to="/blog" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Read our blog posts" aria-label="Navigate to blog">Blog</router-link>
<router-link to="/about" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Learn more about us" aria-label="Navigate to about page">About Us</router-link> <router-link to="/about" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Learn more about us" aria-label="Navigate to about page">About Us</router-link>
<router-link to="/contact" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Get in touch with us" aria-label="Navigate to contact page">Contact</router-link> <router-link to="/contact" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Get in touch with us" aria-label="Navigate to contact page">Contact</router-link>
<router-link to="/faq" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Frequently Asked Questions" aria-label="Navigate to FAQ page">FAQ</router-link>
<router-link to="/privacy-policy" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Read our privacy policy" aria-label="Navigate to privacy policy">Privacy Policy</router-link> <router-link to="/privacy-policy" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="Read our privacy policy" aria-label="Navigate to privacy policy">Privacy Policy</router-link>
<a href="/sitemap.xml" target="_blank" rel="noopener noreferrer" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="View XML sitemap" aria-label="View sitemap">Sitemap</a> <a href="/sitemap.xml" target="_blank" rel="noopener noreferrer" class="hover:text-gray-900 dark:hover:text-white transition-colors" title="View XML sitemap" aria-label="View sitemap">Sitemap</a>
</div> </div>

View File

@@ -18,6 +18,11 @@ export interface BreadcrumbItem {
url: string; url: string;
} }
export interface FAQItem {
question: string;
answer: string;
}
export function useStructuredData() { export function useStructuredData() {
// Organization Schema // Organization Schema
const addOrganizationSchema = () => { const addOrganizationSchema = () => {
@@ -159,11 +164,37 @@ export function useStructuredData() {
}); });
}; };
// FAQ Schema
const addFAQSchema = (faqs: FAQItem[]) => {
const schema = {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: faqs.map(faq => ({
'@type': 'Question',
name: faq.question,
acceptedAnswer: {
'@type': 'Answer',
text: faq.answer,
},
})),
};
useHead({
script: [
{
type: 'application/ld+json',
children: JSON.stringify(schema),
},
],
});
};
return { return {
addOrganizationSchema, addOrganizationSchema,
addWebSiteSchema, addWebSiteSchema,
addBlogPostSchema, addBlogPostSchema,
addBreadcrumbSchema, addBreadcrumbSchema,
addBlogListSchema, addBlogListSchema,
addFAQSchema,
}; };
} }

View File

@@ -24,6 +24,11 @@ const router = createRouter({
name: 'privacy-policy', name: 'privacy-policy',
component: () => import('../views/PrivacyPolicy.vue'), component: () => import('../views/PrivacyPolicy.vue'),
}, },
{
path: '/faq',
name: 'faq',
component: () => import('../views/FAQ.vue'),
},
{ {
path: '/blog', path: '/blog',
name: 'blog-overview', name: 'blog-overview',

80
src/views/FAQ.vue Normal file
View File

@@ -0,0 +1,80 @@
<script setup lang="ts">
import { useSEO } from '../composables/useSEO';
import { useStructuredData } from '../composables/useStructuredData';
const { addFAQSchema, addBreadcrumbSchema } = useStructuredData();
// Set SEO synchronously
useSEO({
title: 'FAQ - Frequently Asked Questions',
description: 'Find answers to common questions about the Spritesheet Generator. Learn about supported formats, export options, and how to use the tool effectively.',
url: '/faq',
type: 'website',
keywords: 'faq, spritesheet generator help, questions, support, documentation',
});
addBreadcrumbSchema([
{ name: 'Home', url: '/' },
{ name: 'FAQ', url: '/faq' },
]);
const faqs = [
{
question: 'What is a spritesheet?',
answer: 'A spritesheet is a single image file that contains multiple smaller images (sprites) arranged in a grid or packed layout. It is commonly used in game development to reduce memory usage and improve performance by reducing the number of draw calls.',
},
{
question: 'Is this tool free to use?',
answer: 'Yes, this Spritesheet Generator is completely free and open-source. You can use it for personal and commercial projects without any restrictions.',
},
{
question: 'What image formats are supported?',
answer: 'We support importing common image formats including PNG, JPG, GIF, and WEBP. You can drag and drop multiple files at once to generate your spritesheet.',
},
{
question: 'How do I export my spritesheet?',
answer: 'Once you have arranged your sprites, click the "Export" button. You can choose to download the spritesheet image (PNG) and the accompanying data file (JSON/CSS) that describes the sprite positions.',
},
{
question: 'Can I contribute to the project?',
answer: 'Absolutely! The project is open-source. You can find the source code on our Gitea repository and contribute by reporting bugs, suggesting features, or submitting pull requests.',
},
];
addFAQSchema(faqs);
</script>
<template>
<div class="w-full">
<div class="bg-white/80 dark:bg-gray-900/80 backdrop-blur-md rounded-3xl shadow-2xl border border-gray-200/50 dark:border-gray-700/50 p-8 sm:p-12">
<h1 class="text-3xl sm:text-4xl font-extrabold text-gray-900 dark:text-white mb-6">Frequently Asked Questions</h1>
<p class="text-gray-700 dark:text-gray-300 leading-relaxed mb-10">
Got questions? We've got answers. If you can't find what you're looking for, feel free to <router-link to="/contact" class="text-blue-600 dark:text-blue-400 hover:underline">contact us</router-link>.
</p>
<div class="space-y-6">
<details v-for="(faq, index) in faqs" :key="index" class="group bg-gray-50 dark:bg-gray-800/50 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden transition-all duration-300 hover:shadow-md open:bg-white dark:open:bg-gray-800 open:shadow-lg open:border-blue-200 dark:open:border-blue-900">
<summary class="flex items-center justify-between p-6 cursor-pointer list-none">
<h3 class="text-lg font-bold text-gray-900 dark:text-white pr-4">{{ faq.question }}</h3>
<span class="transform transition-transform duration-300 group-open:rotate-180 text-gray-500 dark:text-gray-400">
<i class="fas fa-chevron-down"></i>
</span>
</summary>
<div class="px-6 pb-6 text-gray-700 dark:text-gray-300 leading-relaxed border-t border-gray-100 dark:border-gray-700/50 pt-4">
{{ faq.answer }}
</div>
</details>
</div>
</div>
</div>
</template>
<style scoped>
/* Remove default triangle for details/summary */
details > summary {
list-style: none;
}
details > summary::-webkit-details-marker {
display: none;
}
</style>