feat: black unknown color and progressive report configuration UI
All checks were successful
Deployment / deploy-docker (push) Successful in 15s
All checks were successful
Deployment / deploy-docker (push) Successful in 15s
This commit is contained in:
@@ -91,7 +91,12 @@
|
|||||||
|
|
||||||
.field-label {
|
.field-label {
|
||||||
display: block;
|
display: block;
|
||||||
text-xs font-bold text-slate-500 uppercase tracking-widest mb-3;
|
font-size: 0.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #64748b;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-glass {
|
.input-glass {
|
||||||
@@ -177,30 +182,34 @@
|
|||||||
|
|
||||||
<!-- REPORT BUILDER VIEW -->
|
<!-- REPORT BUILDER VIEW -->
|
||||||
<div id="view-analytics" class="view hidden flex-1 flex overflow-hidden">
|
<div id="view-analytics" class="view hidden flex-1 flex overflow-hidden">
|
||||||
<div class="config-sidebar p-8 space-y-8 overflow-y-auto bg-slate-900/30">
|
<!-- Configuration Sidebar -->
|
||||||
<h3 class="text-sky-400 font-bold text-xs uppercase tracking-tighter mb-4">Report Configuration</h3>
|
<div class="config-sidebar p-8 space-y-6 overflow-y-auto bg-slate-900/30" id="reportConfig">
|
||||||
|
<h3 class="text-sky-400 font-bold text-xs uppercase tracking-tighter mb-4">Step-by-Step Configuration
|
||||||
|
</h3>
|
||||||
|
|
||||||
<!-- Time Selection -->
|
<!-- Step 1: Time Range -->
|
||||||
<div>
|
<div class="report-step" id="step1">
|
||||||
<label class="field-label">Time Period</label>
|
<label class="field-label">1. Choose Analysis Period</label>
|
||||||
<select id="timeRangePreset" class="input-glass mb-2" onchange="handlePresetChange()">
|
<select id="timeRangePreset" class="input-glass" onchange="proceedToStep(2)">
|
||||||
|
<option value="" disabled selected>Select... </option>
|
||||||
<option value="1">Today</option>
|
<option value="1">Today</option>
|
||||||
<option value="7" selected>Last 7 Days</option>
|
<option value="7">Last 7 Days</option>
|
||||||
<option value="30">Last 30 Days</option>
|
<option value="30">Last 30 Days</option>
|
||||||
<option value="ytd">Year to Date (YTD)</option>
|
<option value="ytd">Year to Date (YTD)</option>
|
||||||
<option value="year">Full Year 2026</option>
|
<option value="year">Full Year 2026</option>
|
||||||
<option value="custom">Custom Date Range...</option>
|
<option value="custom">Custom Range...</option>
|
||||||
</select>
|
</select>
|
||||||
<div id="customDates" class="hidden grid grid-cols-2 gap-2 mt-2">
|
<div id="customDates" class="hidden grid grid-cols-2 gap-2 mt-2">
|
||||||
<input type="date" id="dateFrom" class="input-glass text-xs p-2">
|
<input type="date" id="dateFrom" class="input-glass text-xs p-2" onchange="checkCustomDates()">
|
||||||
<input type="date" id="dateTo" class="input-glass text-xs p-2">
|
<input type="date" id="dateTo" class="input-glass text-xs p-2" onchange="checkCustomDates()">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dimension Selection (X) -->
|
<!-- Step 2: X-Axis -->
|
||||||
<div>
|
<div class="report-step hidden opacity-50" id="step2">
|
||||||
<label class="field-label">Group By (X-Axis)</label>
|
<label class="field-label">2. Primary Grouping (X-Axis)</label>
|
||||||
<select id="axisX" class="input-glass" onchange="updateSubGroupOptions()">
|
<select id="axisX" class="input-glass" onchange="proceedToStep(3); updateSubGroupOptions();">
|
||||||
|
<option value="" disabled selected>Select... </option>
|
||||||
<option value="day">Time (Daily)</option>
|
<option value="day">Time (Daily)</option>
|
||||||
<option value="month">Time (Monthly)</option>
|
<option value="month">Time (Monthly)</option>
|
||||||
<option value="exchange">Exchange Origin</option>
|
<option value="exchange">Exchange Origin</option>
|
||||||
@@ -210,40 +219,45 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Breakdown Selection (Series) -->
|
<!-- Step 3: Breakdown -->
|
||||||
<div id="subGroupContainer">
|
<div class="report-step hidden opacity-50" id="step3">
|
||||||
<label class="field-label">Breakdown by (Series)</label>
|
<label class="field-label">3. Secondary Breakdown (Series)</label>
|
||||||
<select id="axisSub" class="input-glass">
|
<select id="axisSub" class="input-glass" onchange="proceedToStep(4)">
|
||||||
<option value="">None (Single Series)</option>
|
<option value="">None (Unified)</option>
|
||||||
<option value="exchange">Exchange</option>
|
<option value="exchange">By Exchange</option>
|
||||||
<option value="continent">Continent</option>
|
<option value="continent">By Continent</option>
|
||||||
<option value="sector">Sector</option>
|
<option value="sector">By Sector</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Metric Selection (Y) -->
|
<!-- Step 4: Y-Axis -->
|
||||||
<div>
|
<div class="report-step hidden opacity-50" id="step4">
|
||||||
<label class="field-label">Measurement (Y-Axis)</label>
|
<label class="field-label">4. Select Metric (Y-Axis)</label>
|
||||||
<select id="axisY" class="input-glass">
|
<select id="axisY" class="input-glass" onchange="proceedToStep(5)">
|
||||||
|
<option value="" disabled selected>Select... </option>
|
||||||
<option value="volume">Trade Volume (€)</option>
|
<option value="volume">Trade Volume (€)</option>
|
||||||
<option value="count">Number of Trades</option>
|
<option value="count">Number of Trades</option>
|
||||||
<option value="avg_price">Average Price</option>
|
<option value="avg_price">Average Performance</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Search & Filter -->
|
<!-- Step 5: Filters -->
|
||||||
<div class="relative">
|
<div class="report-step hidden opacity-50" id="step5">
|
||||||
<label class="field-label">Filter to Companies</label>
|
<div class="relative">
|
||||||
<input type="text" id="isinSearch" autocomplete="off" placeholder="Search ISIN or Name..."
|
<label class="field-label">5. Optional Company Filters</label>
|
||||||
class="input-glass" onkeyup="handleSearch(event)">
|
<input type="text" id="isinSearch" autocomplete="off" placeholder="Search ISIN or Name..."
|
||||||
<div id="suggestions" class="suggestion-box hidden"></div>
|
class="input-glass" onkeyup="handleSearch(event)">
|
||||||
<div id="filterChips" class="flex flex-wrap gap-2 mt-4"></div>
|
<div id="suggestions" class="suggestion-box hidden"></div>
|
||||||
</div>
|
<div id="filterChips" class="flex flex-wrap gap-2 mt-4"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="pt-4">
|
<div class="pt-8 space-y-3">
|
||||||
<button onclick="renderAnalyticsReport()" class="btn-primary w-full">GENERATE REPORT</button>
|
<button onclick="renderAnalyticsReport()"
|
||||||
<p class="text-[10px] text-slate-500 mt-4 text-center">Charts are automatically optimized (Line vs
|
class="btn-primary w-full shadow-sky-500/20">REGENERATE G-DRIVE REPORT</button>
|
||||||
Bar) based on selected grouping.</p>
|
<button onclick="resetReportConfig()"
|
||||||
|
class="w-full text-xs text-slate-500 hover:text-white transition">Reset
|
||||||
|
Configuration</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -481,22 +495,25 @@
|
|||||||
|
|
||||||
const contCtx = document.getElementById('continentChart').getContext('2d');
|
const contCtx = document.getElementById('continentChart').getContext('2d');
|
||||||
if (charts.continent) charts.continent.destroy();
|
if (charts.continent) charts.continent.destroy();
|
||||||
|
const labels = store.summary.map(r => r[0]);
|
||||||
|
const baseColors = [
|
||||||
|
'#38bdf8', // Blue
|
||||||
|
'#f43f5e', // Red
|
||||||
|
'#10b981', // Green
|
||||||
|
'#fbbf24', // Yellow
|
||||||
|
'#8b5cf6', // Purple
|
||||||
|
'#f97316', // Orange
|
||||||
|
'#ec4899', // Pink
|
||||||
|
'#475569' // Slate
|
||||||
|
];
|
||||||
|
|
||||||
charts.continent = new Chart(contCtx, {
|
charts.continent = new Chart(contCtx, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
data: {
|
data: {
|
||||||
labels: store.summary.map(r => r[0]),
|
labels: labels,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: store.summary.map(r => r[2]),
|
data: store.summary.map(r => r[2]),
|
||||||
backgroundColor: [
|
backgroundColor: labels.map((l, i) => l.toLowerCase() === 'unknown' ? '#000000' : baseColors[i % baseColors.length]),
|
||||||
'#38bdf8', // Blue
|
|
||||||
'#f43f5e', // Red
|
|
||||||
'#10b981', // Green
|
|
||||||
'#fbbf24', // Yellow
|
|
||||||
'#8b5cf6', // Purple
|
|
||||||
'#f97316', // Orange
|
|
||||||
'#475569', // Slate (for Unknown - high contrast)
|
|
||||||
'#ec4899' // Pink
|
|
||||||
],
|
|
||||||
borderWidth: 0
|
borderWidth: 0
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
@@ -504,6 +521,34 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Progressive Report Configuration ---
|
||||||
|
function proceedToStep(n) {
|
||||||
|
const step = document.getElementById(`step${n}`);
|
||||||
|
if (step) {
|
||||||
|
step.classList.remove('hidden');
|
||||||
|
setTimeout(() => step.classList.remove('opacity-50'), 50);
|
||||||
|
}
|
||||||
|
if (n === 2) handlePresetChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCustomDates() {
|
||||||
|
const from = document.getElementById('dateFrom').value;
|
||||||
|
const to = document.getElementById('dateTo').value;
|
||||||
|
if (from && to) proceedToStep(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetReportConfig() {
|
||||||
|
document.querySelectorAll('.report-step').forEach((s, i) => {
|
||||||
|
if (i > 0) s.classList.add('hidden', 'opacity-50');
|
||||||
|
});
|
||||||
|
document.getElementById('timeRangePreset').value = '';
|
||||||
|
document.getElementById('axisX').value = '';
|
||||||
|
document.getElementById('axisSub').value = '';
|
||||||
|
document.getElementById('axisY').value = '';
|
||||||
|
store.pinnedIsins = [];
|
||||||
|
updateFilterChips();
|
||||||
|
}
|
||||||
|
|
||||||
function fillMetadataTable() {
|
function fillMetadataTable() {
|
||||||
const tbody = document.getElementById('metadataRows');
|
const tbody = document.getElementById('metadataRows');
|
||||||
tbody.innerHTML = store.metadata.map(r => `
|
tbody.innerHTML = store.metadata.map(r => `
|
||||||
|
|||||||
Reference in New Issue
Block a user