motimeline 2.8.1 → 2.10.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 +44 -0
- package/dist/moTimeline.cjs +3 -3
- package/dist/moTimeline.css +2 -2
- package/dist/moTimeline.js +109 -85
- package/dist/moTimeline.umd.js +3 -3
- package/package.json +1 -1
- package/src/moTimeline.css +37 -1
- package/src/moTimeline.js +75 -37
package/README.md
CHANGED
|
@@ -92,6 +92,41 @@ import 'motimeline/dist/moTimeline.css';
|
|
|
92
92
|
</li>
|
|
93
93
|
```
|
|
94
94
|
|
|
95
|
+
### Rendered DOM (after init)
|
|
96
|
+
|
|
97
|
+
The library injects classes and elements into your markup. Here is what a fully rendered item looks like:
|
|
98
|
+
|
|
99
|
+
```html
|
|
100
|
+
<!-- Container gets mo-timeline, mo-theme, mo-twocol added -->
|
|
101
|
+
<ul class="mo-timeline mo-theme mo-twocol">
|
|
102
|
+
|
|
103
|
+
<!-- Left-column item: mo-item + js-mo-item added to every <li> -->
|
|
104
|
+
<li class="mo-item js-mo-item">
|
|
105
|
+
<span class="mo-arrow js-mo-arrow"></span> <!-- injected when showArrow: true -->
|
|
106
|
+
<span class="mo-badge js-mo-badge">1</span> <!-- injected when showBadge: true -->
|
|
107
|
+
<div class="mo-card">
|
|
108
|
+
<div class="mo-card-image">
|
|
109
|
+
<img class="mo-banner" src="banner.jpg" alt="">
|
|
110
|
+
<img class="mo-avatar" src="avatar.jpg" alt="">
|
|
111
|
+
</div>
|
|
112
|
+
<div class="mo-card-body">
|
|
113
|
+
<h3>Title</h3>
|
|
114
|
+
<p class="mo-meta">Date</p>
|
|
115
|
+
<p>Text…</p>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
</li>
|
|
119
|
+
|
|
120
|
+
<!-- Right-column item: also gets mo-inverted + js-mo-inverted -->
|
|
121
|
+
<li class="mo-item js-mo-item mo-inverted js-mo-inverted">
|
|
122
|
+
...
|
|
123
|
+
</li>
|
|
124
|
+
|
|
125
|
+
</ul>
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
> `js-mo-*` classes are JS-only selector mirrors of their `mo-*` counterparts — use them in your own scripts to avoid coupling to styling class names.
|
|
129
|
+
|
|
95
130
|
---
|
|
96
131
|
|
|
97
132
|
## Options
|
|
@@ -109,6 +144,8 @@ import 'motimeline/dist/moTimeline.css';
|
|
|
109
144
|
| `cardMarginInverted` | string | `'0.5rem 0.5rem 0.5rem 1.25rem'` | Margin of right-column (inverted) themed cards. The larger left value creates space toward the center line. Sets `--mo-card-margin-inverted` on the container. |
|
|
110
145
|
| `cardMarginFullWidth` | string | `'0.5rem'` | Margin of full-width themed cards. Sets `--mo-card-margin-fullwidth` on the container. |
|
|
111
146
|
| `randomFullWidth` | number \| boolean | `0` | `0`/`false` = off. A number `0–1` sets the probability that each item is randomly promoted to full-width during init. `true` = 33% chance. Items can also be set manually by adding the `mo-fullwidth` class to the `<li>`. |
|
|
147
|
+
| `animate` | string \| boolean | `false` | Animate items as they scroll into view using `IntersectionObserver`. `'fade'` — items fade in. `'slide'` — left-column items slide in from the left, right-column items from the right. `true` = `'fade'`. Disable for individual items by adding `mo-visible` manually. Control speed via `--mo-animate-duration`. |
|
|
148
|
+
| `renderCard` | function \| null | `null` | `(item, cardEl) => void`. When set, called for every item instead of the built-in HTML renderer. `cardEl` is the `.mo-card` div already placed inside the `<li>`. Populate it via `innerHTML` or DOM methods. The library still owns the `<li>`, column placement, spine, badge, arrow, `addItems()`, and scroll pagination. |
|
|
112
149
|
|
|
113
150
|
---
|
|
114
151
|
|
|
@@ -351,6 +388,7 @@ async function fetchPage(page) {
|
|
|
351
388
|
--mo-card-margin: 0.5rem 1.25rem 0.5rem 0.5rem;
|
|
352
389
|
--mo-card-margin-inverted: 0.5rem 0.5rem 0.5rem 1.25rem;
|
|
353
390
|
--mo-card-margin-fullwidth: 0.5rem;
|
|
391
|
+
--mo-animate-duration: 0.5s;
|
|
354
392
|
}
|
|
355
393
|
```
|
|
356
394
|
|
|
@@ -380,6 +418,12 @@ No framework option needed. Wrap the `<ul>` inside a Bootstrap `.container`:
|
|
|
380
418
|
|
|
381
419
|
## Changelog
|
|
382
420
|
|
|
421
|
+
### v2.10.0
|
|
422
|
+
- New option `renderCard(item, cardEl)` — custom card renderer. When provided, the library skips its built-in card HTML and calls this function instead, passing the item data object and the `.mo-card` div already inserted into the DOM. The library continues to own column placement, spine, badge, arrow, `addItems()`, and scroll pagination. Enables full React component injection via `createRoot(cardEl).render(...)`.
|
|
423
|
+
|
|
424
|
+
### v2.9.0
|
|
425
|
+
- New option `animate` — scroll-triggered animations via `IntersectionObserver`. `'fade'` fades items in as they enter the viewport; `'slide'` slides left-column items from the left and right-column items from the right. `true` defaults to `'fade'`. Speed controlled via `--mo-animate-duration` (default `0.5s`). Works for initial load, `addItems()`, and `insertItem()`.
|
|
426
|
+
|
|
383
427
|
### v2.8.1
|
|
384
428
|
- New method `insertItem(item, index)` — inserts a single item at a specific 0-based index, or at a random position when index is omitted. Badge numbers are re-sequenced automatically.
|
|
385
429
|
|
package/dist/moTimeline.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var
|
|
2
|
-
* moTimeline v2.
|
|
1
|
+
"use strict";var _=Object.defineProperty;var b=(a,e,t)=>e in a?_(a,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):a[e]=t;var p=(a,e,t)=>b(a,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
|
|
2
|
+
* moTimeline v2.10.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
6
|
-
*/const
|
|
6
|
+
*/const m=new WeakMap,v={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},E="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 a=window.innerWidth;return a<600?"xs":a<992?"sm":a<1200?"md":"lg"}function I(a,e=100){let t;return(...r)=>{clearTimeout(t),t=setTimeout(()=>a(...r),e)}}function f(a){return a?{o:a.offsetTop,h:a.offsetHeight,gppu:a.offsetTop+a.offsetHeight}:{o:0,h:0,gppu:0}}function y(a,e){const t=[];let r=a.previousElementSibling;for(;r;)(!e||r.matches(e))&&t.push(r),r=r.previousElementSibling;return t}const d=class d{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({},v,t),this.settings.columnCount=Object.assign({},v.columnCount,t.columnCount),this._resizeHandler=I(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(m.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(m.set(e,t),d.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 r=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${r}`),this._observer=new IntersectionObserver(i=>{i.forEach(s=>{s.isIntersecting&&(s.target.classList.add("mo-visible"),this._observer.unobserve(s.target))})},{threshold:.1})}this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){d.instances.forEach(e=>{const t=e.element,r=m.get(t);r&&(r.col=r.columnCount[w()],e._setDivider(),Array.from(t.children).forEach(i=>{e._setPostPosition(i)}))})}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 r=this.element,i=this._getData();if(!i)return;const s=this._createItemElement(e),o=Array.from(r.children).filter(l=>l.classList.contains("js-mo-item")),n=t==null?Math.floor(Math.random()*(o.length+1)):Math.max(0,Math.min(t,o.length));if(n>=o.length?r.appendChild(s):r.insertBefore(s,o[n]),s.id||(s.id="moT"+crypto.randomUUID()+"_"+n),s.classList.add("mo-item","js-mo-item"),e.fullWidth)s.classList.add("mo-fullwidth","js-mo-fullwidth");else if(i.randomFullWidth){const l=i.randomFullWidth===!0?.33:i.randomFullWidth;Math.random()<l&&s.classList.add("mo-fullwidth","js-mo-fullwidth")}return i.showBadge&&this._createBadge(s,n+1),i.showArrow&&this._createArrow(s),i.showBadge&&i.showCounterStyle==="counter"&&Array.from(r.querySelectorAll(".js-mo-item")).forEach((l,c)=>{const h=l.querySelector(".js-mo-badge");h&&(h.textContent=c+1)}),i.lastItemIdx=Array.from(r.children).length,m.set(r,i),this.refresh(),this._observeItems([s]),s.querySelectorAll("img").forEach(l=>{l.complete||l.addEventListener("load",this._resizeHandler,{once:!0})}),s}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),m.delete(this.element),d.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 m.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 r=t.lastItemIdx,i=Array.from(e.children),s=i.slice(r);if(s.length!==0){if(s.forEach((o,n)=>{o.id||(o.id="moT"+crypto.randomUUID()+"_"+(n+r)),o.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const o=t.randomFullWidth===!0?.33:t.randomFullWidth;s.forEach(n=>{!n.classList.contains("mo-fullwidth")&&Math.random()<o&&n.classList.add("mo-fullwidth","js-mo-fullwidth")})}s.forEach((o,n)=>{t.showBadge&&this._createBadge(o,n+r+1),t.showArrow&&this._createArrow(o)}),t.lastItemIdx=i.length,m.set(e,t),this.refresh(),this._observeItems(s),s.forEach(o=>{o.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 r=t.col,i=y(e,".js-mo-inverted")[0]||null,s=y(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,o=f(s),n=f(i),l=f(e);let c=0,h=0;if(r>1){o.gppu>l.o+1&&(c=1),n.gppu>o.gppu&&(c=0);const g=e.previousElementSibling;g&&Math.abs(l.o-f(g).o)<40&&(h=1)}return{lr:c,badge_offset:h}}_createBadge(e,t){const r=this._getData(),i=document.createElement("span");if(i.className="mo-badge js-mo-badge",r.showCounterStyle==="none")i.style.opacity="0";else if(r.showCounterStyle==="image"){const s=document.createElement("img");s.className="mo-badge-icon",s.alt="",s.src=e.dataset.moIcon||E,i.appendChild(s)}else i.textContent=t;e.prepend(i)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const r=document.createElement("div");r.className="mo-card";const i=this._getData();if(i&&typeof i.renderCard=="function")i.renderCard(e,r);else{if(e.banner){const o=document.createElement("div");o.className="mo-card-image";const n=document.createElement("img");if(n.className="mo-banner",n.src=e.banner,n.alt="",o.appendChild(n),e.avatar){const l=document.createElement("img");l.className="mo-avatar",l.src=e.avatar,l.alt="",o.appendChild(l)}r.appendChild(o)}const s=document.createElement("div");if(s.className="mo-card-body",e.title){const o=document.createElement("h3");o.textContent=e.title,s.appendChild(o)}if(e.meta){const o=document.createElement("p");o.className="mo-meta",o.textContent=e.meta,s.appendChild(o)}if(e.text){const o=document.createElement("p");o.textContent=e.text,s.appendChild(o)}r.appendChild(s)}return t.appendChild(r),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};p(d,"instances",new Set);let u=d;exports.MoTimeline=u;exports.default=u;
|
package/dist/moTimeline.css
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
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}
|
|
2
|
+
* moTimeline v2.10.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)}
|
package/dist/moTimeline.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var g = (a, e, t) =>
|
|
1
|
+
var _ = Object.defineProperty;
|
|
2
|
+
var b = (a, e, t) => e in a ? _(a, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : a[e] = t;
|
|
3
|
+
var g = (a, e, t) => b(a, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
/*!
|
|
5
|
-
* moTimeline v2.
|
|
5
|
+
* moTimeline v2.10.0
|
|
6
6
|
* Responsive two-column timeline layout library
|
|
7
7
|
* https://github.com/MattOpen/moTimeline
|
|
8
8
|
* MIT License
|
|
9
9
|
*/
|
|
10
|
-
const
|
|
10
|
+
const m = /* @__PURE__ */ new WeakMap(), p = {
|
|
11
11
|
columnCount: { xs: 1, sm: 2, md: 2, lg: 2 },
|
|
12
12
|
showBadge: !1,
|
|
13
13
|
showArrow: !1,
|
|
@@ -19,17 +19,21 @@ const c = /* @__PURE__ */ new WeakMap(), p = {
|
|
|
19
19
|
cardMargin: "0.5rem 1.25rem 0.5rem 0.5rem",
|
|
20
20
|
cardMarginInverted: "0.5rem 0.5rem 0.5rem 1.25rem",
|
|
21
21
|
cardMarginFullWidth: "0.5rem",
|
|
22
|
-
randomFullWidth: 0
|
|
22
|
+
randomFullWidth: 0,
|
|
23
23
|
// 0 = off; 0–1 = probability per item; true = 0.33
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
animate: !1,
|
|
25
|
+
// false | 'fade' | 'slide'
|
|
26
|
+
renderCard: null
|
|
27
|
+
// (item, cardEl) => void — custom card renderer; skips built-in HTML
|
|
28
|
+
}, E = "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>";
|
|
29
|
+
function v() {
|
|
26
30
|
const a = window.innerWidth;
|
|
27
31
|
return a < 600 ? "xs" : a < 992 ? "sm" : a < 1200 ? "md" : "lg";
|
|
28
32
|
}
|
|
29
|
-
function
|
|
33
|
+
function I(a, e = 100) {
|
|
30
34
|
let t;
|
|
31
|
-
return (...
|
|
32
|
-
clearTimeout(t), t = setTimeout(() => a(...
|
|
35
|
+
return (...r) => {
|
|
36
|
+
clearTimeout(t), t = setTimeout(() => a(...r), e);
|
|
33
37
|
};
|
|
34
38
|
}
|
|
35
39
|
function f(a) {
|
|
@@ -39,32 +43,40 @@ function f(a) {
|
|
|
39
43
|
gppu: a.offsetTop + a.offsetHeight
|
|
40
44
|
} : { o: 0, h: 0, gppu: 0 };
|
|
41
45
|
}
|
|
42
|
-
function
|
|
46
|
+
function w(a, e) {
|
|
43
47
|
const t = [];
|
|
44
|
-
let
|
|
45
|
-
for (;
|
|
46
|
-
(!e ||
|
|
48
|
+
let r = a.previousElementSibling;
|
|
49
|
+
for (; r; )
|
|
50
|
+
(!e || r.matches(e)) && t.push(r), r = r.previousElementSibling;
|
|
47
51
|
return t;
|
|
48
52
|
}
|
|
49
53
|
const d = class d {
|
|
50
54
|
constructor(e, t = {}) {
|
|
51
55
|
if (typeof e == "string" && (e = document.querySelector(e)), !e) throw new Error("moTimeline: element not found");
|
|
52
|
-
this.element = e, this.settings = Object.assign({}, p, t), this.settings.columnCount = Object.assign({}, p.columnCount, t.columnCount), this._resizeHandler =
|
|
56
|
+
this.element = e, this.settings = Object.assign({}, p, t), this.settings.columnCount = Object.assign({}, p.columnCount, t.columnCount), this._resizeHandler = I(() => this.refresh(), 100), this._initialized = !1, this.init();
|
|
53
57
|
}
|
|
54
58
|
init() {
|
|
55
59
|
const e = this.element;
|
|
56
|
-
if (
|
|
60
|
+
if (m.has(e)) {
|
|
57
61
|
this.refresh();
|
|
58
62
|
return;
|
|
59
63
|
}
|
|
60
64
|
const t = Object.assign({}, this.settings, { lastItemIdx: 0 });
|
|
61
|
-
|
|
65
|
+
if (m.set(e, t), d.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) {
|
|
66
|
+
const r = t.animate === !0 ? "fade" : t.animate;
|
|
67
|
+
e.classList.add("mo-animate", `mo-animate-${r}`), this._observer = new IntersectionObserver((i) => {
|
|
68
|
+
i.forEach((s) => {
|
|
69
|
+
s.isIntersecting && (s.target.classList.add("mo-visible"), this._observer.unobserve(s.target));
|
|
70
|
+
});
|
|
71
|
+
}, { threshold: 0.1 });
|
|
72
|
+
}
|
|
73
|
+
this._initialized = !0, window.addEventListener("resize", this._resizeHandler), Array.from(e.children).length > 0 && this._initItems();
|
|
62
74
|
}
|
|
63
75
|
refresh() {
|
|
64
76
|
d.instances.forEach((e) => {
|
|
65
|
-
const t = e.element,
|
|
66
|
-
|
|
67
|
-
e._setPostPosition(
|
|
77
|
+
const t = e.element, r = m.get(t);
|
|
78
|
+
r && (r.col = r.columnCount[v()], e._setDivider(), Array.from(t.children).forEach((i) => {
|
|
79
|
+
e._setPostPosition(i);
|
|
68
80
|
}));
|
|
69
81
|
});
|
|
70
82
|
}
|
|
@@ -91,53 +103,53 @@ const d = class d {
|
|
|
91
103
|
* @returns {HTMLElement} the inserted <li> element
|
|
92
104
|
*/
|
|
93
105
|
insertItem(e, t) {
|
|
94
|
-
const
|
|
95
|
-
if (!
|
|
96
|
-
const
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
else if (
|
|
100
|
-
const l =
|
|
101
|
-
Math.random() < l &&
|
|
106
|
+
const r = this.element, i = this._getData();
|
|
107
|
+
if (!i) return;
|
|
108
|
+
const s = this._createItemElement(e), o = Array.from(r.children).filter((l) => l.classList.contains("js-mo-item")), n = t == null ? Math.floor(Math.random() * (o.length + 1)) : Math.max(0, Math.min(t, o.length));
|
|
109
|
+
if (n >= o.length ? r.appendChild(s) : r.insertBefore(s, o[n]), s.id || (s.id = "moT" + crypto.randomUUID() + "_" + n), s.classList.add("mo-item", "js-mo-item"), e.fullWidth)
|
|
110
|
+
s.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
111
|
+
else if (i.randomFullWidth) {
|
|
112
|
+
const l = i.randomFullWidth === !0 ? 0.33 : i.randomFullWidth;
|
|
113
|
+
Math.random() < l && s.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
102
114
|
}
|
|
103
|
-
return
|
|
115
|
+
return i.showBadge && this._createBadge(s, n + 1), i.showArrow && this._createArrow(s), i.showBadge && i.showCounterStyle === "counter" && Array.from(r.querySelectorAll(".js-mo-item")).forEach((l, c) => {
|
|
104
116
|
const h = l.querySelector(".js-mo-badge");
|
|
105
|
-
h && (h.textContent =
|
|
106
|
-
}),
|
|
117
|
+
h && (h.textContent = c + 1);
|
|
118
|
+
}), i.lastItemIdx = Array.from(r.children).length, m.set(r, i), this.refresh(), this._observeItems([s]), s.querySelectorAll("img").forEach((l) => {
|
|
107
119
|
l.complete || l.addEventListener("load", this._resizeHandler, { once: !0 });
|
|
108
|
-
}),
|
|
120
|
+
}), s;
|
|
109
121
|
}
|
|
110
122
|
destroy() {
|
|
111
|
-
window.removeEventListener("resize", this._resizeHandler),
|
|
112
|
-
e.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset", "mo-fullwidth", "js-mo-fullwidth"), e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((t) => t.remove());
|
|
123
|
+
window.removeEventListener("resize", this._resizeHandler), this._observer && (this._observer.disconnect(), this._observer = null), m.delete(this.element), d.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) => {
|
|
124
|
+
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());
|
|
113
125
|
});
|
|
114
126
|
}
|
|
115
127
|
// ─── Private ────────────────────────────────────────────────────────────────
|
|
116
128
|
_getData() {
|
|
117
|
-
return
|
|
129
|
+
return m.get(this.element);
|
|
118
130
|
}
|
|
119
131
|
_setDivider() {
|
|
120
132
|
const e = this._getData();
|
|
121
|
-
e && (e.col = e.columnCount[
|
|
133
|
+
e && (e.col = e.columnCount[v()], this.element.classList.toggle("mo-twocol", e.col > 1));
|
|
122
134
|
}
|
|
123
135
|
_initItems() {
|
|
124
136
|
const e = this.element, t = this._getData();
|
|
125
137
|
if (!t) return;
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
if (
|
|
129
|
-
|
|
138
|
+
const r = t.lastItemIdx, i = Array.from(e.children), s = i.slice(r);
|
|
139
|
+
if (s.length !== 0) {
|
|
140
|
+
if (s.forEach((o, n) => {
|
|
141
|
+
o.id || (o.id = "moT" + crypto.randomUUID() + "_" + (n + r)), o.classList.add("mo-item", "js-mo-item");
|
|
130
142
|
}), this._setDivider(), t.randomFullWidth) {
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
!
|
|
143
|
+
const o = t.randomFullWidth === !0 ? 0.33 : t.randomFullWidth;
|
|
144
|
+
s.forEach((n) => {
|
|
145
|
+
!n.classList.contains("mo-fullwidth") && Math.random() < o && n.classList.add("mo-fullwidth", "js-mo-fullwidth");
|
|
134
146
|
});
|
|
135
147
|
}
|
|
136
|
-
|
|
137
|
-
t.showBadge && this._createBadge(
|
|
138
|
-
}), t.lastItemIdx =
|
|
139
|
-
|
|
140
|
-
|
|
148
|
+
s.forEach((o, n) => {
|
|
149
|
+
t.showBadge && this._createBadge(o, n + r + 1), t.showArrow && this._createArrow(o);
|
|
150
|
+
}), t.lastItemIdx = i.length, m.set(e, t), this.refresh(), this._observeItems(s), s.forEach((o) => {
|
|
151
|
+
o.querySelectorAll("img").forEach((n) => {
|
|
152
|
+
n.complete || n.addEventListener("load", this._resizeHandler, { once: !0 });
|
|
141
153
|
});
|
|
142
154
|
});
|
|
143
155
|
}
|
|
@@ -154,59 +166,71 @@ const d = class d {
|
|
|
154
166
|
if (!e) return null;
|
|
155
167
|
const t = this._getData();
|
|
156
168
|
if (!t) return null;
|
|
157
|
-
const
|
|
158
|
-
let
|
|
159
|
-
if (
|
|
160
|
-
|
|
169
|
+
const r = t.col, i = w(e, ".js-mo-inverted")[0] || null, s = w(e, ".js-mo-item:not(.js-mo-inverted)")[0] || null, o = f(s), n = f(i), l = f(e);
|
|
170
|
+
let c = 0, h = 0;
|
|
171
|
+
if (r > 1) {
|
|
172
|
+
o.gppu > l.o + 1 && (c = 1), n.gppu > o.gppu && (c = 0);
|
|
161
173
|
const u = e.previousElementSibling;
|
|
162
174
|
u && Math.abs(l.o - f(u).o) < 40 && (h = 1);
|
|
163
175
|
}
|
|
164
|
-
return { lr:
|
|
176
|
+
return { lr: c, badge_offset: h };
|
|
165
177
|
}
|
|
166
178
|
_createBadge(e, t) {
|
|
167
|
-
const
|
|
168
|
-
if (
|
|
169
|
-
|
|
170
|
-
else if (
|
|
171
|
-
const
|
|
172
|
-
|
|
179
|
+
const r = this._getData(), i = document.createElement("span");
|
|
180
|
+
if (i.className = "mo-badge js-mo-badge", r.showCounterStyle === "none")
|
|
181
|
+
i.style.opacity = "0";
|
|
182
|
+
else if (r.showCounterStyle === "image") {
|
|
183
|
+
const s = document.createElement("img");
|
|
184
|
+
s.className = "mo-badge-icon", s.alt = "", s.src = e.dataset.moIcon || E, i.appendChild(s);
|
|
173
185
|
} else
|
|
174
|
-
|
|
175
|
-
e.prepend(
|
|
186
|
+
i.textContent = t;
|
|
187
|
+
e.prepend(i);
|
|
176
188
|
}
|
|
177
189
|
_createItemElement(e) {
|
|
178
190
|
const t = document.createElement("li");
|
|
179
191
|
e.icon && (t.dataset.moIcon = e.icon);
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
192
|
+
const r = document.createElement("div");
|
|
193
|
+
r.className = "mo-card";
|
|
194
|
+
const i = this._getData();
|
|
195
|
+
if (i && typeof i.renderCard == "function")
|
|
196
|
+
i.renderCard(e, r);
|
|
197
|
+
else {
|
|
198
|
+
if (e.banner) {
|
|
199
|
+
const o = document.createElement("div");
|
|
200
|
+
o.className = "mo-card-image";
|
|
201
|
+
const n = document.createElement("img");
|
|
202
|
+
if (n.className = "mo-banner", n.src = e.banner, n.alt = "", o.appendChild(n), e.avatar) {
|
|
203
|
+
const l = document.createElement("img");
|
|
204
|
+
l.className = "mo-avatar", l.src = e.avatar, l.alt = "", o.appendChild(l);
|
|
205
|
+
}
|
|
206
|
+
r.appendChild(o);
|
|
188
207
|
}
|
|
189
|
-
s.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
r.
|
|
208
|
+
const s = document.createElement("div");
|
|
209
|
+
if (s.className = "mo-card-body", e.title) {
|
|
210
|
+
const o = document.createElement("h3");
|
|
211
|
+
o.textContent = e.title, s.appendChild(o);
|
|
212
|
+
}
|
|
213
|
+
if (e.meta) {
|
|
214
|
+
const o = document.createElement("p");
|
|
215
|
+
o.className = "mo-meta", o.textContent = e.meta, s.appendChild(o);
|
|
216
|
+
}
|
|
217
|
+
if (e.text) {
|
|
218
|
+
const o = document.createElement("p");
|
|
219
|
+
o.textContent = e.text, s.appendChild(o);
|
|
220
|
+
}
|
|
221
|
+
r.appendChild(s);
|
|
203
222
|
}
|
|
204
|
-
return
|
|
223
|
+
return t.appendChild(r), t;
|
|
205
224
|
}
|
|
206
225
|
_createArrow(e) {
|
|
207
226
|
const t = document.createElement("span");
|
|
208
227
|
t.className = "mo-arrow js-mo-arrow", e.prepend(t);
|
|
209
228
|
}
|
|
229
|
+
_observeItems(e) {
|
|
230
|
+
this._observer && e.forEach((t) => {
|
|
231
|
+
t.classList.contains("mo-visible") || this._observer.observe(t);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
210
234
|
};
|
|
211
235
|
g(d, "instances", /* @__PURE__ */ new Set());
|
|
212
236
|
let y = d;
|
package/dist/moTimeline.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(
|
|
2
|
-
* moTimeline v2.
|
|
1
|
+
(function(d,a){typeof exports=="object"&&typeof module<"u"?a(exports):typeof define=="function"&&define.amd?define(["exports"],a):(d=typeof globalThis<"u"?globalThis:d||self,a(d.MoTimeline={}))})(this,function(d){"use strict";var I=Object.defineProperty;var C=(d,a,c)=>a in d?I(d,a,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[a]=c;var _=(d,a,c)=>C(d,typeof a!="symbol"?a+"":a,c);/*!
|
|
2
|
+
* moTimeline v2.10.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
6
|
-
*/const a=new WeakMap,
|
|
6
|
+
*/const a=new WeakMap,c={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},b="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 v(){const m=window.innerWidth;return m<600?"xs":m<992?"sm":m<1200?"md":"lg"}function E(m,e=100){let t;return(...r)=>{clearTimeout(t),t=setTimeout(()=>m(...r),e)}}function g(m){return m?{o:m.offsetTop,h:m.offsetHeight,gppu:m.offsetTop+m.offsetHeight}:{o:0,h:0,gppu:0}}function w(m,e){const t=[];let r=m.previousElementSibling;for(;r;)(!e||r.matches(e))&&t.push(r),r=r.previousElementSibling;return t}const h=class h{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({},c,t),this.settings.columnCount=Object.assign({},c.columnCount,t.columnCount),this._resizeHandler=E(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(a.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});if(a.set(e,t),h.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 r=t.animate===!0?"fade":t.animate;e.classList.add("mo-animate",`mo-animate-${r}`),this._observer=new IntersectionObserver(i=>{i.forEach(s=>{s.isIntersecting&&(s.target.classList.add("mo-visible"),this._observer.unobserve(s.target))})},{threshold:.1})}this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){h.instances.forEach(e=>{const t=e.element,r=a.get(t);r&&(r.col=r.columnCount[v()],e._setDivider(),Array.from(t.children).forEach(i=>{e._setPostPosition(i)}))})}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 r=this.element,i=this._getData();if(!i)return;const s=this._createItemElement(e),o=Array.from(r.children).filter(l=>l.classList.contains("js-mo-item")),n=t==null?Math.floor(Math.random()*(o.length+1)):Math.max(0,Math.min(t,o.length));if(n>=o.length?r.appendChild(s):r.insertBefore(s,o[n]),s.id||(s.id="moT"+crypto.randomUUID()+"_"+n),s.classList.add("mo-item","js-mo-item"),e.fullWidth)s.classList.add("mo-fullwidth","js-mo-fullwidth");else if(i.randomFullWidth){const l=i.randomFullWidth===!0?.33:i.randomFullWidth;Math.random()<l&&s.classList.add("mo-fullwidth","js-mo-fullwidth")}return i.showBadge&&this._createBadge(s,n+1),i.showArrow&&this._createArrow(s),i.showBadge&&i.showCounterStyle==="counter"&&Array.from(r.querySelectorAll(".js-mo-item")).forEach((l,f)=>{const u=l.querySelector(".js-mo-badge");u&&(u.textContent=f+1)}),i.lastItemIdx=Array.from(r.children).length,a.set(r,i),this.refresh(),this._observeItems([s]),s.querySelectorAll("img").forEach(l=>{l.complete||l.addEventListener("load",this._resizeHandler,{once:!0})}),s}destroy(){window.removeEventListener("resize",this._resizeHandler),this._observer&&(this._observer.disconnect(),this._observer=null),a.delete(this.element),h.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 a.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[v()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const r=t.lastItemIdx,i=Array.from(e.children),s=i.slice(r);if(s.length!==0){if(s.forEach((o,n)=>{o.id||(o.id="moT"+crypto.randomUUID()+"_"+(n+r)),o.classList.add("mo-item","js-mo-item")}),this._setDivider(),t.randomFullWidth){const o=t.randomFullWidth===!0?.33:t.randomFullWidth;s.forEach(n=>{!n.classList.contains("mo-fullwidth")&&Math.random()<o&&n.classList.add("mo-fullwidth","js-mo-fullwidth")})}s.forEach((o,n)=>{t.showBadge&&this._createBadge(o,n+r+1),t.showArrow&&this._createArrow(o)}),t.lastItemIdx=i.length,a.set(e,t),this.refresh(),this._observeItems(s),s.forEach(o=>{o.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 r=t.col,i=w(e,".js-mo-inverted")[0]||null,s=w(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,o=g(s),n=g(i),l=g(e);let f=0,u=0;if(r>1){o.gppu>l.o+1&&(f=1),n.gppu>o.gppu&&(f=0);const y=e.previousElementSibling;y&&Math.abs(l.o-g(y).o)<40&&(u=1)}return{lr:f,badge_offset:u}}_createBadge(e,t){const r=this._getData(),i=document.createElement("span");if(i.className="mo-badge js-mo-badge",r.showCounterStyle==="none")i.style.opacity="0";else if(r.showCounterStyle==="image"){const s=document.createElement("img");s.className="mo-badge-icon",s.alt="",s.src=e.dataset.moIcon||b,i.appendChild(s)}else i.textContent=t;e.prepend(i)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const r=document.createElement("div");r.className="mo-card";const i=this._getData();if(i&&typeof i.renderCard=="function")i.renderCard(e,r);else{if(e.banner){const o=document.createElement("div");o.className="mo-card-image";const n=document.createElement("img");if(n.className="mo-banner",n.src=e.banner,n.alt="",o.appendChild(n),e.avatar){const l=document.createElement("img");l.className="mo-avatar",l.src=e.avatar,l.alt="",o.appendChild(l)}r.appendChild(o)}const s=document.createElement("div");if(s.className="mo-card-body",e.title){const o=document.createElement("h3");o.textContent=e.title,s.appendChild(o)}if(e.meta){const o=document.createElement("p");o.className="mo-meta",o.textContent=e.meta,s.appendChild(o)}if(e.text){const o=document.createElement("p");o.textContent=e.text,s.appendChild(o)}r.appendChild(s)}return t.appendChild(r),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}_observeItems(e){this._observer&&e.forEach(t=>{t.classList.contains("mo-visible")||this._observer.observe(t)})}};_(h,"instances",new Set);let p=h;d.MoTimeline=p,d.default=p,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
CHANGED
package/src/moTimeline.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
2
|
+
* moTimeline v2.10.0 — CSS
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* ── CSS custom properties (easy override) ─────────────────── */
|
|
@@ -263,3 +263,39 @@
|
|
|
263
263
|
box-shadow: 0 2px 6px rgba(0, 0, 0, .10);
|
|
264
264
|
color: #374151;
|
|
265
265
|
}
|
|
266
|
+
|
|
267
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
268
|
+
ANIMATION — enabled via animate: 'fade' | 'slide'
|
|
269
|
+
═══════════════════════════════════════════════════════════════ */
|
|
270
|
+
|
|
271
|
+
.mo-timeline.mo-animate > .mo-item {
|
|
272
|
+
transition: opacity var(--mo-animate-duration, 0.5s) ease,
|
|
273
|
+
transform var(--mo-animate-duration, 0.5s) ease;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* Fade: items start invisible */
|
|
277
|
+
.mo-timeline.mo-animate-fade > .mo-item {
|
|
278
|
+
opacity: 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* Slide: left items come from left, right items from right */
|
|
282
|
+
.mo-timeline.mo-animate-slide > .mo-item:not(.mo-inverted) {
|
|
283
|
+
opacity: 0;
|
|
284
|
+
transform: translateX(-40px);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.mo-timeline.mo-animate-slide > .mo-item.mo-inverted {
|
|
288
|
+
opacity: 0;
|
|
289
|
+
transform: translateX(40px);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/* Single-column slide: always comes from left */
|
|
293
|
+
.mo-timeline:not(.mo-twocol).mo-animate-slide > .mo-item {
|
|
294
|
+
transform: translateX(-40px);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* Visible state — added by IntersectionObserver */
|
|
298
|
+
.mo-timeline.mo-animate > .mo-item.mo-visible {
|
|
299
|
+
opacity: 1;
|
|
300
|
+
transform: translateX(0);
|
|
301
|
+
}
|
package/src/moTimeline.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
2
|
+
* moTimeline v2.10.0
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
@@ -22,6 +22,8 @@ const DEFAULTS = {
|
|
|
22
22
|
cardMarginInverted: '0.5rem 0.5rem 0.5rem 1.25rem',
|
|
23
23
|
cardMarginFullWidth: '0.5rem',
|
|
24
24
|
randomFullWidth: 0, // 0 = off; 0–1 = probability per item; true = 0.33
|
|
25
|
+
animate: false, // false | 'fade' | 'slide'
|
|
26
|
+
renderCard: null, // (item, cardEl) => void — custom card renderer; skips built-in HTML
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
const DEFAULT_BADGE_ICON = "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>";
|
|
@@ -100,6 +102,19 @@ export class MoTimeline {
|
|
|
100
102
|
el.style.setProperty('--mo-card-margin-inverted', data.cardMarginInverted);
|
|
101
103
|
el.style.setProperty('--mo-card-margin-fullwidth', data.cardMarginFullWidth);
|
|
102
104
|
|
|
105
|
+
if (data.animate) {
|
|
106
|
+
const type = data.animate === true ? 'fade' : data.animate;
|
|
107
|
+
el.classList.add('mo-animate', `mo-animate-${type}`);
|
|
108
|
+
this._observer = new IntersectionObserver((entries) => {
|
|
109
|
+
entries.forEach((entry) => {
|
|
110
|
+
if (entry.isIntersecting) {
|
|
111
|
+
entry.target.classList.add('mo-visible');
|
|
112
|
+
this._observer.unobserve(entry.target);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}, { threshold: 0.1 });
|
|
116
|
+
}
|
|
117
|
+
|
|
103
118
|
this._initialized = true;
|
|
104
119
|
window.addEventListener('resize', this._resizeHandler);
|
|
105
120
|
|
|
@@ -196,6 +211,8 @@ export class MoTimeline {
|
|
|
196
211
|
|
|
197
212
|
this.refresh();
|
|
198
213
|
|
|
214
|
+
this._observeItems([newEl]);
|
|
215
|
+
|
|
199
216
|
newEl.querySelectorAll('img').forEach((img) => {
|
|
200
217
|
if (!img.complete) img.addEventListener('load', this._resizeHandler, { once: true });
|
|
201
218
|
});
|
|
@@ -205,6 +222,10 @@ export class MoTimeline {
|
|
|
205
222
|
|
|
206
223
|
destroy() {
|
|
207
224
|
window.removeEventListener('resize', this._resizeHandler);
|
|
225
|
+
if (this._observer) {
|
|
226
|
+
this._observer.disconnect();
|
|
227
|
+
this._observer = null;
|
|
228
|
+
}
|
|
208
229
|
instanceData.delete(this.element);
|
|
209
230
|
MoTimeline.instances.delete(this);
|
|
210
231
|
this.element.style.removeProperty('--mo-card-border-radius');
|
|
@@ -212,9 +233,9 @@ export class MoTimeline {
|
|
|
212
233
|
this.element.style.removeProperty('--mo-card-margin');
|
|
213
234
|
this.element.style.removeProperty('--mo-card-margin-inverted');
|
|
214
235
|
this.element.style.removeProperty('--mo-card-margin-fullwidth');
|
|
215
|
-
this.element.classList.remove('mo-timeline', 'mo-theme', 'mo-twocol');
|
|
236
|
+
this.element.classList.remove('mo-timeline', 'mo-theme', 'mo-twocol', 'mo-animate', 'mo-animate-fade', 'mo-animate-slide');
|
|
216
237
|
Array.from(this.element.children).forEach((child) => {
|
|
217
|
-
child.classList.remove('mo-item', 'js-mo-item', 'mo-inverted', 'js-mo-inverted', 'mo-offset', 'mo-fullwidth', 'js-mo-fullwidth');
|
|
238
|
+
child.classList.remove('mo-item', 'js-mo-item', 'mo-inverted', 'js-mo-inverted', 'mo-offset', 'mo-fullwidth', 'js-mo-fullwidth', 'mo-visible');
|
|
218
239
|
child.querySelectorAll('.js-mo-badge, .js-mo-arrow').forEach((b) => b.remove());
|
|
219
240
|
});
|
|
220
241
|
}
|
|
@@ -278,6 +299,8 @@ export class MoTimeline {
|
|
|
278
299
|
|
|
279
300
|
this.refresh();
|
|
280
301
|
|
|
302
|
+
this._observeItems(newItems);
|
|
303
|
+
|
|
281
304
|
// Re-layout after any unloaded images finish, because offsetHeight is
|
|
282
305
|
// based on text-only height until images are ready.
|
|
283
306
|
newItems.forEach((item) => {
|
|
@@ -360,43 +383,49 @@ export class MoTimeline {
|
|
|
360
383
|
const card = document.createElement('div');
|
|
361
384
|
card.className = 'mo-card';
|
|
362
385
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
banner
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
avatar
|
|
376
|
-
|
|
386
|
+
const data = this._getData();
|
|
387
|
+
if (data && typeof data.renderCard === 'function') {
|
|
388
|
+
data.renderCard(item, card);
|
|
389
|
+
} else {
|
|
390
|
+
if (item.banner) {
|
|
391
|
+
const wrap = document.createElement('div');
|
|
392
|
+
wrap.className = 'mo-card-image';
|
|
393
|
+
const banner = document.createElement('img');
|
|
394
|
+
banner.className = 'mo-banner';
|
|
395
|
+
banner.src = item.banner;
|
|
396
|
+
banner.alt = '';
|
|
397
|
+
wrap.appendChild(banner);
|
|
398
|
+
if (item.avatar) {
|
|
399
|
+
const avatar = document.createElement('img');
|
|
400
|
+
avatar.className = 'mo-avatar';
|
|
401
|
+
avatar.src = item.avatar;
|
|
402
|
+
avatar.alt = '';
|
|
403
|
+
wrap.appendChild(avatar);
|
|
404
|
+
}
|
|
405
|
+
card.appendChild(wrap);
|
|
377
406
|
}
|
|
378
|
-
card.appendChild(wrap);
|
|
379
|
-
}
|
|
380
407
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
408
|
+
const body = document.createElement('div');
|
|
409
|
+
body.className = 'mo-card-body';
|
|
410
|
+
if (item.title) {
|
|
411
|
+
const h = document.createElement('h3');
|
|
412
|
+
h.textContent = item.title;
|
|
413
|
+
body.appendChild(h);
|
|
414
|
+
}
|
|
415
|
+
if (item.meta) {
|
|
416
|
+
const m = document.createElement('p');
|
|
417
|
+
m.className = 'mo-meta';
|
|
418
|
+
m.textContent = item.meta;
|
|
419
|
+
body.appendChild(m);
|
|
420
|
+
}
|
|
421
|
+
if (item.text) {
|
|
422
|
+
const p = document.createElement('p');
|
|
423
|
+
p.textContent = item.text;
|
|
424
|
+
body.appendChild(p);
|
|
425
|
+
}
|
|
426
|
+
card.appendChild(body);
|
|
398
427
|
}
|
|
399
|
-
|
|
428
|
+
|
|
400
429
|
li.appendChild(card);
|
|
401
430
|
return li;
|
|
402
431
|
}
|
|
@@ -406,6 +435,15 @@ export class MoTimeline {
|
|
|
406
435
|
span.className = 'mo-arrow js-mo-arrow';
|
|
407
436
|
el.prepend(span);
|
|
408
437
|
}
|
|
438
|
+
|
|
439
|
+
_observeItems(items) {
|
|
440
|
+
if (!this._observer) return;
|
|
441
|
+
items.forEach((item) => {
|
|
442
|
+
if (!item.classList.contains('mo-visible')) {
|
|
443
|
+
this._observer.observe(item);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
}
|
|
409
447
|
}
|
|
410
448
|
|
|
411
449
|
export default MoTimeline;
|