diff --git a/src/components/analytics/ErrorTracker.tsx b/src/components/analytics/ErrorTracker.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/analytics/MetricsDashboard.tsx b/src/components/analytics/MetricsDashboard.tsx new file mode 100644 index 0000000..b24576e --- /dev/null +++ b/src/components/analytics/MetricsDashboard.tsx @@ -0,0 +1,69 @@ + +import React from 'react'; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { AreaChart, DonutChart, BarChart } from '@tremor/react'; + +const chartdata = [ + { date: 'Jan 22', Organic: 2890, Paid: 2338 }, + { date: 'Feb 22', Organic: 2756, Paid: 2103 }, + { date: 'Mar 22', Organic: 3322, Paid: 2194 }, + { date: 'Apr 22', Organic: 3470, Paid: 2108 }, + { date: 'May 22', Organic: 3475, Paid: 1812 }, + { date: 'Jun 22', Organic: 3129, Paid: 1726 }, +]; + +const trafficSource = [ + { name: 'Google Search', value: 9800 }, + { name: 'Direct', value: 4567 }, + { name: 'Social', value: 3908 }, + { name: 'Referral', value: 2400 }, +]; + +const valueFormatter = (number: number) => `$ ${new Intl.NumberFormat('us').format(number).toString()}`; + +export const MetricsDashboard = () => ( +
+ {/* KPI 1: Traffic Growth */} + +

Traffic Growth & Sources

+ console.log(v)} + showAnimation={true} + /> +
+ + {/* KPI 2: Source Breakdown */} + +

Traffic Sources

+ +
+ + {/* KPI 3: Engagement */} + +

Monthly Active Users

+ +
+
+); diff --git a/src/components/analytics/PerformanceDashboard.tsx b/src/components/analytics/PerformanceDashboard.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/analytics/UsageStats.tsx b/src/components/analytics/UsageStats.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/assembler/BulkGenerator.tsx b/src/components/assembler/BulkGenerator.tsx new file mode 100644 index 0000000..0f293ac --- /dev/null +++ b/src/components/assembler/BulkGenerator.tsx @@ -0,0 +1,143 @@ +import React, { useState } from 'react'; +import { useQuery, useMutation } from '@tanstack/react-query'; +import { Card } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@/components/ui/table"; +import { Badge } from "@/components/ui/badge"; +import { Loader2, Play, Users, MapPin, Calendar } from 'lucide-react'; +import { toast } from 'sonner'; + +const BulkGenerator = () => { + const [selectedTemplate, setSelectedTemplate] = useState(null); + const [quantity, setQuantity] = useState(10); + const [jobStatus, setJobStatus] = useState<'idle' | 'running' | 'complete'>('idle'); + + const { data: templates } = useQuery({ + queryKey: ['templates'], + queryFn: async () => { + const res = await fetch('/api/assembler/templates'); + return res.json(); + } + }); + + const runBulkJob = useMutation({ + mutationFn: async () => { + // Placeholder for actual bulk job logic (Phase 5.b) + return new Promise((resolve) => setTimeout(resolve, 3000)); + }, + onMutate: () => setJobStatus('running'), + onSuccess: () => { + setJobStatus('complete'); + toast.success(`Generated ${quantity} articles successfully!`); + } + }); + + return ( +
+ +
+

1. Select Template

+
+ {templates?.map((t: any) => ( +
setSelectedTemplate(t.id)} + className={`p-3 rounded-md border cursor-pointer transition-colors ${selectedTemplate === t.id + ? 'bg-primary/10 border-primary' + : 'bg-card border-border hover:border-primary/50' + }`} + > +
{t.pattern_name}
+
{t.structure_type || 'Custom'}
+
+ ))} +
+
+ +
+

2. Data Source

+
+ + +
+
+ +
+

3. Quantity

+ setQuantity(Number(e.target.value))} + min={1} + max={1000} + /> +
+ + +
+ +
+ +
+

Job Queue & Results

+
+ {jobStatus === 'complete' ? ( +
+ + + + Article Title + Status + SEO Score + Date + + + + {Array.from({ length: 5 }).map((_, i) => ( + + Top 10 Plumbing Tips in New York + Ready + 92/100 + {new Date().toLocaleDateString()} + + ))} + +
+
+ ) : ( +
+ +

No jobs running

+
+ )} +
+
+
+ ); +}; + +export default BulkGenerator; diff --git a/src/components/assembler/ContentAssembly.tsx b/src/components/assembler/ContentAssembly.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/assembler/PreviewPanel.tsx b/src/components/assembler/PreviewPanel.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/assembler/QualityChecker.tsx b/src/components/assembler/QualityChecker.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/assembler/SEOOptimizer.tsx b/src/components/assembler/SEOOptimizer.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/assembler/SpintaxExpander.tsx b/src/components/assembler/SpintaxExpander.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/components/assembler/TemplateComposer.tsx b/src/components/assembler/TemplateComposer.tsx new file mode 100644 index 0000000..2b4b2fa --- /dev/null +++ b/src/components/assembler/TemplateComposer.tsx @@ -0,0 +1,239 @@ +import React, { useState, useEffect } from 'react'; +import { useQuery, useMutation } from '@tanstack/react-query'; +import { Card } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Textarea } from "@/components/ui/textarea"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Play, Save, RefreshCw, Wand2, Plus, Trash2 } from 'lucide-react'; +import { toast } from 'sonner'; + +interface Variable { + key: string; + value: string; +} + +const TemplateComposer = () => { + const [template, setTemplate] = useState(''); + const [variables, setVariables] = useState([ + { key: 'city', value: 'New York' }, + { key: 'niche', value: 'Plumbing' }, + { key: 'service', value: 'Emergency Repair' } + ]); + const [previewContent, setPreviewContent] = useState(''); + const [templates, setTemplates] = useState([]); + const [currentTemplateId, setCurrentTemplateId] = useState(null); + const [templateName, setTemplateName] = useState('Untitled Template'); + + // Load templates on mount + const fetchTemplates = useQuery({ + queryKey: ['templates'], + queryFn: async () => { + const res = await fetch('/api/assembler/templates'); + return res.json(); + } + }); + + const saveTemplate = useMutation({ + mutationFn: async () => { + const res = await fetch('/api/assembler/templates', { + method: 'POST', + body: JSON.stringify({ + id: currentTemplateId, + title: templateName, + content: template + }) + }); + return res.json(); + }, + onSuccess: (data) => { + toast.success('Template saved successfully!'); + fetchTemplates.refetch(); + if (data.id) setCurrentTemplateId(data.id); + }, + onError: () => toast.error('Failed to save template') + }); + + const loadTemplate = (tmpl: any) => { + setTemplate(tmpl.pattern_structure || ''); + setTemplateName(tmpl.pattern_name || 'Untitled'); + setCurrentTemplateId(tmpl.id); + toast.info(`Loaded: ${tmpl.pattern_name}`); + }; + const generatePreview = useMutation({ + mutationFn: async () => { + const varMap = variables.reduce((acc, curr) => { + if (curr.key) acc[curr.key] = curr.value; + return acc; + }, {} as Record); + + const res = await fetch('/api/assembler/preview', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ template, variables: varMap }) + }); + + if (!res.ok) throw new Error('Generation failed'); + return res.json(); + }, + onSuccess: (data) => { + setPreviewContent(data.content); + toast.success('Preview generated successfully'); + }, + onError: () => { + toast.error('Failed to generate preview'); + } + }); + + const addVariable = () => { + setVariables([...variables, { key: '', value: '' }]); + }; + + const updateVariable = (index: number, field: 'key' | 'value', val: string) => { + const newVars = [...variables]; + newVars[index][field] = val; + setVariables(newVars); + }; + + const removeVariable = (index: number) => { + const newVars = [...variables]; + newVars.splice(index, 1); + setVariables(newVars); + }; + + const insertVariable = (key: string) => { + setTemplate(prev => prev + `{{${key}}}`); + }; + + // Initialize with a demo template if empty + useEffect(() => { + if (!template) { + setTemplate("Welcome to {{city}}'s best {{niche}} provider!\n\nWe offer {premium|high-quality|top-rated} {{service}} for all residential customers.\n\n{Call us today|Contact us now|Get a quote} to learn more."); + } + }, []); + + return ( +
+ + {/* Left Panel: Variables & Inputs */} +
+ +
+ + +
+ +
+ {variables.map((v, i) => ( +
+
+ updateVariable(i, 'key', e.target.value)} + className="h-8 text-xs font-mono" + /> + +
+ updateVariable(i, 'value', e.target.value)} + className="h-8 text-xs" + /> + {v.key && ( + + )} +
+ ))} +
+
+
+ + {/* Center Panel: Template Editor */} +
+ +
+
+ + setTemplateName(e.target.value)} + className="h-7 text-sm font-semibold bg-transparent border-transparent hover:border-border focus:border-border w-48" + /> +
+
+ + +
+
+
+ +
+ {article.meta_desc?.length || 0}/160 +
+
+
+
+ + +
+ +
+
+ + +
+ +
+ Saved + +
+
+ + +
+ + + + +
+
Start writing...

'} /> +
+
+
+ + +
+ +
+

SEO Tools

+ +
+
+ Readability + Good +
+ +
+ Keyword Density + 2.3% +
+ +
+ Word Count + 1,247 +
+
+
+ + +
+

Spintax

+ +
+
+ Variations + 432 +
+ + +
+
+ + +
+

Featured Image

+ + {article.featured_image_url ? ( + Featured + ) : ( +
+ No image +
+ )} + + +
+ + +
+

Activity Log

+ +
+
+
2 hours ago
+
Article generated
+
+
+
1 hour ago
+
SEO score calculated
+
+
+
+
+
+ + + diff --git a/src/pages/admin/factory/index.astro b/src/pages/admin/factory/index.astro new file mode 100644 index 0000000..4bf81c7 --- /dev/null +++ b/src/pages/admin/factory/index.astro @@ -0,0 +1,63 @@ +/** + * Factory Floor - Main Production Page + * Kanban/Grid view switcher for articles + */ + +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; + +const currentPath = Astro.url.pathname; +const action = Astro.url.searchParams.get('action'); +--- + + +
+ +
+
+

Factory Floor

+

Content production workflow

+
+ +
+ + + + + +
+

Factory view components will load here

+

Kanban Board and Bulk Grid components coming next...

+
+
+
diff --git a/src/pages/admin/factory/jobs.astro b/src/pages/admin/factory/jobs.astro new file mode 100644 index 0000000..1c32891 --- /dev/null +++ b/src/pages/admin/factory/jobs.astro @@ -0,0 +1,19 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import JobsManager from '@/components/admin/jobs/JobsManager'; +--- + + +
+
+
+

โš™๏ธ Generation Queue

+

+ Monitor background processing jobs. Watch content generation progress in real-time. +

+
+
+ + +
+
diff --git a/src/pages/admin/factory/kanban.astro b/src/pages/admin/factory/kanban.astro new file mode 100644 index 0000000..8b0381c --- /dev/null +++ b/src/pages/admin/factory/kanban.astro @@ -0,0 +1,33 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import KanbanBoard from '@/components/admin/factory/KanbanBoard'; +import { Button } from '@/components/ui/button'; +import { Plus } from 'lucide-react'; +--- + + +
+
+
+

+ ๐Ÿญ Content Factory + Beta +

+

+ Drag and drop articles to move them through the production pipeline. +

+
+ +
+ +
+ +
+
+
diff --git a/src/pages/admin/index.astro b/src/pages/admin/index.astro new file mode 100644 index 0000000..69956e9 --- /dev/null +++ b/src/pages/admin/index.astro @@ -0,0 +1,15 @@ +--- +import AdminLayout from '../../layouts/AdminLayout.astro'; +import SystemMonitor from '../../components/admin/dashboard/SystemMonitor'; +--- + + +
+
+

Command Station

+

System Monitoring, Sub-Station Status, and Content Integrity.

+
+ + +
+
diff --git a/src/pages/admin/intelligence/avatar-metrics.astro b/src/pages/admin/intelligence/avatar-metrics.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/intelligence/avatars.astro b/src/pages/admin/intelligence/avatars.astro new file mode 100644 index 0000000..cbe96e3 --- /dev/null +++ b/src/pages/admin/intelligence/avatars.astro @@ -0,0 +1,107 @@ +/** + * Avatar Intelligence Management + * Full CRUD for avatar_intelligence collection + */ + +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import { getDirectusClient } from '@/lib/directus/client'; +import { readItems } from '@directus/sdk'; + +const client = getDirectusClient(); + +let avatars = []; +let error = null; + +try { + avatars = await client.request(readItems('avatar_intelligence', { + fields: ['*'], + sort: ['base_name'], + })); +} catch (e) { + console.error('Error fetching avatars:', e); + error = e instanceof Error ? e.message : 'Unknown error'; +} +--- + + +
+ +
+
+

Avatar Intelligence

+

Manage persona profiles and variants

+
+
+ + + + โœจ New Avatar + +
+
+ + {error && ( +
+ Error: {error} +
+ )} + + +
+
+
Total Avatars
+
{avatars.length}
+
+
+ + +
+ {avatars.map((avatar: any) => ( +
+
+

{avatar.base_name}

+ +
+ +
+
+ Wealth Cluster: + {avatar.wealth_cluster || 'Not set'} +
+ + {avatar.business_niches && ( +
+ Niches: +
+ {avatar.business_niches.slice(0, 3).map((niche: string) => ( + + {niche} + + ))} + {avatar.business_niches.length > 3 && ( + + +{avatar.business_niches.length - 3} more + + )} +
+
+ )} +
+
+ ))} + + {avatars.length === 0 && !error && ( +
+

No avatars found. Create your first one!

+
+ )} +
+
+
diff --git a/src/pages/admin/intelligence/geo-targeting.astro b/src/pages/admin/intelligence/geo-targeting.astro new file mode 100644 index 0000000..54eea45 --- /dev/null +++ b/src/pages/admin/intelligence/geo-targeting.astro @@ -0,0 +1,21 @@ +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import { GeoMap } from '@/components/intelligence/GeoMap'; +import { MetricsDashboard } from '@/components/analytics/MetricsDashboard'; +--- + + +
+
+

Market Dominance Map

+

Visualize your campaign performance across different territories.

+
+ + + +
+

Regional Performance

+ +
+
+
diff --git a/src/pages/admin/intelligence/index.astro b/src/pages/admin/intelligence/index.astro new file mode 100644 index 0000000..6853c49 --- /dev/null +++ b/src/pages/admin/intelligence/index.astro @@ -0,0 +1,80 @@ +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import PatternAnalyzer from '@/components/intelligence/PatternAnalyzer'; +import GeoTargeting from '@/components/intelligence/GeoTargeting'; +import AvatarMetrics from '@/components/intelligence/AvatarMetrics'; +import { Brain, Globe, Users } from 'lucide-react'; + +// Server-side data fetching (simulated for Phase 4 or connected to local API logic) +// In a real scenario, we might call the DB directly here. +// For now, we'll import the mock data logic or just duplicate the mock data for SSR, +// to ensure the page renders with data immediately. +// We can also fetch from our own API if running, but during build, the API might not be up. +// So we will define the initial data here. + +const patterns = [ + { id: '1', name: 'High-Value Listicle Structure', type: 'structure', confidence: 0.92, occurrences: 145, last_detected: '2023-10-25', tags: ['listicle', 'viral', 'b2b'] }, + { id: '2', name: 'Emotional Storytelling Hook', type: 'semantic', confidence: 0.88, occurrences: 89, last_detected: '2023-10-26', tags: ['hook', 'emotional', 'intro'] }, + { id: '3', name: 'Data-Backed CTA', type: 'conversion', confidence: 0.76, occurrences: 230, last_detected: '2023-10-24', tags: ['cta', 'sales', 'closing'] }, + { id: '4', name: 'Contrarian Viewpoint', type: 'semantic', confidence: 0.65, occurrences: 54, last_detected: '2023-10-22', tags: ['opinion', 'debate'] }, + { id: '5', name: 'How-To Guide Format', type: 'structure', confidence: 0.95, occurrences: 310, last_detected: '2023-10-27', tags: ['educational', 'long-form'] } +] as any[]; + +const geoClusters = [ + { id: '1', name: 'North America Tech Hubs', location: '37.7749, -122.4194', audience_size: 154000, engagement_rate: 0.45, dominant_topic: 'SaaS Marketing' }, + { id: '2', name: 'London Finance Sector', location: '51.5074, -0.1278', audience_size: 89000, engagement_rate: 0.38, dominant_topic: 'FinTech' }, + { id: '3', name: 'Singapore Crypto', location: '1.3521, 103.8198', audience_size: 65000, engagement_rate: 0.52, dominant_topic: 'Web3' }, + { id: '4', name: 'Berlin Startup Scene', location: '52.5200, 13.4050', audience_size: 42000, engagement_rate: 0.41, dominant_topic: 'Growth Hacking' }, + { id: '5', name: 'Sydney E-comm', location: '-33.8688, 151.2093', audience_size: 38000, engagement_rate: 0.35, dominant_topic: 'DTC Brands' } +] as any[]; + +const avatarMetrics = [ + { id: '1', avatar_id: 'a1', name: 'Marketing Max', articles_generated: 45, avg_engagement: 0.82, top_niche: 'SaaS Growth' }, + { id: '2', avatar_id: 'a2', name: 'Finance Fiona', articles_generated: 32, avg_engagement: 0.75, top_niche: 'Personal Finance' }, + { id: '3', avatar_id: 'a3', name: 'Tech Tyler', articles_generated: 68, avg_engagement: 0.68, top_niche: 'AI Tools' }, + { id: '4', avatar_id: 'a4', name: 'Wellness Wendy', articles_generated: 24, avg_engagement: 0.89, top_niche: 'Holistic Health' }, + { id: '5', avatar_id: 'a5', name: 'Crypto Carl', articles_generated: 15, avg_engagement: 0.45, top_niche: 'DeFi' } +] as any[]; + +--- + + +
+
+
+

+ Intelligence Headquarters +

+

+ Real-time analysis of content performance, audience demographics, and conversion patterns. +

+
+
+
+
92%
+
Predictive Acc.
+
+
+
1.4M
+
Data Points
+
+
+
+ +
+ {/* Patterns Section - Spans 2 columns */} +
+ + +
+ +
+
+ + {/* Geo Section - Spans 1 column */} +
+ +
+
+
+
diff --git a/src/pages/admin/intelligence/patterns.astro b/src/pages/admin/intelligence/patterns.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/intelligence/reports.astro b/src/pages/admin/intelligence/reports.astro new file mode 100644 index 0000000..d3219d2 --- /dev/null +++ b/src/pages/admin/intelligence/reports.astro @@ -0,0 +1,19 @@ +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import UnderConstruction from '@/components/ui/UnderConstruction'; +--- + + +
+
+

Reports & Analysis

+

Deep dive into content performance metrics.

+
+ +
+
diff --git a/src/pages/admin/leads/[id].astro b/src/pages/admin/leads/[id].astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/leads/index.astro b/src/pages/admin/leads/index.astro new file mode 100644 index 0000000..b1c833c --- /dev/null +++ b/src/pages/admin/leads/index.astro @@ -0,0 +1,19 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import LeadsManager from '@/components/admin/leads/LeadsManager'; +--- + + +
+
+
+

๐Ÿ‘ฅ Leads & Prospects

+

+ Manage incoming leads and track their status from "New" to "Converted". +

+
+
+ + +
+
diff --git a/src/pages/admin/locations.astro b/src/pages/admin/locations.astro new file mode 100644 index 0000000..32731a0 --- /dev/null +++ b/src/pages/admin/locations.astro @@ -0,0 +1,8 @@ +--- +import AdminLayout from '../../layouts/AdminLayout.astro'; +import LocationBrowser from '../../components/admin/LocationBrowser'; +--- + + + + diff --git a/src/pages/admin/media/templates.astro b/src/pages/admin/media/templates.astro new file mode 100644 index 0000000..e35124c --- /dev/null +++ b/src/pages/admin/media/templates.astro @@ -0,0 +1,8 @@ +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import ImageTemplateEditor from '../../../components/admin/ImageTemplateEditor'; +--- + + + + diff --git a/src/pages/admin/pages/[id].astro b/src/pages/admin/pages/[id].astro new file mode 100644 index 0000000..31c15ff --- /dev/null +++ b/src/pages/admin/pages/[id].astro @@ -0,0 +1,20 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import PageEditor from '@/components/admin/pages/PageEditor'; + +const { id } = Astro.params; +--- + + +
+
+ + + Back to Pages + +

Edit Page

+
+ + +
+
diff --git a/src/pages/admin/pages/index.astro b/src/pages/admin/pages/index.astro new file mode 100644 index 0000000..85fe4c5 --- /dev/null +++ b/src/pages/admin/pages/index.astro @@ -0,0 +1,21 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import PageList from '@/components/admin/pages/PageList'; +--- + + +
+
+
+

Pages

+

Manage static pages across your sites.

+
+ + + New Page + +
+ + +
+
diff --git a/src/pages/admin/scheduler/index.astro b/src/pages/admin/scheduler/index.astro new file mode 100644 index 0000000..8e5a507 --- /dev/null +++ b/src/pages/admin/scheduler/index.astro @@ -0,0 +1,19 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import SchedulerManager from '@/components/admin/scheduler/SchedulerManager'; +--- + + +
+
+
+

๐Ÿ“… Automation Center

+

+ Schedule bulk generation campaigns and automated workflows. +

+
+
+ + +
+
diff --git a/src/pages/admin/seo/articles/[id].astro b/src/pages/admin/seo/articles/[id].astro new file mode 100644 index 0000000..578fe45 --- /dev/null +++ b/src/pages/admin/seo/articles/[id].astro @@ -0,0 +1,20 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import ArticleEditor from '@/components/admin/seo/ArticleEditor'; + +const { id } = Astro.params; +--- + + +
+
+ + + Back to Articles + +

Review Article

+
+ + +
+
diff --git a/src/pages/admin/seo/articles/index.astro b/src/pages/admin/seo/articles/index.astro new file mode 100644 index 0000000..51b19fc --- /dev/null +++ b/src/pages/admin/seo/articles/index.astro @@ -0,0 +1,22 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import ArticleList from '@/components/admin/seo/ArticleList'; +import { getDirectusClient, readItems } from '@/lib/directus/client'; + +const directus = getDirectusClient(); +const articles = await directus.request(readItems('generated_articles', { + fields: ['*'], + limit: 50, + sort: ['-date_created'] +})).catch(() => []); +--- + + +
+
+

Generated Articles

+

Review and manage AI-generated SEO content.

+
+ +
+
diff --git a/src/pages/admin/seo/campaigns.astro b/src/pages/admin/seo/campaigns.astro new file mode 100644 index 0000000..ee58bba --- /dev/null +++ b/src/pages/admin/seo/campaigns.astro @@ -0,0 +1,8 @@ +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import CampaignManager from '../../../components/admin/CampaignManager'; +--- + + + + diff --git a/src/pages/admin/seo/fragments.astro b/src/pages/admin/seo/fragments.astro new file mode 100644 index 0000000..90a5f5f --- /dev/null +++ b/src/pages/admin/seo/fragments.astro @@ -0,0 +1,14 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +--- + + +
+

Content Fragments

+ +
+

Reusable Content Blocks

+

Manage global text snippets, CTAs, and bios here.

+
+
+
diff --git a/src/pages/admin/seo/headlines.astro b/src/pages/admin/seo/headlines.astro new file mode 100644 index 0000000..e23939a --- /dev/null +++ b/src/pages/admin/seo/headlines.astro @@ -0,0 +1,14 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +--- + + +
+

Headlines & Hooks

+ +
+

Pattern Library

+

Manage your Cartesian Headline generation patterns here.

+
+
+
diff --git a/src/pages/admin/settings.astro b/src/pages/admin/settings.astro new file mode 100644 index 0000000..5cde7fd --- /dev/null +++ b/src/pages/admin/settings.astro @@ -0,0 +1,9 @@ +--- +import Layout from '@/layouts/AdminLayout.astro'; +import SettingsManager from '@/components/admin/SettingsManager'; +--- + +
+ +
+
diff --git a/src/pages/admin/system/work-log.astro b/src/pages/admin/system/work-log.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/testing/content-quality.astro b/src/pages/admin/testing/content-quality.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/testing/index.astro b/src/pages/admin/testing/index.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/testing/link-checker.astro b/src/pages/admin/testing/link-checker.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/testing/seo-validation.astro b/src/pages/admin/testing/seo-validation.astro new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/admin/testing/suite.astro b/src/pages/admin/testing/suite.astro new file mode 100644 index 0000000..c5cf507 --- /dev/null +++ b/src/pages/admin/testing/suite.astro @@ -0,0 +1,15 @@ +--- +import AdminLayout from '@/layouts/AdminLayout.astro'; +import TestRunner from '@/components/testing/TestRunner'; +--- + + +
+
+

Quality Assurance Suite

+

Validate content SEO, readability, and structural integrity.

+
+ + +
+