pradit/App.tsx
2025-11-20 17:04:57 +07:00

268 lines
9.4 KiB
TypeScript

import React, { useContext, useState } from "react";
import { HashRouter, Routes, Route, Link, useLocation } from "react-router-dom";
import { Home } from "./pages/Home";
import { BlogPost } from "./pages/BlogPost";
import { Research } from "./pages/Research";
import { Services } from "./pages/Services";
import { HireUs } from "./pages/HireUs";
import { Playground } from "./pages/Playground";
import { ChatWidget } from "./components/ChatWidget";
import { Cpu, Menu, X, Globe, Terminal } from "lucide-react";
// --- Language Context ---
type Language = "en" | "th";
interface LanguageContextType {
language: Language;
toggleLanguage: () => void;
}
export const LanguageContext = React.createContext<LanguageContextType>({
language: "en",
toggleLanguage: () => {},
});
export const useLanguage = () => useContext(LanguageContext);
// --- Navigation ---
const Navigation: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const location = useLocation();
const { language, toggleLanguage } = useLanguage();
const isActive = (path: string) => {
if (path === "/research" && location.pathname.startsWith("/research")) {
return "text-ink font-semibold";
}
return location.pathname === path
? "text-ink font-semibold"
: "text-subtle hover:text-ink transition-colors";
};
return (
<nav className="sticky top-0 z-50 bg-paper/95 backdrop-blur-sm border-b border-gray-100">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between h-20">
<div className="flex items-center">
<Link to="/" className="flex items-center space-x-2">
<Cpu className="h-6 w-6 text-ink" />
<span className="font-sans tracking-widest text-sm font-bold uppercase text-ink">
Pradit
</span>
</Link>
</div>
{/* Desktop Nav */}
<div className="hidden md:flex items-center space-x-8 font-sans text-sm">
<Link to="/" className={isActive("/")}>
{language === "en" ? "Work" : "ผลงาน"}
</Link>
<Link to="/services" className={isActive("/services")}>
{language === "en" ? "Services" : "บริการ"}
</Link>
<Link to="/research" className={isActive("/research")}>
{language === "en" ? "Research" : "วิจัย"}
</Link>
<Link
to="/playground"
className={`${isActive("/playground")} flex items-center gap-1`}
>
<Terminal size={14} />
{language === "en" ? "Playground" : "ลองเล่น"}
</Link>
<Link
to="/hire-us"
className="bg-ink text-white px-4 py-2 rounded-sm hover:bg-gray-800 transition-colors"
>
{language === "en" ? "Hire Us" : "ติดต่อเรา"}
</Link>
{/* Language Toggle */}
<button
onClick={toggleLanguage}
className="flex items-center space-x-1 text-xs font-bold border border-gray-200 rounded-full px-3 py-1 hover:bg-gray-50 transition-colors"
>
<Globe size={14} className="text-subtle" />
<span className={language === "en" ? "text-ink" : "text-subtle"}>
EN
</span>
<span className="text-gray-300">|</span>
<span className={language === "th" ? "text-ink" : "text-subtle"}>
TH
</span>
</button>
</div>
{/* Mobile button */}
<div className="md:hidden flex items-center gap-4">
<button
onClick={toggleLanguage}
className="flex items-center space-x-1 text-xs font-bold border border-gray-200 rounded-full px-3 py-1"
>
<span className={language === "en" ? "text-ink" : "text-subtle"}>
EN
</span>
<span className="text-gray-300">|</span>
<span className={language === "th" ? "text-ink" : "text-subtle"}>
TH
</span>
</button>
<button onClick={() => setIsOpen(!isOpen)} className="text-ink p-2">
{isOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</div>
</div>
{/* Mobile Menu */}
{isOpen && (
<div className="md:hidden bg-white border-b border-gray-100">
<div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
<Link
to="/"
onClick={() => setIsOpen(false)}
className="block px-3 py-2 text-base font-medium text-ink"
>
Work
</Link>
<Link
to="/services"
onClick={() => setIsOpen(false)}
className="block px-3 py-2 text-base font-medium text-subtle"
>
Services
</Link>
<Link
to="/research"
onClick={() => setIsOpen(false)}
className="block px-3 py-2 text-base font-medium text-subtle"
>
Research
</Link>
<Link
to="/playground"
onClick={() => setIsOpen(false)}
className="block px-3 py-2 text-base font-medium text-subtle"
>
Playground
</Link>
<Link
to="/hire-us"
onClick={() => setIsOpen(false)}
className="block px-3 py-2 text-base font-medium text-ink font-bold"
>
Hire Us
</Link>
</div>
</div>
)}
</nav>
);
};
const Footer: React.FC = () => {
const { language } = useLanguage();
return (
<footer className="bg-white border-t border-gray-100 py-12 mt-24">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 grid grid-cols-1 md:grid-cols-4 gap-8">
<div className="col-span-1 md:col-span-2">
<span className="font-sans tracking-widest text-xs font-bold uppercase text-ink">
Pradit
</span>
<p className="mt-4 text-subtle font-serif text-sm max-w-md">
{language === "en"
? "We build production-grade AI systems. No hype, just engineering. Specializing in LLM integration, custom evaluations, and scalable architecture."
: "เราสร้างระบบ AI ระดับใช้งานจริง เน้นวิศวกรรมไม่เน้นโฆษณา เชี่ยวชาญด้านการรวมระบบ LLM, การประเมินผล และสถาปัตยกรรมที่ปรับขนาดได้"}
</p>
</div>
<div>
<h3 className="font-sans font-bold text-xs uppercase tracking-wider mb-4">
Offerings
</h3>
<ul className="space-y-2 text-sm text-subtle font-serif">
<li>
<Link
to="/services"
className="hover:text-ink hover:underline decoration-1 underline-offset-2"
>
MVP Development
</Link>
</li>
<li>
<Link
to="/services"
className="hover:text-ink hover:underline decoration-1 underline-offset-2"
>
System Audits
</Link>
</li>
<li>
<Link
to="/services"
className="hover:text-ink hover:underline decoration-1 underline-offset-2"
>
Custom Integration
</Link>
</li>
</ul>
</div>
<div>
<h3 className="font-sans font-bold text-xs uppercase tracking-wider mb-4">
Connect
</h3>
<ul className="space-y-2 text-sm text-subtle font-serif">
<li>
<a href="#" className="hover:text-ink">
GitHub
</a>
</li>
<li>
<Link to="/playground" className="hover:text-ink">
Playground
</Link>
</li>
<li>
<Link to="/hire-us" className="hover:text-ink">
Hire Us
</Link>
</li>
</ul>
</div>
</div>
</footer>
);
};
export default function App() {
const [language, setLanguage] = useState<Language>("en");
const toggleLanguage = () => {
setLanguage((prev) => (prev === "en" ? "th" : "en"));
};
return (
<LanguageContext.Provider value={{ language, toggleLanguage }}>
<HashRouter>
<div className="min-h-screen bg-paper flex flex-col relative">
<Navigation />
<main className="flex-grow">
<Routes>
<Route path="/" element={<Home />} />
<Route path="/research" element={<Research />} />
<Route
path="/research/lora-without-regret"
element={<BlogPost />}
/>
<Route path="/services" element={<Services />} />
<Route path="/playground" element={<Playground />} />
<Route path="/hire-us" element={<HireUs />} />
</Routes>
</main>
<Footer />
<ChatWidget />
</div>
</HashRouter>
</LanguageContext.Provider>
);
}