Commit 9442fe1d authored by Administrator's avatar Administrator

Update frontend/src/components/CodeBlock.jsx via Son of Anton

parent 1c05548e
import React, { useState, useCallback } from "react"; import React, { useState, useCallback, useMemo } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"; import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
import { Copy, Check, Download, GitCommitVertical, Loader2, Plus, Pencil } from "lucide-react"; import { Copy, Check, Download, GitCommitVertical, Loader2, Plus, Pencil, Eye } from "lucide-react";
import UIPreview, { buildPreviewHTML } from "./UIPreview";
const PREVIEWABLE_LANGS = new Set(["html", "htm", "jsx", "tsx", "vue", "svelte"]);
const PREVIEWABLE_EXTS = /\.(html?|jsx|tsx|vue|svelte)$/i;
export default React.memo(function CodeBlock({ language, filename, code, linkedRepo, onCommit }) { export default React.memo(function CodeBlock({ language, filename, code, linkedRepo, onCommit }) {
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
const [committing, setCommitting] = useState(false); const [committing, setCommitting] = useState(false);
const [commitDone, setCommitDone] = useState(false); const [commitDone, setCommitDone] = useState(false);
const [showCommitOptions, setShowCommitOptions] = useState(false); const [showCommitOptions, setShowCommitOptions] = useState(false);
const [showPreview, setShowPreview] = useState(false);
const canPreview = useMemo(() => {
if (PREVIEWABLE_LANGS.has(language)) return true;
if (filename && PREVIEWABLE_EXTS.test(filename)) return true;
// Check if code looks like HTML
if (code.trim().match(/^<!DOCTYPE|^<html|^<div|^<section|^<main|^<header|^<template/i)) return true;
return false;
}, [language, filename, code]);
const previewHTML = useMemo(() => {
if (!canPreview) return null;
return buildPreviewHTML([{ language, filename, code }]);
}, [canPreview, language, filename, code]);
const handleCopy = useCallback(() => { const handleCopy = useCallback(() => {
navigator.clipboard.writeText(code); navigator.clipboard.writeText(code);
...@@ -41,67 +59,88 @@ export default React.memo(function CodeBlock({ language, filename, code, linkedR ...@@ -41,67 +59,88 @@ export default React.memo(function CodeBlock({ language, filename, code, linkedR
const lineCount = code.split("\n").length; const lineCount = code.split("\n").length;
return ( return (
<div className="my-3 rounded-xl overflow-hidden border border-anton-border bg-[#1a1b26]"> <>
{/* Header */} <div className="my-3 rounded-xl overflow-hidden border border-anton-border bg-[#1a1b26]">
<div className="flex items-center justify-between px-3 py-1.5 bg-anton-surface border-b border-anton-border gap-2"> {/* Header */}
<div className="flex items-center gap-2 min-w-0"> <div className="flex items-center justify-between px-3 py-1.5 bg-anton-surface border-b border-anton-border gap-2">
{language && <span className="text-[10px] text-anton-accent font-mono uppercase shrink-0">{language}</span>} <div className="flex items-center gap-2 min-w-0">
{filename && <span className="text-[10px] text-anton-muted truncate">{filename}</span>} {language && <span className="text-[10px] text-anton-accent font-mono uppercase shrink-0">{language}</span>}
</div> {filename && <span className="text-[10px] text-anton-muted truncate">{filename}</span>}
<div className="flex items-center gap-0.5 shrink-0"> </div>
{/* Git commit buttons */} <div className="flex items-center gap-0.5 shrink-0">
{showGit && !commitDone && ( {/* Preview button */}
<div className="relative"> {canPreview && (
{committing ? ( <button
<span className="flex items-center gap-1 px-2 py-1 text-[10px] text-orange-400"> onClick={() => setShowPreview(true)}
<Loader2 size={11} className="animate-spin" /> Committing… className="flex items-center gap-1 px-2 py-1 text-[10px] text-blue-400 hover:bg-blue-400/10 rounded transition"
</span> title="Preview in browser"
) : ( >
<button onClick={() => setShowCommitOptions(!showCommitOptions)} <Eye size={11} /> Preview
className="flex items-center gap-1 px-2 py-1 text-[10px] text-orange-400 hover:bg-orange-400/10 rounded transition" </button>
title={`Commit to ${linkedRepo.name}`}> )}
<GitCommitVertical size={11} /> Commit {/* Git commit buttons */}
</button> {showGit && !commitDone && (
)} <div className="relative">
{showCommitOptions && ( {committing ? (
<div className="absolute right-0 top-full mt-1 z-20 bg-anton-card border border-anton-border rounded-lg shadow-xl p-1.5 min-w-[140px] animate-fade-in"> <span className="flex items-center gap-1 px-2 py-1 text-[10px] text-orange-400">
<button onClick={() => handleCommit("update")} <Loader2 size={11} className="animate-spin" /> Committing…
className="w-full flex items-center gap-2 px-2.5 py-1.5 text-[11px] text-white hover:bg-anton-accent/10 rounded transition"> </span>
<Pencil size={11} className="text-blue-400" /> Update file ) : (
</button> <button onClick={() => setShowCommitOptions(!showCommitOptions)}
<button onClick={() => handleCommit("create")} className="flex items-center gap-1 px-2 py-1 text-[10px] text-orange-400 hover:bg-orange-400/10 rounded transition"
className="w-full flex items-center gap-2 px-2.5 py-1.5 text-[11px] text-white hover:bg-anton-accent/10 rounded transition"> title={`Commit to ${linkedRepo.name}`}>
<Plus size={11} className="text-green-400" /> Create new <GitCommitVertical size={11} /> Commit
</button> </button>
</div> )}
)} {showCommitOptions && (
</div> <div className="absolute right-0 top-full mt-1 z-20 bg-anton-card border border-anton-border rounded-lg shadow-xl p-1.5 min-w-[140px] animate-fade-in">
)} <button onClick={() => handleCommit("update")}
{commitDone && ( className="w-full flex items-center gap-2 px-2.5 py-1.5 text-[11px] text-white hover:bg-anton-accent/10 rounded transition">
<span className="flex items-center gap-1 px-2 py-1 text-[10px] text-green-400"> <Pencil size={11} className="text-blue-400" /> Update file
<Check size={11} /> Committed! </button>
</span> <button onClick={() => handleCommit("create")}
)} className="w-full flex items-center gap-2 px-2.5 py-1.5 text-[11px] text-white hover:bg-anton-accent/10 rounded transition">
<button onClick={handleDownload} className="p-1.5 text-anton-muted hover:text-white transition" title="Download"> <Plus size={11} className="text-green-400" /> Create new
<Download size={12} /> </button>
</button> </div>
<button onClick={handleCopy} className="p-1.5 text-anton-muted hover:text-white transition" title="Copy"> )}
{copied ? <Check size={12} className="text-green-400" /> : <Copy size={12} />} </div>
</button> )}
{commitDone && (
<span className="flex items-center gap-1 px-2 py-1 text-[10px] text-green-400">
<Check size={11} /> Committed!
</span>
)}
<button onClick={handleDownload} className="p-1.5 text-anton-muted hover:text-white transition" title="Download">
<Download size={12} />
</button>
<button onClick={handleCopy} className="p-1.5 text-anton-muted hover:text-white transition" title="Copy">
{copied ? <Check size={12} className="text-green-400" /> : <Copy size={12} />}
</button>
</div>
</div> </div>
{/* Code */}
<SyntaxHighlighter
language={language || "text"}
style={oneDark}
customStyle={{ margin: 0, padding: "12px 16px", fontSize: "12px", lineHeight: "1.5", background: "transparent" }}
showLineNumbers={lineCount > 3}
lineNumberStyle={{ color: "#555", fontSize: "10px", paddingRight: "12px" }}
wrapLongLines
>
{code}
</SyntaxHighlighter>
</div> </div>
{/* Code */} {/* Preview Modal */}
<SyntaxHighlighter {showPreview && previewHTML && (
language={language || "text"} <UIPreview
style={oneDark} html={previewHTML}
customStyle={{ margin: 0, padding: "12px 16px", fontSize: "12px", lineHeight: "1.5", background: "transparent" }} title={filename || `${language} preview`}
showLineNumbers={lineCount > 3} onClose={() => setShowPreview(false)}
lineNumberStyle={{ color: "#555", fontSize: "10px", paddingRight: "12px" }} />
wrapLongLines )}
> </>
{code}
</SyntaxHighlighter>
</div>
); );
}); });
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment