motimeline 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,7 +19,10 @@ Responsive two-column timeline layout library — plain JavaScript, zero depende
19
19
  - **Badges & arrows** — numbered badges on the center line, directional arrows
20
20
  - **Optional theme** — built-in card theme with image banners and overlapping avatars
21
21
  - **CSS custom properties** — override colors and sizes with one line of CSS
22
+ - **Category filtering** — tag items with `categories` and call `filterByCategory()` to show/hide by category; active filter persists automatically through lazy-loaded batches
22
23
  - **Dynamic items** — append, insert, or inject `<li>` elements at any time via `initNewItems()`, `addItems()`, or `insertItem()`
24
+ - **Custom card renderer** — pass `renderCard(item, cardEl)` to inject any HTML, vanilla JS, or full React components into each card slot; the library handles everything else
25
+ - **Publisher-ready ad slots** — the most publisher-friendly timeline on npm: `adSlots` injects viewport-triggered `<li>` placeholders at configurable cadences (`every_n` or `random`), fires `onEnterViewport` exactly once per slot at ≥ 50% visibility, works seamlessly with infinite scroll, and cleans up on `destroy()`. Drop in AdSense, house ads, or any network with three lines of code.
23
26
  - **Bootstrap compatible** — wrap the `<ul>` in a Bootstrap `.container`, no config needed
24
27
  - **ESM · CJS · UMD** — works with any bundler or as a plain `<script>` tag
25
28
 
@@ -155,6 +158,7 @@ The library injects classes and elements into your markup. Here is what a fully
155
158
  | Attribute | Element | Description |
156
159
  |---|---|---|
157
160
  | `data-mo-icon` | `<li>` | URL of the image shown inside the badge when `showCounterStyle: 'image'`. Accepts any web-safe format including inline SVG data URIs. Falls back to a built-in SVG icon if absent. Also set automatically by `addItems()` when an `icon` field is provided. |
161
+ | `data-categories` | `<li>` | Space-separated list of category tokens this item belongs to (e.g. `"development architecture"`). Used by `filterByCategory()`. Set automatically by `addItems()` / `insertItem()` when a `categories` field is provided. Can also be set manually in HTML. |
158
162
 
159
163
  ---
160
164
 
@@ -178,6 +182,7 @@ The library injects classes and elements into your markup. Here is what a fully
178
182
  | `mo-card-body` | `<div>` | Text content area. Padding and typography when `mo-theme` is active. |
179
183
  | `mo-meta` | `<p>` | Date / subtitle line inside a card body. Muted colour, smaller font. |
180
184
  | `js-mo-item` · `js-mo-inverted` | `<li>` | JS-only selector mirrors of `mo-item` / `mo-inverted`. Use in your own JS queries to avoid coupling to styling class names. |
185
+ | `mo-filtered-out` | `<li>` | Added by `filterByCategory()` to items that do not match the active filter. Sets `display: none` and excludes the item from column-placement calculations. Removed when the filter is cleared or the item's category is selected. |
181
186
 
182
187
  ---
183
188
 
@@ -186,11 +191,13 @@ The library injects classes and elements into your markup. Here is what a fully
186
191
  ```js
187
192
  const tl = new MoTimeline(elementOrSelector, options);
188
193
 
189
- tl.refresh(); // re-layout all items (called automatically on resize)
190
- tl.initNewItems(); // pick up manually appended <li> elements
191
- tl.addItems(items); // create and append <li> from an array of item objects (or JSON string)
192
- tl.insertItem(item, index); // insert a single item at a specific index (or random if omitted)
193
- tl.destroy(); // remove listeners and reset DOM classes
194
+ tl.refresh(); // re-layout all items (called automatically on resize)
195
+ tl.initNewItems(); // pick up manually appended <li> elements
196
+ tl.addItems(items); // create and append <li> from an array of item objects (or JSON string)
197
+ tl.insertItem(item, index); // insert a single item at a specific index (or random if omitted)
198
+ tl.filterByCategory(category); // show only items matching category; null / 'all' shows everything
199
+ tl.clear(); // remove all items and ad slots, reset counters — instance stays alive
200
+ tl.destroy(); // remove listeners and reset DOM classes
194
201
  ```
195
202
 
196
203
  ### insertItem
@@ -218,7 +225,8 @@ tl.addItems([
218
225
  text: "Kicked off the roadmap.", // body paragraph
219
226
  banner: "images/banner.jpg", // img.mo-banner (optional)
220
227
  avatar: "images/avatar.jpg", // img.mo-avatar (optional)
221
- icon: "images/icon.svg" // data-mo-icon on <li>, used by showCounterStyle:'image'
228
+ icon: "images/icon.svg", // data-mo-icon on <li>, used by showCounterStyle:'image'
229
+ categories: ["development", "architecture"] // used by filterByCategory() — array or space-separated string
222
230
  },
223
231
  ]);
224
232
 
@@ -373,6 +381,41 @@ const tl = new MoTimeline('#my-timeline', {
373
381
 
374
382
  Slots are injected after each `addItems()` call, so they work seamlessly with infinite scroll.
375
383
 
384
+ ## Category filter recipe
385
+
386
+ Tag items with `categories` (array or space-separated string) and wire `filterByCategory()` to your own filter buttons. The active filter is stored on the instance — items added later via `addItems()` are filtered automatically, making it fully compatible with infinite scroll.
387
+
388
+ ```js
389
+ const tl = new MoTimeline('#my-timeline', { theme: true, showBadge: true });
390
+
391
+ // Load items with categories
392
+ tl.addItems([
393
+ { title: 'API cleanup', meta: 'Jan 2025', text: '...', categories: ['development', 'architecture'] },
394
+ { title: 'Sprint review', meta: 'Feb 2025', text: '...', categories: 'management' },
395
+ ]);
396
+
397
+ // Wire filter buttons
398
+ document.querySelectorAll('.filters button').forEach(btn => {
399
+ btn.addEventListener('click', () => {
400
+ document.querySelectorAll('.filters button').forEach(b => b.classList.remove('active'));
401
+ btn.classList.add('active');
402
+ tl.filterByCategory(btn.dataset.cat); // pass null or 'all' to show everything
403
+ });
404
+ });
405
+
406
+ // Active filter persists through lazy-loaded batches
407
+ tl.addItems(moreItemsFromServer); // auto-filtered to match current selection
408
+ ```
409
+
410
+ Or set `data-categories` directly in HTML and use `initNewItems()`:
411
+
412
+ ```html
413
+ <li data-categories="development architecture">...</li>
414
+ <li data-categories="management">...</li>
415
+ ```
416
+
417
+ ---
418
+
376
419
  ## Infinite scroll recipe
377
420
 
378
421
  moTimeline handles the layout — you own the data fetching. Wire an `IntersectionObserver` to a sentinel element below the list and call `addItems()` when it comes into view.
@@ -465,6 +508,15 @@ No framework option needed. Wrap the `<ul>` inside a Bootstrap `.container`:
465
508
 
466
509
  ## Changelog
467
510
 
511
+ ### v2.13.0
512
+ - New: **category filtering** — tag items with `categories` (array or space-separated string) and call `filterByCategory(category)` to show only matching items. Pass `null` or `'all'` to clear the filter. The active filter is stored on the instance and applied automatically to items added via `addItems()` or `initNewItems()`, making it fully compatible with infinite scroll / server-side pagination. Column placement recalculates on every filter change so the two-column layout stays correct. New class `mo-filtered-out` is used internally (`display: none`) and new attribute `data-categories` is set on each `<li>`.
513
+
514
+ ### v2.12.1
515
+ - Fix: badge width — use `width` instead of `min-width` to prevent oversized badges ([#8](https://github.com/MattOpen/moTimeline/issues/8))
516
+
517
+ ### v2.12.0
518
+ - New method `clear()` — removes all `.mo-item` and `.mo-ad-slot` elements from the container and resets internal counters (`lastItemIdx`, `_adRealCount`) without destroying the instance. Active `IntersectionObserver`s are disconnected but kept alive so they re-observe items added by the next `addItems()` call. Use this in React wrappers to reinitialize timeline content when props change without recreating the instance.
519
+
468
520
  ### v2.11.0
469
521
  - New option `adSlots` — inject ad slot `<li>` placeholders at configurable positions (`every_n` or `random` mode) and receive an `onEnterViewport(slotEl, position)` callback exactly once per slot when ≥ 50% of it is visible. Works with `addItems()` and infinite scroll. Slots are removed on `tl.destroy()`. See **Ad slots** section.
470
522
 
@@ -1,6 +1,6 @@
1
- "use strict";var C=Object.defineProperty;var S=(l,e,t)=>e in l?C(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var _=(l,e,t)=>S(l,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
2
- * moTimeline v2.11.0
1
+ "use strict";var A=Object.defineProperty;var S=(l,e,t)=>e in l?A(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var _=(l,e,t)=>S(l,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
2
+ * moTimeline v2.13.0
3
3
  * Responsive two-column timeline layout library
4
4
  * https://github.com/MattOpen/moTimeline
5
5
  * MIT License
6
- */const h=new WeakMap,b={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px",cardMargin:"0.5rem 1.25rem 0.5rem 0.5rem",cardMarginInverted:"0.5rem 0.5rem 0.5rem 1.25rem",cardMarginFullWidth:"0.5rem",randomFullWidth:0,animate:!1,renderCard:null,adSlots:null},A="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function w(){const l=window.innerWidth;return l<600?"xs":l<992?"sm":l<1200?"md":"lg"}function I(l,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>l(...s),e)}}function p(l){return l?{o:l.offsetTop,h:l.offsetHeight,gppu:l.offsetTop+l.offsetHeight}:{o:0,h:0,gppu:0}}function y(l,e){const t=[];let s=l.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const f=class f{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},b,t),this.settings.columnCount=Object.assign({},b.columnCount,t.columnCount),this._resizeHandler=I(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(h.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(h.set(e,t),f.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),e.style.setProperty("--mo-card-border-radius",t.cardBorderRadius),e.style.setProperty("--mo-avatar-size",t.avatarSize),e.style.setProperty("--mo-card-margin",t.cardMargin),e.style.setProperty("--mo-card-margin-inverted",t.cardMarginInverted),e.style.setProperty("--mo-card-margin-fullwidth",t.cardMarginFullWidth),t.animate){const s=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${s}`),this._observer=new IntersectionObserver(o=>{o.forEach(r=>{r.isIntersecting&&(r.target.classList.add("mo-visible"),this._observer.unobserve(r.target))})},{threshold:.1})}t.adSlots&&(t._adRealCount=0,typeof t.adSlots.onEnterViewport=="function"&&(this._adObserver=new IntersectionObserver(s=>{s.forEach(o=>{o.isIntersecting&&(this._adObserver.unobserve(o.target),t.adSlots.onEnterViewport(o.target,Number(o.target.dataset.moAdPosition)))})},{threshold:.5}))),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){f.instances.forEach(e=>{const t=e.element,s=h.get(t);s&&(s.col=s.columnCount[w()],e._setDivider(),Array.from(t.children).forEach(o=>{e._setPostPosition(o)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}insertItem(e,t){const s=this.element,o=this._getData();if(!o)return;const r=this._createItemElement(e),i=Array.from(s.children).filter(n=>n.classList.contains("js-mo-item")),a=t==null?Math.floor(Math.random()*(i.length+1)):Math.max(0,Math.min(t,i.length));if(a>=i.length?s.appendChild(r):s.insertBefore(r,i[a]),r.id||(r.id="moT"+crypto.randomUUID()+"_"+a),r.classList.add("mo-item","js-mo-item"),e.fullWidth)r.classList.add("mo-fullwidth","js-mo-fullwidth");else if(o.randomFullWidth){const n=o.randomFullWidth===!0?.33:o.randomFullWidth;Math.random()<n&&r.classList.add("mo-fullwidth","js-mo-fullwidth")}return o.showBadge&&this._createBadge(r,a+1),o.showArrow&&this._createArrow(r),o.showBadge&&o.showCounterStyle==="counter"&&Array.from(s.querySelectorAll(".js-mo-item")).forEach((n,c)=>{const d=n.querySelector(".js-mo-badge");d&&(d.textContent=c+1)}),o.lastItemIdx=Array.from(s.children).length,h.set(s,o),this.refresh(),this._observeItems([r]),r.querySelectorAll("img").forEach(n=>{n.complete||n.addEventListener("load",this._resizeHandler,{once:!0})}),r}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),this._adObserver&&(this._adObserver.disconnect(),this._adObserver=null),Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach(e=>e.remove()),h.delete(this.element),f.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.style.removeProperty("--mo-card-margin"),this.element.style.removeProperty("--mo-card-margin-inverted"),this.element.style.removeProperty("--mo-card-margin-fullwidth"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol","mo-animate","mo-animate-fade","mo-animate-slide"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset","mo-fullwidth","js-mo-fullwidth","mo-visible"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return h.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[w()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,o=Array.from(e.children),r=o.slice(s);if(r.length!==0){if(r.forEach((i,a)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(a+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const i=t.randomFullWidth===!0?.33:t.randomFullWidth;r.forEach(a=>{!a.classList.contains("mo-fullwidth")&&Math.random()<i&&a.classList.add("mo-fullwidth","js-mo-fullwidth")})}r.forEach((i,a)=>{t.showBadge&&this._createBadge(i,a+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=o.length,h.set(e,t),this.refresh(),this._observeItems(r),this._injectAdSlots(r),r.forEach(i=>{i.querySelectorAll("img").forEach(a=>{a.complete||a.addEventListener("load",this._resizeHandler,{once:!0})})})}}_setPostPosition(e){if(e.classList.contains("mo-fullwidth")){e.classList.remove("mo-inverted","js-mo-inverted","mo-offset");return}const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,o=y(e,".js-mo-inverted")[0]||null,r=y(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,i=p(r),a=p(o),n=p(e);let c=0,d=0;if(s>1){i.gppu>n.o+1&&(c=1),a.gppu>i.gppu&&(c=0);const m=e.previousElementSibling;m&&Math.abs(n.o-p(m).o)<40&&(d=1)}return{lr:c,badge_offset:d}}_createBadge(e,t){const s=this._getData(),o=document.createElement("span");if(o.className="mo-badge js-mo-badge",s.showCounterStyle==="none")o.style.opacity="0";else if(s.showCounterStyle==="image"){const r=document.createElement("img");r.className="mo-badge-icon",r.alt="",r.src=e.dataset.moIcon||A,o.appendChild(r)}else o.textContent=t;e.prepend(o)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");s.className="mo-card";const o=this._getData();if(o&&typeof o.renderCard=="function")o.renderCard(e,s);else{if(e.banner){const i=document.createElement("div");i.className="mo-card-image";const a=document.createElement("img");if(a.className="mo-banner",a.src=e.banner,a.alt="",i.appendChild(a),e.avatar){const n=document.createElement("img");n.className="mo-avatar",n.src=e.avatar,n.alt="",i.appendChild(n)}s.appendChild(i)}const r=document.createElement("div");if(r.className="mo-card-body",e.title){const i=document.createElement("h3");i.textContent=e.title,r.appendChild(i)}if(e.meta){const i=document.createElement("p");i.className="mo-meta",i.textContent=e.meta,r.appendChild(i)}if(e.text){const i=document.createElement("p");i.textContent=e.text,r.appendChild(i)}s.appendChild(r)}return t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_injectAdSlots(e){const t=this._getData();if(!t||!t.adSlots||!e.length)return;const{mode:s,interval:o,style:r}=t.adSlots,i=r==="fullwidth",a=this.element;let n=!1;if(s==="every_n")e.forEach((c,d)=>{if((t._adRealCount+d+1)%o===0){const m=this._createAdSlot(i);c.after(m),m.dataset.moAdPosition=String(Array.from(a.children).indexOf(m)),this._adObserver&&this._adObserver.observe(m),i&&(n=!0)}});else if(s==="random"){let c=t._adRealCount%o,d=0;for(;d<e.length;){const m=o-c,u=e.slice(d,d+m);if(u.length===m){const E=u[Math.floor(Math.random()*u.length)],g=this._createAdSlot(i);E.after(g),g.dataset.moAdPosition=String(Array.from(a.children).indexOf(g)),this._adObserver&&this._adObserver.observe(g),i&&(n=!0),c=0}else c+=u.length;d+=m}}t._adRealCount+=e.length,n&&this.refresh()}_createAdSlot(e){const t=document.createElement("li");return t.className="mo-ad-slot",e&&t.classList.add("mo-fullwidth"),t}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};_(f,"instances",new Set);let v=f;exports.MoTimeline=v;exports.default=v;
6
+ */const h=new WeakMap,b={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px",cardMargin:"0.5rem 1.25rem 0.5rem 0.5rem",cardMarginInverted:"0.5rem 0.5rem 0.5rem 1.25rem",cardMarginFullWidth:"0.5rem",randomFullWidth:0,animate:!1,renderCard:null,adSlots:null},C="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function y(){const l=window.innerWidth;return l<600?"xs":l<992?"sm":l<1200?"md":"lg"}function L(l,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>l(...s),e)}}function v(l){return l?{o:l.offsetTop,h:l.offsetHeight,gppu:l.offsetTop+l.offsetHeight}:{o:0,h:0,gppu:0}}function w(l,e){const t=[];let s=l.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const f=class f{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},b,t),this.settings.columnCount=Object.assign({},b.columnCount,t.columnCount),this._resizeHandler=L(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(h.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(h.set(e,t),f.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),e.style.setProperty("--mo-card-border-radius",t.cardBorderRadius),e.style.setProperty("--mo-avatar-size",t.avatarSize),e.style.setProperty("--mo-card-margin",t.cardMargin),e.style.setProperty("--mo-card-margin-inverted",t.cardMarginInverted),e.style.setProperty("--mo-card-margin-fullwidth",t.cardMarginFullWidth),t.animate){const s=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${s}`),this._observer=new IntersectionObserver(r=>{r.forEach(o=>{o.isIntersecting&&(o.target.classList.add("mo-visible"),this._observer.unobserve(o.target))})},{threshold:.1})}t.adSlots&&(t._adRealCount=0,typeof t.adSlots.onEnterViewport=="function"&&(this._adObserver=new IntersectionObserver(s=>{s.forEach(r=>{r.isIntersecting&&(this._adObserver.unobserve(r.target),t.adSlots.onEnterViewport(r.target,Number(r.target.dataset.moAdPosition)))})},{threshold:.5}))),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){f.instances.forEach(e=>{const t=e.element,s=h.get(t);s&&(s.col=s.columnCount[y()],e._setDivider(),Array.from(t.children).forEach(r=>{e._setPostPosition(r)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}insertItem(e,t){const s=this.element,r=this._getData();if(!r)return;const o=this._createItemElement(e),i=Array.from(s.children).filter(n=>n.classList.contains("js-mo-item")),a=t==null?Math.floor(Math.random()*(i.length+1)):Math.max(0,Math.min(t,i.length));if(a>=i.length?s.appendChild(o):s.insertBefore(o,i[a]),o.id||(o.id="moT"+crypto.randomUUID()+"_"+a),o.classList.add("mo-item","js-mo-item"),e.fullWidth)o.classList.add("mo-fullwidth","js-mo-fullwidth");else if(r.randomFullWidth){const n=r.randomFullWidth===!0?.33:r.randomFullWidth;Math.random()<n&&o.classList.add("mo-fullwidth","js-mo-fullwidth")}return r.showBadge&&this._createBadge(o,a+1),r.showArrow&&this._createArrow(o),r.showBadge&&r.showCounterStyle==="counter"&&Array.from(s.querySelectorAll(".js-mo-item")).forEach((n,c)=>{const d=n.querySelector(".js-mo-badge");d&&(d.textContent=c+1)}),r.lastItemIdx=Array.from(s.children).length,h.set(s,r),this.refresh(),this._observeItems([o]),o.querySelectorAll("img").forEach(n=>{n.complete||n.addEventListener("load",this._resizeHandler,{once:!0})}),o}clear(){const e=this._getData();e&&(this._observer&&this._observer.disconnect(),this._adObserver&&this._adObserver.disconnect(),Array.from(this.element.children).forEach(t=>{(t.classList.contains("js-mo-item")||t.classList.contains("mo-ad-slot"))&&t.remove()}),e.lastItemIdx=0,e.adSlots&&(e._adRealCount=0))}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),this._adObserver&&(this._adObserver.disconnect(),this._adObserver=null),Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach(e=>e.remove()),h.delete(this.element),f.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.style.removeProperty("--mo-card-margin"),this.element.style.removeProperty("--mo-card-margin-inverted"),this.element.style.removeProperty("--mo-card-margin-fullwidth"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol","mo-animate","mo-animate-fade","mo-animate-slide"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset","mo-fullwidth","js-mo-fullwidth","mo-visible","mo-filtered-out"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}filterByCategory(e){const t=this._getData();t&&(t._activeFilter=e==null||e===""||e==="all"?null:String(e),h.set(this.element,t),this._applyFilter(Array.from(this.element.querySelectorAll(".js-mo-item"))),this.refresh())}_applyFilter(e){const t=this._getData();if(!t)return;const s=t._activeFilter||null;e.forEach(r=>{if(!s)r.classList.remove("mo-filtered-out");else{const o=(r.dataset.categories||"").split(/\s+/).filter(Boolean);r.classList.toggle("mo-filtered-out",!o.includes(s))}})}_getData(){return h.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[y()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,r=Array.from(e.children),o=r.slice(s);if(o.length!==0){if(o.forEach((i,a)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(a+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const i=t.randomFullWidth===!0?.33:t.randomFullWidth;o.forEach(a=>{!a.classList.contains("mo-fullwidth")&&Math.random()<i&&a.classList.add("mo-fullwidth","js-mo-fullwidth")})}o.forEach((i,a)=>{t.showBadge&&this._createBadge(i,a+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=r.length,h.set(e,t),this._applyFilter(o),this.refresh(),this._observeItems(o),this._injectAdSlots(o),o.forEach(i=>{i.querySelectorAll("img").forEach(a=>{a.complete||a.addEventListener("load",this._resizeHandler,{once:!0})})})}}_setPostPosition(e){if(e.classList.contains("mo-filtered-out"))return;if(e.classList.contains("mo-fullwidth")){e.classList.remove("mo-inverted","js-mo-inverted","mo-offset");return}const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,r=w(e,".js-mo-inverted:not(.mo-filtered-out)")[0]||null,o=w(e,".js-mo-item:not(.js-mo-inverted):not(.mo-filtered-out)")[0]||null,i=v(o),a=v(r),n=v(e);let c=0,d=0;if(s>1){i.gppu>n.o+1&&(c=1),a.gppu>i.gppu&&(c=0);const m=e.previousElementSibling;m&&Math.abs(n.o-v(m).o)<40&&(d=1)}return{lr:c,badge_offset:d}}_createBadge(e,t){const s=this._getData(),r=document.createElement("span");if(r.className="mo-badge js-mo-badge",s.showCounterStyle==="none")r.style.opacity="0";else if(s.showCounterStyle==="image"){const o=document.createElement("img");o.className="mo-badge-icon",o.alt="",o.src=e.dataset.moIcon||C,r.appendChild(o)}else r.textContent=t;e.prepend(r)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon),e.categories&&(t.dataset.categories=Array.isArray(e.categories)?e.categories.join(" "):String(e.categories));const s=document.createElement("div");s.className="mo-card";const r=this._getData();if(r&&typeof r.renderCard=="function")r.renderCard(e,s);else{if(e.banner){const i=document.createElement("div");i.className="mo-card-image";const a=document.createElement("img");if(a.className="mo-banner",a.src=e.banner,a.alt="",i.appendChild(a),e.avatar){const n=document.createElement("img");n.className="mo-avatar",n.src=e.avatar,n.alt="",i.appendChild(n)}s.appendChild(i)}const o=document.createElement("div");if(o.className="mo-card-body",e.title){const i=document.createElement("h3");i.textContent=e.title,o.appendChild(i)}if(e.meta){const i=document.createElement("p");i.className="mo-meta",i.textContent=e.meta,o.appendChild(i)}if(e.text){const i=document.createElement("p");i.textContent=e.text,o.appendChild(i)}s.appendChild(o)}return t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_injectAdSlots(e){const t=this._getData();if(!t||!t.adSlots||!e.length)return;const{mode:s,interval:r,style:o}=t.adSlots,i=o==="fullwidth",a=this.element;let n=!1;if(s==="every_n")e.forEach((c,d)=>{if((t._adRealCount+d+1)%r===0){const m=this._createAdSlot(i);c.after(m),m.dataset.moAdPosition=String(Array.from(a.children).indexOf(m)),this._adObserver&&this._adObserver.observe(m),i&&(n=!0)}});else if(s==="random"){let c=t._adRealCount%r,d=0;for(;d<e.length;){const m=r-c,u=e.slice(d,d+m);if(u.length===m){const E=u[Math.floor(Math.random()*u.length)],g=this._createAdSlot(i);E.after(g),g.dataset.moAdPosition=String(Array.from(a.children).indexOf(g)),this._adObserver&&this._adObserver.observe(g),i&&(n=!0),c=0}else c+=u.length;d+=m}}t._adRealCount+=e.length,n&&this.refresh()}_createAdSlot(e){const t=document.createElement("li");return t.className="mo-ad-slot",e&&t.classList.add("mo-fullwidth"),t}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};_(f,"instances",new Set);let p=f;exports.MoTimeline=p;exports.default=p;
@@ -1,3 +1,3 @@
1
1
  /*!
2
- * moTimeline v2.11.0 — CSS
3
- */:root{--mo-line-color: #dde1e7;--mo-badge-bg: #4f46e5;--mo-badge-color: #fff;--mo-badge-size: 26px;--mo-badge-font-size: 12px;--mo-arrow-color: #dde1e7}.mo-timeline{display:block;list-style:none;margin:0;padding:0;position:relative;width:100%}.mo-timeline:after{content:"";display:table;clear:both}.mo-timeline.mo-twocol:before{background-color:var(--mo-line-color);bottom:0;content:"";left:50%;margin-left:-1.5px;position:absolute;top:0;width:3px;z-index:0}.mo-timeline>.mo-item{box-sizing:border-box;display:block;float:left;position:relative;width:50%}.mo-timeline:not(.mo-twocol)>.mo-item{float:none;width:100%}.mo-timeline>.mo-item.mo-inverted{float:right}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth{clear:both;float:none;width:100%}.mo-theme>.mo-item.mo-fullwidth .mo-card{margin:var(--mo-card-margin-fullwidth, .5rem)}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-badge,.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-arrow{display:none}.mo-badge{align-items:center;background:var(--mo-badge-bg);border-radius:50%;color:var(--mo-badge-color);display:flex;font-size:var(--mo-badge-font-size);font-weight:700;height:var(--mo-badge-size);justify-content:center;min-width:var(--mo-badge-size);overflow:hidden;position:absolute;top:18px;z-index:2}.mo-badge .mo-badge-icon{border-radius:50%;height:100%;object-fit:cover;width:100%}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-badge{left:auto;right:calc(var(--mo-badge-size) / -2)}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-badge{left:calc(var(--mo-badge-size) / -2);right:auto}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-badge{top:calc(18px + var(--mo-badge-size) + 10px)}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-arrow{top:calc(26px + var(--mo-badge-size) + 10px)}.mo-timeline:not(.mo-twocol)>.mo-item .mo-badge{display:none}.mo-arrow{border:8px solid transparent;display:block;height:0;position:absolute;top:26px;width:0;z-index:1}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left:8px solid var(--mo-arrow-color);border-right:none;left:auto;right:0}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right:8px solid var(--mo-arrow-color);border-left:none;left:0;right:auto}.mo-timeline:not(.mo-twocol)>.mo-item .mo-arrow{display:none}.mo-theme{--mo-arrow-color: #fff}.mo-theme>.mo-item .mo-card{background:#fff;border-radius:var(--mo-card-border-radius, 8px);box-shadow:0 2px 14px #0000001a;margin:var(--mo-card-margin, .5rem 1.25rem .5rem .5rem);position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:var(--mo-card-margin-inverted, .5rem .5rem .5rem 1.25rem)}.mo-theme>.mo-item .mo-banner{border-radius:var(--mo-card-border-radius, 8px) var(--mo-card-border-radius, 8px) 0 0;display:block;max-height:240px;object-fit:cover;width:100%}.mo-theme>.mo-item .mo-card-image{overflow:visible;position:relative}.mo-theme>.mo-item .mo-avatar{border:3px solid #fff;border-radius:50%;bottom:calc(var(--mo-avatar-size, 50px) * -.44);box-shadow:0 2px 8px #0000002e;height:var(--mo-avatar-size, 50px);object-fit:cover;position:absolute;right:14px;width:var(--mo-avatar-size, 50px);z-index:1}.mo-theme>.mo-item .mo-card-body{padding:1.75rem 1rem 1rem}.mo-theme>.mo-item .mo-card-body h3{font-size:1rem;font-weight:700;margin:0 0 .3rem}.mo-theme>.mo-item .mo-card-body .mo-meta{color:#9ca3af;font-size:.75rem;margin-bottom:.5rem}.mo-theme>.mo-item .mo-card-body p{color:#6b7280;font-size:.875rem;line-height:1.55;margin:0}.mo-theme.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left-color:var(--mo-arrow-color);right:12px}.mo-theme.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right-color:var(--mo-arrow-color);left:12px}.mo-theme .mo-badge{background:#fff;border:2px solid var(--mo-line-color);box-shadow:0 2px 6px #0000001a;color:#374151}.mo-timeline.mo-animate>.mo-item{transition:opacity var(--mo-animate-duration, .5s) ease,transform var(--mo-animate-duration, .5s) ease}.mo-timeline.mo-animate-fade>.mo-item{opacity:0}.mo-timeline.mo-animate-slide>.mo-item:not(.mo-inverted){opacity:0;transform:translate(-40px)}.mo-timeline.mo-animate-slide>.mo-item.mo-inverted{opacity:0;transform:translate(40px)}.mo-timeline:not(.mo-twocol).mo-animate-slide>.mo-item{transform:translate(-40px)}.mo-timeline.mo-animate>.mo-item.mo-visible{opacity:1;transform:translate(0)}.mo-timeline>.mo-item.mo-ad-slot{min-height:100px}
2
+ * moTimeline v2.13.0 — CSS
3
+ */:root{--mo-line-color: #dde1e7;--mo-badge-bg: #4f46e5;--mo-badge-color: #fff;--mo-badge-size: 26px;--mo-badge-font-size: 12px;--mo-arrow-color: #dde1e7}.mo-timeline{display:block;list-style:none;margin:0;padding:0;position:relative;width:100%}.mo-timeline:after{content:"";display:table;clear:both}.mo-timeline.mo-twocol:before{background-color:var(--mo-line-color);bottom:0;content:"";left:50%;margin-left:-1.5px;position:absolute;top:0;width:3px;z-index:0}.mo-timeline>.mo-item{box-sizing:border-box;display:block;float:left;position:relative;width:50%}.mo-timeline:not(.mo-twocol)>.mo-item{float:none;width:100%}.mo-timeline>.mo-item.mo-inverted{float:right}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth{clear:both;float:none;width:100%}.mo-theme>.mo-item.mo-fullwidth .mo-card{margin:var(--mo-card-margin-fullwidth, .5rem)}.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-badge,.mo-timeline.mo-twocol>.mo-item.mo-fullwidth .mo-arrow{display:none}.mo-badge{align-items:center;background:var(--mo-badge-bg);border-radius:50%;color:var(--mo-badge-color);display:flex;font-size:var(--mo-badge-font-size);font-weight:700;height:var(--mo-badge-size);justify-content:center;width:var(--mo-badge-size);overflow:hidden;position:absolute;top:18px;z-index:2}.mo-badge .mo-badge-icon{border-radius:50%;height:100%;object-fit:cover;width:100%}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-badge{left:auto;right:calc(var(--mo-badge-size) / -2)}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-badge{left:calc(var(--mo-badge-size) / -2);right:auto}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-badge{top:calc(18px + var(--mo-badge-size) + 10px)}.mo-timeline.mo-twocol>.mo-item.mo-offset .mo-arrow{top:calc(26px + var(--mo-badge-size) + 10px)}.mo-timeline:not(.mo-twocol)>.mo-item .mo-badge{display:none}.mo-arrow{border:8px solid transparent;display:block;height:0;position:absolute;top:26px;width:0;z-index:1}.mo-timeline.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left:8px solid var(--mo-arrow-color);border-right:none;left:auto;right:0}.mo-timeline.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right:8px solid var(--mo-arrow-color);border-left:none;left:0;right:auto}.mo-timeline:not(.mo-twocol)>.mo-item .mo-arrow{display:none}.mo-theme{--mo-arrow-color: #fff}.mo-theme>.mo-item .mo-card{background:#fff;border-radius:var(--mo-card-border-radius, 8px);box-shadow:0 2px 14px #0000001a;margin:var(--mo-card-margin, .5rem 1.25rem .5rem .5rem);position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:var(--mo-card-margin-inverted, .5rem .5rem .5rem 1.25rem)}.mo-theme>.mo-item .mo-banner{border-radius:var(--mo-card-border-radius, 8px) var(--mo-card-border-radius, 8px) 0 0;display:block;max-height:240px;object-fit:cover;width:100%}.mo-theme>.mo-item .mo-card-image{overflow:visible;position:relative}.mo-theme>.mo-item .mo-avatar{border:3px solid #fff;border-radius:50%;bottom:calc(var(--mo-avatar-size, 50px) * -.44);box-shadow:0 2px 8px #0000002e;height:var(--mo-avatar-size, 50px);object-fit:cover;position:absolute;right:14px;width:var(--mo-avatar-size, 50px);z-index:1}.mo-theme>.mo-item .mo-card-body{padding:1.75rem 1rem 1rem}.mo-theme>.mo-item .mo-card-body h3{font-size:1rem;font-weight:700;margin:0 0 .3rem}.mo-theme>.mo-item .mo-card-body .mo-meta{color:#9ca3af;font-size:.75rem;margin-bottom:.5rem}.mo-theme>.mo-item .mo-card-body p{color:#6b7280;font-size:.875rem;line-height:1.55;margin:0}.mo-theme.mo-twocol>.mo-item:not(.mo-inverted) .mo-arrow{border-left-color:var(--mo-arrow-color);right:12px}.mo-theme.mo-twocol>.mo-item.mo-inverted .mo-arrow{border-right-color:var(--mo-arrow-color);left:12px}.mo-theme .mo-badge{background:#fff;border:2px solid var(--mo-line-color);box-shadow:0 2px 6px #0000001a;color:#374151}.mo-timeline.mo-animate>.mo-item{transition:opacity var(--mo-animate-duration, .5s) ease,transform var(--mo-animate-duration, .5s) ease}.mo-timeline.mo-animate-fade>.mo-item{opacity:0}.mo-timeline.mo-animate-slide>.mo-item:not(.mo-inverted){opacity:0;transform:translate(-40px)}.mo-timeline.mo-animate-slide>.mo-item.mo-inverted{opacity:0;transform:translate(40px)}.mo-timeline:not(.mo-twocol).mo-animate-slide>.mo-item{transform:translate(-40px)}.mo-timeline.mo-animate>.mo-item.mo-visible{opacity:1;transform:translate(0)}.mo-timeline>.mo-item.mo-ad-slot{min-height:100px}.mo-timeline>.mo-item.mo-filtered-out{display:none}
@@ -1,8 +1,8 @@
1
- var C = Object.defineProperty;
2
- var A = (l, e, t) => e in l ? C(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
- var v = (l, e, t) => A(l, typeof e != "symbol" ? e + "" : e, t);
1
+ var A = Object.defineProperty;
2
+ var C = (l, e, t) => e in l ? A(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
+ var v = (l, e, t) => C(l, typeof e != "symbol" ? e + "" : e, t);
4
4
  /*!
5
- * moTimeline v2.11.0
5
+ * moTimeline v2.13.0
6
6
  * Responsive two-column timeline layout library
7
7
  * https://github.com/MattOpen/moTimeline
8
8
  * MIT License
@@ -27,12 +27,12 @@ const h = /* @__PURE__ */ new WeakMap(), _ = {
27
27
  // (item, cardEl) => void — custom card renderer; skips built-in HTML
28
28
  adSlots: null
29
29
  // { mode, interval, style, onEnterViewport } — see docs
30
- }, I = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";
31
- function w() {
30
+ }, S = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";
31
+ function b() {
32
32
  const l = window.innerWidth;
33
33
  return l < 600 ? "xs" : l < 992 ? "sm" : l < 1200 ? "md" : "lg";
34
34
  }
35
- function S(l, e = 100) {
35
+ function L(l, e = 100) {
36
36
  let t;
37
37
  return (...s) => {
38
38
  clearTimeout(t), t = setTimeout(() => l(...s), e);
@@ -45,7 +45,7 @@ function p(l) {
45
45
  gppu: l.offsetTop + l.offsetHeight
46
46
  } : { o: 0, h: 0, gppu: 0 };
47
47
  }
48
- function b(l, e) {
48
+ function w(l, e) {
49
49
  const t = [];
50
50
  let s = l.previousElementSibling;
51
51
  for (; s; )
@@ -55,7 +55,7 @@ function b(l, e) {
55
55
  const f = class f {
56
56
  constructor(e, t = {}) {
57
57
  if (typeof e == "string" && (e = document.querySelector(e)), !e) throw new Error("moTimeline: element not found");
58
- this.element = e, this.settings = Object.assign({}, _, t), this.settings.columnCount = Object.assign({}, _.columnCount, t.columnCount), this._resizeHandler = S(() => this.refresh(), 100), this._initialized = !1, this.init();
58
+ this.element = e, this.settings = Object.assign({}, _, t), this.settings.columnCount = Object.assign({}, _.columnCount, t.columnCount), this._resizeHandler = L(() => this.refresh(), 100), this._initialized = !1, this.init();
59
59
  }
60
60
  init() {
61
61
  const e = this.element;
@@ -66,23 +66,23 @@ const f = class f {
66
66
  const t = Object.assign({}, this.settings, { lastItemIdx: 0 });
67
67
  if (h.set(e, t), f.instances.add(this), e.classList.add("mo-timeline"), t.theme && e.classList.add("mo-theme"), e.style.setProperty("--mo-card-border-radius", t.cardBorderRadius), e.style.setProperty("--mo-avatar-size", t.avatarSize), e.style.setProperty("--mo-card-margin", t.cardMargin), e.style.setProperty("--mo-card-margin-inverted", t.cardMarginInverted), e.style.setProperty("--mo-card-margin-fullwidth", t.cardMarginFullWidth), t.animate) {
68
68
  const s = t.animate === !0 ? "fade" : t.animate;
69
- e.classList.add("mo-animate", `mo-animate-${s}`), this._observer = new IntersectionObserver((o) => {
70
- o.forEach((r) => {
71
- r.isIntersecting && (r.target.classList.add("mo-visible"), this._observer.unobserve(r.target));
69
+ e.classList.add("mo-animate", `mo-animate-${s}`), this._observer = new IntersectionObserver((r) => {
70
+ r.forEach((o) => {
71
+ o.isIntersecting && (o.target.classList.add("mo-visible"), this._observer.unobserve(o.target));
72
72
  });
73
73
  }, { threshold: 0.1 });
74
74
  }
75
75
  t.adSlots && (t._adRealCount = 0, typeof t.adSlots.onEnterViewport == "function" && (this._adObserver = new IntersectionObserver((s) => {
76
- s.forEach((o) => {
77
- o.isIntersecting && (this._adObserver.unobserve(o.target), t.adSlots.onEnterViewport(o.target, Number(o.target.dataset.moAdPosition)));
76
+ s.forEach((r) => {
77
+ r.isIntersecting && (this._adObserver.unobserve(r.target), t.adSlots.onEnterViewport(r.target, Number(r.target.dataset.moAdPosition)));
78
78
  });
79
79
  }, { threshold: 0.5 }))), this._initialized = !0, window.addEventListener("resize", this._resizeHandler), Array.from(e.children).length > 0 && this._initItems();
80
80
  }
81
81
  refresh() {
82
82
  f.instances.forEach((e) => {
83
83
  const t = e.element, s = h.get(t);
84
- s && (s.col = s.columnCount[w()], e._setDivider(), Array.from(t.children).forEach((o) => {
85
- e._setPostPosition(o);
84
+ s && (s.col = s.columnCount[b()], e._setDivider(), Array.from(t.children).forEach((r) => {
85
+ e._setPostPosition(r);
86
86
  }));
87
87
  });
88
88
  }
@@ -109,51 +109,81 @@ const f = class f {
109
109
  * @returns {HTMLElement} the inserted <li> element
110
110
  */
111
111
  insertItem(e, t) {
112
- const s = this.element, o = this._getData();
113
- if (!o) return;
114
- const r = this._createItemElement(e), i = Array.from(s.children).filter((n) => n.classList.contains("js-mo-item")), a = t == null ? Math.floor(Math.random() * (i.length + 1)) : Math.max(0, Math.min(t, i.length));
115
- if (a >= i.length ? s.appendChild(r) : s.insertBefore(r, i[a]), r.id || (r.id = "moT" + crypto.randomUUID() + "_" + a), r.classList.add("mo-item", "js-mo-item"), e.fullWidth)
116
- r.classList.add("mo-fullwidth", "js-mo-fullwidth");
117
- else if (o.randomFullWidth) {
118
- const n = o.randomFullWidth === !0 ? 0.33 : o.randomFullWidth;
119
- Math.random() < n && r.classList.add("mo-fullwidth", "js-mo-fullwidth");
112
+ const s = this.element, r = this._getData();
113
+ if (!r) return;
114
+ const o = this._createItemElement(e), i = Array.from(s.children).filter((n) => n.classList.contains("js-mo-item")), a = t == null ? Math.floor(Math.random() * (i.length + 1)) : Math.max(0, Math.min(t, i.length));
115
+ if (a >= i.length ? s.appendChild(o) : s.insertBefore(o, i[a]), o.id || (o.id = "moT" + crypto.randomUUID() + "_" + a), o.classList.add("mo-item", "js-mo-item"), e.fullWidth)
116
+ o.classList.add("mo-fullwidth", "js-mo-fullwidth");
117
+ else if (r.randomFullWidth) {
118
+ const n = r.randomFullWidth === !0 ? 0.33 : r.randomFullWidth;
119
+ Math.random() < n && o.classList.add("mo-fullwidth", "js-mo-fullwidth");
120
120
  }
121
- return o.showBadge && this._createBadge(r, a + 1), o.showArrow && this._createArrow(r), o.showBadge && o.showCounterStyle === "counter" && Array.from(s.querySelectorAll(".js-mo-item")).forEach((n, c) => {
121
+ return r.showBadge && this._createBadge(o, a + 1), r.showArrow && this._createArrow(o), r.showBadge && r.showCounterStyle === "counter" && Array.from(s.querySelectorAll(".js-mo-item")).forEach((n, c) => {
122
122
  const d = n.querySelector(".js-mo-badge");
123
123
  d && (d.textContent = c + 1);
124
- }), o.lastItemIdx = Array.from(s.children).length, h.set(s, o), this.refresh(), this._observeItems([r]), r.querySelectorAll("img").forEach((n) => {
124
+ }), r.lastItemIdx = Array.from(s.children).length, h.set(s, r), this.refresh(), this._observeItems([o]), o.querySelectorAll("img").forEach((n) => {
125
125
  n.complete || n.addEventListener("load", this._resizeHandler, { once: !0 });
126
- }), r;
126
+ }), o;
127
+ }
128
+ clear() {
129
+ const e = this._getData();
130
+ e && (this._observer && this._observer.disconnect(), this._adObserver && this._adObserver.disconnect(), Array.from(this.element.children).forEach((t) => {
131
+ (t.classList.contains("js-mo-item") || t.classList.contains("mo-ad-slot")) && t.remove();
132
+ }), e.lastItemIdx = 0, e.adSlots && (e._adRealCount = 0));
127
133
  }
128
134
  destroy() {
129
135
  window.removeEventListener("resize", this._resizeHandler), this._observer && (this._observer.disconnect(), this._observer = null), this._adObserver && (this._adObserver.disconnect(), this._adObserver = null), Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach((e) => e.remove()), h.delete(this.element), f.instances.delete(this), this.element.style.removeProperty("--mo-card-border-radius"), this.element.style.removeProperty("--mo-avatar-size"), this.element.style.removeProperty("--mo-card-margin"), this.element.style.removeProperty("--mo-card-margin-inverted"), this.element.style.removeProperty("--mo-card-margin-fullwidth"), this.element.classList.remove("mo-timeline", "mo-theme", "mo-twocol", "mo-animate", "mo-animate-fade", "mo-animate-slide"), Array.from(this.element.children).forEach((e) => {
130
- e.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset", "mo-fullwidth", "js-mo-fullwidth", "mo-visible"), e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((t) => t.remove());
136
+ e.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset", "mo-fullwidth", "js-mo-fullwidth", "mo-visible", "mo-filtered-out"), e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((t) => t.remove());
131
137
  });
132
138
  }
139
+ /**
140
+ * Filter visible items by category.
141
+ * Pass null / 'all' / '' to show everything.
142
+ * The active filter is remembered and applied automatically to items added later.
143
+ *
144
+ * @param {string|null} category — value to match against data-categories on each item
145
+ */
146
+ filterByCategory(e) {
147
+ const t = this._getData();
148
+ t && (t._activeFilter = e == null || e === "" || e === "all" ? null : String(e), h.set(this.element, t), this._applyFilter(Array.from(this.element.querySelectorAll(".js-mo-item"))), this.refresh());
149
+ }
133
150
  // ─── Private ────────────────────────────────────────────────────────────────
151
+ _applyFilter(e) {
152
+ const t = this._getData();
153
+ if (!t) return;
154
+ const s = t._activeFilter || null;
155
+ e.forEach((r) => {
156
+ if (!s)
157
+ r.classList.remove("mo-filtered-out");
158
+ else {
159
+ const o = (r.dataset.categories || "").split(/\s+/).filter(Boolean);
160
+ r.classList.toggle("mo-filtered-out", !o.includes(s));
161
+ }
162
+ });
163
+ }
134
164
  _getData() {
135
165
  return h.get(this.element);
136
166
  }
137
167
  _setDivider() {
138
168
  const e = this._getData();
139
- e && (e.col = e.columnCount[w()], this.element.classList.toggle("mo-twocol", e.col > 1));
169
+ e && (e.col = e.columnCount[b()], this.element.classList.toggle("mo-twocol", e.col > 1));
140
170
  }
141
171
  _initItems() {
142
172
  const e = this.element, t = this._getData();
143
173
  if (!t) return;
144
- const s = t.lastItemIdx, o = Array.from(e.children), r = o.slice(s);
145
- if (r.length !== 0) {
146
- if (r.forEach((i, a) => {
174
+ const s = t.lastItemIdx, r = Array.from(e.children), o = r.slice(s);
175
+ if (o.length !== 0) {
176
+ if (o.forEach((i, a) => {
147
177
  i.id || (i.id = "moT" + crypto.randomUUID() + "_" + (a + s)), i.classList.add("mo-item", "js-mo-item");
148
178
  }), this._setDivider(), t.randomFullWidth) {
149
179
  const i = t.randomFullWidth === !0 ? 0.33 : t.randomFullWidth;
150
- r.forEach((a) => {
180
+ o.forEach((a) => {
151
181
  !a.classList.contains("mo-fullwidth") && Math.random() < i && a.classList.add("mo-fullwidth", "js-mo-fullwidth");
152
182
  });
153
183
  }
154
- r.forEach((i, a) => {
184
+ o.forEach((i, a) => {
155
185
  t.showBadge && this._createBadge(i, a + s + 1), t.showArrow && this._createArrow(i);
156
- }), t.lastItemIdx = o.length, h.set(e, t), this.refresh(), this._observeItems(r), this._injectAdSlots(r), r.forEach((i) => {
186
+ }), t.lastItemIdx = r.length, h.set(e, t), this._applyFilter(o), this.refresh(), this._observeItems(o), this._injectAdSlots(o), o.forEach((i) => {
157
187
  i.querySelectorAll("img").forEach((a) => {
158
188
  a.complete || a.addEventListener("load", this._resizeHandler, { once: !0 });
159
189
  });
@@ -161,6 +191,7 @@ const f = class f {
161
191
  }
162
192
  }
163
193
  _setPostPosition(e) {
194
+ if (e.classList.contains("mo-filtered-out")) return;
164
195
  if (e.classList.contains("mo-fullwidth")) {
165
196
  e.classList.remove("mo-inverted", "js-mo-inverted", "mo-offset");
166
197
  return;
@@ -172,7 +203,7 @@ const f = class f {
172
203
  if (!e) return null;
173
204
  const t = this._getData();
174
205
  if (!t) return null;
175
- const s = t.col, o = b(e, ".js-mo-inverted")[0] || null, r = b(e, ".js-mo-item:not(.js-mo-inverted)")[0] || null, i = p(r), a = p(o), n = p(e);
206
+ const s = t.col, r = w(e, ".js-mo-inverted:not(.mo-filtered-out)")[0] || null, o = w(e, ".js-mo-item:not(.js-mo-inverted):not(.mo-filtered-out)")[0] || null, i = p(o), a = p(r), n = p(e);
176
207
  let c = 0, d = 0;
177
208
  if (s > 1) {
178
209
  i.gppu > n.o + 1 && (c = 1), a.gppu > i.gppu && (c = 0);
@@ -182,24 +213,24 @@ const f = class f {
182
213
  return { lr: c, badge_offset: d };
183
214
  }
184
215
  _createBadge(e, t) {
185
- const s = this._getData(), o = document.createElement("span");
186
- if (o.className = "mo-badge js-mo-badge", s.showCounterStyle === "none")
187
- o.style.opacity = "0";
216
+ const s = this._getData(), r = document.createElement("span");
217
+ if (r.className = "mo-badge js-mo-badge", s.showCounterStyle === "none")
218
+ r.style.opacity = "0";
188
219
  else if (s.showCounterStyle === "image") {
189
- const r = document.createElement("img");
190
- r.className = "mo-badge-icon", r.alt = "", r.src = e.dataset.moIcon || I, o.appendChild(r);
220
+ const o = document.createElement("img");
221
+ o.className = "mo-badge-icon", o.alt = "", o.src = e.dataset.moIcon || S, r.appendChild(o);
191
222
  } else
192
- o.textContent = t;
193
- e.prepend(o);
223
+ r.textContent = t;
224
+ e.prepend(r);
194
225
  }
195
226
  _createItemElement(e) {
196
227
  const t = document.createElement("li");
197
- e.icon && (t.dataset.moIcon = e.icon);
228
+ e.icon && (t.dataset.moIcon = e.icon), e.categories && (t.dataset.categories = Array.isArray(e.categories) ? e.categories.join(" ") : String(e.categories));
198
229
  const s = document.createElement("div");
199
230
  s.className = "mo-card";
200
- const o = this._getData();
201
- if (o && typeof o.renderCard == "function")
202
- o.renderCard(e, s);
231
+ const r = this._getData();
232
+ if (r && typeof r.renderCard == "function")
233
+ r.renderCard(e, s);
203
234
  else {
204
235
  if (e.banner) {
205
236
  const i = document.createElement("div");
@@ -211,20 +242,20 @@ const f = class f {
211
242
  }
212
243
  s.appendChild(i);
213
244
  }
214
- const r = document.createElement("div");
215
- if (r.className = "mo-card-body", e.title) {
245
+ const o = document.createElement("div");
246
+ if (o.className = "mo-card-body", e.title) {
216
247
  const i = document.createElement("h3");
217
- i.textContent = e.title, r.appendChild(i);
248
+ i.textContent = e.title, o.appendChild(i);
218
249
  }
219
250
  if (e.meta) {
220
251
  const i = document.createElement("p");
221
- i.className = "mo-meta", i.textContent = e.meta, r.appendChild(i);
252
+ i.className = "mo-meta", i.textContent = e.meta, o.appendChild(i);
222
253
  }
223
254
  if (e.text) {
224
255
  const i = document.createElement("p");
225
- i.textContent = e.text, r.appendChild(i);
256
+ i.textContent = e.text, o.appendChild(i);
226
257
  }
227
- s.appendChild(r);
258
+ s.appendChild(o);
228
259
  }
229
260
  return t.appendChild(s), t;
230
261
  }
@@ -235,19 +266,19 @@ const f = class f {
235
266
  _injectAdSlots(e) {
236
267
  const t = this._getData();
237
268
  if (!t || !t.adSlots || !e.length) return;
238
- const { mode: s, interval: o, style: r } = t.adSlots, i = r === "fullwidth", a = this.element;
269
+ const { mode: s, interval: r, style: o } = t.adSlots, i = o === "fullwidth", a = this.element;
239
270
  let n = !1;
240
271
  if (s === "every_n")
241
272
  e.forEach((c, d) => {
242
- if ((t._adRealCount + d + 1) % o === 0) {
273
+ if ((t._adRealCount + d + 1) % r === 0) {
243
274
  const m = this._createAdSlot(i);
244
275
  c.after(m), m.dataset.moAdPosition = String(Array.from(a.children).indexOf(m)), this._adObserver && this._adObserver.observe(m), i && (n = !0);
245
276
  }
246
277
  });
247
278
  else if (s === "random") {
248
- let c = t._adRealCount % o, d = 0;
279
+ let c = t._adRealCount % r, d = 0;
249
280
  for (; d < e.length; ) {
250
- const m = o - c, u = e.slice(d, d + m);
281
+ const m = r - c, u = e.slice(d, d + m);
251
282
  if (u.length === m) {
252
283
  const E = u[Math.floor(Math.random() * u.length)], g = this._createAdSlot(i);
253
284
  E.after(g), g.dataset.moAdPosition = String(Array.from(a.children).indexOf(g)), this._adObserver && this._adObserver.observe(g), i && (n = !0), c = 0;
@@ -1,6 +1,6 @@
1
- (function(d,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(d=typeof globalThis<"u"?globalThis:d||self,l(d.MoTimeline={}))})(this,function(d){"use strict";var I=Object.defineProperty;var L=(d,l,u)=>l in d?I(d,l,{enumerable:!0,configurable:!0,writable:!0,value:u}):d[l]=u;var E=(d,l,u)=>L(d,typeof l!="symbol"?l+"":l,u);/*!
2
- * moTimeline v2.11.0
1
+ (function(d,n){typeof exports=="object"&&typeof module<"u"?n(exports):typeof define=="function"&&define.amd?define(["exports"],n):(d=typeof globalThis<"u"?globalThis:d||self,n(d.MoTimeline={}))})(this,function(d){"use strict";var L=Object.defineProperty;var I=(d,n,u)=>n in d?L(d,n,{enumerable:!0,configurable:!0,writable:!0,value:u}):d[n]=u;var E=(d,n,u)=>I(d,typeof n!="symbol"?n+"":n,u);/*!
2
+ * moTimeline v2.13.0
3
3
  * Responsive two-column timeline layout library
4
4
  * https://github.com/MattOpen/moTimeline
5
5
  * MIT License
6
- */const l=new WeakMap,u={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px",cardMargin:"0.5rem 1.25rem 0.5rem 0.5rem",cardMarginInverted:"0.5rem 0.5rem 0.5rem 1.25rem",cardMarginFullWidth:"0.5rem",randomFullWidth:0,animate:!1,renderCard:null,adSlots:null},C="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function w(){const c=window.innerWidth;return c<600?"xs":c<992?"sm":c<1200?"md":"lg"}function S(c,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>c(...s),e)}}function p(c){return c?{o:c.offsetTop,h:c.offsetHeight,gppu:c.offsetTop+c.offsetHeight}:{o:0,h:0,gppu:0}}function y(c,e){const t=[];let s=c.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const g=class g{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},u,t),this.settings.columnCount=Object.assign({},u.columnCount,t.columnCount),this._resizeHandler=S(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(l.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(l.set(e,t),g.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),e.style.setProperty("--mo-card-border-radius",t.cardBorderRadius),e.style.setProperty("--mo-avatar-size",t.avatarSize),e.style.setProperty("--mo-card-margin",t.cardMargin),e.style.setProperty("--mo-card-margin-inverted",t.cardMarginInverted),e.style.setProperty("--mo-card-margin-fullwidth",t.cardMarginFullWidth),t.animate){const s=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${s}`),this._observer=new IntersectionObserver(o=>{o.forEach(r=>{r.isIntersecting&&(r.target.classList.add("mo-visible"),this._observer.unobserve(r.target))})},{threshold:.1})}t.adSlots&&(t._adRealCount=0,typeof t.adSlots.onEnterViewport=="function"&&(this._adObserver=new IntersectionObserver(s=>{s.forEach(o=>{o.isIntersecting&&(this._adObserver.unobserve(o.target),t.adSlots.onEnterViewport(o.target,Number(o.target.dataset.moAdPosition)))})},{threshold:.5}))),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){g.instances.forEach(e=>{const t=e.element,s=l.get(t);s&&(s.col=s.columnCount[w()],e._setDivider(),Array.from(t.children).forEach(o=>{e._setPostPosition(o)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}insertItem(e,t){const s=this.element,o=this._getData();if(!o)return;const r=this._createItemElement(e),i=Array.from(s.children).filter(a=>a.classList.contains("js-mo-item")),n=t==null?Math.floor(Math.random()*(i.length+1)):Math.max(0,Math.min(t,i.length));if(n>=i.length?s.appendChild(r):s.insertBefore(r,i[n]),r.id||(r.id="moT"+crypto.randomUUID()+"_"+n),r.classList.add("mo-item","js-mo-item"),e.fullWidth)r.classList.add("mo-fullwidth","js-mo-fullwidth");else if(o.randomFullWidth){const a=o.randomFullWidth===!0?.33:o.randomFullWidth;Math.random()<a&&r.classList.add("mo-fullwidth","js-mo-fullwidth")}return o.showBadge&&this._createBadge(r,n+1),o.showArrow&&this._createArrow(r),o.showBadge&&o.showCounterStyle==="counter"&&Array.from(s.querySelectorAll(".js-mo-item")).forEach((a,h)=>{const m=a.querySelector(".js-mo-badge");m&&(m.textContent=h+1)}),o.lastItemIdx=Array.from(s.children).length,l.set(s,o),this.refresh(),this._observeItems([r]),r.querySelectorAll("img").forEach(a=>{a.complete||a.addEventListener("load",this._resizeHandler,{once:!0})}),r}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),this._adObserver&&(this._adObserver.disconnect(),this._adObserver=null),Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach(e=>e.remove()),l.delete(this.element),g.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.style.removeProperty("--mo-card-margin"),this.element.style.removeProperty("--mo-card-margin-inverted"),this.element.style.removeProperty("--mo-card-margin-fullwidth"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol","mo-animate","mo-animate-fade","mo-animate-slide"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset","mo-fullwidth","js-mo-fullwidth","mo-visible"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return l.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[w()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,o=Array.from(e.children),r=o.slice(s);if(r.length!==0){if(r.forEach((i,n)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(n+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const i=t.randomFullWidth===!0?.33:t.randomFullWidth;r.forEach(n=>{!n.classList.contains("mo-fullwidth")&&Math.random()<i&&n.classList.add("mo-fullwidth","js-mo-fullwidth")})}r.forEach((i,n)=>{t.showBadge&&this._createBadge(i,n+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=o.length,l.set(e,t),this.refresh(),this._observeItems(r),this._injectAdSlots(r),r.forEach(i=>{i.querySelectorAll("img").forEach(n=>{n.complete||n.addEventListener("load",this._resizeHandler,{once:!0})})})}}_setPostPosition(e){if(e.classList.contains("mo-fullwidth")){e.classList.remove("mo-inverted","js-mo-inverted","mo-offset");return}const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,o=y(e,".js-mo-inverted")[0]||null,r=y(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,i=p(r),n=p(o),a=p(e);let h=0,m=0;if(s>1){i.gppu>a.o+1&&(h=1),n.gppu>i.gppu&&(h=0);const f=e.previousElementSibling;f&&Math.abs(a.o-p(f).o)<40&&(m=1)}return{lr:h,badge_offset:m}}_createBadge(e,t){const s=this._getData(),o=document.createElement("span");if(o.className="mo-badge js-mo-badge",s.showCounterStyle==="none")o.style.opacity="0";else if(s.showCounterStyle==="image"){const r=document.createElement("img");r.className="mo-badge-icon",r.alt="",r.src=e.dataset.moIcon||C,o.appendChild(r)}else o.textContent=t;e.prepend(o)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");s.className="mo-card";const o=this._getData();if(o&&typeof o.renderCard=="function")o.renderCard(e,s);else{if(e.banner){const i=document.createElement("div");i.className="mo-card-image";const n=document.createElement("img");if(n.className="mo-banner",n.src=e.banner,n.alt="",i.appendChild(n),e.avatar){const a=document.createElement("img");a.className="mo-avatar",a.src=e.avatar,a.alt="",i.appendChild(a)}s.appendChild(i)}const r=document.createElement("div");if(r.className="mo-card-body",e.title){const i=document.createElement("h3");i.textContent=e.title,r.appendChild(i)}if(e.meta){const i=document.createElement("p");i.className="mo-meta",i.textContent=e.meta,r.appendChild(i)}if(e.text){const i=document.createElement("p");i.textContent=e.text,r.appendChild(i)}s.appendChild(r)}return t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_injectAdSlots(e){const t=this._getData();if(!t||!t.adSlots||!e.length)return;const{mode:s,interval:o,style:r}=t.adSlots,i=r==="fullwidth",n=this.element;let a=!1;if(s==="every_n")e.forEach((h,m)=>{if((t._adRealCount+m+1)%o===0){const f=this._createAdSlot(i);h.after(f),f.dataset.moAdPosition=String(Array.from(n.children).indexOf(f)),this._adObserver&&this._adObserver.observe(f),i&&(a=!0)}});else if(s==="random"){let h=t._adRealCount%o,m=0;for(;m<e.length;){const f=o-h,_=e.slice(m,m+f);if(_.length===f){const A=_[Math.floor(Math.random()*_.length)],b=this._createAdSlot(i);A.after(b),b.dataset.moAdPosition=String(Array.from(n.children).indexOf(b)),this._adObserver&&this._adObserver.observe(b),i&&(a=!0),h=0}else h+=_.length;m+=f}}t._adRealCount+=e.length,a&&this.refresh()}_createAdSlot(e){const t=document.createElement("li");return t.className="mo-ad-slot",e&&t.classList.add("mo-fullwidth"),t}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};E(g,"instances",new Set);let v=g;d.MoTimeline=v,d.default=v,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
6
+ */const n=new WeakMap,u={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px",cardMargin:"0.5rem 1.25rem 0.5rem 0.5rem",cardMarginInverted:"0.5rem 0.5rem 0.5rem 1.25rem",cardMarginFullWidth:"0.5rem",randomFullWidth:0,animate:!1,renderCard:null,adSlots:null},A="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='11' fill='%234f46e5'/><circle cx='12' cy='12' r='4.5' fill='white'/></svg>";function y(){const c=window.innerWidth;return c<600?"xs":c<992?"sm":c<1200?"md":"lg"}function S(c,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>c(...s),e)}}function p(c){return c?{o:c.offsetTop,h:c.offsetHeight,gppu:c.offsetTop+c.offsetHeight}:{o:0,h:0,gppu:0}}function w(c,e){const t=[];let s=c.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const g=class g{constructor(e,t={}){if(typeof e=="string"&&(e=document.querySelector(e)),!e)throw new Error("moTimeline: element not found");this.element=e,this.settings=Object.assign({},u,t),this.settings.columnCount=Object.assign({},u.columnCount,t.columnCount),this._resizeHandler=S(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(n.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(n.set(e,t),g.instances.add(this),e.classList.add("mo-timeline"),t.theme&&e.classList.add("mo-theme"),e.style.setProperty("--mo-card-border-radius",t.cardBorderRadius),e.style.setProperty("--mo-avatar-size",t.avatarSize),e.style.setProperty("--mo-card-margin",t.cardMargin),e.style.setProperty("--mo-card-margin-inverted",t.cardMarginInverted),e.style.setProperty("--mo-card-margin-fullwidth",t.cardMarginFullWidth),t.animate){const s=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${s}`),this._observer=new IntersectionObserver(r=>{r.forEach(o=>{o.isIntersecting&&(o.target.classList.add("mo-visible"),this._observer.unobserve(o.target))})},{threshold:.1})}t.adSlots&&(t._adRealCount=0,typeof t.adSlots.onEnterViewport=="function"&&(this._adObserver=new IntersectionObserver(s=>{s.forEach(r=>{r.isIntersecting&&(this._adObserver.unobserve(r.target),t.adSlots.onEnterViewport(r.target,Number(r.target.dataset.moAdPosition)))})},{threshold:.5}))),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){g.instances.forEach(e=>{const t=e.element,s=n.get(t);s&&(s.col=s.columnCount[y()],e._setDivider(),Array.from(t.children).forEach(r=>{e._setPostPosition(r)}))})}initNewItems(){this._initItems()}addItems(e){typeof e=="string"&&(e=JSON.parse(e)),e.forEach(t=>this.element.appendChild(this._createItemElement(t))),this._initItems()}insertItem(e,t){const s=this.element,r=this._getData();if(!r)return;const o=this._createItemElement(e),i=Array.from(s.children).filter(l=>l.classList.contains("js-mo-item")),a=t==null?Math.floor(Math.random()*(i.length+1)):Math.max(0,Math.min(t,i.length));if(a>=i.length?s.appendChild(o):s.insertBefore(o,i[a]),o.id||(o.id="moT"+crypto.randomUUID()+"_"+a),o.classList.add("mo-item","js-mo-item"),e.fullWidth)o.classList.add("mo-fullwidth","js-mo-fullwidth");else if(r.randomFullWidth){const l=r.randomFullWidth===!0?.33:r.randomFullWidth;Math.random()<l&&o.classList.add("mo-fullwidth","js-mo-fullwidth")}return r.showBadge&&this._createBadge(o,a+1),r.showArrow&&this._createArrow(o),r.showBadge&&r.showCounterStyle==="counter"&&Array.from(s.querySelectorAll(".js-mo-item")).forEach((l,h)=>{const m=l.querySelector(".js-mo-badge");m&&(m.textContent=h+1)}),r.lastItemIdx=Array.from(s.children).length,n.set(s,r),this.refresh(),this._observeItems([o]),o.querySelectorAll("img").forEach(l=>{l.complete||l.addEventListener("load",this._resizeHandler,{once:!0})}),o}clear(){const e=this._getData();e&&(this._observer&&this._observer.disconnect(),this._adObserver&&this._adObserver.disconnect(),Array.from(this.element.children).forEach(t=>{(t.classList.contains("js-mo-item")||t.classList.contains("mo-ad-slot"))&&t.remove()}),e.lastItemIdx=0,e.adSlots&&(e._adRealCount=0))}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),this._adObserver&&(this._adObserver.disconnect(),this._adObserver=null),Array.from(this.element.querySelectorAll(".mo-ad-slot")).forEach(e=>e.remove()),n.delete(this.element),g.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.style.removeProperty("--mo-card-margin"),this.element.style.removeProperty("--mo-card-margin-inverted"),this.element.style.removeProperty("--mo-card-margin-fullwidth"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol","mo-animate","mo-animate-fade","mo-animate-slide"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset","mo-fullwidth","js-mo-fullwidth","mo-visible","mo-filtered-out"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}filterByCategory(e){const t=this._getData();t&&(t._activeFilter=e==null||e===""||e==="all"?null:String(e),n.set(this.element,t),this._applyFilter(Array.from(this.element.querySelectorAll(".js-mo-item"))),this.refresh())}_applyFilter(e){const t=this._getData();if(!t)return;const s=t._activeFilter||null;e.forEach(r=>{if(!s)r.classList.remove("mo-filtered-out");else{const o=(r.dataset.categories||"").split(/\s+/).filter(Boolean);r.classList.toggle("mo-filtered-out",!o.includes(s))}})}_getData(){return n.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[y()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,r=Array.from(e.children),o=r.slice(s);if(o.length!==0){if(o.forEach((i,a)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(a+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const i=t.randomFullWidth===!0?.33:t.randomFullWidth;o.forEach(a=>{!a.classList.contains("mo-fullwidth")&&Math.random()<i&&a.classList.add("mo-fullwidth","js-mo-fullwidth")})}o.forEach((i,a)=>{t.showBadge&&this._createBadge(i,a+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=r.length,n.set(e,t),this._applyFilter(o),this.refresh(),this._observeItems(o),this._injectAdSlots(o),o.forEach(i=>{i.querySelectorAll("img").forEach(a=>{a.complete||a.addEventListener("load",this._resizeHandler,{once:!0})})})}}_setPostPosition(e){if(e.classList.contains("mo-filtered-out"))return;if(e.classList.contains("mo-fullwidth")){e.classList.remove("mo-inverted","js-mo-inverted","mo-offset");return}const t=this._getLeftOrRight(e);t&&(e.classList.toggle("mo-inverted",t.lr>0),e.classList.toggle("js-mo-inverted",t.lr>0),e.classList.toggle("mo-offset",t.badge_offset>0))}_getLeftOrRight(e){if(!e)return null;const t=this._getData();if(!t)return null;const s=t.col,r=w(e,".js-mo-inverted:not(.mo-filtered-out)")[0]||null,o=w(e,".js-mo-item:not(.js-mo-inverted):not(.mo-filtered-out)")[0]||null,i=p(o),a=p(r),l=p(e);let h=0,m=0;if(s>1){i.gppu>l.o+1&&(h=1),a.gppu>i.gppu&&(h=0);const f=e.previousElementSibling;f&&Math.abs(l.o-p(f).o)<40&&(m=1)}return{lr:h,badge_offset:m}}_createBadge(e,t){const s=this._getData(),r=document.createElement("span");if(r.className="mo-badge js-mo-badge",s.showCounterStyle==="none")r.style.opacity="0";else if(s.showCounterStyle==="image"){const o=document.createElement("img");o.className="mo-badge-icon",o.alt="",o.src=e.dataset.moIcon||A,r.appendChild(o)}else r.textContent=t;e.prepend(r)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon),e.categories&&(t.dataset.categories=Array.isArray(e.categories)?e.categories.join(" "):String(e.categories));const s=document.createElement("div");s.className="mo-card";const r=this._getData();if(r&&typeof r.renderCard=="function")r.renderCard(e,s);else{if(e.banner){const i=document.createElement("div");i.className="mo-card-image";const a=document.createElement("img");if(a.className="mo-banner",a.src=e.banner,a.alt="",i.appendChild(a),e.avatar){const l=document.createElement("img");l.className="mo-avatar",l.src=e.avatar,l.alt="",i.appendChild(l)}s.appendChild(i)}const o=document.createElement("div");if(o.className="mo-card-body",e.title){const i=document.createElement("h3");i.textContent=e.title,o.appendChild(i)}if(e.meta){const i=document.createElement("p");i.className="mo-meta",i.textContent=e.meta,o.appendChild(i)}if(e.text){const i=document.createElement("p");i.textContent=e.text,o.appendChild(i)}s.appendChild(o)}return t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_injectAdSlots(e){const t=this._getData();if(!t||!t.adSlots||!e.length)return;const{mode:s,interval:r,style:o}=t.adSlots,i=o==="fullwidth",a=this.element;let l=!1;if(s==="every_n")e.forEach((h,m)=>{if((t._adRealCount+m+1)%r===0){const f=this._createAdSlot(i);h.after(f),f.dataset.moAdPosition=String(Array.from(a.children).indexOf(f)),this._adObserver&&this._adObserver.observe(f),i&&(l=!0)}});else if(s==="random"){let h=t._adRealCount%r,m=0;for(;m<e.length;){const f=r-h,_=e.slice(m,m+f);if(_.length===f){const C=_[Math.floor(Math.random()*_.length)],b=this._createAdSlot(i);C.after(b),b.dataset.moAdPosition=String(Array.from(a.children).indexOf(b)),this._adObserver&&this._adObserver.observe(b),i&&(l=!0),h=0}else h+=_.length;m+=f}}t._adRealCount+=e.length,l&&this.refresh()}_createAdSlot(e){const t=document.createElement("li");return t.className="mo-ad-slot",e&&t.classList.add("mo-fullwidth"),t}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};E(g,"instances",new Set);let v=g;d.MoTimeline=v,d.default=v,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});