JSFiddle - React, Tailwind, and code Playground

by velo_ninja

HTML

<div class="presentation">

  <header class="header">
    <div class="logo">BBM</div>
    <div class="progress-info" id="progressText"></div>
  </header>

  <div class="progress-container">
    <div class="progress-bar" id="progress"></div>
  </div>

  <div class="slide active">
    <h1>Graduation Project Proposal</h1>
    <h2>Process & Waste Optimization at BBM</h2>
    <p class="meta">
      Fadi Almadanat<br>
      B.Sc. Industrial Engineering<br>
      December 2025
    </p>
  </div>

  <div class="slide">
    <h1>Problem Definition</h1>
    <ul>
      <li>Ø 18–25 min/day lost per employee due to search activities</li>
      <li>High inventory levels with simultaneous stockouts</li>
      <li>Reactive logistics instead of data-driven planning</li>
    </ul>
  </div>

  <div class="slide">
    <h1>Methodological Framework</h1>
    <ul>
      <li>Lean Manufacturing (Motion & Waiting Waste)</li>
      <li>Time Study & Cost–Benefit Analysis</li>
      <li>ABC Analysis & Quantitative Forecasting</li>
    </ul>
  </div>

  <div class="slide">
    <h1>Case Study 1</h1>
    <h2>Paternoster ROI (€/Year)</h2>
    <canvas id="roiChart" width="650" height="320"></canvas>
  </div>

  <div class="slide">
    <h1>Case Study 1 – Assumptions</h1>
    <ul>
      <li>15 operators × 20 min/day search time</li>
      <li>Labor cost: 28 €/hour (fully burdened)</li>
      <li>Annual waste cost ≈ 35,000 €</li>
      <li>Paternoster investment: 85,000 €</li>
      <li>Payback Period ≈ 2.4 years</li>
    </ul>
  </div>

  <div class="slide">
    <h1>Case Study 2</h1>
    <h2>Inventory Cost Reduction (€/Year)</h2>
    <canvas id="inventoryChart" width="650" height="320"></canvas>
  </div>

  <div class="slide">
    <h1>Case Study 2 – Assumptions</h1>
    <ul>
      <li>Average inventory value: 600,000 €</li>
      <li>Carrying cost rate: 18 %</li>
      <li>Optimized reduction: −22 % inventory</li>
      <li>Annual...

CSS

body {
  margin: 0;
  font-family: "Segoe UI", Arial, sans-serif;
  background: #f2f4f7;
  color: #1c1f23;
  overflow: hidden;
}

.header {
  position: absolute;
  top: 10px;
  left: 20px;
  right: 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.logo {
  font-weight: 700;
  font-size: 1.4em;
  color: #004b8d;
  border: 2px solid #004b8d;
  padding: 4px 10px;
}

.progress-container {
  position: absolute;
  top: 0;
  height: 6px;
  width: 100%;
  background: #d6dbe1;
}

.progress-bar {
  height: 100%;
  width: 0%;
  background: #004b8d;
}

.slide {
  position: absolute;
  inset: 0;
  padding: 90px 140px;
  opacity: 0;
  transform: translateX(30px);
  transition: all 0.45s ease;
}

.slide.active {
  opacity: 1;
  transform: translateX(0);
}

h1 {
  font-size: 2.6em;
  color: #004b8d;
}

h2 {
  font-size: 1.5em;
  color: #006fcf;
  margin-bottom: 25px;
}

ul {
  font-size: 1.3em;
  line-height: 1.7;
}

.meta {
  margin-top: 50px;
  font-size: 1.1em;
}

.controls {
  position: absolute;
  bottom: 30px;
  right: 40px;
}

button {
  background: #004b8d;
  color: #fff;
  border: none;
  padding: 10px 18px;
  margin-left: 10px;
  font-size: 1em;
  border-radius: 4px;
  cursor: pointer;
}

JavaScript

const slides = document.querySelectorAll(".slide");
const progress = document.getElementById("progress");
const progressText = document.getElementById("progressText");
let current = 0;

function update() {
  slides.forEach((s, i) => s.classList.toggle("active", i === current));
  const percent = ((current + 1) / slides.length) * 100;
  progress.style.width = percent + "%";
  progressText.textContent = `Slide ${current + 1} / ${slides.length}`;

  if (slides[current].querySelector("#roiChart")) drawROI();
  if (slides[current].querySelector("#inventoryChart")) drawInventory();
}

document.getElementById("next").onclick = () => {
  if (current < slides.length - 1) current++;
  update();
};

document.getElementById("prev").onclick = () => {
  if (current > 0) current--;
  update();
};

document.addEventListener("keydown", e => {
  if (e.key === "ArrowRight") document.getElementById("next").click();
  if (e.key === "ArrowLeft") document.getElementById("prev").click();
});

function animate(ctx, values, labels, color) {
  let h = 0;
  const max = Math.max(...values);
  function draw() {
    ctx.clearRect(0, 0, 650, 320);
    values.forEach((v, i) => {
      const bar = (v / max) * h;
      ctx.fillStyle = color;
      ctx.fillRect(120 + i * 220, 260 - bar, 100, bar);
      ctx.fillStyle = "#000";
      ctx.fillText(labels[i], 140 + i * 220, 290);
      ctx.fillText(v + " €", 135 + i * 220, 245 - bar);
    });
    h += 4;
    if (h <= 200) requestAnimationFrame(draw);
  }
  draw();
}

function drawROI() {
  const c = document.getElementById("roiChart");
  animate(c.getContext("2d"),
    [35000, 59000],
    ["Labor Waste", "Total Savings"],
    "#004b8d"
  );
}

function drawInventory() {
  const c = document.getElementById("inventoryChart");
  animate(c.getContext("2d"),
    [108000, 84000],
    ["Current Cost", "Optimized Cost"],
    "#006fcf"
  );
}

update();