feat: Add static file import system for docs (#3882)

# What does this PR do?

Add static file import system for docs

- Use `remark-code-import` plugin to embed code at build time
- Support importing Python code with syntax highlighting using
`raw-loader` + `ReactMarkdown`

One caveat is that currently when embedding markdown with code used the
syntax highlighting isn't behaving but I'll investigate that in a follow
up.

## Test Plan

Python Example:
<img width="1372" height="995" alt="Screenshot 2025-10-23 at 9 22 18 PM"
src="https://github.com/user-attachments/assets/656d2c78-4d9b-45a4-bd5e-3f8490352b85"
/>

Markdown example:
<img width="1496" height="1070" alt="Screenshot 2025-10-23 at 9 22
38 PM"
src="https://github.com/user-attachments/assets/6c0a07ec-ff7c-45aa-b05f-8c46acd4445c"
/>

---------

Signed-off-by: Francisco Javier Arceo <farceo@redhat.com>
This commit is contained in:
Francisco Arceo 2025-10-24 14:01:33 -04:00 committed by GitHub
parent 8265d4efc8
commit 4566eebe05
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 683 additions and 914 deletions

View file

@ -0,0 +1,93 @@
import React, { useState, useEffect } from 'react';
import CodeBlock from '@theme/CodeBlock';
export default function CodeFromFile({
src,
language = 'python',
title,
startLine,
endLine,
highlightLines
}) {
const [content, setContent] = useState('');
const [error, setError] = useState(null);
useEffect(() => {
async function loadFile() {
try {
// File registration is now handled by the file-sync-plugin during build
// Load file from static/imported-files directory
const response = await fetch(`/imported-files/${src}`);
if (!response.ok) {
throw new Error(`Failed to fetch: ${response.status}`);
}
let text = await response.text();
// Handle line range if specified (filtering is done at build time)
if (startLine || endLine) {
const lines = text.split('\n');
const start = startLine ? Math.max(0, startLine - 1) : 0;
const end = endLine ? Math.min(lines.length, endLine) : lines.length;
text = lines.slice(start, end).join('\n');
}
setContent(text);
} catch (err) {
console.error('Failed to load file:', err);
setError(`Failed to load ${src}: ${err.message}`);
}
}
loadFile();
}, [src, startLine, endLine]);
if (error) {
return <div style={{ color: 'red', padding: '1rem', border: '1px solid red', borderRadius: '4px' }}>
Error: {error}
</div>;
}
if (!content) {
return <div>Loading {src}...</div>;
}
// Auto-detect language from file extension if not provided
const detectedLanguage = language || getLanguageFromExtension(src);
return (
<CodeBlock
language={detectedLanguage}
title={title || src}
metastring={highlightLines ? `{${highlightLines}}` : undefined}
>
{content}
</CodeBlock>
);
}
function getLanguageFromExtension(filename) {
const ext = filename.split('.').pop();
const languageMap = {
'py': 'python',
'js': 'javascript',
'jsx': 'jsx',
'ts': 'typescript',
'tsx': 'tsx',
'md': 'markdown',
'sh': 'bash',
'yaml': 'yaml',
'yml': 'yaml',
'json': 'json',
'css': 'css',
'html': 'html',
'cpp': 'cpp',
'c': 'c',
'java': 'java',
'go': 'go',
'rs': 'rust',
'php': 'php',
'rb': 'ruby',
};
return languageMap[ext] || 'text';
}