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 }) + } +}