widget.js

@amitmund June 07, 2026

widget system

What you're describing is essentially a CDN-driven widget system where:

Website owner only adds one <script> tag
Everything else (behavior, image, template, styling, messaging) is controlled from GitHub-hosted files served through a CDN
No code changes required on customer websites

Note: It need to for multiple ad. Imagine as a simple ad-engine.


On client side

<script defer src="https://cdn.jsdelivr.net/gh/Amitmund/amitmund_ad_widget/widget.js"></script>

or

# To be able to run the add

### Just add the following 1 line at your website.


<!-- Ionicons -->
<script type="module" src="https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js"></script>

<!-- Lucide -->
<script src="https://unpkg.com/lucide@latest"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
    lucide.createIcons();
});
</script>

<!-- ================= AD RAIL WIDGET ================= -->
<script defer src="https://cdn.jsdelivr.net/gh/Amitmund/amitmund_ad_widget/widget.js?ts=20260607002"></script>


---

# UI Concept: Bottom Ad Rail

Fixed bottom strip across the site:

┌──────────────────────────────────────────────────────┐
│ [Ad1] [Ad2] [Ad3] [Ad4] → scrolling horizontally    │
└──────────────────────────────────────────────────────┘


---

ad-rail-widget/ │ ├── widget.js │ ├── config.json │ ├── README.md │ ├── templates/ │ ├── positive.html │ ├── negative.html │ └── promo.html │ ├── assets/ │ ├── images/ │ │ ├── img1.jpg │ │ ├── img2.jpg │ │ └── img3.jpg │ │ │ └── icons/ │ ├── verified.svg │ ├── warning.svg │ └── sale.svg │ └── docs/ ├── config-schema.md └── usage.md


---

# Core Architecture (FINAL CONTRACT)

widget.js ↓ fetch config.json ↓ render templates → HTML cards ↓ inject into bottom rail container ↓ start horizontal scroll engine



---


# widget.js

(async function () { const CONFIG_URL = "https://cdn.jsdelivr.net/gh/your-org/ad-widget/config.json";

// ----------------------------- // Load Config // ----------------------------- const config = await fetch(CONFIG_URL).then(r => r.json());

if (!config || !config.ads || !config.ads.length) return;

// ----------------------------- // Inject Base Styles // ----------------------------- const style = document.createElement("style"); style.innerHTML = ` #ad-rail { position: fixed; bottom: 0; left: 0; width: 100%; height: 100px; overflow: hidden; background: #ffffff; z-index: 999999; box-shadow: 0 -2px 10px rgba(0,0,0,0.12); }

.ad-track {
  display: flex;
  flex-direction: row;
  gap: 12px;
  width: max-content;
  will-change: transform;
  align-items: center;
  padding: 10px;
}

.ad-card {
  display: flex;
  align-items: center;
  width: 240px;
  height: 80px;
  flex-shrink: 0;
  border-radius: 10px;
  overflow: hidden;
  text-decoration: none;
  font-family: Arial, sans-serif;
  color: #111;
  background: #f7f7f7;
}

.ad-img {
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: 8px;
  margin: 0 10px;
}

.ad-body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}

.ad-title {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ad-msg {
  font-size: 11px;
  opacity: 0.75;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.positive { border-left: 4px solid #2ecc71; background: #eaffea; }
.negative { border-left: 4px solid #e74c3c; background: #fff0f0; }
.promo    { border-left: 4px solid #3498db; background: #eef5ff; }

`; document.head.appendChild(style);

// ----------------------------- // Create DOM // ----------------------------- const rail = document.createElement("div"); rail.id = "ad-rail";

const track = document.createElement("div"); track.className = "ad-track";

rail.appendChild(track); document.body.appendChild(rail);

// ----------------------------- // Build Ad Card // ----------------------------- function createCard(ad) { const a = document.createElement("a");

a.className = `ad-card ${ad.template || "promo"}`;
a.href = ad.url || "#";
a.target = "_blank";

a.innerHTML = `
  <img class="ad-img" src="${ad.image}" />
  <div class="ad-body">
    <div class="ad-title">${ad.title || ""}</div>
    <div class="ad-msg">${ad.message || ""}</div>
  </div>
`;

return a;

}

// ----------------------------- // Render Ads // ----------------------------- config.ads.forEach(ad => { track.appendChild(createCard(ad)); });

// Duplicate for seamless loop track.innerHTML += track.innerHTML;

// ----------------------------- // Scroll Engine // ----------------------------- let x = 0; let paused = false;

const speed = config.scrollSpeed || 1;

rail.addEventListener("mouseenter", () => (paused = true)); rail.addEventListener("mouseleave", () => (paused = false));

function animate() { if (!paused) { x -= speed;

  const halfWidth = track.scrollWidth / 2;

  if (Math.abs(x) >= halfWidth) {
    x = 0;
  }

  track.style.transform = `translateX(${x}px)`;
}

requestAnimationFrame(animate);

}

animate(); })();



---


# config.json

{ "scrollSpeed": 1,

"ads": [ { "template": "positive", "image": "https://cdn.example.com/assets/img1.jpg", "title": "Verified Partner", "message": "Trusted by thousands", "url": "https://example.com" }, { "template": "negative", "image": "https://cdn.example.com/assets/img2.jpg", "title": "Risk Alert", "message": "Reported issues found", "url": "https://example.com/risk" }, { "template": "promo", "image": "https://cdn.example.com/assets/img3.jpg", "title": "Summer Sale", "message": "Up to 50% off", "url": "https://example.com/sale" } ] } ```


0 Likes
58 Views
0 Comments

Filters

No filters available for this view.

Reset All