Spaces:
Sleeping
Sleeping
Download src/features/FixItButton.jsx from goat1242/pixelroast: direct link, hf CLI and curl.
- Browser
- Download file 7.16 kB
-
https://huggingface.co/spaces/goat1242/pixelroast/resolve/main/src/features/FixItButton.jsx
- Command line
-
hf download hf://spaces/goat1242/pixelroast/src/features/FixItButton.jsx
-
curl -L -o FixItButton.jsx https://huggingface.co/spaces/goat1242/pixelroast/resolve/main/src/features/FixItButton.jsx
7.16 kB
| import React, { useState, useRef } from 'react'; | |
| import { motion, AnimatePresence } from 'framer-motion'; | |
| import { Wrench, Check, Copy, X, Eye, EyeOff } from 'lucide-react'; | |
| import { Button } from '../components/ui/Button'; | |
| export const FixItButton = ({ code = "p-4 bg-red-500 rounded-lg" }) => { | |
| const [isOpen, setIsOpen] = useState(false); | |
| const [copied, setCopied] = useState(false); | |
| const [showPreview, setShowPreview] = useState(false); | |
| const iframeRef = useRef(null); | |
| const handleCopy = () => { | |
| navigator.clipboard.writeText(code); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| }; | |
| // Extract the fix code string from various fix formats | |
| const getFixCode = () => { | |
| if (typeof code === 'string') return code; | |
| if (typeof code === 'object' && code.fix_code) return code.fix_code; | |
| if (typeof code === 'object' && code.issue) return `${code.issue}: ${code.fix_code || ''}`; | |
| return String(code); | |
| }; | |
| const fixCode = getFixCode(); | |
| // Generate preview HTML with Tailwind CDN | |
| const getPreviewHTML = () => ` | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style>body{margin:0;padding:16px;background:#f9fafb;display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 32px);}</style> | |
| </head> | |
| <body> | |
| <div class="${fixCode}"> | |
| <p class="text-sm">Preview: Your fix applied</p> | |
| </div> | |
| </body> | |
| </html>`; | |
| return ( | |
| <div className="relative"> | |
| <Button | |
| onClick={() => setIsOpen(!isOpen)} | |
| className={`h-8 px-3 text-xs bg-brutalist-black text-white shrink-0 ${isOpen ? 'bg-brutalist-red hover:bg-red-700' : ''}`} | |
| > | |
| <Wrench size={12} /> | |
| FIX IT | |
| </Button> | |
| <AnimatePresence> | |
| {isOpen && ( | |
| <> | |
| {/* Backdrop to close on click outside */} | |
| <div | |
| className="fixed inset-0 z-40" | |
| onClick={() => setIsOpen(false)} | |
| /> | |
| {/* Popup - opens ABOVE the button to avoid cut-off */} | |
| <motion.div | |
| initial={{ opacity: 0, y: 10, scale: 0.9 }} | |
| animate={{ opacity: 1, y: 0, scale: 1 }} | |
| exit={{ opacity: 0, y: 10, scale: 0.9 }} | |
| className="fixed sm:absolute z-50 left-4 right-4 sm:left-auto sm:right-0 bottom-20 sm:bottom-full sm:mb-2 sm:w-80 p-4 bg-white border-2 border-brutalist-black shadow-hard-lg" | |
| > | |
| {/* Header */} | |
| <div className="flex justify-between items-center mb-3"> | |
| <span className="font-bold text-sm uppercase text-brutalist-black flex items-center gap-2"> | |
| <Wrench size={14} /> | |
| Tailwind Fix | |
| </span> | |
| <button | |
| onClick={() => setIsOpen(false)} | |
| className="p-1 hover:bg-gray-100 rounded" | |
| > | |
| <X size={16} /> | |
| </button> | |
| </div> | |
| {/* Code block */} | |
| <div className="bg-gray-900 text-green-400 p-3 font-mono text-xs break-all rounded mb-3 max-h-32 overflow-y-auto"> | |
| {fixCode} | |
| </div> | |
| {/* Action buttons */} | |
| <div className="flex gap-2 mb-3"> | |
| {/* Copy button */} | |
| <button | |
| onClick={handleCopy} | |
| className={`flex-1 py-2 font-bold text-sm flex items-center justify-center gap-2 border-2 border-brutalist-black transition-colors ${copied | |
| ? 'bg-green-500 text-white' | |
| : 'bg-brutalist-yellow hover:bg-brutalist-black hover:text-white' | |
| }`} | |
| > | |
| {copied ? ( | |
| <> | |
| <Check size={16} /> | |
| COPIED! | |
| </> | |
| ) : ( | |
| <> | |
| <Copy size={16} /> | |
| COPY | |
| </> | |
| )} | |
| </button> | |
| {/* Preview toggle */} | |
| <button | |
| onClick={() => setShowPreview(!showPreview)} | |
| className={`py-2 px-3 font-bold text-sm flex items-center justify-center gap-2 border-2 border-brutalist-black transition-colors ${ | |
| showPreview | |
| ? 'bg-blue-600 text-white' | |
| : 'bg-white hover:bg-gray-100' | |
| }`} | |
| > | |
| {showPreview ? <EyeOff size={16} /> : <Eye size={16} />} | |
| {showPreview ? 'HIDE' : 'PREVIEW'} | |
| </button> | |
| </div> | |
| {/* Live Preview iframe */} | |
| <AnimatePresence> | |
| {showPreview && ( | |
| <motion.div | |
| initial={{ height: 0, opacity: 0 }} | |
| animate={{ height: 120, opacity: 1 }} | |
| exit={{ height: 0, opacity: 0 }} | |
| className="overflow-hidden border-2 border-dashed border-gray-300 rounded" | |
| > | |
| <iframe | |
| ref={iframeRef} | |
| srcDoc={getPreviewHTML()} | |
| title="Tailwind Preview" | |
| className="w-full h-[120px] border-0" | |
| sandbox="allow-scripts" | |
| /> | |
| </motion.div> | |
| )} | |
| </AnimatePresence> | |
| </motion.div> | |
| </> | |
| )} | |
| </AnimatePresence> | |
| </div> | |
| ); | |
| }; | |