Skip to content

Commit 42665fa

Browse files
Add md sites and link
1 parent 9dfbc4e commit 42665fa

File tree

5 files changed

+274
-0
lines changed

5 files changed

+274
-0
lines changed

website/docusaurus.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const config = {
4444
}),
4545
],
4646
],
47+
plugins: [require.resolve("./plugins/copy-markdown-files.js")],
4748
themeConfig:
4849
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
4950
({

website/plugins/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Copy Markdown Files Plugin
2+
3+
This custom Docusaurus plugin automatically copies original markdown (`.md`) and MDX (`.mdx`) files to the build directory alongside the generated HTML files during the build process.
4+
5+
## What it does
6+
7+
When you run `npm run build`, this plugin will:
8+
9+
1. **Copy documentation files**: All `.md` and `.mdx` files from the `docs/` directory are copied to `build/docs/` maintaining the same directory structure
10+
2. **Copy blog files**: All `.md` and `.mdx` files from the `blog/` directory are copied to `build/blog/` maintaining the same directory structure
11+
3. **Copy page files**: Any `.md` or `.mdx` files from `src/pages/` are copied to the root of the build directory
12+
13+
## Example output
14+
15+
After building, you'll have both files for each route:
16+
17+
```
18+
build/
19+
├── docs/
20+
│ ├── intro/
21+
│ │ ├── index.html # Generated HTML
22+
│ │ └── index.md # Original markdown (copied)
23+
│ └── concepts/
24+
│ ├── why-opencomponents/
25+
│ │ ├── index.html # Generated HTML
26+
│ │ └── why-opencomponents.md # Original markdown (copied)
27+
└── blog/
28+
├── first-blog-post/
29+
│ ├── index.html # Generated HTML
30+
│ └── 2019-05-28-first-blog-post.md # Original markdown (copied)
31+
```
32+
33+
## Installation
34+
35+
The plugin is already configured in your `docusaurus.config.js`:
36+
37+
```javascript
38+
plugins: [
39+
require.resolve("./plugins/copy-markdown-files.js"),
40+
],
41+
```
42+
43+
## Usage
44+
45+
Simply run your normal build command:
46+
47+
```bash
48+
npm run build
49+
```
50+
51+
The plugin will automatically run during the build process and copy all markdown files. You'll see output like:
52+
53+
```
54+
📄 Copying original markdown files to build directory...
55+
📁 Copying docs directory...
56+
📄 Copied: docs/intro.md → build/docs/intro.md
57+
📄 Copied: docs/concepts/why-opencomponents.md → build/docs/concepts/why-opencomponents.md
58+
✅ Successfully copied docs files
59+
📁 Copying blog directory...
60+
📄 Copied: blog/2019-05-28-first-blog-post.md → build/blog/2019-05-28-first-blog-post.md
61+
✅ Successfully copied blog files
62+
🎉 All markdown files copied successfully!
63+
```
64+
65+
## Configuration
66+
67+
The plugin doesn't require any configuration, but you can modify the source directories in the plugin file if needed:
68+
69+
- `docs/` - Documentation files
70+
- `blog/` - Blog post files
71+
- `src/pages/` - Page files
72+
73+
## Benefits
74+
75+
- **Access to original content**: You can access the original markdown source alongside the rendered HTML
76+
- **Version control**: Useful for diffing changes or accessing raw content programmatically
77+
- **API integration**: Other tools can consume the original markdown files
78+
- **Backup**: Original files are preserved in the build output
79+
80+
## Technical details
81+
82+
- The plugin uses the `postBuild` lifecycle hook to run after Docusaurus has generated all HTML files
83+
- It recursively traverses directories and only copies `.md` and `.mdx` files
84+
- The plugin uses `fs-extra` (already available through Docusaurus) for file operations
85+
- Directory structure is preserved exactly as it exists in the source
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
const fs = require("fs-extra");
2+
const path = require("path");
3+
4+
/**
5+
* Custom Docusaurus plugin that copies original markdown files
6+
* to the build directory alongside the generated HTML files
7+
*/
8+
async function copyMarkdownFilesPlugin(context, options) {
9+
return {
10+
name: "copy-markdown-files",
11+
async postBuild({ siteDir, outDir }) {
12+
console.log("📄 Copying original markdown files to build directory...");
13+
14+
try {
15+
// Define source directories to copy from
16+
const sourceDirs = [
17+
path.join(siteDir, "docs"),
18+
path.join(siteDir, "blog"),
19+
];
20+
21+
// Define corresponding target directories
22+
const targetDirs = [
23+
path.join(outDir, "docs"),
24+
path.join(outDir, "blog"),
25+
];
26+
27+
// Copy each source directory to its target
28+
for (let i = 0; i < sourceDirs.length; i++) {
29+
const sourceDir = sourceDirs[i];
30+
const targetDir = targetDirs[i];
31+
32+
// Check if source directory exists
33+
if (await fs.pathExists(sourceDir)) {
34+
console.log(
35+
` 📁 Copying ${path.basename(sourceDir)} directory...`
36+
);
37+
38+
// Ensure target directory exists
39+
await fs.ensureDir(targetDir);
40+
41+
// Copy all markdown files recursively
42+
await copyMarkdownFilesRecursive(sourceDir, targetDir);
43+
44+
console.log(
45+
` ✅ Successfully copied ${path.basename(sourceDir)} files`
46+
);
47+
} else {
48+
console.log(
49+
` ⚠️ Source directory ${sourceDir} does not exist, skipping...`
50+
);
51+
}
52+
}
53+
54+
// Copy static markdown files from src/pages if they exist
55+
const srcPagesDir = path.join(siteDir, "src", "pages");
56+
if (await fs.pathExists(srcPagesDir)) {
57+
console.log(" 📄 Checking for markdown files in src/pages...");
58+
await copyMarkdownFilesRecursive(srcPagesDir, outDir);
59+
}
60+
61+
console.log("🎉 All markdown files copied successfully!");
62+
} catch (error) {
63+
console.error("❌ Error copying markdown files:", error);
64+
throw error;
65+
}
66+
},
67+
};
68+
}
69+
70+
/**
71+
* Recursively copy markdown files from source to target directory
72+
* @param {string} sourceDir - Source directory path
73+
* @param {string} targetDir - Target directory path
74+
*/
75+
async function copyMarkdownFilesRecursive(sourceDir, targetDir) {
76+
const items = await fs.readdir(sourceDir);
77+
78+
for (const item of items) {
79+
const sourcePath = path.join(sourceDir, item);
80+
const targetPath = path.join(targetDir, item);
81+
const stat = await fs.stat(sourcePath);
82+
83+
if (stat.isDirectory()) {
84+
// Recursively copy subdirectories
85+
await fs.ensureDir(targetPath);
86+
await copyMarkdownFilesRecursive(sourcePath, targetPath);
87+
} else if (
88+
stat.isFile() &&
89+
(item.endsWith(".md") || item.endsWith(".mdx"))
90+
) {
91+
// Copy markdown files
92+
await fs.copy(sourcePath, targetPath);
93+
console.log(
94+
` 📄 Copied: ${path.relative(
95+
process.cwd(),
96+
sourcePath
97+
)}${path.relative(process.cwd(), targetPath)}`
98+
);
99+
}
100+
}
101+
}
102+
103+
module.exports = copyMarkdownFilesPlugin;
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import React from "react";
2+
import { useLocation } from "@docusaurus/router";
3+
4+
/**
5+
* Button component that links to the original markdown file for the current page
6+
*/
7+
export default function ViewMarkdownButton(): JSX.Element | null {
8+
const location = useLocation();
9+
10+
// Only show on docs pages (not on blog or other pages)
11+
if (!location.pathname.startsWith("/docs/")) {
12+
return null;
13+
}
14+
15+
// Convert the current path to the markdown file path
16+
// Example: /docs/concepts/why-opencomponents -> /docs/concepts/why-opencomponents.md
17+
const markdownPath = location.pathname.replace(/\/$/, "") + ".md";
18+
19+
return (
20+
<a
21+
href={markdownPath}
22+
target="_blank"
23+
rel="noopener noreferrer"
24+
className="view-markdown-button"
25+
style={{
26+
display: "inline-flex",
27+
alignItems: "center",
28+
gap: "0.5rem",
29+
padding: "0.5rem 1rem",
30+
backgroundColor: "var(--ifm-color-primary)",
31+
color: "white",
32+
textDecoration: "none",
33+
borderRadius: "0.375rem",
34+
fontSize: "0.875rem",
35+
fontWeight: "500",
36+
transition: "all 0.2s ease",
37+
marginTop: "1rem",
38+
border: "none",
39+
cursor: "pointer",
40+
fontFamily: "inherit",
41+
}}
42+
onMouseEnter={(e) => {
43+
e.currentTarget.style.backgroundColor = "var(--ifm-color-primary-dark)";
44+
e.currentTarget.style.transform = "translateY(-1px)";
45+
}}
46+
onMouseLeave={(e) => {
47+
e.currentTarget.style.backgroundColor = "var(--ifm-color-primary)";
48+
e.currentTarget.style.transform = "translateY(0)";
49+
}}
50+
>
51+
<svg
52+
width="16"
53+
height="16"
54+
viewBox="0 0 24 24"
55+
fill="none"
56+
stroke="currentColor"
57+
strokeWidth="2"
58+
strokeLinecap="round"
59+
strokeLinejoin="round"
60+
>
61+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" />
62+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />
63+
</svg>
64+
View in Markdown
65+
</a>
66+
);
67+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React, { type ReactNode } from "react";
2+
import Layout from "@theme-original/DocItem/Layout";
3+
import type LayoutType from "@theme/DocItem/Layout";
4+
import type { WrapperProps } from "@docusaurus/types";
5+
import ViewMarkdownButton from "@site/src/components/ViewMarkdownButton";
6+
7+
type Props = WrapperProps<typeof LayoutType>;
8+
9+
export default function LayoutWrapper(props: Props): ReactNode {
10+
return (
11+
<>
12+
<Layout {...props} />
13+
<div style={{ marginTop: "2rem", padding: "0 2rem" }}>
14+
<ViewMarkdownButton />
15+
</div>
16+
</>
17+
);
18+
}

0 commit comments

Comments
 (0)