diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json
index 39bd8f56d..2b4d9ebf5 100644
--- a/public/locales/en/translation.json
+++ b/public/locales/en/translation.json
@@ -4,7 +4,9 @@
"more": "More",
"editThisPage": "Edit this page",
"joinOurCommunity": "Join our community",
- "feedback": "Feedback"
+ "feedback": "Feedback",
+ "askAI": "Ask AI",
+ "copyPage": "Copy page"
},
"ui": {
"whatsNext": "What's Next",
diff --git a/src/components/PageContent/AskAI.astro b/src/components/PageContent/AskAI.astro
new file mode 100644
index 000000000..561e2b8d2
--- /dev/null
+++ b/src/components/PageContent/AskAI.astro
@@ -0,0 +1,306 @@
+---
+const currentUrl = Astro.url.href
+const markdownUrl = currentUrl.endsWith("/") ? `${currentUrl.slice(0, -1)}.md` : `${currentUrl}.md`
+
+const aiServices = [
+ {
+ name: "ChatGPT",
+ url: `https://chatgpt.com/?hints=search&prompt=${encodeURIComponent(
+ `Help me understand this documentation page: ${markdownUrl}`
+ )}`,
+ icon: "chatgpt",
+ },
+ {
+ name: "Claude",
+ url: `https://claude.ai/new?q=${encodeURIComponent(`Help me understand this documentation page: ${markdownUrl}`)}`,
+ icon: "claude",
+ },
+ {
+ name: "Perplexity",
+ url: `https://www.perplexity.ai/search?q=${encodeURIComponent(
+ `Help me understand this documentation page: ${markdownUrl}`
+ )}`,
+ icon: "perplexity",
+ },
+ {
+ name: "Gemini",
+ url: `https://gemini.google.com/app?prompt=${encodeURIComponent(
+ `Help me understand this documentation page: ${markdownUrl}`
+ )}`,
+ icon: "gemini",
+ },
+]
+---
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/PageContent/PageContent.astro b/src/components/PageContent/PageContent.astro
index 5b27e1637..bb1bdb58b 100644
--- a/src/components/PageContent/PageContent.astro
+++ b/src/components/PageContent/PageContent.astro
@@ -2,14 +2,19 @@
import MoreMenu from "../RightSidebar/MoreMenu.astro"
import TableOfContents from "../RightSidebar/TableOfContents"
import WhatsNext from "./WhatsNext.astro"
+import AskAI from "./AskAI.astro"
const { content, githubEditUrl, headings } = Astro.props
const title = content.title
const whatsNext = content.whatsnext
+const isEnglish = content.lang === "en"
---
- {title}
+
+
{title}
+ {isEnglish &&
}
+
@@ -33,6 +38,13 @@ const whatsNext = content.whatsnext
flex-direction: column;
}
+ .title-row {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 8px;
+ }
+
.block {
display: block;
}
diff --git a/src/pages/[lang]/[...slug].md.ts b/src/pages/[lang]/[...slug].md.ts
new file mode 100644
index 000000000..2a7dee138
--- /dev/null
+++ b/src/pages/[lang]/[...slug].md.ts
@@ -0,0 +1,83 @@
+import type { APIRoute, GetStaticPaths } from "astro"
+import { getCollection } from "astro:content"
+import i18next from "i18next"
+import fs from "node:fs"
+import path from "node:path"
+
+export const getStaticPaths: GetStaticPaths = async () => {
+ const pages = await getCollection("docs")
+ const languages = i18next.languages
+
+ const allSlugs = new Set(
+ pages.map((page) => {
+ const [, ...slug] = page.slug.split("/")
+ return slug.join("/")
+ })
+ )
+
+ const allPaths = []
+ for (const slug of allSlugs) {
+ for (const lang of languages) {
+ allPaths.push({ params: { lang, slug: slug || undefined } })
+ }
+ }
+
+ const paths = allPaths.map((pathItem) => {
+ let page = pages.find((page) => {
+ const [pageLang, ...pageSlug] = page.slug.split("/")
+ return pageLang === pathItem.params.lang && pageSlug.join("/") === pathItem.params.slug
+ })
+ if (!page) {
+ // Fallback to English if translation doesn't exist
+ page = pages.find((page) => {
+ const [pageLang, ...pageSlug] = page.slug.split("/")
+ return pageLang === "en" && pageSlug.join("/") === pathItem.params.slug
+ })
+ }
+ return { params: pathItem.params, props: { page } }
+ })
+
+ return paths
+}
+
+export const GET: APIRoute = async ({ props }) => {
+ const { page } = props
+
+ if (!page) {
+ return new Response("Not found", { status: 404 })
+ }
+
+ try {
+ // Construct the file path
+ const contentDir = path.join(process.cwd(), "src/content/docs")
+
+ // Try .mdx first, then .md, then index.mdx/index.md inside folder
+ let filePath = path.join(contentDir, `${page.slug}.mdx`)
+ if (!fs.existsSync(filePath)) {
+ filePath = path.join(contentDir, `${page.slug}.md`)
+ }
+ if (!fs.existsSync(filePath)) {
+ filePath = path.join(contentDir, page.slug, "index.mdx")
+ }
+ if (!fs.existsSync(filePath)) {
+ filePath = path.join(contentDir, page.slug, "index.md")
+ }
+
+ if (!fs.existsSync(filePath)) {
+ return new Response("File not found", { status: 404 })
+ }
+
+ const content = fs.readFileSync(filePath, "utf-8")
+
+ return new Response(content, {
+ status: 200,
+ headers: {
+ "Content-Type": "text/markdown; charset=utf-8",
+ "Cache-Control": "public, max-age=3600",
+ },
+ })
+ } catch (error) {
+ console.error("Error reading markdown file:", error)
+ return new Response("Internal server error", { status: 500 })
+ }
+}