BReadcrumbs
This commit is contained in:
79
src/composables/useSEO.ts
Normal file
79
src/composables/useSEO.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { useHead } from '@vueuse/head';
|
||||
|
||||
export interface SEOMetaData {
|
||||
title: string;
|
||||
description: string;
|
||||
image?: string;
|
||||
url?: string;
|
||||
type?: 'website' | 'article';
|
||||
author?: string;
|
||||
publishedTime?: string;
|
||||
modifiedTime?: string;
|
||||
keywords?: string;
|
||||
}
|
||||
|
||||
const SITE_NAME = 'Spritesheet Generator';
|
||||
const SITE_URL = 'https://spritesheetgenerator.online';
|
||||
const DEFAULT_IMAGE = '/og-image.png';
|
||||
|
||||
export function useSEO(metadata: SEOMetaData) {
|
||||
const fullTitle = metadata.title.includes(SITE_NAME)
|
||||
? metadata.title
|
||||
: `${metadata.title} - ${SITE_NAME}`;
|
||||
|
||||
const fullUrl = metadata.url
|
||||
? `${SITE_URL}${metadata.url}`
|
||||
: SITE_URL;
|
||||
|
||||
const imageUrl = metadata.image
|
||||
? `${SITE_URL}${metadata.image}`
|
||||
: `${SITE_URL}${DEFAULT_IMAGE}`;
|
||||
|
||||
const metaTags: any[] = [
|
||||
// Primary Meta Tags
|
||||
{ name: 'title', content: fullTitle },
|
||||
{ name: 'description', content: metadata.description },
|
||||
{ name: 'robots', content: 'index, follow' },
|
||||
|
||||
// Open Graph / Facebook
|
||||
{ property: 'og:type', content: metadata.type || 'website' },
|
||||
{ property: 'og:url', content: fullUrl },
|
||||
{ property: 'og:title', content: fullTitle },
|
||||
{ property: 'og:description', content: metadata.description },
|
||||
{ property: 'og:image', content: imageUrl },
|
||||
{ property: 'og:site_name', content: SITE_NAME },
|
||||
|
||||
// Twitter
|
||||
{ name: 'twitter:card', content: 'summary_large_image' },
|
||||
{ name: 'twitter:url', content: fullUrl },
|
||||
{ name: 'twitter:title', content: fullTitle },
|
||||
{ name: 'twitter:description', content: metadata.description },
|
||||
{ name: 'twitter:image', content: imageUrl },
|
||||
];
|
||||
|
||||
// Add article-specific meta tags
|
||||
if (metadata.type === 'article') {
|
||||
if (metadata.author) {
|
||||
metaTags.push({ property: 'article:author', content: metadata.author });
|
||||
}
|
||||
if (metadata.publishedTime) {
|
||||
metaTags.push({ property: 'article:published_time', content: metadata.publishedTime });
|
||||
}
|
||||
if (metadata.modifiedTime) {
|
||||
metaTags.push({ property: 'article:modified_time', content: metadata.modifiedTime });
|
||||
}
|
||||
}
|
||||
|
||||
// Add keywords if provided
|
||||
if (metadata.keywords) {
|
||||
metaTags.push({ name: 'keywords', content: metadata.keywords });
|
||||
}
|
||||
|
||||
useHead({
|
||||
title: fullTitle,
|
||||
meta: metaTags,
|
||||
link: [
|
||||
{ rel: 'canonical', href: fullUrl }
|
||||
]
|
||||
});
|
||||
}
|
||||
172
src/composables/useStructuredData.ts
Normal file
172
src/composables/useStructuredData.ts
Normal file
@@ -0,0 +1,172 @@
|
||||
import { useHead } from '@vueuse/head';
|
||||
|
||||
const SITE_URL = 'https://spritesheetgenerator.online';
|
||||
const SITE_NAME = 'Spritesheet Generator';
|
||||
|
||||
export interface BlogPostSchema {
|
||||
title: string;
|
||||
description: string;
|
||||
author: string;
|
||||
datePublished: string;
|
||||
dateModified?: string;
|
||||
image: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface BreadcrumbItem {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function useStructuredData() {
|
||||
// Organization Schema
|
||||
const addOrganizationSchema = () => {
|
||||
const schema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Organization',
|
||||
'name': SITE_NAME,
|
||||
'url': SITE_URL,
|
||||
'logo': `${SITE_URL}/og-image.png`,
|
||||
'description': 'Free online tool to create spritesheets for game development',
|
||||
'sameAs': [
|
||||
'https://gitea.adhd.sh/root/spritesheet-generator',
|
||||
'https://discord.gg/JTev3nzeDa'
|
||||
]
|
||||
};
|
||||
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(schema)
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
// WebSite Schema
|
||||
const addWebSiteSchema = () => {
|
||||
const schema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebSite',
|
||||
'name': SITE_NAME,
|
||||
'url': SITE_URL,
|
||||
'description': 'Create professional spritesheets for your game development projects',
|
||||
'potentialAction': {
|
||||
'@type': 'SearchAction',
|
||||
'target': `${SITE_URL}/blog?search={search_term_string}`,
|
||||
'query-input': 'required name=search_term_string'
|
||||
}
|
||||
};
|
||||
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(schema)
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
// BlogPosting Schema
|
||||
const addBlogPostSchema = (post: BlogPostSchema) => {
|
||||
const schema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BlogPosting',
|
||||
'headline': post.title,
|
||||
'description': post.description,
|
||||
'image': `${SITE_URL}${post.image}`,
|
||||
'author': {
|
||||
'@type': 'Person',
|
||||
'name': post.author
|
||||
},
|
||||
'publisher': {
|
||||
'@type': 'Organization',
|
||||
'name': SITE_NAME,
|
||||
'logo': {
|
||||
'@type': 'ImageObject',
|
||||
'url': `${SITE_URL}/og-image.png`
|
||||
}
|
||||
},
|
||||
'datePublished': post.datePublished,
|
||||
'dateModified': post.dateModified || post.datePublished,
|
||||
'mainEntityOfPage': {
|
||||
'@type': 'WebPage',
|
||||
'@id': `${SITE_URL}${post.url}`
|
||||
}
|
||||
};
|
||||
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(schema)
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
// Breadcrumb Schema
|
||||
const addBreadcrumbSchema = (items: BreadcrumbItem[]) => {
|
||||
const schema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'BreadcrumbList',
|
||||
'itemListElement': items.map((item, index) => ({
|
||||
'@type': 'ListItem',
|
||||
'position': index + 1,
|
||||
'name': item.name,
|
||||
'item': `${SITE_URL}${item.url}`
|
||||
}))
|
||||
};
|
||||
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(schema)
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
// Blog List Schema
|
||||
const addBlogListSchema = (posts: BlogPostSchema[]) => {
|
||||
const schema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'Blog',
|
||||
'name': `${SITE_NAME} Blog`,
|
||||
'description': 'Latest articles about sprite sheet generation and game development',
|
||||
'url': `${SITE_URL}/blog`,
|
||||
'blogPost': posts.map(post => ({
|
||||
'@type': 'BlogPosting',
|
||||
'headline': post.title,
|
||||
'description': post.description,
|
||||
'image': `${SITE_URL}${post.image}`,
|
||||
'author': {
|
||||
'@type': 'Person',
|
||||
'name': post.author
|
||||
},
|
||||
'datePublished': post.datePublished,
|
||||
'url': `${SITE_URL}${post.url}`
|
||||
}))
|
||||
};
|
||||
|
||||
useHead({
|
||||
script: [
|
||||
{
|
||||
type: 'application/ld+json',
|
||||
children: JSON.stringify(schema)
|
||||
}
|
||||
]
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
addOrganizationSchema,
|
||||
addWebSiteSchema,
|
||||
addBlogPostSchema,
|
||||
addBreadcrumbSchema,
|
||||
addBlogListSchema
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user