From f63683dad80437834ee16e89478519a812ced372 Mon Sep 17 00:00:00 2001 From: QuarkPixel Date: Thu, 18 Sep 2025 14:48:01 +0800 Subject: feat(config): make libra more customizable through config.js and libra.css --- src/shadow.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index 9889240..e36affa 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -2,8 +2,7 @@ import Animation from './animation.js' import config from './config' export default class Shadow { - zIndex = '1000' - isOpen = false + isOpen = false; /** * ============ @@ -39,7 +38,8 @@ export default class Shadow { shadow.style.left = `${this.originalPosition.left}px`; shadow.style.width = `${this.originalPosition.width}px`; shadow.style.height = `${this.originalPosition.height}px`; - shadow.style.zIndex = this.zIndex; + // Set transition duration from config + shadow.style.transitionDuration = config.transitionDuration + 'ms'; document.body.appendChild(shadow); this.element = shadow; -- cgit v1.2.3 From b66d25addeefbc60b01adbbf86fa2272700266fe Mon Sep 17 00:00:00 2001 From: QuarkPixel Date: Thu, 18 Sep 2025 14:49:16 +0800 Subject: fix: viewport change causes animation position error --- src/shadow.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index e36affa..be7eb9c 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -51,10 +51,27 @@ export default class Shadow { * ============ */ + updateOriginalPosition() { + const rect = this.original.getBoundingClientRect(); + this.originalPosition = { + top: rect.top + window.scrollY + config.offset.y, + left: rect.left + window.scrollX + config.offset.x, + width: rect.width, + height: rect.height, + }; + } + open() { this.isOpen = true; this.element.classList.add('open'); + // Update original position before animation in case viewport changed + this.updateOriginalPosition(); + this.element.style.top = `${this.originalPosition.top}px`; + this.element.style.left = `${this.originalPosition.left}px`; + this.element.style.width = `${this.originalPosition.width}px`; + this.element.style.height = `${this.originalPosition.height}px`; + this.original.style.visibility = 'hidden'; if (!document.body.contains(this.element)) this.placeItself(); -- cgit v1.2.3 From 755f69bcbd80a0e2fd433a8ccd1427d856cda946 Mon Sep 17 00:00:00 2001 From: QuarkPixel Date: Thu, 18 Sep 2025 14:50:35 +0800 Subject: fix: display nothing when image not fully loaded --- src/shadow.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index be7eb9c..5435532 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -75,11 +75,26 @@ export default class Shadow { this.original.style.visibility = 'hidden'; if (!document.body.contains(this.element)) this.placeItself(); - Animation.transformMatrix( - this.element, - this.originalPosition, - Animation.calculateFinalState(this.element) - ); + // Wait for image to load before animating + if (this.element.naturalWidth === 0 || this.element.naturalHeight === 0) { + this.element.addEventListener( + 'load', + () => { + Animation.transformMatrix( + this.element, + this.originalPosition, + Animation.calculateFinalState(this.element), + ); + }, + { once: true }, + ); + } else { + Animation.transformMatrix( + this.element, + this.originalPosition, + Animation.calculateFinalState(this.element), + ); + } } close() { -- cgit v1.2.3 From 461b268e16f4b9369637da17afba1c814726b58f Mon Sep 17 00:00:00 2001 From: QuarkPixel Date: Thu, 18 Sep 2025 14:51:09 +0800 Subject: fix: missing transition when closing --- src/shadow.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index 5435532..fd3c2f3 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -101,10 +101,12 @@ export default class Shadow { this.isOpen = false; this.element.classList.remove('open'); - this.original.style.visibility = 'visible'; - Animation.resetTransformMatrix(this.element); - setTimeout(() => this.destroyItself(), 300); + // Wait for animation to complete before showing original and destroying shadow + setTimeout(() => { + this.original.style.visibility = 'visible'; + this.destroyItself(); + }, config.transitionDuration); } placeItself() { -- cgit v1.2.3 From 6c3e6e0e3f1a96e92299747d2ec5f552908728cb Mon Sep 17 00:00:00 2001 From: Eltrac Date: Thu, 18 Sep 2025 18:27:37 +0800 Subject: style: consistent unit assignment --- src/shadow.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index fd3c2f3..4e06263 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -34,10 +34,10 @@ export default class Shadow { shadow.classList.add('libra-shadow'); // style and position shadow image - shadow.style.top = `${this.originalPosition.top}px`; - shadow.style.left = `${this.originalPosition.left}px`; - shadow.style.width = `${this.originalPosition.width}px`; - shadow.style.height = `${this.originalPosition.height}px`; + shadow.style.top = this.originalPosition.top + 'px'; + shadow.style.left = this.originalPosition.left + 'px'; + shadow.style.width = this.originalPosition.width + 'px'; + shadow.style.height = this.originalPosition.height + 'px'; // Set transition duration from config shadow.style.transitionDuration = config.transitionDuration + 'ms'; -- cgit v1.2.3 From f383f1cecc713ae5f245cc61a825bd9db9db39bb Mon Sep 17 00:00:00 2001 From: Eltrac Date: Thu, 18 Sep 2025 18:41:51 +0800 Subject: refactor: avoid repeating animation logic --- src/shadow.js | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index 4e06263..b02fad5 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -75,25 +75,20 @@ export default class Shadow { this.original.style.visibility = 'hidden'; if (!document.body.contains(this.element)) this.placeItself(); - // Wait for image to load before animating - if (this.element.naturalWidth === 0 || this.element.naturalHeight === 0) { - this.element.addEventListener( - 'load', - () => { - Animation.transformMatrix( - this.element, - this.originalPosition, - Animation.calculateFinalState(this.element), - ); - }, - { once: true }, - ); - } else { + // play animation + const animate = () => Animation.transformMatrix( this.element, this.originalPosition, Animation.calculateFinalState(this.element), ); + + if (this.element.naturalWidth === 0 || this.element.naturalHeight === 0) { + // Wait for image to load before animating + this.element.addEventListener('load', animate, { once: true }); + } else { + // animate directly if loaded + animate(); } } -- cgit v1.2.3 From 7113655e17a38d9d73cffe469c28b6ddf5b0636f Mon Sep 17 00:00:00 2001 From: Eltrac Date: Thu, 18 Sep 2025 18:51:39 +0800 Subject: refactor: avoid repetition Since we are constantly adjusting shadow's positions and fetching original positions, encapsulate them into functions. --- src/shadow.js | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) (limited to 'src/shadow.js') diff --git a/src/shadow.js b/src/shadow.js index b02fad5..50e3345 100644 --- a/src/shadow.js +++ b/src/shadow.js @@ -12,15 +12,7 @@ export default class Shadow { constructor(image) { this.original = image; - - const rect = this.original.getBoundingClientRect(); - this.originalPosition = { - top: rect.top + window.scrollY + config.offset.y, - left: rect.left + window.scrollX + config.offset.x, - width: rect.width, - height: rect.height - } - + this.fetchOriginalPosition(); this.create(image); return this; @@ -32,26 +24,16 @@ export default class Shadow { shadow.src = image.src; shadow.id = `libra-shadow-${image.id}`; shadow.classList.add('libra-shadow'); - - // style and position shadow image - shadow.style.top = this.originalPosition.top + 'px'; - shadow.style.left = this.originalPosition.left + 'px'; - shadow.style.width = this.originalPosition.width + 'px'; - shadow.style.height = this.originalPosition.height + 'px'; - // Set transition duration from config shadow.style.transitionDuration = config.transitionDuration + 'ms'; - document.body.appendChild(shadow); this.element = shadow; - } - /** - * ============ - * Actions - * ============ - */ + // set positioning and place shadow element + this.positionShadow(); + this.placeItself(); + } - updateOriginalPosition() { + fetchOriginalPosition() { const rect = this.original.getBoundingClientRect(); this.originalPosition = { top: rect.top + window.scrollY + config.offset.y, @@ -61,16 +43,26 @@ export default class Shadow { }; } + positionShadow() { + this.element.style.top = this.originalPosition.top + 'px'; + this.element.style.left = this.originalPosition.left + 'px'; + this.element.style.width = this.originalPosition.width + 'px'; + this.element.style.height = this.originalPosition.height + 'px'; + } + + /** + * ============ + * Actions + * ============ + */ + open() { this.isOpen = true; this.element.classList.add('open'); // Update original position before animation in case viewport changed - this.updateOriginalPosition(); - this.element.style.top = `${this.originalPosition.top}px`; - this.element.style.left = `${this.originalPosition.left}px`; - this.element.style.width = `${this.originalPosition.width}px`; - this.element.style.height = `${this.originalPosition.height}px`; + this.fetchOriginalPosition(); + this.positionShadow(); this.original.style.visibility = 'hidden'; if (!document.body.contains(this.element)) this.placeItself(); -- cgit v1.2.3