import { useEffect, useMemo, useState } from "react"; import { Link } from "react-router-dom"; import Layout from "@/components/Layout"; import LoadingScreen from "@/components/LoadingScreen"; import { useAethexToast } from "@/hooks/use-aethex-toast"; import BlogHero from "@/components/blog/BlogHero"; import BlogTrendingRail from "@/components/blog/BlogTrendingRail"; import BlogCategoryChips from "@/components/blog/BlogCategoryChips"; import BlogPostGrid from "@/components/blog/BlogPostGrid"; import BlogNewsletterSection from "@/components/blog/BlogNewsletterSection"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { ArrowRight, Layers, ListFilter, Newspaper } from "lucide-react"; import type { BlogCategory, BlogPost } from "@/components/blog/types"; const buildSlug = (post: BlogPost): string => post.slug || post.id?.toString() || "article"; const normalizeCategory = (value?: string | null) => (value || "general") .toString() .trim() .toLowerCase() .replace(/[^a-z0-9]+/g, "-"); const Blog = () => { const toast = useAethexToast(); const [isLoading, setIsLoading] = useState(true); const [posts, setPosts] = useState([]); const [searchQuery, setSearchQuery] = useState(""); const [selectedCategory, setSelectedCategory] = useState("all"); const staticPosts = useMemo( () => [ { id: "static-0", slug: "shipping-aethex-multiverse-events", title: "Shipping AeThex Multiverse Events: Behind the Scenes", excerpt: "How the AeThex LiveOps squad orchestrated cross-platform events with zero downtime.", author: "Sofia Alvarez", date: "January 18, 2025", readTime: "8 min read", category: "Company News", likes: 254, comments: 44, trending: true, image: "https://images.unsplash.com/photo-1529101091764-c3526daf38fe?auto=format&fit=crop&w=1200&q=80", }, { id: "static-1", slug: "aethex-guilds-collaboration-toolkit", title: "AeThex Guilds Collaboration Toolkit Launch", excerpt: "New creator guild features help communities prototype faster and ship together.", author: "Priya Desai", date: "January 16, 2025", readTime: "7 min read", category: "Product Updates", likes: 311, comments: 59, trending: false, image: "https://images.unsplash.com/photo-1526402464885-402318f32905?auto=format&fit=crop&w=1200&q=80", }, { id: "static-2", slug: "horizon-engine-2-0-preview", title: "Horizon Engine 2.0 Preview: Performance Notes", excerpt: "Peek into the renderer upgrades, tooling, and ergonomics coming to Horizon Engine 2.0.", author: "Liam Hart", date: "January 14, 2025", readTime: "9 min read", category: "Technology", likes: 368, comments: 71, trending: false, image: "https://images.unsplash.com/photo-1498050108023-c5249f4df085?auto=format&fit=crop&w=1200&q=80", }, { id: "static-3", slug: "community-creators-spotlight-january", title: "Community Creators Spotlight — January Edition", excerpt: "Celebrating five AeThex creators pushing storytelling, accessibility, and esports forward.", author: "AeThex Community Team", date: "January 13, 2025", readTime: "6 min read", category: "Community", likes: 427, comments: 95, trending: false, image: "https://images.unsplash.com/photo-1522199710521-72d69614c702?auto=format&fit=crop&w=1200&q=80", }, { id: "static-4", slug: "building-scalable-game-architecture", title: "Building Scalable Game Architecture with Microservices", excerpt: "Learn how to design game backends that can handle millions of concurrent players using modern microservices patterns.", author: "Marcus Rodriguez", date: "December 12, 2024", readTime: "6 min read", category: "Technology", likes: 89, comments: 15, trending: false, image: "https://images.unsplash.com/photo-1518770660439-4636190af475?auto=format&fit=crop&w=1200&q=80", }, { id: "static-5", slug: "advanced-unity-optimization-techniques", title: "Advanced Unity Optimization Techniques", excerpt: "Performance optimization strategies that can boost your Unity game's frame rate by up to 300%.", author: "Alex Thompson", date: "December 10, 2024", readTime: "12 min read", category: "Tutorials", likes: 156, comments: 34, trending: false, image: "https://images.unsplash.com/photo-1527443224154-dcc0707b462b?auto=format&fit=crop&w=1200&q=80", }, { id: "static-6", slug: "aethex-labs-neural-network-compression", title: "AeThex Labs: Breakthrough in Neural Network Compression", excerpt: "Our research team achieves 90% model size reduction while maintaining accuracy for mobile game AI.", author: "Dr. Aisha Patel", date: "December 8, 2024", readTime: "5 min read", category: "Research", likes: 203, comments: 41, trending: true, image: "https://images.unsplash.com/photo-1504384308090-c894fdcc538d?auto=format&fit=crop&w=1200&q=80", }, { id: "static-7", slug: "introducing-aethex-cloud-gaming-platform", title: "Introducing AeThex Cloud Gaming Platform", excerpt: "Launch games instantly across any device with our new cloud gaming infrastructure and global CDN.", author: "AeThex Team", date: "December 5, 2024", readTime: "4 min read", category: "Company News", likes: 278, comments: 52, trending: false, image: "https://images.unsplash.com/photo-1511512578047-dfb367046420?auto=format&fit=crop&w=1200&q=80", }, { id: "static-8", slug: "real-time-ray-tracing-in-web-games", title: "Real-time Ray Tracing in Web Games", excerpt: "Tutorial: Implementing hardware-accelerated ray tracing in browser-based games using WebGPU.", author: "Jordan Kim", date: "December 3, 2024", readTime: "15 min read", category: "Tutorials", likes: 94, comments: 18, trending: false, image: "https://images.unsplash.com/photo-1489515217757-5fd1be406fef?auto=format&fit=crop&w=1200&q=80", }, { id: "static-9", slug: "the-evolution-of-game-ai", title: "The Evolution of Game AI: From Scripts to Neural Networks", excerpt: "A comprehensive look at how artificial intelligence in games has evolved and where it's heading next.", author: "Dr. Michael Chen", date: "December 1, 2024", readTime: "10 min read", category: "Technology", likes: 167, comments: 29, trending: false, image: "https://images.unsplash.com/photo-1523580846011-d3a5bc25702b?auto=format&fit=crop&w=1200&q=80", }, ], [], ); useEffect(() => { let cancelled = false; (async () => { try { const res = await fetch("/api/blog?limit=50"); let data: any = []; try { if (res.ok) { data = await res.json(); } } catch (error) { console.warn("Failed to parse blog API response, falling back to Supabase", error); } if ((!Array.isArray(data) || !data.length) && import.meta.env.VITE_SUPABASE_URL && import.meta.env.VITE_SUPABASE_ANON_KEY) { try { const sbUrl = import.meta.env.VITE_SUPABASE_URL.replace(/\/$/, ""); const url = `${sbUrl}/rest/v1/blog_posts?select=slug,title,excerpt,author,date,read_time,category,image,likes,comments,published_at&order=published_at.desc&limit=50`; const fallbackRes = await fetch(url, { headers: { apikey: import.meta.env.VITE_SUPABASE_ANON_KEY, Authorization: `Bearer ${import.meta.env.VITE_SUPABASE_ANON_KEY}`, }, }); if (fallbackRes.ok) { data = await fallbackRes.json(); } } catch (error) { console.warn("Supabase fallback failed", error); } } if (!cancelled && Array.isArray(data)) { const mapped: BlogPost[] = data.map((record: any) => ({ id: record.id ?? record.slug, slug: record.slug, title: record.title, excerpt: record.excerpt ?? record.summary ?? null, author: record.author ?? "AeThex Team", date: record.date ?? record.published_at, readTime: record.read_time ?? record.readTime ?? null, category: record.category ?? "General", image: record.image ?? null, likes: typeof record.likes === "number" ? record.likes : null, comments: typeof record.comments === "number" ? record.comments : null, trending: Boolean(record.trending) || (typeof record.likes === "number" && record.likes > 250), body: record.body_html ?? record.body ?? null, })); setPosts(mapped); } } catch (error) { console.warn("Blog fetch failed", error); toast.system("Loaded curated AeThex articles"); } finally { if (!cancelled) { setIsLoading(false); } } })(); return () => { cancelled = true; }; }, [toast]); const dataset = posts.length ? posts : staticPosts; const filteredPosts = useMemo(() => { const query = searchQuery.trim().toLowerCase(); return dataset.filter((post) => { const matchesCategory = selectedCategory === "all" || normalizeCategory(post.category) === selectedCategory; if (!matchesCategory) return false; if (!query) return true; const haystack = [post.title, post.excerpt, post.author] .filter(Boolean) .map((value) => value!.toLowerCase()) .join(" "); return haystack.includes(query); }); }, [dataset, selectedCategory, searchQuery]); const featuredPost = useMemo(() => { if (!filteredPosts.length) { return dataset.find((post) => post.trending) ?? dataset[0] ?? null; } return filteredPosts.find((post) => post.trending) ?? filteredPosts[0] ?? null; }, [dataset, filteredPosts]); const displayedPosts = useMemo(() => { if (!featuredPost) return filteredPosts; return filteredPosts.filter((post) => buildSlug(post) !== buildSlug(featuredPost)); }, [filteredPosts, featuredPost]); const trendingPosts = useMemo(() => { const sorted = [...dataset] .filter((post) => post.trending || (post.likes ?? 0) >= 200) .sort((a, b) => (b.likes ?? 0) - (a.likes ?? 0)); return sorted.slice(0, 3); }, [dataset]); const categories: BlogCategory[] = useMemo(() => { const counts = new Map(); dataset.forEach((post) => { const id = normalizeCategory(post.category); const name = post.category || "General"; counts.set(id, { id, name, count: (counts.get(id)?.count ?? 0) + 1, }); }); const ordered = [ { id: "all", name: "All posts", count: dataset.length }, ...Array.from(counts.values()).sort((a, b) => b.count - a.count), ]; return ordered; }, [dataset]); const insights = useMemo( () => [ { label: "Teams publishing", value: new Set(dataset.map((post) => (post.author || "AeThex Team").split(" ")[0])).size, helper: "Active contributors this month", icon: , }, { label: "Focus areas", value: new Set(dataset.map((post) => post.category || "General")).size, helper: "Distinct categories covered", icon: , }, { label: "Stories published", value: dataset.length, helper: "All-time AeThex blog posts", icon: , }, ], [dataset], ); if (isLoading) { return ; } const handleResetFilters = () => { setSelectedCategory("all"); setSearchQuery(""); }; return (

Filter by track

Navigate the AeThex knowledge graph

{insights.map((insight) => ( {insight.icon}

{insight.label}

{insight.value}

{insight.helper}

))}

Latest updates

Fresh from the AeThex ship room

Explore more

Dive into AeThex documentation

Looking for implementation guides, deployment recipes, or program onboarding materials? Visit our documentation hub for developer tutorials, platform references, and community playbooks.

); }; export default Blog;