motimeline 2.6.0 → 2.7.1
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 +12 -1
- package/dist/moTimeline.cjs +3 -3
- package/dist/moTimeline.css +2 -2
- package/dist/moTimeline.js +38 -36
- package/dist/moTimeline.umd.js +3 -3
- package/package.json +2 -2
- package/src/moTimeline.css +16 -17
- package/src/moTimeline.js +11 -6
package/README.md
CHANGED
|
@@ -103,6 +103,8 @@ import 'motimeline/dist/moTimeline.css';
|
|
|
103
103
|
| `showArrow` | boolean | `false` | Render a triangle arrow pointing from each card toward the center line. Automatically hidden in single-column mode. |
|
|
104
104
|
| `theme` | boolean | `false` | Enable the built-in card theme: white cards with drop shadow, full-width image banners (160 px), overlapping circular avatars, and styled badges. Adds `mo-theme` to the container — can also be set manually in HTML. |
|
|
105
105
|
| `showCounterStyle` | string | `'counter'` | `'counter'` — sequential item number (1, 2, 3…). `'image'` — image from `data-mo-icon` on the `<li>`; falls back to a built-in flat SVG dot if the attribute is absent. `'none'` — badge element is created (preserving center-line spacing) but rendered with `opacity: 0`. |
|
|
106
|
+
| `cardBorderRadius` | string | `'8px'` | Border radius of the themed card and its banner image top corners. Sets `--mo-card-border-radius` on the container. Any valid CSS length is accepted (e.g. `'0'`, `'16px'`, `'1rem'`). |
|
|
107
|
+
| `avatarSize` | string | `'50px'` | Width and height of the circular avatar image. Sets `--mo-avatar-size` on the container. Any valid CSS length is accepted (e.g. `'40px'`, `'4rem'`). |
|
|
106
108
|
|
|
107
109
|
---
|
|
108
110
|
|
|
@@ -130,7 +132,7 @@ import 'motimeline/dist/moTimeline.css';
|
|
|
130
132
|
| `mo-card` | `<div>` | Card wrapper. Shadow, border-radius, and margins when `mo-theme` is active. |
|
|
131
133
|
| `mo-card-image` | `<div>` | Optional image container inside a card. Required for the avatar-over-banner overlap. |
|
|
132
134
|
| `mo-banner` | `<img>` | Full-width banner image at the top of a themed card. |
|
|
133
|
-
| `mo-avatar` | `<img>` | Circular avatar overlapping the bottom of the banner.
|
|
135
|
+
| `mo-avatar` | `<img>` | Circular avatar overlapping the bottom of the banner. Always positioned on the right side of the card. |
|
|
134
136
|
| `mo-card-body` | `<div>` | Text content area. Padding and typography when `mo-theme` is active. |
|
|
135
137
|
| `mo-meta` | `<p>` | Date / subtitle line inside a card body. Muted colour, smaller font. |
|
|
136
138
|
| `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. |
|
|
@@ -324,6 +326,8 @@ async function fetchPage(page) {
|
|
|
324
326
|
--mo-badge-size: 26px;
|
|
325
327
|
--mo-badge-font-size: 12px;
|
|
326
328
|
--mo-arrow-color: #dde1e7;
|
|
329
|
+
--mo-card-border-radius: 8px;
|
|
330
|
+
--mo-avatar-size: 50px;
|
|
327
331
|
}
|
|
328
332
|
```
|
|
329
333
|
|
|
@@ -353,6 +357,13 @@ No framework option needed. Wrap the `<ul>` inside a Bootstrap `.container`:
|
|
|
353
357
|
|
|
354
358
|
## Changelog
|
|
355
359
|
|
|
360
|
+
### v2.7.1
|
|
361
|
+
- Fix: resize listener not attached when container is empty at init time ([#1](https://github.com/MattOpen/moTimeline/issues/1)) — `addItems()` on an empty timeline now correctly responds to window resize
|
|
362
|
+
|
|
363
|
+
### v2.7.0
|
|
364
|
+
- New option `cardBorderRadius` (string, default `'8px'`) — controls card and banner border radius via `--mo-card-border-radius`
|
|
365
|
+
- New option `avatarSize` (string, default `'50px'`) — controls avatar width/height via `--mo-avatar-size`
|
|
366
|
+
|
|
356
367
|
### v2.6.0
|
|
357
368
|
- **Breaking:** `badgeShow` renamed to `showBadge`; `arrowShow` renamed to `showArrow` — consistent `show*` naming alongside `showCounterStyle`
|
|
358
369
|
|
package/dist/moTimeline.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";var _=Object.defineProperty;var
|
|
2
|
-
* moTimeline v2.
|
|
1
|
+
"use strict";var _=Object.defineProperty;var y=(o,e,t)=>e in o?_(o,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):o[e]=t;var p=(o,e,t)=>y(o,typeof e!="symbol"?e+"":e,t);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});/*!
|
|
2
|
+
* moTimeline v2.7.1
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
6
|
-
*/const c=new WeakMap,v={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter"},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 w(){const o=window.innerWidth;return o<600?"xs":o<992?"sm":o<1200?"md":"lg"}function
|
|
6
|
+
*/const c=new WeakMap,v={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px"},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 w(){const o=window.innerWidth;return o<600?"xs":o<992?"sm":o<1200?"md":"lg"}function C(o,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>o(...s),e)}}function m(o){return o?{o:o.offsetTop,h:o.offsetHeight,gppu:o.offsetTop+o.offsetHeight}:{o:0,h:0,gppu:0}}function E(o,e){const t=[];let s=o.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const l=class l{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=C(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(c.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});c.set(e,t),l.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),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){l.instances.forEach(e=>{const t=e.element,s=c.get(t);s&&(s.col=s.columnCount[w()],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()}destroy(){window.removeEventListener("resize",this._resizeHandler),c.delete(this.element),l.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return c.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,r=Array.from(e.children),n=r.slice(s);n.length!==0&&(n.forEach((i,a)=>{i.id||(i.id="moT"+crypto.randomUUID()+"_"+(a+s)),i.classList.add("mo-item","js-mo-item")}),this._setDivider(),n.forEach((i,a)=>{t.showBadge&&this._createBadge(i,a+s+1),t.showArrow&&this._createArrow(i)}),t.lastItemIdx=r.length,c.set(e,t),this.refresh())}_setPostPosition(e){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=E(e,".js-mo-inverted")[0]||null,n=E(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,i=m(n),a=m(r),u=m(e);let h=0,f=0;if(s>1){i.gppu>u.o&&(h=1),a.gppu>i.gppu&&(h=0);const g=e.previousElementSibling;g&&Math.abs(u.o-m(g).o)<40&&(f=1)}return{lr:h,badge_offset:f}}_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 n=document.createElement("img");n.className="mo-badge-icon",n.alt="",n.src=e.dataset.moIcon||b,r.appendChild(n)}else r.textContent=t;e.prepend(r)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");if(s.className="mo-card",e.banner){const n=document.createElement("div");n.className="mo-card-image";const i=document.createElement("img");if(i.className="mo-banner",i.src=e.banner,i.alt="",n.appendChild(i),e.avatar){const a=document.createElement("img");a.className="mo-avatar",a.src=e.avatar,a.alt="",n.appendChild(a)}s.appendChild(n)}const r=document.createElement("div");if(r.className="mo-card-body",e.title){const n=document.createElement("h3");n.textContent=e.title,r.appendChild(n)}if(e.meta){const n=document.createElement("p");n.className="mo-meta",n.textContent=e.meta,r.appendChild(n)}if(e.text){const n=document.createElement("p");n.textContent=e.text,r.appendChild(n)}return s.appendChild(r),t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}};p(l,"instances",new Set);let d=l;exports.MoTimeline=d;exports.default=d;
|
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-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-item .mo-card{background:#fff;border-radius:8px;box-shadow:0 2px 14px #0000001a;margin:.5rem 1.25rem .5rem .5rem;
|
|
2
|
+
* moTimeline v2.7.1 — 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-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:.5rem 1.25rem .5rem .5rem;position:relative}.mo-theme>.mo-item.mo-inverted .mo-card{margin:.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}
|
package/dist/moTimeline.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
var _ = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var g = (o, e, t) =>
|
|
2
|
+
var y = (o, e, t) => e in o ? _(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
|
|
3
|
+
var g = (o, e, t) => y(o, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
/*!
|
|
5
|
-
* moTimeline v2.
|
|
5
|
+
* moTimeline v2.7.1
|
|
6
6
|
* Responsive two-column timeline layout library
|
|
7
7
|
* https://github.com/MattOpen/moTimeline
|
|
8
8
|
* MIT License
|
|
@@ -12,14 +12,16 @@ const c = /* @__PURE__ */ new WeakMap(), p = {
|
|
|
12
12
|
showBadge: !1,
|
|
13
13
|
showArrow: !1,
|
|
14
14
|
theme: !1,
|
|
15
|
-
showCounterStyle: "counter"
|
|
15
|
+
showCounterStyle: "counter",
|
|
16
16
|
// 'counter' | 'image' | 'none'
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
cardBorderRadius: "8px",
|
|
18
|
+
avatarSize: "50px"
|
|
19
|
+
}, 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>";
|
|
20
|
+
function v() {
|
|
19
21
|
const o = window.innerWidth;
|
|
20
22
|
return o < 600 ? "xs" : o < 992 ? "sm" : o < 1200 ? "md" : "lg";
|
|
21
23
|
}
|
|
22
|
-
function
|
|
24
|
+
function b(o, e = 100) {
|
|
23
25
|
let t;
|
|
24
26
|
return (...s) => {
|
|
25
27
|
clearTimeout(t), t = setTimeout(() => o(...s), e);
|
|
@@ -32,7 +34,7 @@ function m(o) {
|
|
|
32
34
|
gppu: o.offsetTop + o.offsetHeight
|
|
33
35
|
} : { o: 0, h: 0, gppu: 0 };
|
|
34
36
|
}
|
|
35
|
-
function
|
|
37
|
+
function w(o, e) {
|
|
36
38
|
const t = [];
|
|
37
39
|
let s = o.previousElementSibling;
|
|
38
40
|
for (; s; )
|
|
@@ -42,7 +44,7 @@ function v(o, e) {
|
|
|
42
44
|
const l = class l {
|
|
43
45
|
constructor(e, t = {}) {
|
|
44
46
|
if (typeof e == "string" && (e = document.querySelector(e)), !e) throw new Error("moTimeline: element not found");
|
|
45
|
-
this.element = e, this.settings = Object.assign({}, p, t), this.settings.columnCount = Object.assign({}, p.columnCount, t.columnCount), this._resizeHandler =
|
|
47
|
+
this.element = e, this.settings = Object.assign({}, p, t), this.settings.columnCount = Object.assign({}, p.columnCount, t.columnCount), this._resizeHandler = b(() => this.refresh(), 100), this._initialized = !1, this.init();
|
|
46
48
|
}
|
|
47
49
|
init() {
|
|
48
50
|
const e = this.element;
|
|
@@ -51,13 +53,13 @@ const l = class l {
|
|
|
51
53
|
return;
|
|
52
54
|
}
|
|
53
55
|
const t = Object.assign({}, this.settings, { lastItemIdx: 0 });
|
|
54
|
-
c.set(e, t), l.instances.add(this), e.classList.add("mo-timeline"), t.theme && e.classList.add("mo-theme"),
|
|
56
|
+
c.set(e, t), l.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), this._initialized = !0, window.addEventListener("resize", this._resizeHandler), Array.from(e.children).length > 0 && this._initItems();
|
|
55
57
|
}
|
|
56
58
|
refresh() {
|
|
57
59
|
l.instances.forEach((e) => {
|
|
58
60
|
const t = e.element, s = c.get(t);
|
|
59
|
-
s && (s.col = s.columnCount[
|
|
60
|
-
e._setPostPosition(
|
|
61
|
+
s && (s.col = s.columnCount[v()], e._setDivider(), Array.from(t.children).forEach((r) => {
|
|
62
|
+
e._setPostPosition(r);
|
|
61
63
|
}));
|
|
62
64
|
});
|
|
63
65
|
}
|
|
@@ -77,7 +79,7 @@ const l = class l {
|
|
|
77
79
|
typeof e == "string" && (e = JSON.parse(e)), e.forEach((t) => this.element.appendChild(this._createItemElement(t))), this._initItems();
|
|
78
80
|
}
|
|
79
81
|
destroy() {
|
|
80
|
-
window.removeEventListener("resize", this._resizeHandler), c.delete(this.element), l.instances.delete(this), this.element.classList.remove("mo-timeline", "mo-theme", "mo-twocol"), Array.from(this.element.children).forEach((e) => {
|
|
82
|
+
window.removeEventListener("resize", this._resizeHandler), c.delete(this.element), l.instances.delete(this), this.element.style.removeProperty("--mo-card-border-radius"), this.element.style.removeProperty("--mo-avatar-size"), this.element.classList.remove("mo-timeline", "mo-theme", "mo-twocol"), Array.from(this.element.children).forEach((e) => {
|
|
81
83
|
e.classList.remove("mo-item", "js-mo-item", "mo-inverted", "js-mo-inverted", "mo-offset"), e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach((t) => t.remove());
|
|
82
84
|
});
|
|
83
85
|
}
|
|
@@ -87,17 +89,17 @@ const l = class l {
|
|
|
87
89
|
}
|
|
88
90
|
_setDivider() {
|
|
89
91
|
const e = this._getData();
|
|
90
|
-
e && (e.col = e.columnCount[
|
|
92
|
+
e && (e.col = e.columnCount[v()], this.element.classList.toggle("mo-twocol", e.col > 1));
|
|
91
93
|
}
|
|
92
94
|
_initItems() {
|
|
93
95
|
const e = this.element, t = this._getData();
|
|
94
96
|
if (!t) return;
|
|
95
|
-
const s = t.lastItemIdx,
|
|
96
|
-
n.length !== 0 && (n.forEach((
|
|
97
|
-
|
|
98
|
-
}), this._setDivider(), n.forEach((
|
|
99
|
-
t.showBadge && this._createBadge(
|
|
100
|
-
}), t.lastItemIdx =
|
|
97
|
+
const s = t.lastItemIdx, r = Array.from(e.children), n = r.slice(s);
|
|
98
|
+
n.length !== 0 && (n.forEach((i, a) => {
|
|
99
|
+
i.id || (i.id = "moT" + crypto.randomUUID() + "_" + (a + s)), i.classList.add("mo-item", "js-mo-item");
|
|
100
|
+
}), this._setDivider(), n.forEach((i, a) => {
|
|
101
|
+
t.showBadge && this._createBadge(i, a + s + 1), t.showArrow && this._createArrow(i);
|
|
102
|
+
}), t.lastItemIdx = r.length, c.set(e, t), this.refresh());
|
|
101
103
|
}
|
|
102
104
|
_setPostPosition(e) {
|
|
103
105
|
const t = this._getLeftOrRight(e);
|
|
@@ -107,25 +109,25 @@ const l = class l {
|
|
|
107
109
|
if (!e) return null;
|
|
108
110
|
const t = this._getData();
|
|
109
111
|
if (!t) return null;
|
|
110
|
-
const s = t.col,
|
|
112
|
+
const s = t.col, r = w(e, ".js-mo-inverted")[0] || null, n = w(e, ".js-mo-item:not(.js-mo-inverted)")[0] || null, i = m(n), a = m(r), h = m(e);
|
|
111
113
|
let d = 0, f = 0;
|
|
112
114
|
if (s > 1) {
|
|
113
|
-
|
|
115
|
+
i.gppu > h.o && (d = 1), a.gppu > i.gppu && (d = 0);
|
|
114
116
|
const u = e.previousElementSibling;
|
|
115
117
|
u && Math.abs(h.o - m(u).o) < 40 && (f = 1);
|
|
116
118
|
}
|
|
117
119
|
return { lr: d, badge_offset: f };
|
|
118
120
|
}
|
|
119
121
|
_createBadge(e, t) {
|
|
120
|
-
const s = this._getData(),
|
|
121
|
-
if (
|
|
122
|
-
|
|
122
|
+
const s = this._getData(), r = document.createElement("span");
|
|
123
|
+
if (r.className = "mo-badge js-mo-badge", s.showCounterStyle === "none")
|
|
124
|
+
r.style.opacity = "0";
|
|
123
125
|
else if (s.showCounterStyle === "image") {
|
|
124
126
|
const n = document.createElement("img");
|
|
125
|
-
n.className = "mo-badge-icon", n.alt = "", n.src = e.dataset.moIcon ||
|
|
127
|
+
n.className = "mo-badge-icon", n.alt = "", n.src = e.dataset.moIcon || C, r.appendChild(n);
|
|
126
128
|
} else
|
|
127
|
-
|
|
128
|
-
e.prepend(
|
|
129
|
+
r.textContent = t;
|
|
130
|
+
e.prepend(r);
|
|
129
131
|
}
|
|
130
132
|
_createItemElement(e) {
|
|
131
133
|
const t = document.createElement("li");
|
|
@@ -134,27 +136,27 @@ const l = class l {
|
|
|
134
136
|
if (s.className = "mo-card", e.banner) {
|
|
135
137
|
const n = document.createElement("div");
|
|
136
138
|
n.className = "mo-card-image";
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
139
|
+
const i = document.createElement("img");
|
|
140
|
+
if (i.className = "mo-banner", i.src = e.banner, i.alt = "", n.appendChild(i), e.avatar) {
|
|
139
141
|
const a = document.createElement("img");
|
|
140
142
|
a.className = "mo-avatar", a.src = e.avatar, a.alt = "", n.appendChild(a);
|
|
141
143
|
}
|
|
142
144
|
s.appendChild(n);
|
|
143
145
|
}
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
146
|
+
const r = document.createElement("div");
|
|
147
|
+
if (r.className = "mo-card-body", e.title) {
|
|
146
148
|
const n = document.createElement("h3");
|
|
147
|
-
n.textContent = e.title,
|
|
149
|
+
n.textContent = e.title, r.appendChild(n);
|
|
148
150
|
}
|
|
149
151
|
if (e.meta) {
|
|
150
152
|
const n = document.createElement("p");
|
|
151
|
-
n.className = "mo-meta", n.textContent = e.meta,
|
|
153
|
+
n.className = "mo-meta", n.textContent = e.meta, r.appendChild(n);
|
|
152
154
|
}
|
|
153
155
|
if (e.text) {
|
|
154
156
|
const n = document.createElement("p");
|
|
155
|
-
n.textContent = e.text,
|
|
157
|
+
n.textContent = e.text, r.appendChild(n);
|
|
156
158
|
}
|
|
157
|
-
return s.appendChild(
|
|
159
|
+
return s.appendChild(r), t.appendChild(s), t;
|
|
158
160
|
}
|
|
159
161
|
_createArrow(e) {
|
|
160
162
|
const t = document.createElement("span");
|
package/dist/moTimeline.umd.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
(function(a,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(a=typeof globalThis<"u"?globalThis:a||self,o(a.MoTimeline={}))})(this,function(a){"use strict";var
|
|
2
|
-
* moTimeline v2.
|
|
1
|
+
(function(a,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(a=typeof globalThis<"u"?globalThis:a||self,o(a.MoTimeline={}))})(this,function(a){"use strict";var C=Object.defineProperty;var I=(a,o,d)=>o in a?C(a,o,{enumerable:!0,configurable:!0,writable:!0,value:d}):a[o]=d;var E=(a,o,d)=>I(a,typeof o!="symbol"?o+"":o,d);/*!
|
|
2
|
+
* moTimeline v2.7.1
|
|
3
3
|
* Responsive two-column timeline layout library
|
|
4
4
|
* https://github.com/MattOpen/moTimeline
|
|
5
5
|
* MIT License
|
|
6
|
-
*/const o=new WeakMap,
|
|
6
|
+
*/const o=new WeakMap,d={columnCount:{xs:1,sm:2,md:2,lg:2},showBadge:!1,showArrow:!1,theme:!1,showCounterStyle:"counter",cardBorderRadius:"8px",avatarSize:"50px"},_="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 p(){const c=window.innerWidth;return c<600?"xs":c<992?"sm":c<1200?"md":"lg"}function b(c,e=100){let t;return(...s)=>{clearTimeout(t),t=setTimeout(()=>c(...s),e)}}function h(c){return c?{o:c.offsetTop,h:c.offsetHeight,gppu:c.offsetTop+c.offsetHeight}:{o:0,h:0,gppu:0}}function g(c,e){const t=[];let s=c.previousElementSibling;for(;s;)(!e||s.matches(e))&&t.push(s),s=s.previousElementSibling;return t}const m=class m{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({},d,t),this.settings.columnCount=Object.assign({},d.columnCount,t.columnCount),this._resizeHandler=b(()=>this.refresh(),100),this._initialized=!1,this.init()}init(){const e=this.element;if(o.has(e)){this.refresh();return}const t=Object.assign({},this.settings,{lastItemIdx:0});o.set(e,t),m.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),this._initialized=!0,window.addEventListener("resize",this._resizeHandler),Array.from(e.children).length>0&&this._initItems()}refresh(){m.instances.forEach(e=>{const t=e.element,s=o.get(t);s&&(s.col=s.columnCount[p()],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()}destroy(){window.removeEventListener("resize",this._resizeHandler),o.delete(this.element),m.instances.delete(this),this.element.style.removeProperty("--mo-card-border-radius"),this.element.style.removeProperty("--mo-avatar-size"),this.element.classList.remove("mo-timeline","mo-theme","mo-twocol"),Array.from(this.element.children).forEach(e=>{e.classList.remove("mo-item","js-mo-item","mo-inverted","js-mo-inverted","mo-offset"),e.querySelectorAll(".js-mo-badge, .js-mo-arrow").forEach(t=>t.remove())})}_getData(){return o.get(this.element)}_setDivider(){const e=this._getData();e&&(e.col=e.columnCount[p()],this.element.classList.toggle("mo-twocol",e.col>1))}_initItems(){const e=this.element,t=this._getData();if(!t)return;const s=t.lastItemIdx,i=Array.from(e.children),n=i.slice(s);n.length!==0&&(n.forEach((r,l)=>{r.id||(r.id="moT"+crypto.randomUUID()+"_"+(l+s)),r.classList.add("mo-item","js-mo-item")}),this._setDivider(),n.forEach((r,l)=>{t.showBadge&&this._createBadge(r,l+s+1),t.showArrow&&this._createArrow(r)}),t.lastItemIdx=i.length,o.set(e,t),this.refresh())}_setPostPosition(e){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,i=g(e,".js-mo-inverted")[0]||null,n=g(e,".js-mo-item:not(.js-mo-inverted)")[0]||null,r=h(n),l=h(i),v=h(e);let u=0,w=0;if(s>1){r.gppu>v.o&&(u=1),l.gppu>r.gppu&&(u=0);const y=e.previousElementSibling;y&&Math.abs(v.o-h(y).o)<40&&(w=1)}return{lr:u,badge_offset:w}}_createBadge(e,t){const s=this._getData(),i=document.createElement("span");if(i.className="mo-badge js-mo-badge",s.showCounterStyle==="none")i.style.opacity="0";else if(s.showCounterStyle==="image"){const n=document.createElement("img");n.className="mo-badge-icon",n.alt="",n.src=e.dataset.moIcon||_,i.appendChild(n)}else i.textContent=t;e.prepend(i)}_createItemElement(e){const t=document.createElement("li");e.icon&&(t.dataset.moIcon=e.icon);const s=document.createElement("div");if(s.className="mo-card",e.banner){const n=document.createElement("div");n.className="mo-card-image";const r=document.createElement("img");if(r.className="mo-banner",r.src=e.banner,r.alt="",n.appendChild(r),e.avatar){const l=document.createElement("img");l.className="mo-avatar",l.src=e.avatar,l.alt="",n.appendChild(l)}s.appendChild(n)}const i=document.createElement("div");if(i.className="mo-card-body",e.title){const n=document.createElement("h3");n.textContent=e.title,i.appendChild(n)}if(e.meta){const n=document.createElement("p");n.className="mo-meta",n.textContent=e.meta,i.appendChild(n)}if(e.text){const n=document.createElement("p");n.textContent=e.text,i.appendChild(n)}return s.appendChild(i),t.appendChild(s),t}_createArrow(e){const t=document.createElement("span");t.className="mo-arrow js-mo-arrow",e.prepend(t)}};E(m,"instances",new Set);let f=m;a.MoTimeline=f,a.default=f,Object.defineProperties(a,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "motimeline",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.1",
|
|
4
4
|
"description": "Responsive two-column timeline layout library. Plain JavaScript, no dependencies.",
|
|
5
5
|
"main": "./dist/moTimeline.cjs",
|
|
6
6
|
"module": "./dist/moTimeline.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
20
|
"build": "vite build",
|
|
21
|
-
"dev": "vite
|
|
21
|
+
"dev": "vite"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"vite": "^5.0.0"
|
package/src/moTimeline.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
2
|
+
* moTimeline v2.7.1 — CSS
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* ── CSS custom properties (easy override) ─────────────────── */
|
|
@@ -156,13 +156,16 @@
|
|
|
156
156
|
or by adding .mo-theme manually to the container
|
|
157
157
|
═══════════════════════════════════════════════════════════════ */
|
|
158
158
|
|
|
159
|
+
.mo-theme {
|
|
160
|
+
--mo-arrow-color: #fff;
|
|
161
|
+
}
|
|
162
|
+
|
|
159
163
|
/* Themed card shell */
|
|
160
164
|
.mo-theme > .mo-item .mo-card {
|
|
161
165
|
background: #fff;
|
|
162
|
-
border-radius: 8px;
|
|
166
|
+
border-radius: var(--mo-card-border-radius, 8px);
|
|
163
167
|
box-shadow: 0 2px 14px rgba(0, 0, 0, .10);
|
|
164
168
|
margin: 0.5rem 1.25rem 0.5rem 0.5rem;
|
|
165
|
-
overflow: hidden;
|
|
166
169
|
position: relative;
|
|
167
170
|
}
|
|
168
171
|
|
|
@@ -170,10 +173,11 @@
|
|
|
170
173
|
margin: 0.5rem 0.5rem 0.5rem 1.25rem;
|
|
171
174
|
}
|
|
172
175
|
|
|
173
|
-
/* Banner image */
|
|
176
|
+
/* Banner image — top corners rounded to match card, no overflow:hidden needed on card */
|
|
174
177
|
.mo-theme > .mo-item .mo-banner {
|
|
178
|
+
border-radius: var(--mo-card-border-radius, 8px) var(--mo-card-border-radius, 8px) 0 0;
|
|
175
179
|
display: block;
|
|
176
|
-
height:
|
|
180
|
+
max-height: 240px;
|
|
177
181
|
object-fit: cover;
|
|
178
182
|
width: 100%;
|
|
179
183
|
}
|
|
@@ -188,21 +192,16 @@
|
|
|
188
192
|
.mo-theme > .mo-item .mo-avatar {
|
|
189
193
|
border: 3px solid #fff;
|
|
190
194
|
border-radius: 50%;
|
|
191
|
-
bottom: -
|
|
195
|
+
bottom: calc(var(--mo-avatar-size, 50px) * -0.44);
|
|
192
196
|
box-shadow: 0 2px 8px rgba(0, 0, 0, .18);
|
|
193
|
-
height: 50px;
|
|
197
|
+
height: var(--mo-avatar-size, 50px);
|
|
194
198
|
object-fit: cover;
|
|
195
199
|
position: absolute;
|
|
196
200
|
right: 14px;
|
|
197
|
-
width: 50px;
|
|
201
|
+
width: var(--mo-avatar-size, 50px);
|
|
198
202
|
z-index: 1;
|
|
199
203
|
}
|
|
200
204
|
|
|
201
|
-
/* Mirror: right-column items → avatar on left side (toward center) */
|
|
202
|
-
.mo-theme > .mo-item.mo-inverted .mo-avatar {
|
|
203
|
-
left: 14px;
|
|
204
|
-
right: auto;
|
|
205
|
-
}
|
|
206
205
|
|
|
207
206
|
/* Card body text area */
|
|
208
207
|
.mo-theme > .mo-item .mo-card-body {
|
|
@@ -230,13 +229,13 @@
|
|
|
230
229
|
|
|
231
230
|
/* Theme: arrow color matches card shadow edge */
|
|
232
231
|
.mo-theme.mo-twocol > .mo-item:not(.mo-inverted) .mo-arrow {
|
|
233
|
-
border-left-color:
|
|
234
|
-
right:
|
|
232
|
+
border-left-color: var(--mo-arrow-color);
|
|
233
|
+
right: 12px;
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
.mo-theme.mo-twocol > .mo-item.mo-inverted .mo-arrow {
|
|
238
|
-
border-right-color:
|
|
239
|
-
left:
|
|
237
|
+
border-right-color: var(--mo-arrow-color);
|
|
238
|
+
left: 12px;
|
|
240
239
|
}
|
|
241
240
|
|
|
242
241
|
/* Theme: badge styled to match card aesthetic */
|
package/src/moTimeline.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* moTimeline v2.
|
|
2
|
+
* moTimeline v2.7.1
|
|
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
|
showArrow: false,
|
|
23
23
|
theme: false,
|
|
24
24
|
showCounterStyle: 'counter', // 'counter' | 'image' | 'none'
|
|
25
|
+
cardBorderRadius: '8px',
|
|
26
|
+
avatarSize: '50px',
|
|
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>";
|
|
@@ -94,14 +96,15 @@ export class MoTimeline {
|
|
|
94
96
|
|
|
95
97
|
el.classList.add('mo-timeline');
|
|
96
98
|
if (data.theme) el.classList.add('mo-theme');
|
|
99
|
+
el.style.setProperty('--mo-card-border-radius', data.cardBorderRadius);
|
|
100
|
+
el.style.setProperty('--mo-avatar-size', data.avatarSize);
|
|
97
101
|
|
|
98
|
-
const children = Array.from(el.children);
|
|
99
|
-
if (children.length === 0) return;
|
|
100
|
-
|
|
101
|
-
this._initItems();
|
|
102
102
|
this._initialized = true;
|
|
103
|
-
|
|
104
103
|
window.addEventListener('resize', this._resizeHandler);
|
|
104
|
+
|
|
105
|
+
if (Array.from(el.children).length > 0) {
|
|
106
|
+
this._initItems();
|
|
107
|
+
}
|
|
105
108
|
}
|
|
106
109
|
|
|
107
110
|
refresh() {
|
|
@@ -142,6 +145,8 @@ export class MoTimeline {
|
|
|
142
145
|
window.removeEventListener('resize', this._resizeHandler);
|
|
143
146
|
instanceData.delete(this.element);
|
|
144
147
|
MoTimeline.instances.delete(this);
|
|
148
|
+
this.element.style.removeProperty('--mo-card-border-radius');
|
|
149
|
+
this.element.style.removeProperty('--mo-avatar-size');
|
|
145
150
|
this.element.classList.remove('mo-timeline', 'mo-theme', 'mo-twocol');
|
|
146
151
|
Array.from(this.element.children).forEach((child) => {
|
|
147
152
|
child.classList.remove('mo-item', 'js-mo-item', 'mo-inverted', 'js-mo-inverted', 'mo-offset');
|