diff --git a/app/src/scripts/script.js b/app/src/scripts/script.js index 5f7e4df..1af13fb 100644 --- a/app/src/scripts/script.js +++ b/app/src/scripts/script.js @@ -298,7 +298,9 @@ function renderData(data) { labels = labels.slice(-n); } - renderChartsAndTable({ ...data, feeds, labels }); + const slicedData = { ...data, feeds, labels }; + renderChartsAndTable(slicedData); + renderAIOverview(slicedData); }; document.querySelectorAll('input[name="slicer"]').forEach(radio => { @@ -654,4 +656,72 @@ Data: ${JSON.stringify(data || {})} function clearChat() { const responseContainer = document.getElementById("response-container"); responseContainer.innerHTML = ""; -} \ No newline at end of file +} + +function computeAIStats(data) { + return data.fields.map(field => { + const values = data.feeds + .map(f => Number(f[field.key])) + .filter(v => Number.isFinite(v)); + + if (!values.length) { + return { label: field.label, avg: 0 }; + } + + const avg = values.reduce((a, b) => a + b, 0) / values.length; + + return { + label: field.label, + avg: Number(avg.toFixed(2)) + }; + }); +} + + +function renderAIOverview(data) { + const canvas = document.getElementById("aiOverviewChart"); + if (!canvas) return; + + const ctx = canvas.getContext("2d"); + const stats = computeAIStats(data); + + if (window.aiChart) window.aiChart.destroy(); + + window.aiChart = new Chart(ctx, { + type: "bar", + data: { + labels: stats.map(s => s.label), + datasets: [{ + label: "Average Value", + data: stats.map(s => s.avg), + backgroundColor: "rgba(0, 255, 255, 0.6)", + borderColor: "rgba(0, 255, 255, 1)", + borderWidth: 1.5, + borderRadius: 6 + }] + }, + options: { + responsive: true, + plugins: { + legend: { + labels: { color: "#ddd" } + }, + tooltip: { + backgroundColor: "#111", + borderColor: "#00ffff", + borderWidth: 1 + } + }, + scales: { + x: { + ticks: { color: "#aaa" }, + grid: { display: false } + }, + y: { + ticks: { color: "#aaa" }, + grid: { color: "rgba(255,255,255,0.05)" } + } + } + } + }); +} diff --git a/app/src/styles/style.css b/app/src/styles/style.css index 7a24db5..b0b2486 100644 --- a/app/src/styles/style.css +++ b/app/src/styles/style.css @@ -1,633 +1,519 @@ -/*list of variables*/ -/*text input bg color: #151515*/ +/* ========================================= + 1. VARIABLES & RESET + ========================================= */ :root { - --bg-color: #101010; - --border-color: #313131; + /* Palette - strictly monochrome */ + --bg-body: #050505; /* Deepest Black */ + --bg-panel: #0a0a0a; /* Sidebar Background */ + --bg-card: #111111; /* Card/Element Background */ + --bg-input: #161616; /* Input Fields */ + + --border-light: #333333; + --border-dark: #1f1f1f; + + --text-main: #ffffff; + --text-muted: #888888; + + --accent-glow: rgba(255, 255, 255, 0.1); + --hover-state: #222222; + + /* Dimensions */ + --header-height: 55px; + --footer-height: 30px; } * { - padding: 0; margin: 0; + padding: 0; + box-sizing: border-box; + font-family: 'Poppins', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } body { - font-family: "poppins", sans-serif; - background: #000000; - color: #e7e7e7; - margin: 0; + background-color: var(--bg-body); + color: var(--text-main); + overflow: hidden; /* App-like feel, no window scroll */ + height: 100vh; + width: 100vw; } +/* ========================================= + 2. SCROLLBARS (Custom & Sleek) + ========================================= */ ::-webkit-scrollbar { - display: none; -} - -a { - text-decoration: none; - color: inherit; -} - -.theme-btn { - border: none; - padding: 0px; + width: 6px; + height: 6px; } -.invert { - filter: invert(1) hue-rotate(180deg); +::-webkit-scrollbar-track { + background: var(--bg-body); } -/* Elements that should remain same in both themes */ -.same.invert { - filter: invert(1) hue-rotate(180deg); -} - -button { - cursor: pointer; - padding: 7px 15px; +::-webkit-scrollbar-thumb { + background: #333; border-radius: 3px; - background-color: transparent; - color: rgb(201, 201, 201); - cursor: pointer; - border: 1px solid var(--border-color); -} - -main { - padding-top: 47px; -} - -.icon { - height: 20px; - margin: 0 5px 3px 0; - vertical-align: middle; + border: 1px solid var(--bg-body); } -.loading { - filter: brightness(0) invert(1); +::-webkit-scrollbar-thumb:hover { + background: #555; } +/* ========================================= + 3. HEADER + ========================================= */ .header { - position: fixed; - top: 0; - left: 0; - background-color: #000000; - border-bottom: 1px solid #3d3d3d; - padding: 10px; - width: calc(100% - 20px); - z-index: 10; + height: var(--header-height); display: flex; justify-content: space-between; align-items: center; + padding: 0 20px; + background: rgba(5, 5, 5, 0.85); + backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border-light); + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 100; } .headerIcons { display: flex; - gap: 5px; - align-items: center; + gap: 10px; } -header button { - padding: 5px; - position: relative; - height: 27px; - width: 27px; +.header button { + background: transparent; + border: 1px solid var(--border-light); + border-radius: 6px; cursor: pointer; - border-radius: 5px; - cursor: pointer; - border: 1px solid var(--border-color); + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; } -header button img { - width: 100%; - height: auto; +.header button:hover { + background: var(--hover-state); + border-color: #555; +} + +.headerIcon { + width: 16px; + height: 16px; + filter: invert(1); /* Ensures icons are white */ } +/* Hamburger Animation */ #burger { display: flex; flex-direction: column; - gap: 5px; -} - -#infinity{ - display: none; + gap: 4px; } #burger span { - width: 15px; - height: 0.1px; - background-color: #fff; + width: 16px; + height: 2px; + background: #fff; + transition: 0.3s; } -#loader { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgb(0, 0, 0); - visibility: hidden; - opacity: 0; - transition: opacity 0.3s ease; +a { + text-decoration: none; + color: var(--text-main); + font-weight: 600; + font-size: 1.1rem; display: flex; - justify-content: center; align-items: center; + gap: 8px; } -#loader.visible { - opacity: 1; - visibility: visible; +.icon { + height: 20px; + width: auto; } +/* ========================================= + 4. MAIN LAYOUT + ========================================= */ .container { display: flex; - height: calc(100vh - 75px); - width: 100vw; - overflow: hidden; + margin-top: var(--header-height); + height: calc(100vh - var(--header-height) - var(--footer-height)); + width: 100%; } -#config, -#ai { - flex-shrink: 0; +/* Common Sidebar Styles */ +#config, #ai { + background: var(--bg-panel); display: flex; flex-direction: column; - padding: 15px; - border-color: #3d3d3d; -} - -#config { - width: 300px; -} - -#ai { - width: 300px; - position: relative; -} - -#ai-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; + padding: 20px; + flex-shrink: 0; } -#ai input { - width: calc(100% - 60px); - padding-right: 50px; - border: 1px solid var(--border-color); -} +#config { width: 300px; } +#ai { width: 320px; border-left: 1px solid var(--border-dark); } -#sendBtn { - padding: 3px 12px 1px 12px; - position: absolute; - bottom: 19px; - right: 18px; +h4 { + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 1px; + font-size: 0.75rem; + margin-bottom: 15px; + border-bottom: 1px solid var(--border-dark); + padding-bottom: 5px; } -#sendBtn:hover { - background-color: #1f1f1f; +/* ========================================= + 5. DASHBOARD (Center) + ========================================= */ +#dashboard { + flex-grow: 1; + background: var(--bg-body); + padding: 20px; + overflow-y: auto; + position: relative; + /* Subtle grid pattern for tech feel */ + background-image: + linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px); + background-size: 40px 40px; } -#ai h4, -#config h4 { - margin-bottom: 10px; +/* Chart Cards */ +.chart-block { + background: var(--bg-card); + border: 1px solid var(--border-dark); + border-radius: 12px; + padding: 15px; + margin-bottom: 15px; + box-shadow: 0 4px 20px rgba(0,0,0,0.5); + transition: transform 0.2s ease, border-color 0.2s; } -#response-container { - overflow-y: auto; - padding: 10px; - padding-bottom: 50px; - border: 1px solid var(--border-color); - border-radius: 5px; - height: 100%; - color: #cbcbcb; - font-size: 14px; - display: flex; - flex-direction: column; +.chart-block:hover { + border-color: #444; + transform: translateY(-2px); } -#response-container .ai-response, -#response-container .user-query { +.chart-block h3 { + font-size: 0.9rem; + font-weight: 500; margin-bottom: 10px; - padding: 5px 10px; - border-radius: 5px; - width: fit-content; - max-width: 80%; + text-align: center; + color: var(--text-muted); } -#response-container .user-query { - align-self: flex-end; - background-color: #1a1a1a; - +#chartsContainer { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: 20px; } -#response-container .ai-response { - align-self: flex-start; - background-color: #0f0f0f; +/* Slicers (Radio Buttons as Chips) */ +.slicer { + display: flex; + gap: 10px; + margin-bottom: 20px; + flex-wrap: wrap; } +.slicer input[type="radio"] { display: none; } -#dashboard { - position: relative; - flex-grow: 1; - padding: 10px; - overflow-y: auto; +.slicer label { + font-size: 0.85rem; + padding: 6px 16px; + background: var(--bg-card); + border: 1px solid var(--border-dark); + color: var(--text-muted); + border-radius: 20px; + cursor: pointer; + transition: all 0.2s; } -.divider { - width: 5px; - cursor: col-resize; - border: 1px solid #2e2e2e; - transition: background 0.2s, box-shadow 0.2s; +.slicer label:hover { + background: var(--hover-state); + color: var(--text-main); } -.divider:hover { - background: var(--border-color); +.slicer input[type="radio"]:checked + label { + background: #fff; + color: #000; + border-color: #fff; + font-weight: 600; } -.divider-handle { - width: 3px; - height: 30px; - background-color: var(--border-color); - position: relative; - left: 1px; - top: calc(50% - 15px); - border-radius: 3px; -} - -select { - padding: 0 5px; - height: 30px; - border-radius: 2px; - border: none; +/* ========================================= + 6. CONFIG & FORMS + ========================================= */ +select, input[type="text"] { + width: 100%; + background: var(--bg-input); + border: 1px solid var(--border-dark); color: white; - background-color: var(--bg-color); - border-radius: 5px; - border: 1px solid var(--border-color); -} - -select:focus { - background-color: var(--bg-color); + padding: 10px 12px; + border-radius: 6px; + margin-bottom: 12px; outline: none; + font-size: 0.9rem; + transition: border 0.2s; } -option { - background-color: #000000; - color: white; +select:focus, input[type="text"]:focus { + border-color: #666; } -input[type="text"] { - width: calc(100% - 20px); - flex: 1; - padding: 5px 10px; - margin-top: 10px; - border: none; - color: white; - background-color: var(--bg-color); - border: 1px solid var(--border-color); - border-radius: 5px; - font-size: 15px; - cursor: text; -} - -input:focus { - color: white; - caret-color: white; - outline: none; - background-color: var(--bg-color); +/* Buttons */ +button { + cursor: pointer; + font-family: inherit; } -input:-webkit-autofill { - background-color: var(--bg-color) !important; - -webkit-text-fill-color: #fff !important; +#loadBtn, #sendBtn { + background: #fff; + color: #000; + border: none; + padding: 8px 16px; + border-radius: 4px; + font-weight: 600; + transition: opacity 0.2s; + width: 100%; } -input:-internal-autofill-selected { - background-color: var(--bg-color) !important; - -webkit-text-fill-color: #fff !important; +#loadBtn:hover, #sendBtn:hover { + opacity: 0.9; } -/* For Firefox */ -input:-moz-autofill { - background-color: var(--bg-color) !important; - -moz-text-fill-color: #fff !important; +#sendBtn { + width: auto; + position: absolute; + right: 5px; + bottom: 5px; + padding: 5px 12px; } -#loadBtn { - display: none; - flex-direction: row; - margin: 10px 0 10px auto; - padding: 7px 25px; - width: min-content; - border-radius: 5px; - color: white; - cursor: pointer; +/* ========================================= + 7. AI CHAT SECTION + ========================================= */ +#ai-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; } #clearBtn { - padding: 7px 25px; - border-radius: 5px; - color: white; - cursor: pointer; + background: transparent; + color: var(--text-muted); + border: 1px solid var(--border-dark); + padding: 4px 10px; + font-size: 0.8rem; + border-radius: 4px; } -.details { - margin-top: 10px; - line-height: 23px; +#clearBtn:hover { + color: #fff; + border-color: #fff; } -.slicer { +#response-container { + flex-grow: 1; + overflow-y: auto; + border: 1px solid var(--border-dark); + background: rgba(0,0,0,0.2); + border-radius: 8px; + padding: 10px; + margin-bottom: 10px; display: flex; - gap: 8px; - margin: 10px 0; + flex-direction: column; + gap: 15px; } -.slicer input[type="radio"] { - display: none; - /* hide default dots */ +.ai-response, .user-query { + max-width: 85%; + padding: 10px 14px; + border-radius: 10px; + font-size: 0.9rem; + line-height: 1.5; } -.slicer label { - padding: 6px 14px; - border-radius: 20px; - cursor: pointer; - font-size: 14px; - background: var(--bg-color); - color: #eee; - border: 1px solid var(--border-color); -} - -.slicer label:hover { - background: #2a2a2a; +.ai-response { + align-self: flex-start; + background: #1a1a1a; + border: 1px solid #2a2a2a; + color: #ddd; + border-top-left-radius: 2px; } -.slicer input[type="radio"]:checked+label { - background: rgb(0, 31, 31); - /* highlight color */ - border-color: rgb(1, 185, 185); - color: rgb(1, 185, 185); +.user-query { + align-self: flex-end; + background: #e0e0e0; + color: #000; + border-bottom-right-radius: 2px; } -#chartsContainer { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - /* fills all available space */ - gap: 10px; +.ai-inputs { + position: relative; width: 100%; - box-sizing: border-box; - justify-content: stretch; - /* ensures full width usage */ - align-items: start; } -.chart-block { - padding: 5px; - width: 100%; - /* fill grid cell */ - display: flex; - flex-direction: column; - align-items: stretch; - border: 1px solid #1a1a1a; - border-radius: 7px; - box-sizing: border-box; - cursor: pointer; +.ai-inputs input { + margin-bottom: 0; + padding-right: 45px; /* Space for button */ } -.chart-block h3 { - text-align: center; - margin-bottom: 10px; - font-size: 1rem; +/* ========================================= + 8. TABLES & LOGS + ========================================= */ +#logSection { + margin-top: 20px; + border: 1px solid var(--border-dark); + border-radius: 8px; + background: var(--bg-card); } -/* Keep charts proportional without stretching */ -.chart-block canvas { - width: 100% !important; - height: 200px !important; - object-fit: contain; +summary { + padding: 12px; + cursor: pointer; + font-weight: 600; + background: #151515; + border-bottom: 1px solid var(--border-dark); + list-style: none; /* Hide default triangle */ } - -.copy-btn { - background-color: #1b1b1b; - border: 1px solid var(--border-color); - cursor: pointer; - position: absolute; - left: 0px; - padding: 1px 2px; - display: none; +summary:after { + content: "+"; + float: right; + font-weight: bold; } -.copy-btn img { - height: 12px; - vertical-align: middle; - filter: brightness(0) invert(1); +details[open] summary:after { + content: "-"; } .table-wrapper { - width: 100%; overflow-x: auto; + padding: 0; } table { width: 100%; border-collapse: collapse; - margin-top: 18px; - font-size: 13px; - border-radius: 7px; - min-width: 600px; -} - -th, -td { - border: 1px solid #1b1b1b; - padding: 8px; - text-align: center; - white-space: nowrap; + font-size: 0.85rem; } th { - background: #1b1b1b; -} - -tr:nth-child(even) { background: #0f0f0f; + color: var(--text-muted); + font-weight: 500; + text-align: left; + padding: 10px; + border-bottom: 1px solid var(--border-dark); } -tr:hover { - background: rgb(25, 21, 0); - color: rgb(255, 214, 0); +td { + padding: 8px 10px; + border-bottom: 1px solid #1a1a1a; + color: #ccc; } -tr:hover .copy-btn { - display: inline-block; +tr:hover td { + background: #1a1a1a; + color: #fff; } -#logSection { - position: relative; - max-width: calc(100vw - 590px); - overflow-x: scroll; - display: none; - margin: 20px 0; - border-radius: 5px; - background-color: #0f0f0f; - padding: 0 10px; +/* ========================================= + 9. UTILITIES & DIVIDERS + ========================================= */ +.divider { + width: 8px; + cursor: col-resize; + background: var(--bg-body); + display: flex; + justify-content: center; + align-items: center; + border-left: 1px solid var(--border-dark); + border-right: 1px solid var(--border-dark); } -#logSection summary { - padding: 10px; - cursor: pointer; - user-select: none; +.divider:hover { + background: #111; } -#chName { - font-size: 30px; - font-weight: bold; +.divider-handle { + width: 2px; + height: 30px; + background: #444; } -#msg-container { - height: auto; - pointer-events: none; +#loader { display: flex; - flex-direction: column-reverse; -} - -.msg { - visibility: hidden; - margin-top: 5px; - z-index: 50; - opacity: 0; - padding: 5px; - width: calc(100% - 12px); - max-width: calc(100vw - 40px); - border-radius: 5px; - background-color: #0f0b00; - border: 1px solid #9b6d00; - color: #eda600; - transition: visibility 0.3s, opacity 0.3s linear, transform 0.3s ease-out; + justify-content: center; + align-items: center; + margin: 20px 0; } +/* ========================================= + 10. FOOTER + ========================================= */ footer { - border-top: 1px solid #3d3d3d; - color: #777; - font-size: 12px; - line-height: 14px; - padding: 3px; + height: var(--footer-height); + background: var(--bg-body); + border-top: 1px solid var(--border-dark); display: flex; justify-content: space-between; - width: calc(100% - 6px); -} - -/* Modal overlay */ -.chart-modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - backdrop-filter: blur(10px); - background: rgba(0, 0, 0, 0.7); - display: flex; align-items: center; - justify-content: center; - z-index: 9999; - opacity: 0; - filter: blur(10px); - pointer-events: none; - transition: opacity 0.5s ease-in-out, filter 0.5s ease-in-out; -} - -/* Show modal */ -.chart-modal.active { - opacity: 1; - pointer-events: all; - filter: blur(0); -} - -/* Modal content box */ -.chart-modal-content { - position: relative; - width: 95%; - max-width: 900px; - box-shadow: 0 0 25px rgba(0, 0, 0, 0.4); -} - -/* Close button */ -.chart-modal-close { - position: absolute; - top: 0px; - right: 0px; - color: #fff; - font-size: 22px; - font-weight: bold; - cursor: pointer; - z-index: 10; -} - -/* Canvas inside modal */ -.chart-modal canvas { - width: 100% !important; - height: 70vh !important; - cursor: crosshair; + padding: 0 20px; + font-size: 0.75rem; + color: #444; } - +/* ========================================= + 11. RESPONSIVE / MOBILE + ========================================= */ @media screen and (max-width: 900px) { - - #config, - #ai, - #dashboard { - width: calc(100vw - 30px); - } - .container { flex-direction: column; - position: relative; height: auto; - width: calc(100vw); + overflow-y: auto; } - .chart-block { - width: calc(100vw - 30px) !important; + #config, #dashboard { + width: 100%; + border-right: none; } - - #logSection { - max-width: calc(100vw - 30px); + + #config { + border-bottom: 1px solid var(--border-dark); } - #msg-container { - width: calc(100vw - 30px); - position: fixed; - top: 60px; - justify-content: center; - align-items: center; - z-index: 200; - } + /* Hide divider on mobile */ + .divider { display: none; } - .msg { + /* AI becomes an overlay on mobile */ + #ai { + display: none; /* JS toggles this */ + position: fixed; + top: var(--header-height); + right: 0; width: 100%; + height: calc(100vh - var(--header-height)); + z-index: 200; + background: black; } - .divider { - display: none; - } - - footer { - position: fixed; - bottom: 0; - background-color: #000000; + /* Show the infinity button on mobile */ + #infinity { + display: flex !important; } -#infinity{ - display: block; } - #ai { - display: none; - position: fixed; - top:65px; - height: calc(100vh - 130px); - background-color: #000000; - border: 1px solid var(--border-color); - width: calc(100vw - 50px); - z-index: 10; - left: 9px; - } - #response-container { - height: calc(100vh - 274px); - } +/* Infinity button only shows on desktop if you want, + but based on HTML it seems it's a mobile toggle. + Hidden by default on Desktop usually, but let's keep it clean: */ +@media screen and (min-width: 901px) { + #infinity { display: none; } } \ No newline at end of file diff --git a/index.html b/index.html index f112bca..0bd957d 100644 --- a/index.html +++ b/index.html @@ -60,6 +60,11 @@