mga-basic-test / index.html
phvv8's picture
we need a frontend web ui which ties together the backend consisting of our insight scraping algorithms:
6b2a750 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MarketGap - Market Intelligence Dashboard</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://unpkg.com/aos@2.3.1/dist/aos.css" rel="stylesheet">
<script src="https://unpkg.com/aos@2.3.1/dist/aos.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
:root {
--primary: #6366f1;
--primary-dark: #4f46e5;
--secondary: #06b6d4;
--accent: #f59e0b;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--dark: #1e293b;
--light: #f8fafc;
}
body {
font-family: 'Inter', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
.glass-morphism {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 16px;
}
.gradient-text {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.pulse-animation {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.floating {
animation: floating 3s ease-in-out infinite;
}
@keyframes floating {
0% { transform: translateY(0px); }
50% { transform: translateY(-10px); }
100% { transform: translateY(0px); }
}
.chart-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(4px);
}
.loading-spinner {
border: 3px solid #f3f3f3;
border-top: 3px solid var(--primary);
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.metric-card {
transition: all 0.3s ease;
}
.metric-card:hover {
transform: translateY(-5px);
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15);
}
.opportunity-card {
transition: all 0.3s ease;
border-left: 4px solid var(--primary);
}
.opportunity-card:hover {
transform: translateX(5px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}
.btn-primary {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
border: none;
color: white;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
cursor: pointer;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 16px rgba(99, 102, 241, 0.3);
}
.btn-secondary {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
cursor: pointer;
}
.btn-secondary:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.keyword-tag {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: white;
padding: 4px 12px;
border-radius: 20px;
font-size: 14px;
margin: 2px;
display: inline-block;
}
.trend-indicator {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 12px;
font-weight: 600;
}
.trend-up { color: var(--success); }
.trend-down { color: var(--danger); }
.trend-neutral { color: var(--warning); }
.sentiment-positive { color: var(--success); }
.sentiment-negative { color: var(--danger); }
.sentiment-neutral { color: var(--warning); }
.animate-fade-in {
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
</style>
</head>
<body>
<!-- Background Animation -->
<div id="vanta-bg" class="fixed inset-0 z-0"></div>
<!-- Navigation -->
<nav class="relative z-10 glass-morphism m-4 p-4 flex justify-between items-center animate-fade-in">
<div class="flex items-center gap-3">
<div class="w-10 h-10 bg-gradient-to-r from-indigo-500 to-purple-600 rounded-lg flex items-center justify-center">
<i data-feather="trending-up" class="text-white"></i>
</div>
<h1 class="text-xl font-bold text-white">MarketGap</h1>
</div>
<div class="flex items-center gap-4">
<button id="refresh-btn" class="btn-secondary">
<i data-feather="refresh-cw" class="w-4 h-4 inline mr-2"></i>Refresh
</button>
<button id="export-btn" class="btn-primary">
<i data-feather="download" class="w-4 h-4 inline mr-2"></i>Export
</button>
</div>
</nav>
<!-- Main Content -->
<div class="relative z-10 container mx-auto px-4 py-8">
<!-- Header Section -->
<div class="text-center mb-12 animate-fade-in" data-aos="fade-up">
<h2 class="text-5xl font-bold text-white mb-4 gradient-text">Market Intelligence Dashboard</h2>
<p class="text-xl text-white/80 max-w-2xl mx-auto">
Discover hidden market opportunities with AI-powered trend analysis across multiple platforms
</p>
</div>
<!-- Input Section -->
<div class="glass-morphism p-8 mb-12 animate-fade-in" data-aos="fade-up" data-aos-delay="200">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
<div>
<label class="block text-white font-semibold mb-3">Keywords to Analyze</label>
<input
id="keywords-input"
type="text"
placeholder="e.g., AI productivity, remote work, sustainable packaging"
class="w-full px-4 py-3 rounded-lg bg-white/20 border border-white/30 text-white placeholder-white/60 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-transparent"
>
<div class="mt-2 flex flex-wrap gap-2" id="keyword-tags">
<span class="keyword-tag">AI productivity</span>
<span class="keyword-tag">remote work</span>
<span class="keyword-tag">sustainable packaging</span>
</div>
</div>
<div>
<label class="block text-white font-semibold mb-3">Analysis Options</label>
<div class="grid grid-cols-2 gap-4 mb-4">
<div>
<label class="block text-white/80 text-sm mb-1">Time Period</label>
<select id="time-period" class="w-full px-3 py-2 rounded-lg bg-white/20 border border-white/30 text-white">
<option value="7">7 days</option>
<option value="30" selected>30 days</option>
<option value="90">90 days</option>
<option value="365">1 year</option>
</select>
</div>
<div>
<label class="block text-white/80 text-sm mb-1">Data Sources</label>
<select id="data-sources" class="w-full px-3 py-2 rounded-lg bg-white/20 border border-white/30 text-white">
<option value="all" selected>All Sources</option>
<option value="reddit">Reddit</option>
<option value="twitter">Twitter</option>
<option value="github">GitHub</option>
<option value="news">News</option>
</select>
</div>
</div>
<div class="flex gap-3">
<button id="analyze-btn" class="btn-primary flex-1">
<i data-feather="search" class="w-4 h-4 inline mr-2"></i>Analyze Trends
</button>
<button id="quick-scan-btn" class="btn-secondary">
<i data-feather="zap" class="w-4 h-4 inline mr-2"></i>Quick Scan
</button>
</div>
</div>
</div>
</div>
<!-- Metrics Overview -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12 animate-fade-in" data-aos="fade-up" data-aos-delay="300">
<div class="metric-card glass-morphism p-6 text-center">
<div class="text-3xl font-bold text-white mb-2" id="total-data-points">0</div>
<div class="text-white/70">Data Points</div>
<div class="trend-indicator trend-up mt-2">
<i data-feather="trending-up" class="w-4 h-4"></i>
<span>+12.5%</span>
</div>
</div>
<div class="metric-card glass-morphism p-6 text-center">
<div class="text-3xl font-bold text-white mb-2" id="market-gaps">0</div>
<div class="text-white/70">Market Gaps</div>
<div class="trend-indicator trend-up mt-2">
<i data-feather="trending-up" class="w-4 h-4"></i>
<span>+8.3%</span>
</div>
</div>
<div class="metric-card glass-morphism p-6 text-center">
<div class="text-3xl font-bold text-white mb-2" id="avg-sentiment">0.0</div>
<div class="text-white/70">Avg Sentiment</div>
<div class="trend-indicator trend-neutral mt-2">
<i data-feather="minus" class="w-4 h-4"></i>
<span>Neutral</span>
</div>
</div>
<div class="metric-card glass-morphism p-6 text-center">
<div class="text-3xl font-bold text-white mb-2" id="confidence-score">0%</div>
<div class="text-white/70">Confidence</div>
<div class="trend-indicator trend-up mt-2">
<i data-feather="trending-up" class="w-4 h-4"></i>
<span>+15.2%</span>
</div>
</div>
</div>
<!-- Main Dashboard -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8 animate-fade-in" data-aos="fade-up" data-aos-delay="400">
<!-- Left Column: Charts -->
<div class="lg:col-span-2 space-y-8">
<!-- Trend Timeline Chart -->
<div class="chart-container p-6">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-gray-800">Trend Timeline</h3>
<div class="flex gap-2">
<button class="btn-secondary text-sm px-3 py-1">
<i data-feather="bar-chart-2" class="w-3 h-3"></i>
</button>
<button class="btn-secondary text-sm px-3 py-1">
<i data-feather="pie-chart" class="w-3 h-3"></i>
</button>
</div>
</div>
<div id="trend-timeline-chart" style="height: 300px;"></div>
</div>
<!-- Source Distribution -->
<div class="chart-container p-6">
<h3 class="text-xl font-bold text-gray-800 mb-4">Data Source Distribution</h3>
<div id="source-distribution-chart" style="height: 250px;"></div>
</div>
<!-- Sentiment Heatmap -->
<div class="chart-container p-6">
<h3 class="text-xl font-bold text-gray-800 mb-4">Sentiment Analysis</h3>
<div id="sentiment-heatmap-chart" style="height: 300px;"></div>
</div>
</div>
<!-- Right Column: Opportunities -->
<div class="space-y-8">
<!-- Top Opportunities -->
<div class="chart-container p-6">
<h3 class="text-xl font-bold text-gray-800 mb-4">Top Opportunities</h3>
<div id="opportunities-list" class="space-y-3">
<div class="opportunity-card bg-gradient-to-r from-indigo-50 to-purple-50 p-4 rounded-lg">
<div class="flex justify-between items-start mb-2">
<h4 class="font-semibold text-gray-800 text-sm">AI Productivity Tools</h4>
<span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">High</span>
</div>
<p class="text-xs text-gray-600 mb-2">Growing demand for AI-powered productivity solutions</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Evidence: 0.85</span>
<span class="text-xs text-indigo-600 font-semibold">Explore →</span>
</div>
</div>
<div class="opportunity-card bg-gradient-to-r from-cyan-50 to-blue-50 p-4 rounded-lg">
<div class="flex justify-between items-start mb-2">
<h4 class="font-semibold text-gray-800 text-sm">Remote Work Platforms</h4>
<span class="text-xs bg-yellow-100 text-yellow-800 px-2 py-1 rounded-full">Medium</span>
</div>
<p class="text-xs text-gray-600 mb-2">Hybrid work solutions gaining traction</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Evidence: 0.72</span>
<span class="text-xs text-cyan-600 font-semibold">Explore →</span>
</div>
</div>
<div class="opportunity-card bg-gradient-to-r from-emerald-50 to-teal-50 p-4 rounded-lg">
<div class="flex justify-between items-start mb-2">
<h4 class="font-semibold text-gray-800 text-sm">Sustainable Packaging</h4>
<span class="text-xs bg-green-100 text-green-800 px-2 py-1 rounded-full">High</span>
</div>
<p class="text-xs text-gray-600 mb-2">Eco-friendly packaging solutions in demand</p>
<div class="flex justify-between items-center">
<span class="text-xs text-gray-500">Evidence: 0.68</span>
<span class="text-xs text-emerald-600 font-semibold">Explore →</span>
</div>
</div>
</div>
</div>
<!-- Market Gaps -->
<div class="chart-container p-6">
<h3 class="text-xl font-bold text-gray-800 mb-4">Market Gaps</h3>
<div id="market-gaps-chart" style="height: 200px;"></div>
</div>
<!-- Keyword Network -->
<div class="chart-container p-6">
<h3 class="text-xl font-bold text-gray-800 mb-4">Keyword Network</h3>
<div id="keyword-network-chart" style="height: 250px;"></div>
</div>
</div>
</div>
<!-- Detailed Analysis Section -->
<div class="mt-12 animate-fade-in" data-aos="fade-up" data-aos-delay="500">
<div class="chart-container p-8">
<h3 class="text-2xl font-bold text-gray-800 mb-6">Detailed Market Analysis</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div>
<h4 class="text-lg font-semibold text-gray-700 mb-4">Cross-Platform Correlations</h4>
<div id="correlations-chart" style="height: 300px;"></div>
</div>
<div>
<h4 class="text-lg font-semibold text-gray-700 mb-4">ROI Estimates</h4>
<div id="roi-chart" style="height: 300px;"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Loading Overlay -->
<div id="loading-overlay" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center hidden">
<div class="glass-morphism p-8 rounded-lg text-center">
<div class="loading-spinner mx-auto mb-4"></div>
<p class="text-white text-lg">Analyzing market trends...</p>
<p class="text-white/70 text-sm mt-2">This may take a few moments</p>
</div>
</div>
<!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/three@0.155.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<script>
// Initialize AOS
AOS.init({
duration: 800,
once: true
});
// Initialize Feather Icons
feather.replace();
// Initialize Vanta Background
VANTA.GLOBE({
el: "#vanta-bg",
mouseControls: true,
touchControls: true,
gyroControls: false,
minHeight: 200.00,
minWidth: 200.00,
scale: 1.00,
scaleMobile: 1.00,
color: 0x6366f1,
backgroundColor: 0x1e293b,
size: 1.2
});
// Sample data for charts
const sampleData = {
timeline: {
keywords: ['AI productivity', 'remote work', 'sustainable packaging'],
dates: Array.from({length: 30}, (_, i) => {
const date = new Date();
date.setDate(date.getDate() - (29 - i));
return date.toISOString().split('T')[0];
}),
volumes: {
'AI productivity': Array.from({length: 30}, () => Math.floor(Math.random() * 1000) + 500),
'remote work': Array.from({length: 30}, () => Math.floor(Math.random() * 800) + 300),
'sustainable packaging': Array.from({length: 30}, () => Math.floor(Math.random() * 600) + 200)
}
},
sources: {
'Reddit': 35,
'Twitter': 25,
'GitHub': 20,
'News': 15,
'Google Trends': 5
},
sentiments: {
'AI productivity': 0.72,
'remote work': 0.45,
'sustainable packaging': 0.68
},
opportunities: [
{ name: 'AI Productivity Tools', score: 0.85, confidence: 0.92 },
{ name: 'Remote Work Platforms', score: 0.72, confidence: 0.78 },
{ name: 'Sustainable Packaging', score: 0.68, confidence: 0.85 },
{ name: 'Mental Health Apps', score: 0.65, confidence: 0.73 },
{ name: 'Electric Vehicle Charging', score: 0.58, confidence: 0.69 }
],
marketGaps: [
{ name: 'Supply Gap 1', value: 45 },
{ name: 'Demand Indicator', value: 35 },
{ name: 'Competition Void', value: 20 }
]
};
// Initialize Charts
function initCharts() {
// Timeline Chart
const timelineChart = echarts.init(document.getElementById('trend-timeline-chart'));
const timelineOption = {
title: { text: 'Trend Volume Over Time', textStyle: { color: '#374151' } },
tooltip: { trigger: 'axis' },
legend: { data: sampleData.timeline.keywords, top: 30 },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: sampleData.timeline.dates, axisLabel: { rotate: 45 } },
yAxis: { type: 'value', name: 'Volume' },
series: sampleData.timeline.keywords.map(keyword => ({
name: keyword,
type: 'line',
smooth: true,
data: sampleData.timeline.volumes[keyword],
lineStyle: { width: 3 },
areaStyle: { opacity: 0.1 }
}))
};
timelineChart.setOption(timelineOption);
// Source Distribution Chart
const sourceChart = echarts.init(document.getElementById('source-distribution-chart'));
const sourceOption = {
title: { text: 'Data Sources', textStyle: { color: '#374151' } },
tooltip: { trigger: 'item' },
series: [{
type: 'pie',
radius: ['40%', '70%'],
data: Object.entries(sampleData.sources).map(([name, value]) => ({ name, value })),
emphasis: { itemStyle: { shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' } }
}]
};
sourceChart.setOption(sourceOption);
// Sentiment Heatmap
const sentimentChart = echarts.init(document.getElementById('sentiment-heatmap-chart'));
const sentimentOption = {
title: { text: 'Sentiment by Keyword', textStyle: { color: '#374151' } },
tooltip: { position: 'top' },
grid: { height: '50%', top: '10%' },
xAxis: { type: 'category', data: ['Reddit', 'Twitter', 'GitHub', 'News'], splitArea: { show: true } },
yAxis: { type: 'category', data: sampleData.timeline.keywords, splitArea: { show: true } },
visualMap: { min: -1, max: 1, calculable: true, orient: 'horizontal', left: 'center', bottom: '15%' },
series: [{
name: 'Sentiment',
type: 'heatmap',
data: sampleData.timeline.keywords.flatMap((keyword, i) =>
['Reddit', 'Twitter', 'GitHub', 'News'].map((source, j) => [j, i, Math.random() * 2 - 1])
),
label: { show: true }
}]
};
sentimentChart.setOption(sentimentOption);
// Market Gaps Chart
const gapsChart = echarts.init(document.getElementById('market-gaps-chart'));
const gapsOption = {
title: { text: 'Gap Types', textStyle: { color: '#374151' } },
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
xAxis: { type: 'category', data: sampleData.marketGaps.map(item => item.name) },
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: sampleData.marketGaps.map(item => item.value),
itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#6366f1' },
{ offset: 1, color: '#8b5cf6' }
]) }
}]
};
gapsChart.setOption(gapsOption);
// Keyword Network
const networkChart = echarts.init(document.getElementById('keyword-network-chart'));
const networkOption = {
title: { text: 'Keyword Relationships', textStyle: { color: '#374151' } },
series: [{
type: 'graph',
layout: 'force',
symbolSize: 50,
roam: true,
label: { show: true },
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 10],
data: sampleData.timeline.keywords.map(name => ({ name, value: Math.random() * 100 })),
links: sampleData.timeline.keywords.flatMap((source, i) =>
sampleData.timeline.keywords.slice(i + 1).map(target => ({
source,
target,
value: Math.random() * 10
}))
),
lineStyle: { opacity: 0.9, width: 2, curveness: 0.3 }
}]
};
networkChart.setOption(networkOption);
// Correlations Chart
const corrChart = echarts.init(document.getElementById('correlations-chart'));
const corrOption = {
title: { text: 'Platform Correlations', textStyle: { color: '#374151' } },
xAxis: { type: 'category', data: ['Reddit', 'Twitter', 'GitHub', 'News'] },
yAxis: { type: 'category', data: ['Reddit', 'Twitter', 'GitHub', 'News'] },
visualMap: { min: 0, max: 1, calculable: true, orient: 'horizontal', left: 'center', bottom: '15%' },
series: [{
type: 'heatmap',
data: ['Reddit', 'Twitter', 'GitHub', 'News'].flatMap((source, i) =>
['Reddit', 'Twitter', 'GitHub', 'News'].map((target, j) => [j, i, i === j ? 1 : Math.random()])
)
}]
};
corrChart.setOption(corrOption);
// ROI Chart
const roiChart = echarts.init(document.getElementById('roi-chart'));
const roiOption = {
title: { text: 'ROI Potential', textStyle: { color: '#374151' } },
tooltip: { trigger: 'item', formatter: '{a} <br/>{b}: {c}%' },
series: [{
name: 'ROI',
type: 'gauge',
detail: { formatter: '{value}%' },
data: [{ value: 75, name: 'Potential ROI' }]
}]
};
roiChart.setOption(roiOption);
// Responsive charts
window.addEventListener('resize', () => {
[timelineChart, sourceChart, sentimentChart, gapsChart, networkChart, corrChart, roiChart].forEach(chart => {
chart.resize();
});
});
}
// Update Metrics
function updateMetrics() {
document.getElementById('total-data-points').textContent = '12,847';
document.getElementById('market-gaps').textContent = '23';
document.getElementById('avg-sentiment').textContent = '0.68';
document.getElementById('confidence-score').textContent = '87%';
}
// Event Listeners
document.getElementById('analyze-btn').addEventListener('click', function() {
const loadingOverlay = document.getElementById('loading-overlay');
loadingOverlay.classList.remove('hidden');
setTimeout(() => {
loadingOverlay.classList.add('hidden');
initCharts();
updateMetrics();
}, 3000);
});
document.getElementById('refresh-btn').addEventListener('click', function() {
location.reload();
});
document.getElementById('export-btn').addEventListener('click', function() {
alert('Export functionality would be implemented here');
});
// Quick Scan
document.getElementById('quick-scan-btn').addEventListener('click', function() {
const loadingOverlay = document.getElementById('loading-overlay');
loadingOverlay.classList.remove('hidden');
setTimeout(() => {
loadingOverlay.classList.add('hidden');
// Show quick results
updateMetrics();
}, 1500);
});
// Initialize
document.addEventListener('DOMContentLoaded', function() {
initCharts();
updateMetrics();
});
</script>
</body>
</html>