crisislens-dashboard / index.html
MoShow's picture
Here is a high-level proposal for developing a smart dashboard for executives and incident management, based on your requirements and the provided data.
2f09561 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CrisisLens Dashboard</title>
<link rel="icon" type="image/x-icon" href="https://static.photos/abstract/320x240/1">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
:root {
--primary: #4361ee;
--secondary: #3f37c9;
--accent: #4895ef;
--background: #f8f9fa;
--card-bg: #ffffff;
--text: #212529;
}
.dark-mode {
--primary: #4895ef;
--secondary: #4361ee;
--accent: #3f37c9;
--background: #121212;
--card-bg: #1e1e1e;
--text: #f8f9fa;
}
body {
background-color: var(--background);
color: var(--text);
transition: background-color 0.3s, color 0.3s;
}
.card {
background-color: var(--card-bg);
border-radius: 0.75rem;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
}
.metric-value {
font-size: 2rem;
font-weight: 700;
color: var(--primary);
}
.filter-container {
background-color: var(--card-bg);
border-radius: 0.5rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
#globe-container {
height: 400px;
border-radius: 0.75rem;
overflow: hidden;
}
.treemap-cell {
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
padding: 4px;
font-size: 0.75rem;
color: white;
transition: all 0.3s ease;
}
.treemap-cell:hover {
opacity: 0.9;
transform: scale(1.02);
}
.ai-chat {
max-height: 300px;
overflow-y: auto;
}
.message-user {
background-color: var(--primary);
color: white;
border-radius: 1rem 1rem 0 1rem;
}
.message-ai {
background-color: var(--card-bg);
color: var(--text);
border-radius: 1rem 1rem 1rem 0;
border: 1px solid rgba(0, 0, 0, 0.1);
}
</style>
</head>
<body class="font-sans">
<!-- Header -->
<header class="bg-white dark:bg-gray-800 shadow-sm">
<div class="container mx-auto px-4 py-4 flex justify-between items-center">
<div class="flex items-center space-x-2">
<i data-feather="activity" class="text-blue-500"></i>
<h1 class="text-2xl font-bold text-gray-800 dark:text-white">CrisisLens Dashboard</h1>
</div>
<div class="flex items-center space-x-4">
<button id="theme-toggle" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700">
<i data-feather="moon" class="dark:hidden"></i>
<i data-feather="sun" class="hidden dark:block"></i>
</button>
<div class="flex items-center space-x-2">
<div class="w-8 h-8 rounded-full bg-blue-500 flex items-center justify-center text-white font-bold">A</div>
<span class="text-gray-700 dark:text-gray-300">Admin</span>
</div>
</div>
</div>
</header>
<!-- Main Content -->
<main class="container mx-auto px-4 py-8">
<!-- Metrics Cards -->
<section class="mb-10">
<h2 class="text-xl font-bold mb-4 text-gray-800 dark:text-white">Key Metrics</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-6">
<div class="card p-6">
<div class="flex justify-between items-start">
<div>
<p class="text-gray-500 dark:text-gray-400 text-sm">Total Budget</p>
<p class="metric-value">$24.8M</p>
</div>
<div class="p-2 bg-blue-100 dark:bg-blue-900 rounded-full">
<i data-feather="dollar-sign" class="text-blue-500 dark:text-blue-300"></i>
</div>
</div>
<div class="mt-4 flex items-center text-green-500">
<i data-feather="trending-up" class="mr-1"></i>
<span class="text-sm">12.5% from last month</span>
</div>
</div>
<div class="card p-6">
<div class="flex justify-between items-start">
<div>
<p class="text-gray-500 dark:text-gray-400 text-sm">Active Response Countries</p>
<p class="metric-value">18</p>
</div>
<div class="p-2 bg-green-100 dark:bg-green-900 rounded-full">
<i data-feather="globe" class="text-green-500 dark:text-green-300"></i>
</div>
</div>
<div class="mt-4 flex items-center text-green-500">
<i data-feather="trending-up" class="mr-1"></i>
<span class="text-sm">3 new this week</span>
</div>
</div>
<div class="card p-6">
<div class="flex justify-between items-start">
<div>
<p class="text-gray-500 dark:text-gray-400 text-sm">Preparedness Phase</p>
<p class="metric-value">7</p>
</div>
<div class="p-2 bg-yellow-100 dark:bg-yellow-900 rounded-full">
<i data-feather="shield" class="text-yellow-500 dark:text-yellow-300"></i>
</div>
</div>
<div class="mt-4 flex items-center text-red-500">
<i data-feather="trending-down" class="mr-1"></i>
<span class="text-sm">2 less than last month</span>
</div>
</div>
<div class="card p-6">
<div class="flex justify-between items-start">
<div>
<p class="text-gray-500 dark:text-gray-400 text-sm">Activated Pillars</p>
<p class="metric-value">5/5</p>
</div>
<div class="p-2 bg-purple-100 dark:bg-purple-900 rounded-full">
<i data-feather="layers" class="text-purple-500 dark:text-purple-300"></i>
</div>
</div>
<div class="mt-4 flex items-center text-green-500">
<i data-feather="check-circle" class="mr-1"></i>
<span class="text-sm">All active</span>
</div>
</div>
<div class="card p-6">
<div class="flex justify-between items-start">
<div>
<p class="text-gray-500 dark:text-gray-400 text-sm">Funded Activities</p>
<p class="metric-value">142</p>
</div>
<div class="p-2 bg-indigo-100 dark:bg-indigo-900 rounded-full">
<i data-feather="check-square" class="text-indigo-500 dark:text-indigo-300"></i>
</div>
</div>
<div class="mt-4 flex items-center text-green-500">
<i data-feather="trending-up" class="mr-1"></i>
<span class="text-sm">8% increase</span>
</div>
</div>
</div>
</section>
<!-- Filters and Globe -->
<section class="mb-10">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Filters -->
<div class="lg:col-span-1">
<div class="filter-container p-6 mb-6">
<h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Filters</h3>
<div class="mb-4">
<label class="block text-gray-700 dark:text-gray-300 text-sm font-medium mb-2" for="hazard-type">
Hazard Type
</label>
<select id="hazard-type" class="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-800 dark:text-white">
<option>All Hazards</option>
<option>Cholera</option>
<option>Ebola</option>
<option>Marburg</option>
<option>Flood</option>
<option>Drought</option>
</select>
</div>
<div class="mb-4">
<label class="block text-gray-700 dark:text-gray-300 text-sm font-medium mb-2" for="country-filter">
Country
</label>
<select id="country-filter" multiple class="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-800 dark:text-white">
<option>DRC</option>
<option>Tanzania</option>
<option>Uganda</option>
<option>Kenya</option>
<option>South Sudan</option>
<option>Ethiopia</option>
</select>
</div>
<button class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-md transition duration-300">
Apply Filters
</button>
</div>
<!-- AI Assistant -->
<div class="filter-container p-6">
<h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">AI Assistant</h3>
<div class="ai-chat mb-4">
<div class="message-ai p-3 mb-3">
Hello! I'm your CrisisLens AI assistant. How can I help you today?
</div>
<div class="message-user p-3 mb-3 text-right">
Show me budget allocation for Cholera response in DRC
</div>
<div class="message-ai p-3 mb-3">
The total budget for Cholera response in DRC is $16.46M across 23 activities.
</div>
</div>
<div class="flex">
<input type="text" placeholder="Ask me anything..." class="flex-grow p-2 border border-gray-300 dark:border-gray-600 rounded-l-md bg-white dark:bg-gray-700 text-gray-800 dark:text-white">
<button class="bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-r-md transition duration-300">
<i data-feather="send"></i>
</button>
</div>
</div>
</div>
<!-- 3D Globe -->
<div class="lg:col-span-2">
<div class="card p-6">
<h3 class="text-lg font-semibold mb-4 text-gray-800 dark:text-white">Global Incident Overview</h3>
<div id="globe-container"></div>
</div>
</div>
</div>
</section>
<!-- IMS Visualization -->
<section>
<div class="card p-6">
<h2 class="text-xl font-bold mb-4 text-gray-800 dark:text-white">IMS Structure Visualization</h2>
<div id="treemap" class="h-96"></div>
</div>
</section>
</main>
<!-- Footer -->
<footer class="bg-white dark:bg-gray-800 border-t border-gray-200 dark:border-gray-700 mt-12">
<div class="container mx-auto px-4 py-6">
<div class="flex flex-col md:flex-row justify-between items-center">
<div class="mb-4 md:mb-0">
<p class="text-gray-600 dark:text-gray-400">© 2023 CrisisLens Dashboard. All rights reserved.</p>
</div>
<div class="flex space-x-6">
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-blue-500 dark:hover:text-blue-400">
<i data-feather="help-circle"></i>
</a>
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-blue-500 dark:hover:text-blue-400">
<i data-feather="settings"></i>
</a>
<a href="#" class="text-gray-600 dark:text-gray-400 hover:text-blue-500 dark:hover:text-blue-400">
<i data-feather="lock"></i>
</a>
</div>
</div>
</div>
</footer>
<script>
// Initialize Feather Icons
feather.replace();
// Theme Toggle
const themeToggle = document.getElementById('theme-toggle');
themeToggle.addEventListener('click', () => {
document.body.classList.toggle('dark-mode');
const isDarkMode = document.body.classList.contains('dark-mode');
localStorage.setItem('darkMode', isDarkMode);
feather.replace();
});
// Check for saved theme preference
if (localStorage.getItem('darkMode') === 'true') {
document.body.classList.add('dark-mode');
feather.replace();
}
// Initialize Vanta.js Globe
VANTA.GLOBE({
el: "#globe-container",
mouseControls: true,
touchControls: true,
gyroControls: false,
minHeight: 200.00,
minWidth: 200.00,
scale: 1.00,
scaleMobile: 1.00,
color: 0x4361ee,
color2: 0x4cc9f0,
size: 1.00,
backgroundColor: 0xffffff
});
// Create Treemap Visualization
const treemapData = {
name: "IMS Structure",
children: [
{
name: "Coordination",
value: 5000000,
children: [
{name: "Leadership", value: 2000000},
{name: "Planning", value: 1500000},
{name: "Monitoring", value: 1500000}
]
},
{
name: "Community",
value: 7000000,
children: [
{name: "Engagement", value: 3000000},
{name: "Protection", value: 2500000},
{name: "Education", value: 1500000}
]
},
{
name: "Capacity",
value: 4500000,
children: [
{name: "Training", value: 2000000},
{name: "Equipment", value: 1500000},
{name: "Infrastructure", value: 1000000}
]
},
{
name: "Cross-cutting",
value: 3500000,
children: [
{name: "Gender", value: 1500000},
{name: "Environment", value: 1000000},
{name: "Technology", value: 1000000}
]
},
{
name: "Cash",
value: 4800000,
children: [
{name: "Transfers", value: 2500000},
{name: "Vouchers", value: 1500000},
{name: "Market Support", value: 800000}
]
}
]
};
// Set up dimensions and margins for the treemap
const width = document.getElementById('treemap').clientWidth;
const height = document.getElementById('treemap').clientHeight;
// Create SVG container
const svg = d3.select("#treemap")
.append("svg")
.attr("width", width)
.attr("height", height);
// Create color scale
const color = d3.scaleOrdinal()
.domain(["Coordination", "Community", "Capacity", "Cross-cutting", "Cash"])
.range(["#4361ee", "#3a0ca3", "#4cc9f0", "#f72585", "#7209b7"]);
// Create treemap layout
const treemap = d3.treemap()
.size([width, height])
.padding(1);
// Create root node
const root = d3.hierarchy(treemapData)
.sum(d => d.value)
.sort((a, b) => b.value - a.value);
// Generate treemap
treemap(root);
// Create cells
const cell = svg.selectAll("g")
.data(root.leaves())
.enter().append("g")
.attr("transform", d => `translate(${d.x0},${d.y0})`);
// Add rectangles
cell.append("rect")
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.attr("class", "treemap-cell")
.style("background-color", d => color(d.parent.data.name));
// Add labels
cell.append("text")
.attr("x", d => (d.x1 - d.x0) / 2)
.attr("y", d => (d.y1 - d.y0) / 2)
.attr("text-anchor", "middle")
.attr("dy", "0.35em")
.attr("fill", "white")
.text(d => `${d.data.name}\n$${(d.value/1000000).toFixed(1)}M`)
.style("font-size", d => {
const size = Math.min(d.x1 - d.x0, d.y1 - d.y0);
return `${Math.max(10, size/8)}px`;
})
.style("font-weight", "bold");
</script>
</body>
</html>