From 7d939010491528c87238252a7be250537553be7d Mon Sep 17 00:00:00 2001 From: Shivangi Chaurasia Date: Fri, 22 May 2026 04:58:11 +0530 Subject: [PATCH] feat: auto-populate README fields from GitHub repository URL --- src/hooks/useReadmeState.js | 10 +++- src/pages/ReadmeMaker/EditorPanel.jsx | 58 ++++++++++++++++++- src/pages/ReadmeMaker/ReadmeMaker.jsx | 27 ++++++++- src/styles/index.css | 82 +++++++++++++++++++++++++++ src/utils/githubApi.js | 74 ++++++++++++++++++++++++ 5 files changed, 248 insertions(+), 3 deletions(-) create mode 100644 src/utils/githubApi.js diff --git a/src/hooks/useReadmeState.js b/src/hooks/useReadmeState.js index 1e8246d..d859fe7 100644 --- a/src/hooks/useReadmeState.js +++ b/src/hooks/useReadmeState.js @@ -68,6 +68,14 @@ export function useReadmeState() { }); }, [sectionState, selectedTechs, selectedBadges, scheduleSave]); + const updateMultipleFields = useCallback((fieldsObj) => { + setFormData(prev => { + const next = { ...prev, ...fieldsObj }; + scheduleSave(next, sectionState, selectedTechs, selectedBadges); + return next; + }); + }, [sectionState, selectedTechs, selectedBadges, scheduleSave]); + const toggleSection = useCallback((id, checked) => { setSectionState(prev => { const next = { ...prev, [id]: checked }; @@ -145,7 +153,7 @@ export function useReadmeState() { }, []); return { - formData, updateField, + formData, updateField, updateMultipleFields, sectionState, toggleSection, selectedTechs, toggleTech, selectedBadges, toggleBadge, diff --git a/src/pages/ReadmeMaker/EditorPanel.jsx b/src/pages/ReadmeMaker/EditorPanel.jsx index 4fe52ff..ac8e94e 100644 --- a/src/pages/ReadmeMaker/EditorPanel.jsx +++ b/src/pages/ReadmeMaker/EditorPanel.jsx @@ -1,8 +1,9 @@ import { isValidUrl } from '../../hooks/useUrlValidation'; -import { useRef } from 'react'; +import { useRef, useState } from 'react'; import { TECHS, BADGES } from '../../utils/constants'; import { convertStructure } from '../../utils/structureUtils'; import { getWordCount } from '../../utils/markdownUtils'; +import { parseGitHubUrl, fetchRepoData } from '../../utils/githubApi'; function WordCount({ text }) { const count = getWordCount(text); @@ -34,10 +35,34 @@ export default function EditorPanel({ selectedTechs, toggleTech, selectedBadges, toggleBadge, screenshots, addScreenshots, removeScreenshot, + onGitHubImport, }) { const fileInputRef = useRef(null); const dropZoneRef = useRef(null); + const [ghUrl, setGhUrl] = useState(''); + const [ghLoading, setGhLoading] = useState(false); + const [ghStatus, setGhStatus] = useState({ type: '', message: '' }); + + async function handleGitHubFetch() { + setGhStatus({ type: '', message: '' }); + const parsed = parseGitHubUrl(ghUrl); + if (!parsed) { + setGhStatus({ type: 'error', message: 'Invalid GitHub URL. Use format: https://github.com/owner/repo' }); + return; + } + setGhLoading(true); + try { + const data = await fetchRepoData(parsed.owner, parsed.repo); + onGitHubImport(data); + setGhStatus({ type: 'success', message: `✓ Imported "${data.name}" successfully!` }); + } catch (err) { + setGhStatus({ type: 'error', message: err.message }); + } finally { + setGhLoading(false); + } + } + const structPreview = formData.rawStructure ? convertStructure(formData.rawStructure, formData.projName || 'project') : 'Paste structure above to preview...'; @@ -61,6 +86,37 @@ export default function EditorPanel({
+
+
+ + + + Import from GitHub +
+
+ setGhUrl(e.target.value)} + onKeyDown={e => e.key === 'Enter' && handleGitHubFetch()} + /> + +
+ {ghStatus.message && ( +
+ {ghStatus.message} +
+ )} +
+