From 3727fc0f303802fe631fb09587b3721c8fa0d544 Mon Sep 17 00:00:00 2001
From: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
Date: Thu, 21 Aug 2025 17:51:59 +1000
Subject: [PATCH 1/7] Add files via upload
Signed-off-by: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
---
new-frontend/frontend/postcss.config.js | 6 ++++++
new-frontend/frontend/tailwind.config.js | 6 ++++++
2 files changed, 12 insertions(+)
create mode 100644 new-frontend/frontend/postcss.config.js
create mode 100644 new-frontend/frontend/tailwind.config.js
diff --git a/new-frontend/frontend/postcss.config.js b/new-frontend/frontend/postcss.config.js
new file mode 100644
index 0000000..1e8e944
--- /dev/null
+++ b/new-frontend/frontend/postcss.config.js
@@ -0,0 +1,6 @@
+// postcss.config.js
+export default {
+ plugins: {
+ '@tailwindcss/postcss': {},
+ },
+}
\ No newline at end of file
diff --git a/new-frontend/frontend/tailwind.config.js b/new-frontend/frontend/tailwind.config.js
new file mode 100644
index 0000000..76ab992
--- /dev/null
+++ b/new-frontend/frontend/tailwind.config.js
@@ -0,0 +1,6 @@
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
+ theme: { extend: {} },
+ plugins: [],
+}
From b6bc5d8f85f5430e454bc35f0d58f6a826af84f1 Mon Sep 17 00:00:00 2001
From: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
Date: Thu, 21 Aug 2025 17:52:39 +1000
Subject: [PATCH 2/7] Add files via upload
Signed-off-by: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
---
new-frontend/frontend/src/index.css | 69 +----------------------------
1 file changed, 1 insertion(+), 68 deletions(-)
diff --git a/new-frontend/frontend/src/index.css b/new-frontend/frontend/src/index.css
index 08a3ac9..a461c50 100644
--- a/new-frontend/frontend/src/index.css
+++ b/new-frontend/frontend/src/index.css
@@ -1,68 +1 @@
-:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
-}
+@import "tailwindcss";
\ No newline at end of file
From 0aae8a5116786756789f7898bfc85854f71148f8 Mon Sep 17 00:00:00 2001
From: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
Date: Thu, 21 Aug 2025 17:53:06 +1000
Subject: [PATCH 3/7] Add files via upload
Signed-off-by: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
---
new-frontend/frontend/src/pages/HomePage.jsx | 179 +++++++++++++++++--
1 file changed, 162 insertions(+), 17 deletions(-)
diff --git a/new-frontend/frontend/src/pages/HomePage.jsx b/new-frontend/frontend/src/pages/HomePage.jsx
index cc3f45e..91889d2 100644
--- a/new-frontend/frontend/src/pages/HomePage.jsx
+++ b/new-frontend/frontend/src/pages/HomePage.jsx
@@ -1,22 +1,167 @@
-import { Link } from 'react-router-dom';
+import { Link } from "react-router-dom";
+
+const ThermometerIcon = (props) => (
+
+);
+const DropletIcon = (props) => (
+
+);
+const AirIcon = (props) => (
+
+);
const datasets = [
- { id: 'sensor1', name: 'Sensor 1' },
- { id: 'sensor2', name: 'Sensor 2' },
- { id: 'sensor3', name: 'Sensor 3' },
+ {
+ id: "sensor1",
+ name: "Sensor 1",
+ desc: "Temperature readings",
+ gradient: "from-teal-600 to-teal-500",
+ icon: ThermometerIcon,
+ status: "live",
+ anomalies24h: 2,
+ },
+ {
+ id: "sensor2",
+ name: "Sensor 2",
+ desc: "Humidity monitoring",
+ gradient: "from-orange-600 to-amber-500",
+ icon: DropletIcon,
+ status: "live",
+ anomalies24h: 0,
+ },
+ {
+ id: "sensor3",
+ name: "Sensor 3",
+ desc: "Air quality index",
+ gradient: "from-violet-600 to-fuchsia-500",
+ icon: AirIcon,
+ status: "offline",
+ anomalies24h: 5,
+ },
];
-const HomePage = () => (
-
-
Available Sensor Datasets
-
- {datasets.map(ds => (
- -
- {ds.name}
-
- ))}
-
-
-);
+function StatusBadge({ status }) {
+ const isLive = status === "live";
+ return (
+
+
+ {isLive ? "Live" : "Offline"}
+
+ );
+}
+
+export default function HomePage() {
+ return (
+
+
+
+
+
+
+ IoT Sensors Dashboard
+
+
+ Time-series data, anomaly awareness, and correlation insights — all in one place.
+
+
+
+
+ Available Sensor Datasets
+
+
+ {datasets.map((ds) => {
+ const Icon = ds.icon;
+ return (
+
+
+
+
+
+
+
+
+
Dataset
+
+ {ds.name}
+
+
+
+
+
+
+
+
+
+
+
+ Last 24h anomalies
+ 0
+ ? "bg-rose-50 text-rose-600"
+ : "bg-emerald-50 text-emerald-600"
+ }`}
+ >
+ {ds.anomalies24h}
+
+
+
+
+ View dashboard →
+
+
+
+
+ );
+ })}
+
+
-export default HomePage;
+
+
+ );
+}
From eb4cc13b8538e26cbb3ef1158fd6c19293ac098f Mon Sep 17 00:00:00 2001
From: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
Date: Tue, 2 Sep 2025 18:12:57 +1000
Subject: [PATCH 4/7] Add files via upload
Signed-off-by: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
---
.../frontend/src/components/DatasetCard.jsx | 63 +++++++++++++++++++
.../frontend/src/components/DatasetsGrid.jsx | 38 +++++++++++
.../frontend/src/components/Footer.jsx | 9 +++
.../frontend/src/components/Header.jsx | 19 ++++++
new-frontend/frontend/src/components/Icon.jsx | 14 +++++
.../frontend/src/components/Section.jsx | 10 +++
.../frontend/src/components/StatusBadge.jsx | 13 ++++
7 files changed, 166 insertions(+)
create mode 100644 new-frontend/frontend/src/components/DatasetCard.jsx
create mode 100644 new-frontend/frontend/src/components/DatasetsGrid.jsx
create mode 100644 new-frontend/frontend/src/components/Footer.jsx
create mode 100644 new-frontend/frontend/src/components/Header.jsx
create mode 100644 new-frontend/frontend/src/components/Icon.jsx
create mode 100644 new-frontend/frontend/src/components/Section.jsx
create mode 100644 new-frontend/frontend/src/components/StatusBadge.jsx
diff --git a/new-frontend/frontend/src/components/DatasetCard.jsx b/new-frontend/frontend/src/components/DatasetCard.jsx
new file mode 100644
index 0000000..97e5104
--- /dev/null
+++ b/new-frontend/frontend/src/components/DatasetCard.jsx
@@ -0,0 +1,63 @@
+import { Link } from "react-router-dom";
+import StatusBadge from "./StatusBadge";
+import Icon from "./Icon";
+
+const GRADIENT = {
+ temperature: "from-teal-600 to-teal-500",
+ humidity: "from-orange-600 to-amber-500",
+ air: "from-violet-600 to-fuchsia-500",
+ default: "from-slate-600 to-slate-500",
+};
+
+export default function DatasetCard({ dataset }) {
+ const {
+ id, // string (e.g., "temp-sensor-01")
+ name, // display name
+ description, // short text
+ type, // "temperature" | "humidity" | "air" | ...
+ status, // "live" | "offline" | "degraded"
+ anomalies24h, // number
+ gradient, // optional override
+ } = dataset;
+
+ const g = gradient || GRADIENT[type] || GRADIENT.default;
+
+ return (
+
+
+
+
+
+ Last 24h anomalies
+ 0 ? "bg-rose-50 text-rose-600" : "bg-emerald-50 text-emerald-600"}`}>
+ {anomalies24h ?? 0}
+
+
+
+
+ View dashboard →
+
+
+
+
+ );
+}
diff --git a/new-frontend/frontend/src/components/DatasetsGrid.jsx b/new-frontend/frontend/src/components/DatasetsGrid.jsx
new file mode 100644
index 0000000..60fdadf
--- /dev/null
+++ b/new-frontend/frontend/src/components/DatasetsGrid.jsx
@@ -0,0 +1,38 @@
+import DatasetCard from "./DatasetCard";
+import Section from "./Section";
+
+function Skeleton() {
+ return (
+
+ {[...Array(3)].map((_, i) => (
+
+ ))}
+
+ );
+}
+
+export default function DatasetsGrid({ datasets = [], loading = false, error = null }) {
+ return (
+
+ {error && (
+
+ Could not load datasets. Please try again.
+
+ )}
+ {loading ? (
+
+ ) : (
+
+ {datasets.map((ds) => )}
+
+ )}
+
+ );
+}
diff --git a/new-frontend/frontend/src/components/Footer.jsx b/new-frontend/frontend/src/components/Footer.jsx
new file mode 100644
index 0000000..9fc1498
--- /dev/null
+++ b/new-frontend/frontend/src/components/Footer.jsx
@@ -0,0 +1,9 @@
+export default function Footer({ note = "Built with React & Tailwind" }) {
+ return (
+
+ );
+}
diff --git a/new-frontend/frontend/src/components/Header.jsx b/new-frontend/frontend/src/components/Header.jsx
new file mode 100644
index 0000000..b11fb68
--- /dev/null
+++ b/new-frontend/frontend/src/components/Header.jsx
@@ -0,0 +1,19 @@
+export default function Header({ brand = "Intelligent IoT", nav = [] }) {
+ return (
+
+
+
+
+ IoT
+
+ {brand}
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/new-frontend/frontend/src/components/Icon.jsx b/new-frontend/frontend/src/components/Icon.jsx
new file mode 100644
index 0000000..27f2a08
--- /dev/null
+++ b/new-frontend/frontend/src/components/Icon.jsx
@@ -0,0 +1,14 @@
+function Thermometer(props){return()}
+function Droplet(props){return()}
+function Air(props){return()}
+
+const ICONS = {
+ temperature: Thermometer,
+ humidity: Droplet,
+ air: Air,
+};
+
+export default function Icon({ name, className = "h-6 w-6" }) {
+ const Comp = ICONS[name] || Air; // fallback generic
+ return ;
+}
diff --git a/new-frontend/frontend/src/components/Section.jsx b/new-frontend/frontend/src/components/Section.jsx
new file mode 100644
index 0000000..bc98c05
--- /dev/null
+++ b/new-frontend/frontend/src/components/Section.jsx
@@ -0,0 +1,10 @@
+export default function Section({ id, title, center = false, className = "", children }) {
+ return (
+
+ {title && (
+ {title}
+ )}
+ {children}
+
+ );
+}
\ No newline at end of file
diff --git a/new-frontend/frontend/src/components/StatusBadge.jsx b/new-frontend/frontend/src/components/StatusBadge.jsx
new file mode 100644
index 0000000..5ca544b
--- /dev/null
+++ b/new-frontend/frontend/src/components/StatusBadge.jsx
@@ -0,0 +1,13 @@
+export default function StatusBadge({ status = "offline" }) {
+ const palette = {
+ live: { pill: "bg-emerald-100 text-emerald-700", dot: "bg-emerald-600", text: "Live" },
+ offline:{ pill: "bg-rose-100 text-rose-700", dot: "bg-rose-600", text: "Offline" },
+ degraded:{ pill:"bg-amber-100 text-amber-800", dot: "bg-amber-600", text: "Degraded" },
+ };
+ const s = palette[status] || palette.offline;
+ return (
+
+ {s.text}
+
+ );
+}
From 6bb859178a71f48fc6ed72d6b8b05349babdea69 Mon Sep 17 00:00:00 2001
From: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
Date: Tue, 2 Sep 2025 18:15:01 +1000
Subject: [PATCH 5/7] Add files via upload
Signed-off-by: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
---
.../frontend/src/hooks/useDatasets.js | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 new-frontend/frontend/src/hooks/useDatasets.js
diff --git a/new-frontend/frontend/src/hooks/useDatasets.js b/new-frontend/frontend/src/hooks/useDatasets.js
new file mode 100644
index 0000000..c8fdac9
--- /dev/null
+++ b/new-frontend/frontend/src/hooks/useDatasets.js
@@ -0,0 +1,27 @@
+import { useEffect, useState } from "react";
+
+export default function useDatasets() {
+ const [datasets, setDatasets] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ let cancelled = false;
+ (async () => {
+ try {
+ // Replace with your real endpoint
+ const res = await fetch("/api/datasets");
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
+ const data = await res.json();
+ if (!cancelled) setDatasets(Array.isArray(data) ? data : []);
+ } catch (e) {
+ if (!cancelled) setError(e);
+ } finally {
+ if (!cancelled) setLoading(false);
+ }
+ })();
+ return () => { cancelled = true; };
+ }, []);
+
+ return { datasets, loading, error };
+}
From f0449afff1b7953d0fca896580afb08cbb075a80 Mon Sep 17 00:00:00 2001
From: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
Date: Tue, 2 Sep 2025 18:15:31 +1000
Subject: [PATCH 6/7] Add files via upload
Signed-off-by: Sukunadot <85873221+Sukunadot@users.noreply.github.com>
---
new-frontend/frontend/src/pages/HomePage.jsx | 166 ++-----------------
1 file changed, 12 insertions(+), 154 deletions(-)
diff --git a/new-frontend/frontend/src/pages/HomePage.jsx b/new-frontend/frontend/src/pages/HomePage.jsx
index 91889d2..c154acf 100644
--- a/new-frontend/frontend/src/pages/HomePage.jsx
+++ b/new-frontend/frontend/src/pages/HomePage.jsx
@@ -1,167 +1,25 @@
-import { Link } from "react-router-dom";
-
-const ThermometerIcon = (props) => (
-
-);
-const DropletIcon = (props) => (
-
-);
-const AirIcon = (props) => (
-
-);
-
-const datasets = [
- {
- id: "sensor1",
- name: "Sensor 1",
- desc: "Temperature readings",
- gradient: "from-teal-600 to-teal-500",
- icon: ThermometerIcon,
- status: "live",
- anomalies24h: 2,
- },
- {
- id: "sensor2",
- name: "Sensor 2",
- desc: "Humidity monitoring",
- gradient: "from-orange-600 to-amber-500",
- icon: DropletIcon,
- status: "live",
- anomalies24h: 0,
- },
- {
- id: "sensor3",
- name: "Sensor 3",
- desc: "Air quality index",
- gradient: "from-violet-600 to-fuchsia-500",
- icon: AirIcon,
- status: "offline",
- anomalies24h: 5,
- },
-];
-
-function StatusBadge({ status }) {
- const isLive = status === "live";
- return (
-
-
- {isLive ? "Live" : "Offline"}
-
- );
-}
+import Header from "../components/Header";
+import Section from "../components/Section";
+import DatasetsGrid from "../components/DatasetsGrid";
+import Footer from "../components/Footer";
+import useDatasets from "../hooks/useDatasets";
export default function HomePage() {
+ const { datasets, loading, error } = useDatasets();
+
return (
-
-
-
-
+
+
IoT Sensors Dashboard
Time-series data, anomaly awareness, and correlation insights — all in one place.
-
-
-
- Available Sensor Datasets
-
-
- {datasets.map((ds) => {
- const Icon = ds.icon;
- return (
-
-
-
-
-
-
-
-
-
Dataset
-
- {ds.name}
-
-
-
-
-
-
-
-
-
-
-
- Last 24h anomalies
- 0
- ? "bg-rose-50 text-rose-600"
- : "bg-emerald-50 text-emerald-600"
- }`}
- >
- {ds.anomalies24h}
-
-
-
-
- View dashboard →
-
-
-
-
- );
- })}
-
-
-
-
+
+
+
);
}
From fcd254212da6bc2df4322992b4aa8f48b69f36a9 Mon Sep 17 00:00:00 2001
From: Bhanu Singh Thakur
Date: Tue, 2 Sep 2025 19:46:22 +1000
Subject: [PATCH 7/7] updated files
---
new-frontend/frontend/src/data/datasets.js | 29 +++++++++++++++++++
.../frontend/src/hooks/useDatasets.js | 14 +++++----
2 files changed, 38 insertions(+), 5 deletions(-)
create mode 100644 new-frontend/frontend/src/data/datasets.js
diff --git a/new-frontend/frontend/src/data/datasets.js b/new-frontend/frontend/src/data/datasets.js
new file mode 100644
index 0000000..98e96c9
--- /dev/null
+++ b/new-frontend/frontend/src/data/datasets.js
@@ -0,0 +1,29 @@
+export const datasets = [
+ {
+ id: "temp-01",
+ name: "Sensor 1",
+ description: "Temperature readings",
+ type: "temperature",
+ status: "live",
+ anomalies24h: 2,
+ gradient: "from-teal-600 to-teal-500",
+ },
+ {
+ id: "hum-02",
+ name: "Sensor 2",
+ description: "Humidity monitoring",
+ type: "humidity",
+ status: "live",
+ anomalies24h: 0,
+ gradient: "from-orange-600 to-amber-500",
+ },
+ {
+ id: "aqi-03",
+ name: "Sensor 3",
+ description: "Air quality index",
+ type: "air",
+ status: "offline",
+ anomalies24h: 5,
+ gradient: "from-violet-600 to-fuchsia-500",
+ },
+];
diff --git a/new-frontend/frontend/src/hooks/useDatasets.js b/new-frontend/frontend/src/hooks/useDatasets.js
index c8fdac9..6b850b5 100644
--- a/new-frontend/frontend/src/hooks/useDatasets.js
+++ b/new-frontend/frontend/src/hooks/useDatasets.js
@@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
+import { datasets as seed } from "../data/datasets";
export default function useDatasets() {
const [datasets, setDatasets] = useState([]);
@@ -7,19 +8,22 @@ export default function useDatasets() {
useEffect(() => {
let cancelled = false;
+
(async () => {
try {
- // Replace with your real endpoint
- const res = await fetch("/api/datasets");
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
- const data = await res.json();
- if (!cancelled) setDatasets(Array.isArray(data) ? data : []);
+ // Try real API here later; for now just use seed
+ await new Promise(r => setTimeout(r, 120)); // optional tiny delay for skeleton
+ if (!cancelled) {
+ setDatasets(seed);
+ setError(null);
+ }
} catch (e) {
if (!cancelled) setError(e);
} finally {
if (!cancelled) setLoading(false);
}
})();
+
return () => { cancelled = true; };
}, []);