Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.

This commit is contained in:
becarta
2025-05-23 12:43:00 +02:00
parent f40db0f5c9
commit a544759a3b
11127 changed files with 1647032 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
---
import { SITE } from '../site.config';
import { getCurrentLocale } from '../utils/i18n';
import '../styles/global.css';
export interface Props {
title?: string;
description?: string;
image?: string;
lang?: string;
keywords?: string;
}
const {
title = SITE.title,
description = SITE.description,
image = SITE.ogImage,
lang = getCurrentLocale(),
keywords = ''
} = Astro.props;
// Safe URL creation with fallbacks
let canonicalURL;
let ogImageURL;
let twitterImageURL;
try {
const siteURL = Astro.site || new URL('http://localhost:4321');
canonicalURL = new URL(Astro.url.pathname, siteURL);
ogImageURL = new URL(image, siteURL);
twitterImageURL = new URL(image, siteURL);
} catch (error) {
// Fallback URLs if there's an issue
const fallbackSite = 'https://tiber365.it';
canonicalURL = new URL(Astro.url?.pathname || '/', fallbackSite);
ogImageURL = new URL(image, fallbackSite);
twitterImageURL = new URL(image, fallbackSite);
}
const fullTitle = title === SITE.title ? title : `${title} | ${SITE.title}`;
---
<!doctype html>
<html lang={lang} class="scroll-smooth">
<head>
<meta charset="UTF-8" />
<meta name="description" content={description} />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="generator" content={Astro.generator} />
{keywords && <meta name="keywords" content={keywords} />}
<!-- Canonical URL -->
<link rel="canonical" href={canonicalURL} />
<!-- Primary Meta Tags -->
<title>{fullTitle}</title>
<meta name="title" content={fullTitle} />
<meta name="description" content={description} />
<meta name="author" content={SITE.author} />
<!-- Prevent automatic language redirects -->
<meta name="google" content="notranslate" />
<meta http-equiv="Content-Language" content={lang} />
<!-- Theme Color -->
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#3b82f6" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content={canonicalURL} />
<meta property="og:title" content={fullTitle} />
<meta property="og:description" content={description} />
<meta property="og:image" content={ogImageURL} />
<meta property="og:site_name" content={SITE.title} />
<meta property="og:locale" content={lang === 'en' ? 'en_US' : lang === 'nl' ? 'nl_NL' : 'it_IT'} />
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={canonicalURL} />
<meta property="twitter:title" content={fullTitle} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={twitterImageURL} />
<!-- Favicons -->
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="manifest" href="/manifest.json" />
<!-- Preconnect to external domains -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<!-- Content Security Policy -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https:; connect-src 'self'; frame-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self';" />
<!-- Structured Data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Tiber365",
"url": "https://tiber365.it",
"logo": "https://tiber365.it/images/logo.png",
"description": "Professional IT services for freelancers and small businesses. Microsoft 365 support, networking solutions, web hosting, and custom IT projects.",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+39-123-456-7890",
"contactType": "customer service",
"email": "info@tiber365.it"
},
"sameAs": [
"https://blog.tiber365.it",
"https://support.tiber365.it"
],
"address": {
"@type": "PostalAddress",
"addressCountry": "IT"
}
}
</script>
<!-- Initialize theme before page load -->
<script is:inline>
(function() {
function getThemePreference() {
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
return localStorage.getItem('theme');
}
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function reflectPreference(theme) {
document.documentElement.setAttribute('data-theme', theme);
const themeColorMeta = document.querySelector('meta[name="theme-color"]');
if (themeColorMeta) {
themeColorMeta.setAttribute('content', theme === 'dark' ? '#0f172a' : '#ffffff');
}
}
const theme = getThemePreference();
reflectPreference(theme);
})();
</script>
</head>
<body class="min-h-screen bg-background text-foreground">
<slot />
<!-- Initialize animations -->
<script>
import { initScrollAnimations } from '../utils/animations';
import { initTheme } from '../utils/theme';
document.addEventListener('DOMContentLoaded', () => {
initTheme();
initScrollAnimations();
});
</script>
</body>
</html>