# Website Restructure Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Restructure the single-page OCR app into a multi-section marketing website with dedicated workspace, docs, and blog pages. **Architecture:** SPA with react-router-dom layout routes. MarketingLayout (Navbar + Footer) wraps Home/Docs/Blog. AppLayout wraps the OCR workspace at `/app`. Markdown content compiled at build time via a Vite plugin. SEO handled by react-helmet-async + vite-plugin-prerender. **Tech Stack:** React 18, react-router-dom, Tailwind CSS, react-helmet-async, vite-plugin-prerender, remark/rehype (existing), gray-matter --- ## File Structure ``` src/ ├── components/ │ ├── home/ │ │ ├── HeroSection.tsx — Hero with OCR demo + CTA │ │ ├── FeaturesSection.tsx — Feature cards grid │ │ ├── HowItWorksSection.tsx — 3-step flow │ │ ├── PricingSection.tsx — Price cards │ │ └── ContactSection.tsx — Contact info + form │ ├── layout/ │ │ ├── MarketingNavbar.tsx — Full site nav │ │ ├── AppNavbar.tsx — Workspace nav (from Navbar.tsx) │ │ ├── Footer.tsx — Site footer │ │ ├── MarketingLayout.tsx — MarketingNavbar + Outlet + Footer │ │ └── AppLayout.tsx — AppNavbar + Outlet │ └── seo/ │ └── SEOHead.tsx — react-helmet-async wrapper ├── pages/ │ ├── HomePage.tsx │ ├── WorkspacePage.tsx — migrated from App.tsx │ ├── DocsListPage.tsx │ ├── DocDetailPage.tsx │ ├── BlogListPage.tsx │ └── BlogDetailPage.tsx ├── lib/ │ └── content.ts — Load markdown manifests ├── routes/ │ └── AppRouter.tsx — Updated with layout routes content/ ├── docs/ │ ├── en/getting-started.md │ └── zh/getting-started.md └── blog/ ├── en/2026-03-25-introducing-texpixel.md └── zh/2026-03-25-introducing-texpixel.md scripts/ └── build-content.ts — Compile markdown to JSON ``` --- ### Task 1: Install dependencies and setup **Files:** - Modify: `package.json` - [ ] **Step 1: Install react-helmet-async and gray-matter** ```bash npm install react-helmet-async gray-matter ``` - [ ] **Step 2: Wrap app with HelmetProvider** In `src/main.tsx`, add `HelmetProvider` wrapping: ```tsx import { HelmetProvider } from 'react-helmet-async'; // Wrap inside StrictMode: ``` - [ ] **Step 3: Commit** ```bash git add package.json package-lock.json src/main.tsx git commit -m "feat: install react-helmet-async and gray-matter, add HelmetProvider" ``` --- ### Task 2: Create SEOHead component **Files:** - Create: `src/components/seo/SEOHead.tsx` - [ ] **Step 1: Create SEOHead component** ```tsx import { Helmet } from 'react-helmet-async'; interface SEOHeadProps { title: string; description: string; path: string; type?: 'website' | 'article'; image?: string; publishedTime?: string; noindex?: boolean; } const BASE_URL = 'https://texpixel.com'; export default function SEOHead({ title, description, path, type = 'website', image = 'https://cdn.texpixel.com/public/og-cover.png', publishedTime, noindex = false, }: SEOHeadProps) { const url = `${BASE_URL}${path}`; const fullTitle = path === '/' ? title : `${title} | TexPixel`; return ( {fullTitle} {noindex && } {/* Open Graph */} {publishedTime && } {/* Twitter */} ); } ``` - [ ] **Step 2: Commit** ```bash git add src/components/seo/SEOHead.tsx git commit -m "feat: add SEOHead component with react-helmet-async" ``` --- ### Task 3: Create layout components **Files:** - Create: `src/components/layout/MarketingNavbar.tsx` - Create: `src/components/layout/AppNavbar.tsx` - Create: `src/components/layout/Footer.tsx` - Create: `src/components/layout/MarketingLayout.tsx` - Create: `src/components/layout/AppLayout.tsx` - [ ] **Step 1: Create MarketingNavbar** Full-width navbar with logo, nav links (Home, Docs, Blog), anchor links (Pricing, Contact on home page), language switcher, and CTA button to `/app`. Use `useLocation` to show anchor links only when on `/`. Responsive with mobile hamburger menu. ```tsx // src/components/layout/MarketingNavbar.tsx import { useState } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { Languages, ChevronDown, Check, Menu, X } from 'lucide-react'; import { useLanguage } from '../../contexts/LanguageContext'; export default function MarketingNavbar() { const { language, setLanguage, t } = useLanguage(); const location = useLocation(); const [showLangMenu, setShowLangMenu] = useState(false); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const isHome = location.pathname === '/'; const navLinks = [ { to: '/', label: t.marketing?.nav?.home ?? 'Home' }, { to: '/docs', label: t.marketing?.nav?.docs ?? 'Docs' }, { to: '/blog', label: t.marketing?.nav?.blog ?? 'Blog' }, ]; const anchorLinks = isHome ? [ { href: '#pricing', label: t.marketing?.nav?.pricing ?? 'Pricing' }, { href: '#contact', label: t.marketing?.nav?.contact ?? 'Contact' }, ] : []; return ( ); } ``` - [ ] **Step 2: Create AppNavbar** Simplified version of current `Navbar.tsx` for the workspace. Keep language switcher, reward, contact, guide, help — remove marketing nav links. Add a "Back to Home" link. Copy current `src/components/Navbar.tsx` content into `src/components/layout/AppNavbar.tsx`. Add a `Link` to `/` (home icon or "TexPixel" logo links to `/`). Keep all existing functionality (reward modal, contact dropdown, language switcher, guide button). - [ ] **Step 3: Create Footer** ```tsx // src/components/layout/Footer.tsx import { Link } from 'react-router-dom'; import { useLanguage } from '../../contexts/LanguageContext'; export default function Footer() { const { t } = useLanguage(); return ( ); } ``` - [ ] **Step 4: Create MarketingLayout and AppLayout** ```tsx // src/components/layout/MarketingLayout.tsx import { Outlet } from 'react-router-dom'; import MarketingNavbar from './MarketingNavbar'; import Footer from './Footer'; export default function MarketingLayout() { return (
); } ``` ```tsx // src/components/layout/AppLayout.tsx import { Outlet } from 'react-router-dom'; import AppNavbar from './AppNavbar'; export default function AppLayout() { return (
); } ``` - [ ] **Step 5: Commit** ```bash git add src/components/layout/ git commit -m "feat: add layout components (MarketingNavbar, AppNavbar, Footer, layouts)" ``` --- ### Task 4: Add marketing translations **Files:** - Modify: `src/lib/translations.ts` - [ ] **Step 1: Add marketing section to translations** Add `marketing` key to both `en` and `zh` objects in `translations.ts`: ```typescript marketing: { nav: { home: 'Home', // zh: '首页' docs: 'Docs', // zh: '文档' blog: 'Blog', // zh: '博客' pricing: 'Pricing', // zh: '价格' contact: 'Contact', // zh: '联系我们' launchApp: 'Launch App', // zh: '启动应用' }, hero: { title: 'Convert Math Formulas to LaTeX in Seconds', // zh: '数学公式秒级转换为 LaTeX' subtitle: 'AI-powered OCR for handwritten and printed mathematical formulas. Get LaTeX, MathML, and Markdown output instantly.', // zh: 'AI 驱动的手写和印刷体数学公式识别,即时输出 LaTeX、MathML 和 Markdown。' cta: 'Try It Free', // zh: '免费试用' ctaSecondary: 'Learn More', // zh: '了解更多' }, features: { title: 'Features', // zh: '功能特性' subtitle: 'Everything you need for formula recognition', // zh: '公式识别所需的一切' items: [ { title: 'Handwriting Recognition', description: 'Accurately recognize handwritten math formulas from photos or scans' }, { title: 'Multi-Format Output', description: 'Export to LaTeX, MathML, Markdown, Word, and more' }, { title: 'PDF Support', description: 'Upload PDF documents and extract formulas automatically' }, { title: 'Batch Processing', description: 'Process multiple files at once for maximum efficiency' }, { title: 'High Accuracy', description: 'Powered by advanced AI models for industry-leading accuracy' }, { title: 'Free to Start', description: 'Get started with free uploads, no credit card required' }, ], // zh versions of items array }, howItWorks: { title: 'How It Works', // zh: '使用流程' steps: [ { title: 'Upload', description: 'Upload an image or PDF containing math formulas' }, { title: 'Recognize', description: 'Our AI analyzes and recognizes the formulas' }, { title: 'Export', description: 'Copy or export results in your preferred format' }, ], }, pricing: { title: 'Pricing', // zh: '价格方案' subtitle: 'Choose the plan that fits your needs', // zh: '选择适合您的方案' plans: [ { name: 'Free', price: '$0', period: '/month', features: ['3 uploads/day', 'LaTeX & Markdown output', 'Community support'], cta: 'Get Started' }, { name: 'Pro', price: '$9.9', period: '/month', features: ['Unlimited uploads', 'All export formats', 'Priority processing', 'API access'], cta: 'Coming Soon', popular: true }, { name: 'Enterprise', price: 'Custom', period: '', features: ['Custom volume', 'Dedicated support', 'SLA guarantee', 'On-premise option'], cta: 'Contact Us' }, ], }, contact: { title: 'Contact Us', // zh: '联系我们' subtitle: 'Get in touch with our team', // zh: '与我们的团队取得联系' nameLabel: 'Name', // zh: '姓名' emailLabel: 'Email', // zh: '邮箱' messageLabel: 'Message', // zh: '留言' send: 'Send Message', // zh: '发送消息' sending: 'Sending...', // zh: '发送中...' sent: 'Message sent!', // zh: '消息已发送!' qqGroup: 'QQ Group', // zh: 'QQ 群' }, footer: { tagline: 'AI-powered math formula recognition', // zh: 'AI 驱动的数学公式识别' product: 'Product', // zh: '产品' resources: 'Resources', // zh: '资源' contactTitle: 'Contact', // zh: '联系方式' }, }, ``` - [ ] **Step 2: Commit** ```bash git add src/lib/translations.ts git commit -m "feat: add marketing translations for en and zh" ``` --- ### Task 5: Create Home page sections **Files:** - Create: `src/components/home/HeroSection.tsx` - Create: `src/components/home/FeaturesSection.tsx` - Create: `src/components/home/HowItWorksSection.tsx` - Create: `src/components/home/PricingSection.tsx` - Create: `src/components/home/ContactSection.tsx` - Create: `src/pages/HomePage.tsx` - [ ] **Step 1: Create HeroSection** Hero with product tagline, a mini drag-and-drop demo area (visual only, clicking it navigates to `/app`), and CTA buttons. Use Tailwind for gradient backgrounds and animations. Key elements: - Large heading from `t.marketing.hero.title` - Subtitle from `t.marketing.hero.subtitle` - Primary CTA button → links to `/app` - Secondary CTA button → scrolls to `#features` - A decorative mock preview showing a formula being converted (static image or CSS illustration) - [ ] **Step 2: Create FeaturesSection** 6-card grid from `t.marketing.features.items`. Each card has an icon (from lucide-react), title, and description. Use icons: `PenTool`, `FileOutput`, `FileText`, `Layers`, `Zap`, `Gift`. - [ ] **Step 3: Create HowItWorksSection** 3-step horizontal flow with numbered circles, title, description. Steps from `t.marketing.howItWorks.steps`. Use icons: `Upload`, `Cpu`, `Download`. - [ ] **Step 4: Create PricingSection** 3-column card layout from `t.marketing.pricing.plans`. Middle card (Pro) has `popular: true` → highlighted border/badge. CTA buttons: Free → link to `/app`, Pro → disabled "Coming Soon", Enterprise → link to `#contact`. Section has `id="pricing"` for anchor navigation. - [ ] **Step 5: Create ContactSection** Two-column layout. Left: contact info (email, QQ group). Right: form with name, email, message fields + submit button. Form initially just shows a success toast on submit (no backend). `id="contact"` for anchor nav. - [ ] **Step 6: Create HomePage** ```tsx // src/pages/HomePage.tsx import SEOHead from '../components/seo/SEOHead'; import HeroSection from '../components/home/HeroSection'; import FeaturesSection from '../components/home/FeaturesSection'; import HowItWorksSection from '../components/home/HowItWorksSection'; import PricingSection from '../components/home/PricingSection'; import ContactSection from '../components/home/ContactSection'; import { useLanguage } from '../contexts/LanguageContext'; export default function HomePage() { const { t } = useLanguage(); return ( <> ); } ``` - [ ] **Step 7: Commit** ```bash git add src/components/home/ src/pages/HomePage.tsx git commit -m "feat: add Home page with Hero, Features, HowItWorks, Pricing, Contact sections" ``` --- ### Task 6: Migrate App.tsx to WorkspacePage **Files:** - Create: `src/pages/WorkspacePage.tsx` - Modify: `src/App.tsx` (will become thin redirect or removed) - [ ] **Step 1: Create WorkspacePage** Move all logic from `App.tsx` into `WorkspacePage.tsx`. Remove the outer `
` and `` wrappers since `AppLayout` provides those. Keep the inner flex container with LeftSidebar, FilePreview, ResultPanel, modals, and loading overlay. The component should render: ```tsx <> {/* Left Sidebar */}
{/* Resize Handle */}
{/* Middle: FilePreview */}
{/* Right: ResultPanel */}
{/* Modals */} {showUploadModal && } {showAuthModal && } {loading &&
...
} ``` Note: `AppLayout` already provides `
` and `` and `
`, so WorkspacePage renders directly inside that flex container. - [ ] **Step 2: Update App.tsx** Replace `App.tsx` with a simple redirect to maintain backward compatibility if anything imports it: ```tsx import { Navigate } from 'react-router-dom'; export default function App() { return ; } ``` - [ ] **Step 3: Verify build** ```bash npm run typecheck ``` - [ ] **Step 4: Commit** ```bash git add src/pages/WorkspacePage.tsx src/App.tsx git commit -m "feat: migrate App.tsx logic to WorkspacePage" ``` --- ### Task 7: Update AppRouter with layout routes **Files:** - Modify: `src/routes/AppRouter.tsx` - [ ] **Step 1: Update AppRouter** ```tsx import { lazy, Suspense } from 'react'; import { Routes, Route } from 'react-router-dom'; import MarketingLayout from '../components/layout/MarketingLayout'; import AppLayout from '../components/layout/AppLayout'; import AuthCallbackPage from '../pages/AuthCallbackPage'; const HomePage = lazy(() => import('../pages/HomePage')); const WorkspacePage = lazy(() => import('../pages/WorkspacePage')); const DocsListPage = lazy(() => import('../pages/DocsListPage')); const DocDetailPage = lazy(() => import('../pages/DocDetailPage')); const BlogListPage = lazy(() => import('../pages/BlogListPage')); const BlogDetailPage = lazy(() => import('../pages/BlogDetailPage')); function LoadingFallback() { return (
); } export default function AppRouter() { return ( }> }> } /> } /> } /> } /> } /> }> } /> } /> ); } ``` - [ ] **Step 2: Commit** ```bash git add src/routes/AppRouter.tsx git commit -m "feat: update AppRouter with layout routes and lazy loading" ``` --- ### Task 8: Create placeholder Docs and Blog pages **Files:** - Create: `src/pages/DocsListPage.tsx` - Create: `src/pages/DocDetailPage.tsx` - Create: `src/pages/BlogListPage.tsx` - Create: `src/pages/BlogDetailPage.tsx` - [ ] **Step 1: Create DocsListPage** List page showing available docs. For now, hardcode a few placeholder entries. Each entry links to `/docs/:slug`. Include SEOHead. ```tsx import { Link } from 'react-router-dom'; import SEOHead from '../components/seo/SEOHead'; import { useLanguage } from '../contexts/LanguageContext'; const docs = [ { slug: 'getting-started', title: 'Getting Started', titleZh: '快速开始', description: 'Learn how to use TexPixel', descriptionZh: '了解如何使用 TexPixel' }, ]; export default function DocsListPage() { const { language } = useLanguage(); return ( <>

{language === 'en' ? 'Documentation' : '文档'}

{docs.map((doc) => (

{language === 'en' ? doc.title : doc.titleZh}

{language === 'en' ? doc.description : doc.descriptionZh}

))}
); } ``` - [ ] **Step 2: Create DocDetailPage** Placeholder that reads `:slug` from params and shows a coming-soon message. ```tsx import { useParams } from 'react-router-dom'; import SEOHead from '../components/seo/SEOHead'; export default function DocDetailPage() { const { slug } = useParams<{ slug: string }>(); return ( <>

{slug}

Content coming soon.

); } ``` - [ ] **Step 3: Create BlogListPage and BlogDetailPage** Same pattern as docs. BlogListPage shows placeholder blog entries with date and title. BlogDetailPage reads `:slug` param. - [ ] **Step 4: Commit** ```bash git add src/pages/DocsListPage.tsx src/pages/DocDetailPage.tsx src/pages/BlogListPage.tsx src/pages/BlogDetailPage.tsx git commit -m "feat: add placeholder Docs and Blog pages" ``` --- ### Task 9: Build content pipeline (Markdown → JSON) **Files:** - Create: `content/docs/en/getting-started.md` - Create: `content/docs/zh/getting-started.md` - Create: `content/blog/en/2026-03-25-introducing-texpixel.md` - Create: `content/blog/zh/2026-03-25-introducing-texpixel.md` - Create: `scripts/build-content.ts` - Create: `src/lib/content.ts` - Modify: `package.json` (add build:content script) - [ ] **Step 1: Create sample markdown files** Each file has frontmatter (title, description, slug, date, tags, order) and body content. - [ ] **Step 2: Create build-content script** Node script that: 1. Scans `content/docs/{en,zh}/` and `content/blog/{en,zh}/` 2. Parses frontmatter with `gray-matter` 3. Compiles markdown body with `remark` + `rehype` → HTML string 4. Outputs `public/content/docs-manifest.json` and `public/content/blog-manifest.json` 5. Outputs individual `public/content/docs/{lang}/{slug}.json` and `public/content/blog/{lang}/{slug}.json` Manifest format: ```json { "en": [{ "slug": "getting-started", "title": "...", "description": "...", "date": "...", "tags": [], "order": 1 }], "zh": [...] } ``` Individual file format: ```json { "meta": { ... frontmatter ... }, "html": "

compiled html

" } ``` - [ ] **Step 3: Create content loader utility** ```tsx // src/lib/content.ts import type { Language } from './translations'; export interface ContentMeta { slug: string; title: string; description: string; date: string; tags: string[]; order?: number; cover?: string; } export interface ContentManifest { en: ContentMeta[]; zh: ContentMeta[]; } export interface ContentItem { meta: ContentMeta; html: string; } const BASE = '/content'; export async function loadManifest(type: 'docs' | 'blog'): Promise { const res = await fetch(`${BASE}/${type}-manifest.json`); return res.json(); } export async function loadContent(type: 'docs' | 'blog', lang: Language, slug: string): Promise { const res = await fetch(`${BASE}/${type}/${lang}/${slug}.json`); return res.json(); } ``` - [ ] **Step 4: Add npm script** In `package.json`, add: ```json "build:content": "npx tsx scripts/build-content.ts", "build": "npm run build:content && vite build" ``` - [ ] **Step 5: Commit** ```bash git add content/ scripts/build-content.ts src/lib/content.ts package.json git commit -m "feat: add markdown content pipeline with build script" ``` --- ### Task 10: Wire Docs/Blog pages to content pipeline **Files:** - Modify: `src/pages/DocsListPage.tsx` - Modify: `src/pages/DocDetailPage.tsx` - Modify: `src/pages/BlogListPage.tsx` - Modify: `src/pages/BlogDetailPage.tsx` - [ ] **Step 1: Update DocsListPage to load from manifest** Use `useEffect` + `loadManifest('docs')` to fetch doc list. Render based on current language. - [ ] **Step 2: Update DocDetailPage to load content** Use `useEffect` + `loadContent('docs', language, slug)` to fetch and render HTML. Use `dangerouslySetInnerHTML` for the compiled HTML (safe since we control the source markdown). Apply Tailwind typography classes (`prose`). - [ ] **Step 3: Update Blog pages similarly** Same pattern. BlogListPage shows date + cover image. BlogDetailPage renders article with `type="article"` in SEOHead. - [ ] **Step 4: Run build:content and test** ```bash npm run build:content && npm run dev ``` Visit `/docs`, `/docs/getting-started`, `/blog`, `/blog/introducing-texpixel`. - [ ] **Step 5: Commit** ```bash git add src/pages/ git commit -m "feat: wire Docs and Blog pages to markdown content pipeline" ``` --- ### Task 11: Update sitemap and SEO infrastructure **Files:** - Modify: `public/sitemap.xml` - Modify: `public/robots.txt` - Modify: `index.html` - [ ] **Step 1: Update sitemap.xml** Add all new routes: `/`, `/app`, `/docs`, `/docs/getting-started`, `/blog`, `/blog/introducing-texpixel`. Set appropriate `changefreq` and `priority`. - [ ] **Step 2: Update robots.txt** Add `Disallow: /app` to prevent indexing of the workspace. - [ ] **Step 3: Clean up index.html** Since SEOHead now manages per-page meta tags via react-helmet-async, simplify `index.html` to only keep the base defaults. Remove the inline language detection script (LanguageContext handles this). - [ ] **Step 4: Commit** ```bash git add public/sitemap.xml public/robots.txt index.html git commit -m "feat: update sitemap, robots.txt, and index.html for new routes" ``` --- ### Task 12: Final verification - [ ] **Step 1: Type check** ```bash npm run typecheck ``` - [ ] **Step 2: Lint** ```bash npm run lint ``` - [ ] **Step 3: Build** ```bash npm run build ``` - [ ] **Step 4: Test all routes in dev** ```bash npm run dev ``` Visit: `/`, `/app`, `/docs`, `/docs/getting-started`, `/blog`, `/blog/introducing-texpixel` Verify: - Home page shows all sections, anchor links work - `/app` workspace functions as before - Docs/Blog pages load content - Language switching works across all pages - Mobile responsive nav works - [ ] **Step 5: Commit any fixes and final commit** ```bash git add -A git commit -m "feat: complete website restructure with marketing pages, docs, and blog" ```