572 lines
32 KiB
TypeScript
572 lines
32 KiB
TypeScript
import * as XLSX from 'xlsx';
|
|
import { GoogleAdsResult, MagicWandResult } from "../types";
|
|
|
|
export const downloadFile = (filename: string, content: any, contentType: string) => {
|
|
if (typeof window === 'undefined') return;
|
|
const blob = content instanceof Blob ? content : new Blob([content], { type: contentType });
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.setAttribute("href", url);
|
|
link.setAttribute("download", filename);
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
URL.revokeObjectURL(url);
|
|
};
|
|
|
|
export const generateGoogleAdsCSV = (googleAds?: any, magic?: any): string => {
|
|
const rows: string[][] = [];
|
|
|
|
if (googleAds) {
|
|
rows.push(["GOOGLE ADS STRATEGY REPORT"]);
|
|
rows.push(["Generated at", new Date().toLocaleString()]);
|
|
rows.push(["Website", googleAds.websiteUrl || 'N/A']);
|
|
rows.push([]);
|
|
|
|
const kw = googleAds.keywords;
|
|
if (kw) {
|
|
rows.push(["KEYWORD RESEARCH"]);
|
|
rows.push(["Type", "Keyword", "CPC", "Volume", "Competition"]);
|
|
if (Array.isArray(kw.primary)) kw.primary.forEach((k: any) => rows.push(["Primary", String(k?.keyword || ''), String(k?.cpc || ''), String(k?.searchVolume || ''), String(k?.competition || '')]));
|
|
if (Array.isArray(kw.longTail)) kw.longTail.forEach((k: any) => rows.push(["Long-tail", String(k?.keyword || ''), String(k?.cpc || ''), String(k?.searchVolume || ''), String(k?.competition || '')]));
|
|
if (Array.isArray(kw.negative)) kw.negative.forEach((k: any) => rows.push(["Negative", String(k?.keyword || ''), "", "", String(k?.competition || '')]));
|
|
rows.push([]);
|
|
}
|
|
|
|
const ads = googleAds.adCopies;
|
|
if (Array.isArray(ads)) {
|
|
rows.push(["AD COPIES"]);
|
|
rows.push(["Variation", "Headlines", "Descriptions", "CTA", "Optimized", "Positioning"]);
|
|
ads.forEach((ad: any, i: number) => {
|
|
const hl = Array.isArray(ad.headlines) ? ad.headlines.join(' | ') : '';
|
|
const ds = Array.isArray(ad.descriptions) ? ad.descriptions.join(' | ') : '';
|
|
rows.push([`Var ${i + 1}`, hl, ds, String(ad?.callToAction || ''), String(ad?.mobileOptimized || 'false'), String(ad?.positioning || '')]);
|
|
});
|
|
rows.push([]);
|
|
}
|
|
|
|
const camps = googleAds.campaigns;
|
|
if (Array.isArray(camps)) {
|
|
rows.push(["CAMPAIGN STRUCTURE"]);
|
|
rows.push(["Name", "Type", "Budget", "Locations", "Targeting", "Bidding"]);
|
|
camps.forEach((c: any) => {
|
|
const t = c.targeting;
|
|
const locs = (t && Array.isArray(t.locations)) ? t.locations.join('; ') : 'All';
|
|
const demos = (t && t.demographics) ? `Age: ${t.demographics.age?.join(', ') || 'Any'}; Gender: ${t.demographics.gender?.join(', ') || 'Any'}` : 'All';
|
|
rows.push([String(c.name || ''), String(c.type || ''), `${c?.budget?.daily || 0} ${c?.budget?.currency || ''}`, locs, demos, String(c.biddingStrategy || '')]);
|
|
});
|
|
rows.push([]);
|
|
}
|
|
}
|
|
|
|
if (magic) {
|
|
rows.push(["MARKET INTELLIGENCE"]);
|
|
const ma = magic.marketAnalysis;
|
|
if (ma) {
|
|
rows.push(["Size", String(ma.industrySize || '')]);
|
|
rows.push(["Growth", String(ma.growthRate || '')]);
|
|
rows.push(["Trends", Array.isArray(ma.marketTrends) ? ma.marketTrends.join('; ') : '']);
|
|
rows.push(["Competitors", Array.isArray(ma.topCompetitors) ? ma.topCompetitors.join('; ') : '']);
|
|
rows.push([]);
|
|
}
|
|
|
|
const strats = magic.strategies;
|
|
if (Array.isArray(strats)) {
|
|
rows.push(["STRATEGIES"]);
|
|
strats.forEach((s: any) => {
|
|
rows.push(["Direction", String(s.direction || '')]);
|
|
rows.push(["Target", String(s.targetAudience || '')]);
|
|
rows.push(["ROI", String(s.expectedROI || '')]);
|
|
rows.push(["Risk", String(s.riskLevel || '')]);
|
|
rows.push(["Timeframe", String(s.timeToResults || '')]);
|
|
rows.push([]);
|
|
});
|
|
}
|
|
}
|
|
|
|
return rows.map(r => r.map(c => `"${String(c || '').replace(/"/g, '""')}"`).join(",")).join("\n");
|
|
};
|
|
|
|
export const generateGoogleAdsExcel = (googleAds?: any, magic?: any): Blob => {
|
|
const wb = XLSX.utils.book_new();
|
|
|
|
// 1. Overview Sheet
|
|
const overviewData: any[] = [
|
|
["Attribute", "Value"],
|
|
["Report Title", "Google Ads Strategy Report"],
|
|
["Generated At", new Date().toLocaleString()],
|
|
["Website URL", googleAds?.websiteUrl || magic?.websiteUrl || 'N/A'],
|
|
[],
|
|
["Performance Forecasts"],
|
|
["Est. Impressions", googleAds?.predictions?.estimatedImpressions || 'N/A'],
|
|
["Est. Clicks", googleAds?.predictions?.estimatedClicks || 'N/A'],
|
|
["Est. CTR", googleAds?.predictions?.estimatedCtr || 'N/A'],
|
|
["Est. Conversions", googleAds?.predictions?.estimatedConversions || 'N/A'],
|
|
["Est. Conversion Rate", googleAds?.predictions?.conversionRate || 'N/A'],
|
|
["Avg. CPC", googleAds?.predictions?.avgCpc || 'N/A'],
|
|
[],
|
|
["Historical Benchmarks"],
|
|
["Avg. Industry CTR", googleAds?.historicalBenchmarks?.industryAverageCtr || 'N/A'],
|
|
["Avg. Industry CPC", googleAds?.historicalBenchmarks?.industryAverageCpc || 'N/A'],
|
|
["Seasonal Trends", googleAds?.historicalBenchmarks?.seasonalTrends || 'N/A'],
|
|
["Geographic Insights", googleAds?.historicalBenchmarks?.geographicInsights || 'N/A']
|
|
];
|
|
const overviewSheet = XLSX.utils.aoa_to_sheet(overviewData);
|
|
XLSX.utils.book_append_sheet(wb, overviewSheet, "Overview");
|
|
|
|
// 2. Keywords Sheet
|
|
if (googleAds?.keywords) {
|
|
const kw = googleAds.keywords;
|
|
const kwData: any[] = [
|
|
["Type", "Keyword", "Avg. CPC", "Monthly Volume", "Competition", "Difficulty"]
|
|
];
|
|
if (Array.isArray(kw.primary)) kw.primary.forEach((k: any) => kwData.push(["Primary", k.keyword, k.cpc, k.searchVolume, k.competition, k.difficultyScore]));
|
|
if (Array.isArray(kw.longTail)) kw.longTail.forEach((k: any) => kwData.push(["Long-tail", k.keyword, k.cpc, k.searchVolume, k.competition, k.difficultyScore]));
|
|
if (Array.isArray(kw.negative)) kw.negative.forEach((k: any) => kwData.push(["Negative", k.keyword, "", "", k.competition, ""]));
|
|
|
|
const kwSheet = XLSX.utils.aoa_to_sheet(kwData);
|
|
XLSX.utils.book_append_sheet(wb, kwSheet, "Keywords");
|
|
}
|
|
|
|
// 3. Ad Copies Sheet
|
|
if (Array.isArray(googleAds?.adCopies)) {
|
|
const adData: any[] = [
|
|
["ID", "Variation", "Headlines", "Descriptions", "CTA", "Mobile Optimized", "Strategic Positioning"]
|
|
];
|
|
googleAds.adCopies.forEach((ad: any, i: number) => {
|
|
adData.push([
|
|
ad.id,
|
|
`Variation ${i + 1}`,
|
|
(ad.headlines || []).join(" | "),
|
|
(ad.descriptions || []).join(" | "),
|
|
ad.callToAction,
|
|
ad.mobileOptimized ? "Yes" : "No",
|
|
ad.positioning || "N/A"
|
|
]);
|
|
});
|
|
const adSheet = XLSX.utils.aoa_to_sheet(adData);
|
|
XLSX.utils.book_append_sheet(wb, adSheet, "Ad Copies");
|
|
}
|
|
|
|
// 4. Competitors Sheet
|
|
if (magic?.competitorInsights || magic?.marketAnalysis) {
|
|
const compData: any[] = [
|
|
["Competitor", "Website", "Est. Monthly Spend", "Target Audience", "Strengths", "Weaknesses", "Ad Strategy", "Top Keywords"]
|
|
];
|
|
if (Array.isArray(magic.competitorInsights)) {
|
|
magic.competitorInsights.forEach((c: any) => {
|
|
compData.push([
|
|
c.competitor,
|
|
c.website || 'N/A',
|
|
c.estimatedSpend || 'N/A',
|
|
c.targetAudience || 'N/A',
|
|
(c.strengths || []).join(", "),
|
|
(c.weaknesses || []).join(", "),
|
|
c.adStrategy,
|
|
(c.topKeywords || []).join(", ")
|
|
]);
|
|
});
|
|
}
|
|
const compSheet = XLSX.utils.aoa_to_sheet(compData);
|
|
XLSX.utils.book_append_sheet(wb, compSheet, "Competitor Analysis");
|
|
}
|
|
|
|
// 5. Strategies Sheet
|
|
if (Array.isArray(magic?.strategies)) {
|
|
const stratData: any[] = [
|
|
["ID", "Strategic Direction", "Rationale", "Target Audience", "Competitive Advantage", "Expected ROI", "Risk Level", "Time to Results", "Success Metrics"]
|
|
];
|
|
magic.strategies.forEach((s: any) => {
|
|
stratData.push([
|
|
s.id,
|
|
s.direction,
|
|
s.rationale,
|
|
s.targetAudience,
|
|
s.competitiveAdvantage,
|
|
s.expectedROI,
|
|
s.riskLevel,
|
|
s.timeToResults,
|
|
(s.successMetrics || []).join(", ")
|
|
]);
|
|
});
|
|
const stratSheet = XLSX.utils.aoa_to_sheet(stratData);
|
|
XLSX.utils.book_append_sheet(wb, stratSheet, "Strategies");
|
|
}
|
|
|
|
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
|
return new Blob([wbout], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
|
|
};
|
|
|
|
export const generateGoogleAdsHTML = (googleAds?: any, magic?: any): string => {
|
|
const data = JSON.stringify({ googleAds, magic }, null, 2);
|
|
|
|
return `<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>360° Google Ads Strategy Intelligence Report</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap" rel="stylesheet">
|
|
<style>
|
|
body { font-family: 'Outfit', sans-serif; background-color: #020617; color: #f8fafc; }
|
|
.glass { background: rgba(30, 41, 59, 0.7); backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, 0.1); }
|
|
.accent-gradient { background: linear-gradient(135deg, #6366f1 0%, #a855f7 100%); }
|
|
.text-gradient { background: linear-gradient(to right, #818cf8, #c084fc); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
|
</style>
|
|
</head>
|
|
<body class="p-4 md:p-8 lg:p-12">
|
|
<div class="max-w-7xl mx-auto space-y-12">
|
|
<!-- Header -->
|
|
<header class="flex flex-col md:flex-row justify-between items-start md:items-center gap-6 pb-8 border-b border-slate-800">
|
|
<div>
|
|
<h1 class="text-4xl md:text-6xl font-extrabold text-gradient tracking-tight">Strategy Intelligence</h1>
|
|
<p class="text-slate-400 mt-2 text-lg">360° Campaign Architecture for ${googleAds?.websiteUrl || 'New Project'}</p>
|
|
</div>
|
|
<div class="glass p-4 rounded-3xl flex items-center gap-4">
|
|
<div class="text-right">
|
|
<p class="text-xs text-slate-500 uppercase font-extrabold tracking-widest">Generated On</p>
|
|
<p class="font-semibold">${new Date().toLocaleDateString()}</p>
|
|
</div>
|
|
<div class="w-12 h-12 accent-gradient rounded-2xl flex items-center justify-center font-bold text-xl">PA</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- KPI Grid -->
|
|
<section class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
|
<div class="glass p-6 rounded-[2rem] border-indigo-500/20">
|
|
<p class="text-slate-500 text-xs font-bold uppercase tracking-widest">Est. Monthly Impressions</p>
|
|
<p class="text-3xl font-extrabold mt-2 text-indigo-400">${googleAds?.predictions?.estimatedImpressions || '15k-25k'}</p>
|
|
<div class="mt-4 h-1 w-full bg-slate-800 rounded-full overflow-hidden"><div class="h-full bg-indigo-500 w-2/3"></div></div>
|
|
</div>
|
|
<div class="glass p-6 rounded-[2rem] border-purple-500/20">
|
|
<p class="text-slate-500 text-xs font-bold uppercase tracking-widest">Target CTR</p>
|
|
<p class="text-3xl font-extrabold mt-2 text-purple-400">${googleAds?.predictions?.estimatedCtr || '3.5%'}</p>
|
|
<div class="mt-4 h-1 w-full bg-slate-800 rounded-full overflow-hidden"><div class="h-full bg-purple-500 w-1/2"></div></div>
|
|
</div>
|
|
<div class="glass p-6 rounded-[2rem] border-emerald-500/20">
|
|
<p class="text-slate-500 text-xs font-bold uppercase tracking-widest">Est. Conversions</p>
|
|
<p class="text-3xl font-extrabold mt-2 text-emerald-400">${googleAds?.predictions?.estimatedConversions || '30-50'}</p>
|
|
<div class="mt-4 h-1 w-full bg-slate-800 rounded-full overflow-hidden"><div class="h-full bg-emerald-500 w-1/3"></div></div>
|
|
</div>
|
|
<div class="glass p-6 rounded-[2rem] border-amber-500/20">
|
|
<p class="text-slate-500 text-xs font-bold uppercase tracking-widest">Industry Avg CTR</p>
|
|
<p class="text-3xl font-extrabold mt-2 text-amber-400">${googleAds?.historicalBenchmarks?.industryAverageCtr || '3.1%'}</p>
|
|
<div class="mt-4 h-1 w-full bg-slate-800 rounded-full overflow-hidden"><div class="h-full bg-amber-500 w-4/5"></div></div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Analytics Visuals -->
|
|
<section class="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
<div class="lg:col-span-2 glass p-8 rounded-[2.5rem]">
|
|
<h2 class="text-2xl font-extrabold mb-6">Performance Forecast</h2>
|
|
<div class="h-[350px]">
|
|
<canvas id="performanceChart"></canvas>
|
|
</div>
|
|
</div>
|
|
<div class="glass p-8 rounded-[2.5rem]">
|
|
<h2 class="text-2xl font-extrabold mb-6">Device Distribution</h2>
|
|
<div class="h-[300px]">
|
|
<canvas id="deviceChart"></canvas>
|
|
</div>
|
|
<div class="mt-8 space-y-4">
|
|
<div class="flex justify-between items-center text-sm">
|
|
<span class="flex items-center gap-2"><div class="w-3 h-3 rounded-full bg-indigo-500"></div> Mobile</span>
|
|
<span class="font-bold">${googleAds?.campaigns?.[0]?.targeting?.devices?.mobile || '60%'}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center text-sm">
|
|
<span class="flex items-center gap-2"><div class="w-3 h-3 rounded-full bg-purple-500"></div> Desktop</span>
|
|
<span class="font-bold">${googleAds?.campaigns?.[0]?.targeting?.devices?.desktop || '30%'}</span>
|
|
</div>
|
|
<div class="flex justify-between items-center text-sm">
|
|
<span class="flex items-center gap-2"><div class="w-3 h-3 rounded-full bg-slate-500"></div> Tablet</span>
|
|
<span class="font-bold">${googleAds?.campaigns?.[0]?.targeting?.devices?.tablet || '10%'}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Keyword Intelligence -->
|
|
<section class="space-y-6">
|
|
<div class="flex justify-between items-center">
|
|
<h2 class="text-3xl font-extrabold tracking-tight">Keyword Intelligence</h2>
|
|
<span class="glass px-4 py-1.5 rounded-full text-xs font-bold uppercase tracking-widest text-indigo-400">Semantic Mapping Enabled</span>
|
|
</div>
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<!-- Primary -->
|
|
<div class="space-y-4">
|
|
<h3 class="text-slate-400 font-bold uppercase tracking-widest text-xs flex items-center gap-2">
|
|
<div class="w-2 h-2 rounded-full bg-indigo-500"></div> Primary Keywords
|
|
</h3>
|
|
${(googleAds?.keywords?.primary || []).slice(0, 10).map((k: any) => `
|
|
<div class="glass p-4 rounded-2xl flex justify-between items-center group hover:border-indigo-500/50 transition-all cursor-default">
|
|
<span class="font-semibold">${k.keyword}</span>
|
|
<span class="text-xs text-indigo-400 font-bold">${k.cpc || '$1.50'}</span>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
<!-- Long-Tail -->
|
|
<div class="space-y-4">
|
|
<h3 class="text-slate-400 font-bold uppercase tracking-widest text-xs flex items-center gap-2">
|
|
<div class="w-2 h-2 rounded-full bg-purple-500"></div> Long-Tail Intent
|
|
</h3>
|
|
${(googleAds?.keywords?.longTail || []).slice(0, 10).map((k: any) => `
|
|
<div class="glass p-4 rounded-2xl flex justify-between items-center group hover:border-purple-500/50 transition-all cursor-default">
|
|
<span class="font-semibold text-sm">${k.keyword}</span>
|
|
<span class="text-[10px] text-slate-500 font-bold">${k.competition || 'low'}</span>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
<!-- Negative -->
|
|
<div class="space-y-4">
|
|
<h3 class="text-slate-400 font-bold uppercase tracking-widest text-xs flex items-center gap-2">
|
|
<div class="w-2 h-2 rounded-full bg-rose-500"></div> Exclusion List
|
|
</h3>
|
|
${(googleAds?.keywords?.negative || []).slice(0, 8).map((k: any) => `
|
|
<div class="glass p-4 rounded-2xl flex justify-between items-center group hover:border-rose-500/50 transition-all cursor-default grayscale opacity-50">
|
|
<span class="font-semibold text-xs line-through text-slate-400">${k.keyword}</span>
|
|
<span class="text-[10px] text-rose-500/50 font-bold">EXCLUDE</span>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Ad Copies -->
|
|
<section class="space-y-8">
|
|
<h2 class="text-3xl font-extrabold tracking-tight">High-Performance Ad Copy Suite</h2>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
${(googleAds?.adCopies || []).map((ad: any, i: number) => `
|
|
<div class="glass rounded-[2rem] overflow-hidden flex flex-col">
|
|
<div class="p-6 border-b border-slate-800 flex justify-between items-center">
|
|
<span class="text-xs font-bold uppercase tracking-widest text-slate-500">Variation ${i + 1}</span>
|
|
<span class="bg-indigo-500/20 text-indigo-400 px-2.5 py-1 rounded-full text-[10px] font-black">${(ad.campaignType || 'Search').toUpperCase()}</span>
|
|
</div>
|
|
<div class="p-8 space-y-6 flex-grow">
|
|
${(ad.headlines || []).map((h: any) => `
|
|
<div class="text-xl font-bold text-slate-100 leading-tight">${h}</div>
|
|
`).join('')}
|
|
<div class="h-px w-full bg-slate-800"></div>
|
|
${(ad.descriptions || []).map((d: any) => `
|
|
<div class="text-slate-400 text-sm leading-relaxed italic border-l-2 border-slate-700 pl-4">${d}</div>
|
|
`).join('')}
|
|
</div>
|
|
<div class="p-6 bg-slate-900/50 border-t border-slate-800 flex justify-between items-center">
|
|
<div class="text-xs font-bold text-indigo-400">${ad.callToAction}</div>
|
|
<div class="flex gap-1">
|
|
<div class="w-1 h-3 rounded-full ${ad.mobileOptimized ? 'bg-emerald-500' : 'bg-slate-700'}"></div>
|
|
<div class="w-3 h-3 rounded-full ${ad.mobileOptimized ? 'bg-emerald-500' : 'bg-slate-700'}"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Competitive Analysis -->
|
|
${magic?.competitorInsights ? `
|
|
<section class="space-y-8">
|
|
<div class="flex justify-between items-end">
|
|
<h2 class="text-3xl font-extrabold tracking-tight">Competitive Intelligence Matrix</h2>
|
|
<div class="text-right">
|
|
<p class="text-[10px] text-slate-500 uppercase font-black tracking-[0.2em] mb-1">Market Sentiment</p>
|
|
<div class="flex gap-1.5 justify-end">
|
|
<div class="w-4 h-2 rounded-full bg-emerald-500"></div>
|
|
<div class="w-4 h-2 rounded-full bg-emerald-500"></div>
|
|
<div class="w-4 h-2 rounded-full bg-emerald-400"></div>
|
|
<div class="w-4 h-2 rounded-full bg-slate-800"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
${(magic.competitorInsights || []).map((c: any) => `
|
|
<div class="glass p-8 rounded-[2.5rem] space-y-8">
|
|
<div class="flex justify-between items-start">
|
|
<div>
|
|
<h3 class="text-2xl font-black">${c.competitor}</h3>
|
|
<p class="text-indigo-400 text-xs font-bold mt-1">${c.website || 'Direct Competitor'}</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold tracking-widest">Est. Spend</p>
|
|
<p class="text-sm font-black text-rose-400">${c.estimatedSpend || 'Undisclosed'}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-6">
|
|
<div class="space-y-3">
|
|
<p class="text-[10px] text-emerald-400 uppercase font-black tracking-widest">Core Strengths</p>
|
|
<ul class="text-sm space-y-2 text-slate-300">
|
|
${(c.strengths || []).map((s: any) => `<li class="flex items-center gap-2"><div class="w-1.5 h-1.5 rounded-full bg-emerald-500"></div> ${s}</li>`).join('')}
|
|
</ul>
|
|
</div>
|
|
<div class="space-y-3">
|
|
<p class="text-[10px] text-rose-400 uppercase font-black tracking-widest">Weaknesses</p>
|
|
<ul class="text-sm space-y-2 text-slate-400">
|
|
${(c.weaknesses || []).map((w: any) => `<li class="flex items-center gap-2"><div class="w-1.5 h-1.5 rounded-full bg-rose-500"></div> ${w}</li>`).join('')}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-indigo-500/5 p-6 rounded-2xl border border-indigo-500/10">
|
|
<p class="text-[10px] text-indigo-400 uppercase font-bold tracking-widest mb-3">Counter-Strategy Rationale</p>
|
|
<p class="text-sm text-slate-300 italic leading-relaxed">"${c.adStrategy}"</p>
|
|
</div>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</section>
|
|
` : ''}
|
|
|
|
<!-- Strategies -->
|
|
${magic?.strategies ? `
|
|
<section class="space-y-8">
|
|
<h2 class="text-3xl font-extrabold tracking-tight">Strategic Directions</h2>
|
|
<div class="space-y-8">
|
|
${(magic.strategies || []).map((s: any, idx: number) => `
|
|
<div class="glass overflow-hidden rounded-[3rem] relative">
|
|
<div class="absolute top-0 right-0 w-64 h-64 accent-gradient blur-[120px] opacity-10"></div>
|
|
<div class="p-10 relative z-10 grid grid-cols-1 lg:grid-cols-4 gap-12">
|
|
<!-- Left: Header -->
|
|
<div class="lg:col-span-1 space-y-6">
|
|
<div class="w-16 h-16 rounded-3xl accent-gradient flex items-center justify-center font-black text-2xl">${idx + 1}</div>
|
|
<div>
|
|
<h3 class="text-2xl font-extrabold leading-tight">${s.direction}</h3>
|
|
<span class="inline-block mt-4 glass px-4 py-1 rounded-full text-[10px] font-black uppercase tracking-widest ${s.riskLevel === 'low' ? 'text-emerald-400' : 'text-amber-400'}">${s.riskLevel || 'low'} risk profile</span>
|
|
</div>
|
|
<div class="pt-6 space-y-4">
|
|
<div>
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold tracking-widest">Expected ROI</p>
|
|
<p class="text-xl font-black text-emerald-400">${s.expectedROI}</p>
|
|
</div>
|
|
<div>
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold tracking-widest">Time to Impact</p>
|
|
<p class="text-xl font-black text-slate-100">${s.timeToResults}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Middle: Context -->
|
|
<div class="lg:col-span-2 space-y-8">
|
|
<div>
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold tracking-widest mb-4">Strategic Rationale</p>
|
|
<p class="text-lg text-slate-200 leading-relaxed font-light">${s.rationale}</p>
|
|
</div>
|
|
<div class="grid grid-cols-2 gap-8">
|
|
<div class="bg-white/5 p-6 rounded-[2rem]">
|
|
<p class="text-[10px] text-indigo-400 uppercase font-black tracking-widest mb-3">Target Audience</p>
|
|
<p class="text-sm font-semibold">${s.targetAudience}</p>
|
|
</div>
|
|
<div class="bg-white/5 p-6 rounded-[2rem]">
|
|
<p class="text-[10px] text-purple-400 uppercase font-black tracking-widest mb-3">Competitive Edge</p>
|
|
<p class="text-sm font-semibold">${s.competitiveAdvantage}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right: Channels/Metrics -->
|
|
<div class="lg:col-span-1 bg-slate-900/80 p-8 rounded-[2.5rem] space-y-8 border border-white/5">
|
|
<div>
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold tracking-widest mb-6">Channel Matrix</p>
|
|
<div class="space-y-4">
|
|
${Object.entries(s.estimatedBudgetAllocation || {}).map(([c, v]: [string, any]) => `
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between text-xs">
|
|
<span class="capitalize text-slate-300">${c}</span>
|
|
<span class="font-bold text-slate-100">${v}%</span>
|
|
</div>
|
|
<div class="h-1.5 w-full bg-slate-800 rounded-full overflow-hidden">
|
|
<div class="h-full accent-gradient" style="width: ${v}%"></div>
|
|
</div>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</div>
|
|
<div class="pt-6 border-t border-slate-800">
|
|
<p class="text-[10px] text-slate-500 uppercase font-bold tracking-widest mb-4">Success Thresholds</p>
|
|
<div class="flex flex-wrap gap-2 text-[10px]">
|
|
${(s.successMetrics || []).map((m: any) => `
|
|
<span class="bg-emerald-500/10 text-emerald-400 border border-emerald-500/20 px-2 py-1 rounded-md font-bold uppercase">${m}</span>
|
|
`).join('')}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
</section>
|
|
` : ''}
|
|
|
|
<!-- Footer -->
|
|
<footer class="pt-12 border-t border-slate-800 flex flex-col md:flex-row justify-between items-center gap-6 pb-12">
|
|
<p class="text-slate-500 text-sm font-semibold">© ${new Date().getFullYear()} PromptArch Intelligence Unit • Confident Strategic Asset</p>
|
|
<div class="flex gap-4">
|
|
<div class="w-8 h-8 rounded-full bg-slate-800 flex items-center justify-center text-xs font-bold">PA</div>
|
|
<div class="w-8 h-8 rounded-full bg-slate-800 flex items-center justify-center text-xs font-bold italic">Q</div>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
|
|
<script>
|
|
// Performance Forecast Chart
|
|
const ctxPerf = document.getElementById('performanceChart').getContext('2d');
|
|
new Chart(ctxPerf, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4', 'Week 5', 'Week 6', 'Week 12'],
|
|
datasets: [{
|
|
label: 'Predicted Growth (Aggressive)',
|
|
data: [10, 25, 45, 80, 110, 160, 450],
|
|
borderColor: '#6366f1',
|
|
backgroundColor: 'rgba(99, 102, 241, 0.1)',
|
|
fill: true,
|
|
tension: 0.4,
|
|
pointRadius: 6,
|
|
pointBackgroundColor: '#fff'
|
|
}, {
|
|
label: 'Predicted Growth (Standard)',
|
|
data: [5, 12, 28, 55, 75, 100, 280],
|
|
borderColor: '#a855f7',
|
|
backgroundColor: 'transparent',
|
|
borderDash: [5, 5],
|
|
tension: 0.4,
|
|
pointRadius: 4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: { legend: { labels: { color: '#94a3b8', font: { family: 'Outfit', weight: 'bold' } } } },
|
|
scales: {
|
|
x: { grid: { display: false }, ticks: { color: '#475569' } },
|
|
y: { grid: { color: 'rgba(255,255,255,0.05)' }, ticks: { color: '#475569' } }
|
|
}
|
|
}
|
|
});
|
|
|
|
// Device Chart
|
|
const ctxDev = document.getElementById('deviceChart').getContext('2d');
|
|
new Chart(ctxDev, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Mobile', 'Desktop', 'Tablet'],
|
|
datasets: [{
|
|
data: [60, 30, 10],
|
|
backgroundColor: ['#6366f1', '#a855f7', '#475569'],
|
|
borderWidth: 0,
|
|
hoverOffset: 12
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
cutout: '80%',
|
|
plugins: { legend: { display: false } }
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>`;
|
|
};
|