diff --git a/docs/site/src/components/GitHubCodeBlock/GitHubCodeBlock.tsx b/docs/site/src/components/GitHubCodeBlock/GitHubCodeBlock.tsx index a6b61efda..65c2bbb66 100644 --- a/docs/site/src/components/GitHubCodeBlock/GitHubCodeBlock.tsx +++ b/docs/site/src/components/GitHubCodeBlock/GitHubCodeBlock.tsx @@ -1,119 +1,41 @@ -import React, { useEffect, useState } from 'react'; -import axios from 'axios'; -import CodeBlock from "@theme/CodeBlock"; import { useColorMode } from '@docusaurus/theme-common'; +import CodeBlock from "@theme/CodeBlock"; +import { useEffect, useState } from 'react'; +import useGitHubCodeBlock from './useGitHubCodeBlock'; import './GitHubCodeBlock.css'; const GitHubCodeBlock = ({ repoUrl }) => { - const [code, setCode] = useState(''); - const [language, setLanguage] = useState('plaintext'); - const [sourceUrl, setSourceUrl] = useState(''); - const [mainUrl, setMainUrl] = useState(''); - const [isCodeMatch, setCodeMatch] = useState(true); + const [data, setData] = useState(null); + const colorMode = useColorMode(); useEffect(() => { - fetchCode(); - }, [repoUrl]); - - async function fetchCode() { - if (!repoUrl) { - console.error("No URL provided."); - setCode("Error: No URL provided."); - return; - } - - var match = matchUrl(repoUrl); - if (!match) { - return; - } - - const [wholeUrl, site, owner, repo, branch, filePath, startLine, endLine] = match; - - const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${filePath}` + (startLine && endLine ? `#L${startLine}-L${endLine}` : ''); // Fetch the raw content from GitHub - const mainRawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/main/${filePath}`; // main branch raw content URL - setSourceUrl(`https://github.com/${owner}/${repo}/blob/${branch}/${filePath}` + (startLine && endLine ? `#L${startLine}-L${endLine}` : '')); // Build the source URL to view on GitHub, including line numbers if available - setMainUrl(`https://github.com/${owner}/${repo}/blob/main/${filePath}`); // main branch source URL - - try { - const response = await axios.get(rawUrl); // Fetch the raw content from the specified commit hash - const lines = extractLines(response, startLine, endLine); - - const mainResponse = await axios.get(mainRawUrl); // Fetch the raw content from the main branch - const mainLines = extractLines(mainResponse, startLine, endLine); - - if (lines !== mainLines) { // Check if the code matches the main branch - setCodeMatch(false); + const fetchData = async () => { + try { + const result = await useGitHubCodeBlock(repoUrl); + setData(result); + } catch (error) { + console.error(error); } + }; - setCode(lines); - setLanguage(determineLanguage(filePath)); - } catch (error) { - console.error('Error fetching code:', error.response ? error.response.data : error.message); - setCode(`Error: ${error.response ? error.response.data : "Could not fetch file"}`); - } - } - - function extractLines(mainResponse, startLine: string, endLine: string) { - const allLines = mainResponse.data.split('\n'); - const lines = (startLine && endLine) ? allLines.slice(parseInt(startLine) - 1, parseInt(endLine)).join('\n') : allLines.join('\n'); - return lines; - } - - function matchUrl(url: string) { - const permalinkLinesRegex = /(https:\/\/github\.com\/)([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/([^#]+)#L(\d+)-L(\d+)/; - const repoFileRegex = /(https:\/\/github\.com\/)([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/([^#]+)/; - let match = url.match(permalinkLinesRegex); - if (match) { - if (match[4].length !== 40) { - console.error("Invalid URL: Permalink with lines URL should include a commit hash."); - setCode("Error: Invalid GitHub Permalink Lines URL format."); - return null; - } - return match; - } - match = url.match(repoFileRegex); - if (!match) { - console.error("Invalid URL: Check the URL format."); - setCode("Error: Invalid GitHub URL format."); - } - return match; - } + fetchData(); + }, [repoUrl]); - function determineLanguage(filePath) { - const extension = filePath.slice(filePath.lastIndexOf('.')); - const languageMap = { - '.js': 'javascript', - '.ts': 'typescript', - '.py': 'python', - '.cpp': 'cpp', - '.c': 'c', - '.java': 'java', - '.rs': 'rust', - '.html': 'html', - '.css': 'css', - '.md': 'markdown', - '.sh': 'bash', - '.sol': 'solidity', - '.go': 'go', - '.json': 'json', - '.yml': 'yaml', - '.yaml': 'yaml', - '.toml': 'toml', - '.xml': 'xml', - '.sql': 'sql', - }; - return languageMap[extension] || 'plaintext'; + if (!data) { + return ( +
+ Fetching code from GitHub... +
+ ); } - function getGitHubIcon() { - const { colorMode } = useColorMode(); - return colorMode === 'dark' ? "/img/github-icon-light.svg" : "/img/github-icon-dark.svg"; - } + const { code, isCodeMatch, mainUrl, sourceUrl, language, isError } = data; return (
{code} + {!isCodeMatch &&
@@ -121,11 +43,14 @@ const GitHubCodeBlock = ({ repoUrl }) => {
} -
- - See source on GitHub GitHub - -
+ + {!isError && +
+ + See source on GitHub GitHub + +
+ }
); } diff --git a/docs/site/src/components/GitHubCodeBlock/useGitHubCodeBlock.tsx b/docs/site/src/components/GitHubCodeBlock/useGitHubCodeBlock.tsx new file mode 100644 index 000000000..cb34d75f0 --- /dev/null +++ b/docs/site/src/components/GitHubCodeBlock/useGitHubCodeBlock.tsx @@ -0,0 +1,93 @@ +export default async function useGitHubCodeBlock(repoUrl: string) { + let match = matchUrl(repoUrl); + if (match[0] === "Error") { + return { + code: match[1], + isCodeMatch: true, + mainUrl: "", + sourceUrl: "", + language: "plaintext", + isError: true, + }; + } + + const [, , owner, repo, branch, filePath, startLine, endLine] = match; + const rawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${filePath}` + (startLine && endLine ? `#L${startLine}-L${endLine}` : ''); + const mainRawUrl = `https://raw.githubusercontent.com/${owner}/${repo}/main/${filePath}`; + + const linesRes = await fetchCodeLinesFromUrl(rawUrl, startLine, endLine); + const mainLinesRes = await fetchCodeLinesFromUrl(mainRawUrl, startLine, endLine); + + const isCodeMatch = linesRes === mainLinesRes; + const sourceUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${filePath}` + (startLine && endLine ? `#L${startLine}-L${endLine}` : ''); + const mainUrl = `https://github.com/${owner}/${repo}/blob/main/${filePath}`; + + return { + code: linesRes, + isCodeMatch, + mainUrl, + sourceUrl, + language: determineLanguage(filePath), + isError: false, + }; +} + +async function fetchCodeLinesFromUrl(url: string, startLine: string, endLine: string) { + const response = await fetch(url); + const data = await response.text(); + const lines = extractLines(data, startLine, endLine); + return lines; +} + +function extractLines(mainResponse: string, startLine: string, endLine: string) { + const allLines = mainResponse.split('\n'); + const lines = (startLine && endLine) ? allLines.slice(parseInt(startLine) - 1, parseInt(endLine)).join('\n') : allLines.join('\n'); + return lines; +} + +function matchUrl(url: string) { + const permalinkLinesRegex = /(https:\/\/github\.com\/)([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/([^#]+)#L(\d+)-L(\d+)/; + let match = url.match(permalinkLinesRegex); + if (match) { + if (match[4].length !== 40) { + console.error("Invalid URL: Permalink with lines URL should include a commit hash."); + let err = "Error: Invalid GitHub URL with commit hash and lines format."; + return ["Error", err]; + } + return match; + } + const repoFileRegex = /(https:\/\/github\.com\/)([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/([^#]+)/; + match = url.match(repoFileRegex); + if (!match) { + console.error("Invalid URL: Check the URL format."); + let err = "Error: Invalid GitHub URL format."; + return ["Error", err]; + } + return match; +} + +function determineLanguage(filePath: string) { + const extension = filePath.slice(filePath.lastIndexOf('.')); + const languageMap = { + '.js': 'javascript', + '.ts': 'typescript', + '.py': 'python', + '.cpp': 'cpp', + '.c': 'c', + '.java': 'java', + '.rs': 'rust', + '.html': 'html', + '.css': 'css', + '.md': 'markdown', + '.sh': 'bash', + '.sol': 'solidity', + '.go': 'go', + '.json': 'json', + '.yml': 'yaml', + '.yaml': 'yaml', + '.toml': 'toml', + '.xml': 'xml', + '.sql': 'sql', + }; + return languageMap[extension] || 'plaintext'; +} diff --git a/docs/site/src/components/HomepageFeatures/index.tsx b/docs/site/src/components/HomepageFeatures/index.tsx deleted file mode 100644 index 50a9e6f4c..000000000 --- a/docs/site/src/components/HomepageFeatures/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import clsx from 'clsx'; -import Heading from '@theme/Heading'; -import styles from './styles.module.css'; - -type FeatureItem = { - title: string; - Svg: React.ComponentType>; - description: JSX.Element; -}; - -const FeatureList: FeatureItem[] = [ - { - title: 'Easy to Use', - Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default, - description: ( - <> - Docusaurus was designed from the ground up to be easily installed and - used to get your website up and running quickly. - - ), - }, - { - title: 'Focus on What Matters', - Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default, - description: ( - <> - Docusaurus lets you focus on your docs, and we'll do the chores. Go - ahead and move your docs into the docs directory. - - ), - }, - { - title: 'Powered by React', - Svg: require('@site/static/img/undraw_docusaurus_react.svg').default, - description: ( - <> - Extend or customize your website layout by reusing React. Docusaurus can - be extended while reusing the same header and footer. - - ), - }, -]; - -function Feature({title, Svg, description}: FeatureItem) { - return ( -
-
- -
-
- {title} -

{description}

-
-
- ); -} - -export default function HomepageFeatures(): JSX.Element { - return ( -
-
-
- {FeatureList.map((props, idx) => ( - - ))} -
-
-
- ); -} diff --git a/docs/site/src/components/HomepageFeatures/styles.module.css b/docs/site/src/components/HomepageFeatures/styles.module.css deleted file mode 100644 index b248eb2e5..000000000 --- a/docs/site/src/components/HomepageFeatures/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.features { - display: flex; - align-items: center; - padding: 2rem 0; - width: 100%; -} - -.featureSvg { - height: 200px; - width: 200px; -} diff --git a/docs/site/src/pages/index.module.css b/docs/site/src/pages/index.module.css deleted file mode 100644 index 9f71a5da7..000000000 --- a/docs/site/src/pages/index.module.css +++ /dev/null @@ -1,23 +0,0 @@ -/** - * CSS files with the .module.css suffix will be treated as CSS modules - * and scoped locally. - */ - -.heroBanner { - padding: 4rem 0; - text-align: center; - position: relative; - overflow: hidden; -} - -@media screen and (max-width: 996px) { - .heroBanner { - padding: 2rem; - } -} - -.buttons { - display: flex; - align-items: center; - justify-content: center; -} diff --git a/docs/site/src/pages/index.tsx.old b/docs/site/src/pages/index.tsx.old deleted file mode 100644 index 87bb847f6..000000000 --- a/docs/site/src/pages/index.tsx.old +++ /dev/null @@ -1,43 +0,0 @@ -import Link from '@docusaurus/Link'; -import { Redirect } from '@docusaurus/router'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -import Heading from '@theme/Heading'; -import clsx from 'clsx'; - -import styles from './index.module.css'; - -function HomepageHeader() { - const {siteConfig} = useDocusaurusContext(); - return ( -
-
- - {siteConfig.title} - -

{siteConfig.tagline}

-
- - Docusaurus Tutorial - 5min ⏱️ - -
-
-
- ); -} - -export default function Home(): JSX.Element { - // const {siteConfig} = useDocusaurusContext(); - // return ( - // - // - //
- // - //
- //
- // ); - return ; -}