Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions app/components/MarkdownNotes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";
import type { Components } from "react-markdown";

const markdownComponents: Components = {
h1: ({ children }) => (
<h1 className="text-3xl md:text-4xl font-bold mb-4">{children}</h1>
),
h2: ({ children }) => (
<h2 className="section-heading mt-8 mb-3">{children}</h2>
),
h3: ({ children }) => (
<h3 className="text-xl md:text-2xl font-bold mt-6 mb-2">{children}</h3>
),
p: ({ children }) => <p className="p-text">{children}</p>,
ul: ({ children }) => <ul className="section-list mb-6">{children}</ul>,
ol: ({ children }) => (
<ol className="section-list list-decimal mb-6">{children}</ol>
),
li: ({ children }) => <li className="mb-1">{children}</li>,
blockquote: ({ children }) => (
<blockquote className="border-l-4 border-[#fccc7e] bg-[#2b1b0e]/40 pl-4 py-2 my-4 italic">
{children}
</blockquote>
),
pre: ({ children }) => (
<pre className="example-box overflow-x-auto text-sm md:text-base mb-6">
{children}
</pre>
),
code: ({ className, children }) => {
const isBlock = Boolean(className);
if (isBlock) {
return <code className={className}>{children}</code>;
}
return (
<code className="bg-[#2b1b0e]/50 px-1.5 py-0.5 rounded text-[#fccc7e]">
{children}
</code>
);
},
img: ({ src, alt }) => (
// eslint-disable-next-line @next/next/no-img-element
<img
src={src}
alt={alt ?? ""}
className="my-4 max-w-full rounded border border-[#e2d1c1]/30"
/>
),
table: ({ children }) => (
<div className="overflow-x-auto mb-6">
<table className="w-full border-collapse text-sm md:text-base">
{children}
</table>
</div>
),
th: ({ children }) => (
<th className="border border-[#e2d1c1]/40 bg-[#2b1b0e]/60 px-3 py-2 text-left">
{children}
</th>
),
td: ({ children }) => (
<td className="border border-[#e2d1c1]/40 px-3 py-2">{children}</td>
),
hr: () => <hr className="my-8 border-t-2 border-[#e2d1c1]/40" />,
a: ({ href, children }) => (
<a
href={href}
className="text-[#fccc7e] underline hover:text-[#ffdda7]"
target={href?.startsWith("http") ? "_blank" : undefined}
rel={href?.startsWith("http") ? "noopener noreferrer" : undefined}
>
{children}
</a>
),
};

type MarkdownNotesProps = {
content: string;
};

export function MarkdownNotes({ content }: MarkdownNotesProps) {
return (
<div className="course-content iot-markdown">
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
{content}
</ReactMarkdown>
</div>
);
}
148 changes: 148 additions & 0 deletions app/sem5/iot/[chapter]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import fs from "fs/promises";
import Link from "next/link";
import { Metadata } from "next";
import { Righteous } from "next/font/google";
import { ArrowBigLeft, ArrowBigRight } from "lucide-react";

import { MarkdownNotes } from "@/app/components/MarkdownNotes";
import {
getIotChapter,
iotChapters,
iotNotesDir,
} from "@/lib/iotChapters";
import { Ch0Content } from "../content/chapter0";

const righteous = Righteous({
subsets: ["latin"],
weight: "400",
variable: "--font-righteous",
});

type ChapterProps = {
params: Promise<{ chapter: string }>;
};

export async function generateMetadata({
params,
}: ChapterProps): Promise<Metadata> {
const { chapter: chapterId } = await params;
const chapter = getIotChapter(chapterId);
const title = chapter
? `${chapter.title} | IoT | openCSE`
: "Internet of Things | openCSE";
return { title };
}

async function loadMarkdown(fileName: string) {
const filePath = `${iotNotesDir}/${fileName}`;
return fs.readFile(filePath, "utf8");
}

export default async function ChapterPage({ params }: ChapterProps) {
const { chapter: chapterId } = await params;
const currentIndex = iotChapters.findIndex((c) => c.id === chapterId);
const chapter = iotChapters[currentIndex];

if (!chapter) {
return (
<div className="flex flex-col items-center justify-center min-h-[50vh] text-[#e2d1c1]">
<h1 className="text-2xl font-bold mb-4">Module not found</h1>
<Link
href="/sem5/iot/ch0"
className="px-4 py-2 bg-[#e2d1c1] text-[#1b0d00] rounded hover:bg-[#ac9e91] transition font-bold"
>
Return to Course Outline
</Link>
</div>
);
}

const prevChapter = currentIndex > 0 ? iotChapters[currentIndex - 1] : null;
const nextChapter =
currentIndex < iotChapters.length - 1
? iotChapters[currentIndex + 1]
: null;

let body: React.ReactNode;
if (chapter.id === "ch0") {
body = <Ch0Content />;
} else if (chapter.markdownFile) {
const markdown = await loadMarkdown(chapter.markdownFile);
body = <MarkdownNotes content={markdown} />;
} else {
body = <p className="p-text">Content coming soon.</p>;
}

const navLinkClass =
"px-4 py-1 text-2xl flex items-center justify-center bg-[#e2d1c1] text-[#1b0d00] rounded hover:bg-[#ac9e91] transition";

return (
<div className="flex flex-col bg-[#1B0D00] min-h-full p-2 pt-16 text-[#e2d1c1]">
<div className="flex-1">
<h1 className={`text-4xl font-bold ${righteous.className} mb-2`}>
Internet of Things (IoT)
</h1>

<p className={`text-2xl mt-[-8px] ${righteous.className}`}>
{chapter.title}
</p>

<div className="flex justify-between mt-3">
{prevChapter ? (
<Link
href={`/sem5/iot/${prevChapter.id}`}
className={navLinkClass}
style={{ fontFamily: "Rockwell, Serif, serif" }}
>
<ArrowBigLeft className="inline-block mr-1" /> Previous
</Link>
) : (
<div />
)}

{nextChapter ? (
<Link
href={`/sem5/iot/${nextChapter.id}`}
className={navLinkClass}
style={{ fontFamily: "Rockwell, Serif, serif" }}
>
Next <ArrowBigRight className="inline-block ml-1" />
</Link>
) : (
<div />
)}
</div>

<hr className="my-6 border-t-3" />
{body}
</div>

<div className="flex justify-between my-8">
{prevChapter ? (
<Link
href={`/sem5/iot/${prevChapter.id}`}
className="px-4 py-2 bg-[#e2d1c1] text-xl flex items-center justify-center text-[#1b0d00] rounded hover:bg-[#ac9e91] transition"
style={{ fontFamily: "Rockwell, Serif, serif" }}
>
<ArrowBigLeft className="inline-block mr-1" /> {prevChapter.title}
</Link>
) : (
<div />
)}

{nextChapter ? (
<Link
href={`/sem5/iot/${nextChapter.id}`}
className="px-4 py-2 bg-[#e2d1c1] text-xl flex items-center justify-center text-[#1b0d00] rounded hover:bg-[#ac9e91] transition"
style={{ fontFamily: "Rockwell, Serif, serif" }}
>
{nextChapter.title}{" "}
<ArrowBigRight className="inline-block ml-1" />
</Link>
) : (
<div />
)}
</div>
</div>
);
}
65 changes: 65 additions & 0 deletions app/sem5/iot/components/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
"use client";

import { Righteous } from "next/font/google";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useState } from "react";

import { iotChapters } from "@/lib/iotChapters";

const righteous = Righteous({
subsets: ["latin"],
weight: "400",
variable: "--font-righteous",
});

export default function Sidebar() {
const pathname = usePathname();
const [open, setOpen] = useState(true);

return (
<div className="flex relative">
<aside
className={`h-[100vh] sticky top-0 bg-[#fae8d7] text-[#1B0D00] p-0 flex flex-col transition-all duration-300 ${
open ? "w-64" : "w-0 overflow-hidden"
}`}
>
<h2
className="flex items-center text-2xl font-normal pt-3 pl-3 mb-2 bg-[#cebb9c] text-[#1B0D00] pb-2 border-b-4 border-[#1B0D00]"
style={{ fontFamily: "Rockwell, Serif, serif" }}
>
Modules
</h2>

<ul className="flex-1 overflow-y-auto space-y-0">
{iotChapters.map((ch) => {
const active = pathname === `/sem5/iot/${ch.id}`;
return (
<li key={ch.id}>
<Link
href={`/sem5/iot/${ch.id}`}
className={`block px-3 py-2 text-lg transition ${
active ? "bg-[#fccc7e]" : "hover:bg-[#ffdda7af]"
} ${righteous.className}`}
>
{ch.title}
</Link>
</li>
);
})}
</ul>
</aside>

<button
type="button"
onClick={() => setOpen(!open)}
className="toggle-sidebar sticky top-[10%] left-full bg-[#ffdda7d0] h-[85vh] w-[50px] text-[#1B0D00] text-center font-semibold text-2xl border-l-4 rounded-r-2xl border-[#1B0D00] flex items-center justify-center transition-all duration-300"
style={{ fontFamily: "Rockwell, Serif, serif" }}
>
<p className="leading-5">
M<br />O<br />D<br />U<br />L<br />E<br />S
</p>
</button>
</div>
);
}
76 changes: 76 additions & 0 deletions app/sem5/iot/content/chapter0.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
export const Ch0Content = () => {
return (
<div className="course-content">
<p className="p-text">
Welcome to the <span className="font-semibold">Internet of Things (IoT)</span>{" "}
masterclass on openCSE. This 10-module engineering-first curriculum takes you
from basic sensor reads to industrial cloud deployments, smart automation, and
capstone system design.
</p>

<section>
<h3 className="section-heading">Module I: Introduction to IoT</h3>
<ul className="section-list">
<li>IoT architecture: Sensor → Controller → Cloud → Action</li>
<li>Human-body analogy for system design</li>
<li>First Arduino/ESP32 project: LED blink & serial monitor</li>
</ul>
</section>

<section>
<h3 className="section-heading">Module II: Sensors & Actuators</h3>
<ul className="section-list">
<li>Analog vs digital sensors, voltage dividers</li>
<li>PIR, ultrasonic, relays, and motors</li>
<li>Reactive edge-computing projects</li>
</ul>
</section>

<section>
<h3 className="section-heading">Module III: Microcontrollers (Arduino)</h3>
<ul className="section-list">
<li>Pin modes, PWM, and non-blocking code</li>
<li>LDR light sensors and servo control</li>
</ul>
</section>

<section>
<h3 className="section-heading">Module IV: Advanced Controllers (ESP32)</h3>
<ul className="section-list">
<li>Wi-Fi, web server dashboards, OTA updates</li>
<li>Relay-controlled appliances</li>
</ul>
</section>

<section>
<h3 className="section-heading">Module V: Communication Protocols</h3>
<ul className="section-list">
<li>UART, I2C, SPI, RFID, and MQTT pub/sub</li>
</ul>
</section>

<section>
<h3 className="section-heading">Module VI: Cloud Integration</h3>
<ul className="section-list">
<li>ThingSpeak, REST APIs, and remote dashboards</li>
<li>DHT11 environmental logging</li>
</ul>
</section>

<section>
<h3 className="section-heading">Modules VII–X: Analytics to Capstone</h3>
<ul className="section-list">
<li>Edge analytics and smart irrigation (Module 7)</li>
<li>Smart home automation with gas detection (Module 8)</li>
<li>Industrial IoT, TLS security, thermocouples (Module 9)</li>
<li>Multi-sensor health monitoring capstone (Module 10)</li>
</ul>
</section>

<p className="p-text">
Use the sidebar to open each module. Content is written for hands-on labs with
Arduino IDE or PlatformIO and common hobbyist hardware.
</p>
</div>
);
};
Loading