Skip to content

feat: add raw markdown endpoint and Copy as Markdown button#9

Open
RanaMoizHaider wants to merge 2 commits intovitodeploy:mainfrom
RanaMoizHaider:main
Open

feat: add raw markdown endpoint and Copy as Markdown button#9
RanaMoizHaider wants to merge 2 commits intovitodeploy:mainfrom
RanaMoizHaider:main

Conversation

@RanaMoizHaider
Copy link

No description provided.

Copilot AI review requested due to automatic review settings March 12, 2026 09:37
@netlify
Copy link

netlify bot commented Mar 12, 2026

Deploy Preview for vitodeploy ready!

Name Link
🔨 Latest commit fba77b6
🔍 Latest deploy log https://app.netlify.com/projects/vitodeploy/deploys/69b2894d45cf540008f715d7
😎 Deploy Preview https://deploy-preview-9--vitodeploy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for accessing docs as raw Markdown (.md) and introduces a “Copy as Markdown” control in the docs UI, with a build step to emit .md files into the static export output.

Changes:

  • Add a build-time script to copy docs from content/docs/** into out/docs/** as .md (frontmatter removed).
  • Add a dev-only raw docs route and a rewrite so /docs/...*.md works in development.
  • Add a “Copy as Markdown” button to the docs table of contents sidebar.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
scripts/copy-docs-md.ts New build script to generate .md files into out/docs for static hosting.
package.json Extends build to run the new docs markdown copy script.
next.config.mjs Makes output: "export" prod-only, adds .dev.* routing extensions in dev, and introduces a .md rewrite.
components/table-of-contents.tsx Adds Copy/Check UI and clipboard logic gated by rawContent.
app/docs/[...slug]/page.tsx Passes raw doc content into the TOC so the copy button can copy it.
app/docs-raw/[...slug]/route.dev.ts Adds a dev-only route to serve raw docs content with a Markdown content-type.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines 60 to 61
if (headings.length === 0) return null

Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new rawContent prop, the “Copy as Markdown” button is part of this component’s output, but if (headings.length === 0) return null makes it impossible to show the button on pages without headings. Consider rendering the copy button even when there are no headings, and only conditionally render the headings list.

Copilot uses AI. Check for mistakes.
return (
<nav aria-label="Table of contents">
{rawContent && (
<button
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This <button> doesn’t specify type. If this component is ever rendered inside a <form>, the default type="submit" can cause unintended submissions. Set type="button" to make the click behavior unambiguous.

Suggested change
<button
<button
type="button"

Copilot uses AI. Check for mistakes.
Comment on lines 104 to 109
{/* Table of Contents - right sidebar */}
{headings.length > 0 && (
<aside className="sticky top-14 hidden h-[calc(100vh-3.5rem)] w-56 shrink-0 overflow-y-auto py-8 pr-4 xl:block">
<TableOfContents headings={headings} />
<TableOfContents headings={headings} rawContent={doc.content} />
</aside>
)}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TableOfContents is only rendered when headings.length > 0, but the new “Copy as Markdown” UI lives inside that component. This means docs pages without headings can’t show the copy button even though doc.content is available. If the copy feature should work for all docs, render the sidebar (or at least the copy control) regardless of headings length.

Copilot uses AI. Check for mistakes.
Comment on lines 105 to 108
{headings.length > 0 && (
<aside className="sticky top-14 hidden h-[calc(100vh-3.5rem)] w-56 shrink-0 overflow-y-auto py-8 pr-4 xl:block">
<TableOfContents headings={headings} />
<TableOfContents headings={headings} rawContent={doc.content} />
</aside>
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing the full doc.content string into a client component means the entire raw doc source is serialized into the RSC payload and sent to the browser on every docs page view (even if the user never clicks copy). To avoid a potentially large page payload, consider fetching the raw markdown on-demand from the new *.md endpoint when the button is clicked instead of embedding it in props.

Copilot uses AI. Check for mistakes.
import fs from "fs"
import path from "path"
import matter from "gray-matter"
import { VERSIONS, DEFAULT_VERSION, type Version } from "../lib/docs-config"
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

type Version is imported but never used in this script. This will typically fail lint/typecheck with unused-import rules; remove it (or use it) to keep the script clean.

Suggested change
import { VERSIONS, DEFAULT_VERSION, type Version } from "../lib/docs-config"
import { VERSIONS, DEFAULT_VERSION } from "../lib/docs-config"

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +36
fs.writeFileSync(outPath, content.trim() + "\n")
count++
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Writing content.trim() will remove leading whitespace/newlines from the document body, which can change Markdown semantics (e.g., leading-indented code blocks) and produce output that doesn't match the source. Prefer preserving the content as-is and only normalize the trailing newline (e.g., ensure it ends with exactly one \n).

Copilot uses AI. Check for mistakes.
Comment on lines +25 to +27
await navigator.clipboard.writeText(rawContent)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

navigator.clipboard.writeText(...) can throw/reject (permission denied, insecure context, etc.). Right now that would result in an unhandled rejection and copied state never resetting. Wrap this in try/catch (and optionally surface a non-intrusive error state) so the UI doesn’t silently fail.

Suggested change
await navigator.clipboard.writeText(rawContent)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
if (!navigator?.clipboard?.writeText) {
console.error("Clipboard API is not available in this environment.")
return
}
try {
await navigator.clipboard.writeText(rawContent)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch (error) {
console.error("Failed to copy markdown to clipboard:", error)
}

Copilot uses AI. Check for mistakes.
Comment on lines +26 to +28
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setTimeout started after copying is never cleared. If the user navigates away within 2s, this can trigger a state update on an unmounted component. Store the timeout id (e.g., in a ref) and clear it in an effect cleanup (and/or before setting a new timeout).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants