feat(website): add SEO landing pages for Claude Code, Codex, and OpenCode
Extract homepage into reusable LandingPage component with configurable hero. Add /claude-code, /codex, and /opencode routes targeting agent-specific mobile app search terms. Replace single-link footer with four-column layout (Product, Agents, Community, Download).
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,10 @@
|
|||||||
|
|
||||||
import { Route as rootRouteImport } from './routes/__root'
|
import { Route as rootRouteImport } from './routes/__root'
|
||||||
import { Route as PrivacyRouteImport } from './routes/privacy'
|
import { Route as PrivacyRouteImport } from './routes/privacy'
|
||||||
|
import { Route as OpencodeRouteImport } from './routes/opencode'
|
||||||
import { Route as DocsRouteImport } from './routes/docs'
|
import { Route as DocsRouteImport } from './routes/docs'
|
||||||
|
import { Route as CodexRouteImport } from './routes/codex'
|
||||||
|
import { Route as ClaudeCodeRouteImport } from './routes/claude-code'
|
||||||
import { Route as ChangelogRouteImport } from './routes/changelog'
|
import { Route as ChangelogRouteImport } from './routes/changelog'
|
||||||
import { Route as IndexRouteImport } from './routes/index'
|
import { Route as IndexRouteImport } from './routes/index'
|
||||||
import { Route as DocsIndexRouteImport } from './routes/docs/index'
|
import { Route as DocsIndexRouteImport } from './routes/docs/index'
|
||||||
@@ -27,11 +30,26 @@ const PrivacyRoute = PrivacyRouteImport.update({
|
|||||||
path: '/privacy',
|
path: '/privacy',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const OpencodeRoute = OpencodeRouteImport.update({
|
||||||
|
id: '/opencode',
|
||||||
|
path: '/opencode',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const DocsRoute = DocsRouteImport.update({
|
const DocsRoute = DocsRouteImport.update({
|
||||||
id: '/docs',
|
id: '/docs',
|
||||||
path: '/docs',
|
path: '/docs',
|
||||||
getParentRoute: () => rootRouteImport,
|
getParentRoute: () => rootRouteImport,
|
||||||
} as any)
|
} as any)
|
||||||
|
const CodexRoute = CodexRouteImport.update({
|
||||||
|
id: '/codex',
|
||||||
|
path: '/codex',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
|
const ClaudeCodeRoute = ClaudeCodeRouteImport.update({
|
||||||
|
id: '/claude-code',
|
||||||
|
path: '/claude-code',
|
||||||
|
getParentRoute: () => rootRouteImport,
|
||||||
|
} as any)
|
||||||
const ChangelogRoute = ChangelogRouteImport.update({
|
const ChangelogRoute = ChangelogRouteImport.update({
|
||||||
id: '/changelog',
|
id: '/changelog',
|
||||||
path: '/changelog',
|
path: '/changelog',
|
||||||
@@ -86,7 +104,10 @@ const DocsBestPracticesRoute = DocsBestPracticesRouteImport.update({
|
|||||||
export interface FileRoutesByFullPath {
|
export interface FileRoutesByFullPath {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/changelog': typeof ChangelogRoute
|
'/changelog': typeof ChangelogRoute
|
||||||
|
'/claude-code': typeof ClaudeCodeRoute
|
||||||
|
'/codex': typeof CodexRoute
|
||||||
'/docs': typeof DocsRouteWithChildren
|
'/docs': typeof DocsRouteWithChildren
|
||||||
|
'/opencode': typeof OpencodeRoute
|
||||||
'/privacy': typeof PrivacyRoute
|
'/privacy': typeof PrivacyRoute
|
||||||
'/docs/best-practices': typeof DocsBestPracticesRoute
|
'/docs/best-practices': typeof DocsBestPracticesRoute
|
||||||
'/docs/cli': typeof DocsCliRoute
|
'/docs/cli': typeof DocsCliRoute
|
||||||
@@ -100,6 +121,9 @@ export interface FileRoutesByFullPath {
|
|||||||
export interface FileRoutesByTo {
|
export interface FileRoutesByTo {
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/changelog': typeof ChangelogRoute
|
'/changelog': typeof ChangelogRoute
|
||||||
|
'/claude-code': typeof ClaudeCodeRoute
|
||||||
|
'/codex': typeof CodexRoute
|
||||||
|
'/opencode': typeof OpencodeRoute
|
||||||
'/privacy': typeof PrivacyRoute
|
'/privacy': typeof PrivacyRoute
|
||||||
'/docs/best-practices': typeof DocsBestPracticesRoute
|
'/docs/best-practices': typeof DocsBestPracticesRoute
|
||||||
'/docs/cli': typeof DocsCliRoute
|
'/docs/cli': typeof DocsCliRoute
|
||||||
@@ -114,7 +138,10 @@ export interface FileRoutesById {
|
|||||||
__root__: typeof rootRouteImport
|
__root__: typeof rootRouteImport
|
||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/changelog': typeof ChangelogRoute
|
'/changelog': typeof ChangelogRoute
|
||||||
|
'/claude-code': typeof ClaudeCodeRoute
|
||||||
|
'/codex': typeof CodexRoute
|
||||||
'/docs': typeof DocsRouteWithChildren
|
'/docs': typeof DocsRouteWithChildren
|
||||||
|
'/opencode': typeof OpencodeRoute
|
||||||
'/privacy': typeof PrivacyRoute
|
'/privacy': typeof PrivacyRoute
|
||||||
'/docs/best-practices': typeof DocsBestPracticesRoute
|
'/docs/best-practices': typeof DocsBestPracticesRoute
|
||||||
'/docs/cli': typeof DocsCliRoute
|
'/docs/cli': typeof DocsCliRoute
|
||||||
@@ -130,7 +157,10 @@ export interface FileRouteTypes {
|
|||||||
fullPaths:
|
fullPaths:
|
||||||
| '/'
|
| '/'
|
||||||
| '/changelog'
|
| '/changelog'
|
||||||
|
| '/claude-code'
|
||||||
|
| '/codex'
|
||||||
| '/docs'
|
| '/docs'
|
||||||
|
| '/opencode'
|
||||||
| '/privacy'
|
| '/privacy'
|
||||||
| '/docs/best-practices'
|
| '/docs/best-practices'
|
||||||
| '/docs/cli'
|
| '/docs/cli'
|
||||||
@@ -144,6 +174,9 @@ export interface FileRouteTypes {
|
|||||||
to:
|
to:
|
||||||
| '/'
|
| '/'
|
||||||
| '/changelog'
|
| '/changelog'
|
||||||
|
| '/claude-code'
|
||||||
|
| '/codex'
|
||||||
|
| '/opencode'
|
||||||
| '/privacy'
|
| '/privacy'
|
||||||
| '/docs/best-practices'
|
| '/docs/best-practices'
|
||||||
| '/docs/cli'
|
| '/docs/cli'
|
||||||
@@ -157,7 +190,10 @@ export interface FileRouteTypes {
|
|||||||
| '__root__'
|
| '__root__'
|
||||||
| '/'
|
| '/'
|
||||||
| '/changelog'
|
| '/changelog'
|
||||||
|
| '/claude-code'
|
||||||
|
| '/codex'
|
||||||
| '/docs'
|
| '/docs'
|
||||||
|
| '/opencode'
|
||||||
| '/privacy'
|
| '/privacy'
|
||||||
| '/docs/best-practices'
|
| '/docs/best-practices'
|
||||||
| '/docs/cli'
|
| '/docs/cli'
|
||||||
@@ -172,7 +208,10 @@ export interface FileRouteTypes {
|
|||||||
export interface RootRouteChildren {
|
export interface RootRouteChildren {
|
||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
ChangelogRoute: typeof ChangelogRoute
|
ChangelogRoute: typeof ChangelogRoute
|
||||||
|
ClaudeCodeRoute: typeof ClaudeCodeRoute
|
||||||
|
CodexRoute: typeof CodexRoute
|
||||||
DocsRoute: typeof DocsRouteWithChildren
|
DocsRoute: typeof DocsRouteWithChildren
|
||||||
|
OpencodeRoute: typeof OpencodeRoute
|
||||||
PrivacyRoute: typeof PrivacyRoute
|
PrivacyRoute: typeof PrivacyRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +224,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof PrivacyRouteImport
|
preLoaderRoute: typeof PrivacyRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/opencode': {
|
||||||
|
id: '/opencode'
|
||||||
|
path: '/opencode'
|
||||||
|
fullPath: '/opencode'
|
||||||
|
preLoaderRoute: typeof OpencodeRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/docs': {
|
'/docs': {
|
||||||
id: '/docs'
|
id: '/docs'
|
||||||
path: '/docs'
|
path: '/docs'
|
||||||
@@ -192,6 +238,20 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof DocsRouteImport
|
preLoaderRoute: typeof DocsRouteImport
|
||||||
parentRoute: typeof rootRouteImport
|
parentRoute: typeof rootRouteImport
|
||||||
}
|
}
|
||||||
|
'/codex': {
|
||||||
|
id: '/codex'
|
||||||
|
path: '/codex'
|
||||||
|
fullPath: '/codex'
|
||||||
|
preLoaderRoute: typeof CodexRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
|
'/claude-code': {
|
||||||
|
id: '/claude-code'
|
||||||
|
path: '/claude-code'
|
||||||
|
fullPath: '/claude-code'
|
||||||
|
preLoaderRoute: typeof ClaudeCodeRouteImport
|
||||||
|
parentRoute: typeof rootRouteImport
|
||||||
|
}
|
||||||
'/changelog': {
|
'/changelog': {
|
||||||
id: '/changelog'
|
id: '/changelog'
|
||||||
path: '/changelog'
|
path: '/changelog'
|
||||||
@@ -292,7 +352,10 @@ const DocsRouteWithChildren = DocsRoute._addFileChildren(DocsRouteChildren)
|
|||||||
const rootRouteChildren: RootRouteChildren = {
|
const rootRouteChildren: RootRouteChildren = {
|
||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
ChangelogRoute: ChangelogRoute,
|
ChangelogRoute: ChangelogRoute,
|
||||||
|
ClaudeCodeRoute: ClaudeCodeRoute,
|
||||||
|
CodexRoute: CodexRoute,
|
||||||
DocsRoute: DocsRouteWithChildren,
|
DocsRoute: DocsRouteWithChildren,
|
||||||
|
OpencodeRoute: OpencodeRoute,
|
||||||
PrivacyRoute: PrivacyRoute,
|
PrivacyRoute: PrivacyRoute,
|
||||||
}
|
}
|
||||||
export const routeTree = rootRouteImport
|
export const routeTree = rootRouteImport
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
import { LandingPage } from '~/components/landing-page'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/claude-code')({
|
||||||
|
head: () => ({
|
||||||
|
meta: [
|
||||||
|
{ title: 'Claude Code Mobile App – Ship from your phone | Paseo' },
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
content:
|
||||||
|
'Run Claude Code from your phone. Launch agents, check on progress, review diffs, and merge — all from your pocket. Self-hosted, your code stays on your machine.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
component: ClaudeCodePage,
|
||||||
|
})
|
||||||
|
|
||||||
|
function ClaudeCodePage() {
|
||||||
|
return (
|
||||||
|
<LandingPage
|
||||||
|
title="Ship with Claude Code from your phone"
|
||||||
|
subtitle="Launch agents, check on progress, and merge from anywhere. Your Claude Code setup, your machine, your pocket."
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
import { LandingPage } from '~/components/landing-page'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/codex')({
|
||||||
|
head: () => ({
|
||||||
|
meta: [
|
||||||
|
{ title: 'Codex Mobile App – Run Codex from anywhere | Paseo' },
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
content:
|
||||||
|
'Run OpenAI Codex from your phone. Kick off agents, monitor progress, and ship code without being at your desk. Self-hosted, your code never leaves your machine.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
component: CodexPage,
|
||||||
|
})
|
||||||
|
|
||||||
|
function CodexPage() {
|
||||||
|
return (
|
||||||
|
<LandingPage
|
||||||
|
title="Run Codex from anywhere"
|
||||||
|
subtitle="Kick off Codex agents on your machine from your phone. Check in on the train, review on the couch, merge from the park."
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
import { LandingPage } from '~/components/landing-page'
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/opencode')({
|
||||||
|
head: () => ({
|
||||||
|
meta: [
|
||||||
|
{ title: 'OpenCode Mobile App – Code from anywhere | Paseo' },
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
content:
|
||||||
|
'Run OpenCode from your phone. Launch agents, watch them work, and ship code from wherever you are. Self-hosted, open source, your code stays local.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
component: OpenCodePage,
|
||||||
|
})
|
||||||
|
|
||||||
|
function OpenCodePage() {
|
||||||
|
return (
|
||||||
|
<LandingPage
|
||||||
|
title="Run OpenCode from your phone"
|
||||||
|
subtitle="Launch agents, check on builds, and ship code from anywhere. Same setup, same machine, just not at your desk."
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user