feat: Initialize frontend with React, Vite, and Tailwind CSS

- Set up main entry point for React application.
- Create About, Home, NotFound, Privacy, and Terms pages with SEO support.
- Implement API service for file uploads and task management.
- Add global styles using Tailwind CSS.
- Create utility functions for SEO and text processing.
- Configure Vite for development and production builds.
- Set up Nginx configuration for serving frontend and backend.
- Add scripts for cleanup of expired files and sitemap generation.
- Implement deployment script for production environment.
This commit is contained in:
Your Name
2026-02-28 23:31:19 +02:00
parent 3b84ebb916
commit 85d98381df
93 changed files with 5940 additions and 0 deletions

69
frontend/src/utils/seo.ts Normal file
View File

@@ -0,0 +1,69 @@
/**
* SEO utility functions for structured data generation.
*/
export interface ToolSeoData {
name: string;
description: string;
url: string;
category?: string;
}
/**
* Generate WebApplication JSON-LD structured data for a tool page.
*/
export function generateToolSchema(tool: ToolSeoData): object {
return {
'@context': 'https://schema.org',
'@type': 'WebApplication',
name: tool.name,
url: tool.url,
applicationCategory: tool.category || 'UtilitiesApplication',
operatingSystem: 'Any',
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
description: tool.description,
inLanguage: ['en', 'ar'],
};
}
/**
* Generate BreadcrumbList JSON-LD.
*/
export function generateBreadcrumbs(
items: { name: string; url: string }[]
): object {
return {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: items.map((item, index) => ({
'@type': 'ListItem',
position: index + 1,
name: item.name,
item: item.url,
})),
};
}
/**
* Generate FAQ structured data.
*/
export function generateFAQ(
questions: { question: string; answer: string }[]
): object {
return {
'@context': 'https://schema.org',
'@type': 'FAQPage',
mainEntity: questions.map((q) => ({
'@type': 'Question',
name: q.question,
acceptedAnswer: {
'@type': 'Answer',
text: q.answer,
},
})),
};
}