diff --git a/packages/website/public/robots.txt b/packages/website/public/robots.txt
new file mode 100644
index 0000000..fa1ce2b
--- /dev/null
+++ b/packages/website/public/robots.txt
@@ -0,0 +1,4 @@
+User-agent: *
+Allow: /
+
+Sitemap: https://alibaba.github.io/page-agent/sitemap.xml
diff --git a/packages/website/src/lib/useDocumentTitle.ts b/packages/website/src/lib/useDocumentTitle.ts
new file mode 100644
index 0000000..1e18324
--- /dev/null
+++ b/packages/website/src/lib/useDocumentTitle.ts
@@ -0,0 +1,9 @@
+import { useEffect } from 'react'
+
+const DEFAULT_TITLE = 'PageAgent - The GUI Agent Living in Your Webpage'
+
+export function useDocumentTitle(title?: string) {
+ useEffect(() => {
+ document.title = title ? `${title} - PageAgent` : DEFAULT_TITLE
+ }, [title])
+}
diff --git a/packages/website/src/pages/docs/Layout.tsx b/packages/website/src/pages/docs/Layout.tsx
index 0a4210f..e9abee8 100644
--- a/packages/website/src/pages/docs/Layout.tsx
+++ b/packages/website/src/pages/docs/Layout.tsx
@@ -4,6 +4,7 @@ import { Link, useLocation } from 'wouter'
import { SparklesText } from '@/components/ui/sparkles-text'
import { useLanguage } from '@/i18n/context'
+import { useDocumentTitle } from '@/lib/useDocumentTitle'
interface DocsLayoutProps {
children: ReactNode
@@ -65,6 +66,12 @@ export default function DocsLayout({ children }: DocsLayoutProps) {
},
]
+ const activeTitle = navigationSections
+ .flatMap((s) => s.items)
+ .find((item) => item.path === location)?.title
+
+ useDocumentTitle(activeTitle)
+
return (
diff --git a/packages/website/src/pages/home/index.tsx b/packages/website/src/pages/home/index.tsx
index c6589a7..9781e6b 100644
--- a/packages/website/src/pages/home/index.tsx
+++ b/packages/website/src/pages/home/index.tsx
@@ -1,5 +1,7 @@
import { Suspense, lazy } from 'react'
+import { useDocumentTitle } from '@/lib/useDocumentTitle'
+
import HeroSection from './HeroSection'
const FeaturesSection = lazy(() => import('./FeaturesSection'))
@@ -7,6 +9,8 @@ const ScenariosSection = lazy(() => import('./ScenariosSection'))
const OneMoreThingSection = lazy(() => import('./OneMoreThingSection'))
export default function HomePage() {
+ useDocumentTitle()
+
return (
<>
diff --git a/packages/website/vite.config.js b/packages/website/vite.config.js
index d200751..f5cdeec 100644
--- a/packages/website/vite.config.js
+++ b/packages/website/vite.config.js
@@ -1,7 +1,7 @@
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react-swc'
import { config as dotenvConfig } from 'dotenv'
-import { copyFileSync, mkdirSync, readFileSync } from 'node:fs'
+import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import process from 'node:process'
import { dirname, join, resolve } from 'path'
import { fileURLToPath } from 'url'
@@ -35,6 +35,8 @@ const SPA_ROUTES = [
'docs/advanced/security-permissions',
]
+const SITE_URL = 'https://alibaba.github.io/page-agent'
+
function spaRoutes() {
return {
name: 'spa-routes',
@@ -47,6 +49,19 @@ function spaRoutes() {
copyFileSync(src, join(dir, 'index.html'))
}
console.log(` ✓ Copied index.html to ${SPA_ROUTES.length} SPA routes`)
+
+ const today = new Date().toISOString().split('T')[0]
+ const urls = ['', ...SPA_ROUTES]
+ .map(
+ (route) =>
+ ` \n ${SITE_URL}/${route}\n ${today}\n `
+ )
+ .join('\n')
+ writeFileSync(
+ join(dist, 'sitemap.xml'),
+ `\n\n${urls}\n\n`
+ )
+ console.log(` ✓ Generated sitemap.xml with ${SPA_ROUTES.length + 1} URLs`)
},
}
}