feat: SEO audit export, default Vibe Architect, /vibe route (v2.0.0)
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect, useRef, memo } from "react";
|
||||
import { downloadSeoReport } from "@/lib/seo-report";
|
||||
import {
|
||||
MessageSquare, Send, Code2, Palette, Search,
|
||||
Trash2, Copy, Monitor, StopCircle, X, Zap, Ghost,
|
||||
Wand2, LayoutPanelLeft, Play, Orbit, Plus, Key, ShieldCheck, Wrench
|
||||
Wand2, LayoutPanelLeft, Play, Orbit, Plus, Key, ShieldCheck, Wrench, FileText
|
||||
} from "lucide-react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import remarkGfm from "remark-gfm";
|
||||
@@ -520,6 +521,7 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
|
||||
const [deviceSize, setDeviceSize] = useState<"full" | "desktop" | "tablet" | "mobile">("full");
|
||||
const deviceWidths: Record<string, string> = { full: "100%", desktop: "1280px", tablet: "768px", mobile: "375px" };
|
||||
const [isModifying, setIsModifying] = useState(false);
|
||||
const [seoAuditData, setSeoAuditData] = useState<any>(null);
|
||||
const [abortController, setAbortController] = useState<AbortController | null>(null);
|
||||
|
||||
// Agent suggestion state
|
||||
@@ -711,6 +713,7 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
|
||||
const auditRes = await fetch("/api/fetch-url?url=" + encodeURIComponent(url));
|
||||
if (auditRes.ok) {
|
||||
const d = await auditRes.json();
|
||||
setSeoAuditData(d);
|
||||
enrichedInput += "\n\n[COMPREHENSIVE SEO AUDIT - " + url + "]\n";
|
||||
enrichedInput += "== OVERALL SCORE: " + (d.scores?.overall || "?") + "/100 ==\n";
|
||||
enrichedInput += "Technical: " + (d.scores?.technical || "?") + " | Content: " + (d.scores?.content || "?") + " | Performance: " + (d.scores?.performance || "?") + " | Social: " + (d.scores?.social || "?") + "\n\n";
|
||||
@@ -911,6 +914,11 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
|
||||
setIsProcessing(false);
|
||||
}
|
||||
};
|
||||
const exportSeoReport = (format: "html" | "pdf") => {
|
||||
if (!seoAuditData) return;
|
||||
downloadSeoReport(seoAuditData, format);
|
||||
};
|
||||
|
||||
|
||||
const clearHistory = () => {
|
||||
updateActiveTab({
|
||||
@@ -1338,6 +1346,7 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
|
||||
|
||||
{/* Post-coding action buttons */}
|
||||
{msg.role === "assistant" && assistStep === "preview" && i === aiAssistHistory.length - 1 && !isProcessing && (
|
||||
<>
|
||||
<div className="mt-4 grid grid-cols-3 gap-2 animate-in zoom-in-95 duration-300">
|
||||
<Button
|
||||
onClick={() => { setShowCanvas(true); setViewMode(isPreviewRenderable(previewData as PreviewData) ? "preview" : "code"); }}
|
||||
@@ -1361,6 +1370,25 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
|
||||
<LayoutPanelLeft className="h-3.5 w-3.5 mr-1" /> <span className="truncate">Modify</span>
|
||||
</Button>
|
||||
</div>
|
||||
{currentAgent === "seo" && seoAuditData && (
|
||||
<div className="mt-2 flex gap-2 animate-in zoom-in-95 duration-300">
|
||||
<Button
|
||||
onClick={() => exportSeoReport("html")}
|
||||
variant="outline"
|
||||
className="flex-1 bg-emerald-500/10 hover:bg-emerald-500/20 border-emerald-500/20 text-emerald-300 font-black uppercase text-[9px] tracking-wider py-3 rounded-xl min-w-0"
|
||||
>
|
||||
<Download className="h-3.5 w-3.5 mr-1" /> <span className="truncate">Export HTML</span>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => exportSeoReport("pdf")}
|
||||
variant="outline"
|
||||
className="flex-1 bg-amber-500/10 hover:bg-amber-500/20 border-amber-500/20 text-amber-300 font-black uppercase text-[9px] tracking-wider py-3 rounded-xl min-w-0"
|
||||
>
|
||||
<FileText className="h-3.5 w-3.5 mr-1" /> <span className="truncate">Export PDF</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user