mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-15 23:56:29 +03:00
Fix split-compare clip-path angle to match divider's skewX(-10deg)
The divider uses a fixed CSS angle (skewX(-10deg)) but the clip-path mask used a fixed percentage offset (skewOffset=8), which only matches at one specific aspect ratio. Now computes skewOffset dynamically from the container's actual dimensions via ResizeObserver. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
b5af865d84
commit
a3633c66f0
+3933
-1
File diff suppressed because one or more lines are too long
@@ -221,10 +221,7 @@ function updateTerminal(cmd, container, allCommands) {
|
||||
const splitComparison = container.querySelector('.demo-split-comparison');
|
||||
if (splitComparison) {
|
||||
currentSplitInstance = initSplitCompare(splitComparison, {
|
||||
defaultPosition: 50,
|
||||
skewOffset: 8,
|
||||
|
||||
|
||||
defaultPosition: 50
|
||||
});
|
||||
}
|
||||
initCommandDemo(cmd.id, container);
|
||||
@@ -293,7 +290,6 @@ function setupMobileInteractions(commands) {
|
||||
if (initialSplit) {
|
||||
currentSplitInstance = initSplitCompare(initialSplit, {
|
||||
defaultPosition: 50,
|
||||
skewOffset: 6,
|
||||
minPosition: 10,
|
||||
maxPosition: 90
|
||||
});
|
||||
@@ -334,10 +330,7 @@ function setupMobileInteractions(commands) {
|
||||
const splitComparison = demoArea.querySelector('.demo-split-comparison');
|
||||
if (splitComparison) {
|
||||
currentSplitInstance = initSplitCompare(splitComparison, {
|
||||
defaultPosition: 50,
|
||||
skewOffset: 6,
|
||||
|
||||
|
||||
defaultPosition: 50
|
||||
});
|
||||
}
|
||||
initCommandDemo(cmdId, demoArea);
|
||||
|
||||
@@ -5,8 +5,7 @@ export function initLensEffect() {
|
||||
if (!container) return;
|
||||
|
||||
initSplitCompare(container, {
|
||||
defaultPosition: 70,
|
||||
skewOffset: 8
|
||||
defaultPosition: 70
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
export function initSplitCompare(container, options = {}) {
|
||||
const {
|
||||
defaultPosition = 70,
|
||||
skewOffset = 8,
|
||||
minPosition = -skewOffset,
|
||||
maxPosition = 100 + skewOffset,
|
||||
skewAngle = 10, // Degrees — matches CSS skewX(-10deg) on .split-divider
|
||||
lerpSpeed = 0.15,
|
||||
animationThreshold = 40, // Re-trigger animations when crossing this threshold
|
||||
onCrossThreshold = null // Callback when crossing threshold toward "after" side
|
||||
@@ -24,6 +22,26 @@ export function initSplitCompare(container, options = {}) {
|
||||
|
||||
if (!splitContainer || !splitAfter || !splitDivider) return null;
|
||||
|
||||
// Compute skewOffset from container dimensions so clip-path angle matches CSS skewX
|
||||
const tanAngle = Math.tan(skewAngle * Math.PI / 180);
|
||||
let skewOffset = 8; // fallback
|
||||
|
||||
function recalcSkewOffset() {
|
||||
const rect = splitContainer.getBoundingClientRect();
|
||||
if (rect.width > 0 && rect.height > 0) {
|
||||
skewOffset = 50 * rect.height * tanAngle / rect.width;
|
||||
}
|
||||
}
|
||||
recalcSkewOffset();
|
||||
|
||||
const resizeObserver = new ResizeObserver(recalcSkewOffset);
|
||||
resizeObserver.observe(splitContainer);
|
||||
|
||||
let minPosition = -skewOffset;
|
||||
let maxPosition = 100 + skewOffset;
|
||||
if (options.minPosition != null) minPosition = options.minPosition;
|
||||
if (options.maxPosition != null) maxPosition = options.maxPosition;
|
||||
|
||||
let isHovering = false;
|
||||
let currentX = defaultPosition;
|
||||
let targetX = defaultPosition;
|
||||
@@ -31,7 +49,9 @@ export function initSplitCompare(container, options = {}) {
|
||||
let wasAboveThreshold = defaultPosition > animationThreshold;
|
||||
|
||||
function updateSplit(percent) {
|
||||
const clampedX = Math.max(minPosition, Math.min(maxPosition, percent));
|
||||
const minPos = options.minPosition != null ? minPosition : -skewOffset;
|
||||
const maxPos = options.maxPosition != null ? maxPosition : 100 + skewOffset;
|
||||
const clampedX = Math.max(minPos, Math.min(maxPos, percent));
|
||||
|
||||
// Check if we crossed the threshold toward the "after" side (moving left)
|
||||
const isAboveThreshold = clampedX > animationThreshold;
|
||||
@@ -42,7 +62,7 @@ export function initSplitCompare(container, options = {}) {
|
||||
}
|
||||
wasAboveThreshold = isAboveThreshold;
|
||||
|
||||
// Angled clip-path matching divider's skewX(-10deg)
|
||||
// Angled clip-path matching divider's skewX — offset computed from actual dimensions
|
||||
splitAfter.style.clipPath = `polygon(${clampedX + skewOffset}% 0%, 100% 0%, 100% 100%, ${clampedX - skewOffset}% 100%)`;
|
||||
splitDivider.style.left = `${clampedX}%`;
|
||||
}
|
||||
@@ -184,6 +204,7 @@ export function initSplitCompare(container, options = {}) {
|
||||
splitContainer.removeEventListener('touchend', handleTouchEnd);
|
||||
splitContainer.removeEventListener('touchmove', handleTouchMove);
|
||||
if (animationId) cancelAnimationFrame(animationId);
|
||||
resizeObserver.disconnect();
|
||||
},
|
||||
setPosition(percent) {
|
||||
targetX = percent;
|
||||
|
||||
Reference in New Issue
Block a user