diff --git a/src/pages/ReadmeMaker/PreviewPanel.jsx b/src/pages/ReadmeMaker/PreviewPanel.jsx index f6bac8c..f7c6ab8 100644 --- a/src/pages/ReadmeMaker/PreviewPanel.jsx +++ b/src/pages/ReadmeMaker/PreviewPanel.jsx @@ -51,6 +51,7 @@ function calculateQuality({ formData, sectionState, selectedTechs, screenshots } export default function PreviewPanel({ currentMd, formData, sectionState, selectedTechs, screenshots }) { const toast = useToast(); + const [copied, setCopied] = useState(false); const [tab, setTabState] = useState('rendered'); const [zoom, setZoom] = useState(() => { try { @@ -102,13 +103,22 @@ export default function PreviewPanel({ currentMd, formData, sectionState, select try { await navigator.clipboard.writeText(currentMd); toast('✓ Copied to clipboard!'); + setCopied(true); + setTimeout(() => setCopied(false), 2000); } catch { const ta = document.createElement('textarea'); ta.value = currentMd; ta.style.cssText = 'position:absolute;left:-9999px'; document.body.appendChild(ta); ta.select(); - try { document.execCommand('copy'); toast('✓ Copied!'); } catch { toast('Copy failed'); } + try { + document.execCommand('copy'); + toast('✓ Copied!'); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } catch { + toast('Copy failed'); + } document.body.removeChild(ta); } }, [currentMd, toast]); @@ -158,11 +168,22 @@ export default function PreviewPanel({ currentMd, formData, sectionState, select -
) : ( -
+
+
{currentMd}
)} diff --git a/src/pages/ReadmeMaker/ReadmeMaker.jsx b/src/pages/ReadmeMaker/ReadmeMaker.jsx index cdbed40..779883b 100644 --- a/src/pages/ReadmeMaker/ReadmeMaker.jsx +++ b/src/pages/ReadmeMaker/ReadmeMaker.jsx @@ -12,6 +12,7 @@ import { useState } from 'react'; export default function ReadmeMaker() { const toast = useToast(); + const [copied, setCopied] = useState(false); const { formData, updateField, @@ -41,7 +42,11 @@ export default function ReadmeMaker() { function handleCopyMarkdown() { if (!currentMd) { toast('Generate content first!'); return; } navigator.clipboard.writeText(currentMd) - .then(() => toast('✓ Copied to clipboard!')) + .then(() => { + toast('✓ Copied to clipboard!'); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }) .catch(() => toast('Copy failed')); } @@ -81,7 +86,9 @@ export default function ReadmeMaker() { - +
diff --git a/src/styles/index.css b/src/styles/index.css index 3c875d4..2c039ba 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -3401,3 +3401,53 @@ body.light-mode .gh-preview { .faq-question { font-size: 14px; padding: 16px; } .faq-answer { padding: 0 16px 16px; padding-top: 12px; } } + +/* ── Floating Copy Button inside Preview ── */ +.copy-floating-btn { + position: absolute; + top: 16px; + right: 16px; + z-index: 50; + display: flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + background: var(--surface2); + border: 1px solid var(--border2); + border-radius: 8px; + color: var(--muted2); + font-family: 'Space Grotesk', sans-serif; + font-size: 12px; + font-weight: 600; + cursor: pointer; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + user-select: none; +} + +.copy-floating-btn:hover { + background: var(--surface3); + border-color: var(--accent); + color: var(--accent); + transform: translateY(-1px); +} + +.copy-floating-btn.copied { + background: rgba(16, 185, 129, 0.15); + border-color: var(--green); + color: var(--green); + box-shadow: 0 4px 12px rgba(16, 185, 129, 0.2); +} + +.pbtn.green.copied { + background: rgba(16, 185, 129, 0.25); + border-color: var(--green); + color: var(--green); +} + +.hbtn.copied { + background: rgba(16, 185, 129, 0.15); + border-color: var(--green); + color: var(--green); +} +