Spaces:
Running
Running
| <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> | |