feat(routing): route links page to links.crischarles.com subdomain
This commit is contained in:
1 parent
c3f9ab43ab
commit
a628246e0b
4 files changed
+50
-18
No files matched your search
@@ -165,7 +165,7 @@ export default function Footer({ fullName = 'Cris Charles Garcia', socialLinks =
|
||||
<span className="opacity-40">•</span>
|
||||
<a href="/contact" className="hover:text-foreground-custom transition-colors">Contact</a>
|
||||
<span className="opacity-40">•</span>
|
||||
<a href="/links" className="text-primary-custom hover:underline font-medium">Links Directory</a>
|
||||
<a href="https://links.crischarles.com" className="text-primary-custom hover:underline font-medium">Links Directory</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ interface Props {
|
||||
image?: string;
|
||||
preloadImage?: string;
|
||||
type?: 'website' | 'article' | 'profile';
|
||||
canonicalURL?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
@@ -21,7 +22,8 @@ const {
|
||||
description = "Personal portfolio website of Cris Charles Garcia, showcasing projects, skills, experience, and custom AI chatbot assistant.",
|
||||
image = "/logo.png",
|
||||
preloadImage,
|
||||
type = "website"
|
||||
type = "website",
|
||||
canonicalURL
|
||||
} = Astro.props;
|
||||
|
||||
const isRootPage = Astro.url.pathname === '/';
|
||||
@@ -51,7 +53,7 @@ const isRootPage = Astro.url.pathname === '/';
|
||||
<meta name="apple-mobile-web-app-title" content="Cris Charles" />
|
||||
|
||||
<!-- SEO & Structured Data -->
|
||||
<SEO title={title} description={description} image={image} type={type} />
|
||||
<SEO title={title} description={description} image={image} type={type} canonicalURL={canonicalURL} />
|
||||
<link rel="sitemap" href="/sitemap-index.xml" />
|
||||
<!-- Astro ClientRouter for seamless SPA page transitions (no reload, no twitch) -->
|
||||
<ClientRouter />
|
||||
|
||||
+43
-14
@@ -1,25 +1,54 @@
|
||||
import { defineMiddleware } from 'astro:middleware';
|
||||
|
||||
export const onRequest = defineMiddleware((context, next) => {
|
||||
export const onRequest = defineMiddleware(async (context, next) => {
|
||||
const isMaintenanceMode = import.meta.env.MAINTENANCE_MODE === 'true';
|
||||
|
||||
// If maintenance mode is off, let all requests through
|
||||
if (!isMaintenanceMode) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const pathname = context.url.pathname;
|
||||
const hostname = context.url.hostname.toLowerCase();
|
||||
|
||||
// Always allow the maintenance page itself, static assets, and API routes
|
||||
if (
|
||||
pathname === '/maintenance' ||
|
||||
// Static assets and internal Astro assets pass through immediately
|
||||
const isStaticOrInternal =
|
||||
pathname.startsWith('/_astro') ||
|
||||
pathname.startsWith('/_image') ||
|
||||
pathname.startsWith('/api') ||
|
||||
/\.(png|svg|ico|webp|jpg|jpeg|gif|css|js|txt|xml|json|woff2?|ttf|eot|pdf)$/i.test(pathname)
|
||||
) {
|
||||
/\.(png|svg|ico|webp|jpg|jpeg|gif|css|js|txt|xml|json|woff2?|ttf|eot|pdf)$/i.test(pathname);
|
||||
|
||||
if (isStaticOrInternal) {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Redirect all other traffic to /maintenance
|
||||
return context.redirect('/maintenance', 307);
|
||||
// Maintenance mode handling
|
||||
if (isMaintenanceMode) {
|
||||
if (pathname === '/maintenance') {
|
||||
return next();
|
||||
}
|
||||
return context.redirect('/maintenance', 307);
|
||||
}
|
||||
|
||||
// Subdomain handling: links.crischarles.com (or links.localhost in dev)
|
||||
const isLinksSubdomain =
|
||||
hostname === 'links.crischarles.com' ||
|
||||
(hostname.startsWith('links.') && (hostname.includes('localhost') || hostname.includes('127.0.0.1')));
|
||||
|
||||
if (isLinksSubdomain) {
|
||||
// Root on subdomain renders the /links page seamlessly
|
||||
if (pathname === '/') {
|
||||
return context.rewrite('/links');
|
||||
}
|
||||
// Redundant /links path redirects to /
|
||||
if (pathname === '/links' || pathname === '/links/') {
|
||||
return context.redirect('/', 301);
|
||||
}
|
||||
// Any other path on links subdomain redirects to main portfolio
|
||||
return context.redirect(`https://crischarles.com${pathname}`, 302);
|
||||
}
|
||||
|
||||
// Main domain: redirect /links to dedicated links.crischarles.com subdomain (in production)
|
||||
if (pathname === '/links' || pathname === '/links/') {
|
||||
if (hostname === 'crischarles.com' || hostname === 'www.crischarles.com') {
|
||||
return context.redirect('https://links.crischarles.com', 301);
|
||||
}
|
||||
}
|
||||
|
||||
return next();
|
||||
});
|
||||
|
||||
@@ -51,6 +51,7 @@ const getIconSvg = (platform: string) => {
|
||||
<Layout
|
||||
title={`Links & Socials | ${settings.fullName}`}
|
||||
description="Official social links, contact options, and developer directory for Cris Charles Garcia."
|
||||
canonicalURL="https://links.crischarles.com"
|
||||
>
|
||||
<style is:global>
|
||||
body {
|
||||
@@ -86,7 +87,7 @@ const getIconSvg = (platform: string) => {
|
||||
{/* Return to Main Portfolio Pill & Status */}
|
||||
<div class="w-full max-w-md md:max-w-4xl lg:max-w-5xl flex justify-between items-center mb-4 sm:mb-6 links-header-pills">
|
||||
<a
|
||||
href="/"
|
||||
href="https://crischarles.com"
|
||||
class="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-foreground-custom/5 hover:bg-foreground-custom/10 text-muted-foreground-custom hover:text-foreground-custom text-xs font-mono border border-border-custom transition-all"
|
||||
>
|
||||
<span>←</span>
|
||||
|
||||
Reference in new issue
Block a user