mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 11:03:50 +00:00
hide custom cursor om mobile devices
This commit is contained in:
@@ -6,7 +6,7 @@ interface CursorState {
|
|||||||
isPointer: boolean;
|
isPointer: boolean;
|
||||||
isClicking: boolean;
|
isClicking: boolean;
|
||||||
isOverBackground: boolean;
|
isOverBackground: boolean;
|
||||||
isOverIframe: boolean;
|
isMobile: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Cursor: React.FC = () => {
|
const Cursor: React.FC = () => {
|
||||||
@@ -16,7 +16,7 @@ const Cursor: React.FC = () => {
|
|||||||
isPointer: false,
|
isPointer: false,
|
||||||
isClicking: false,
|
isClicking: false,
|
||||||
isOverBackground: false,
|
isOverBackground: false,
|
||||||
isOverIframe: false
|
isMobile: false
|
||||||
});
|
});
|
||||||
|
|
||||||
const cursorRef = useRef<HTMLDivElement>(null);
|
const cursorRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -25,16 +25,62 @@ const Cursor: React.FC = () => {
|
|||||||
const targetY = useRef(0);
|
const targetY = useRef(0);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Check if device is mobile or tablet
|
||||||
|
const checkMobile = () => {
|
||||||
|
const isMobileOrTablet = window.matchMedia('(max-width: 1024px)').matches ||
|
||||||
|
('ontouchstart' in window) ||
|
||||||
|
(navigator.maxTouchPoints > 0);
|
||||||
|
setState(prev => ({ ...prev, isMobile: isMobileOrTablet }));
|
||||||
|
};
|
||||||
|
|
||||||
|
checkMobile();
|
||||||
|
|
||||||
|
// Add resize listener to detect device changes
|
||||||
|
window.addEventListener('resize', checkMobile);
|
||||||
|
|
||||||
|
// Function to inject styles into shadow DOM
|
||||||
|
const injectShadowStyles = () => {
|
||||||
|
const giscusElements = document.querySelectorAll('.giscus-frame');
|
||||||
|
giscusElements.forEach(element => {
|
||||||
|
if (element.shadowRoot) {
|
||||||
|
// Check if we already injected styles
|
||||||
|
if (!element.shadowRoot.querySelector('#custom-cursor-style')) {
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.id = 'custom-cursor-style';
|
||||||
|
style.textContent = `
|
||||||
|
* {
|
||||||
|
cursor: none !important;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
element.shadowRoot.appendChild(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Watch for Giscus loading
|
||||||
|
const observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
|
if (mutation.addedNodes.length) {
|
||||||
|
injectShadowStyles();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
observer.observe(document.body, {
|
||||||
|
childList: true,
|
||||||
|
subtree: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initial injection
|
||||||
|
injectShadowStyles();
|
||||||
|
|
||||||
const updateCursorPosition = (e: MouseEvent) => {
|
const updateCursorPosition = (e: MouseEvent) => {
|
||||||
targetX.current = e.clientX;
|
targetX.current = e.clientX;
|
||||||
targetY.current = e.clientY;
|
targetY.current = e.clientY;
|
||||||
|
|
||||||
const target = e.target as HTMLElement;
|
const target = e.target as HTMLElement;
|
||||||
|
|
||||||
// Check if we're over an iframe
|
|
||||||
const isOverIframe = target.tagName === 'IFRAME' ||
|
|
||||||
target.closest('iframe') !== null;
|
|
||||||
|
|
||||||
// Check if the element is interactive
|
// Check if the element is interactive
|
||||||
const isInteractive = target.tagName === 'A' || target.tagName === 'BUTTON' ||
|
const isInteractive = target.tagName === 'A' || target.tagName === 'BUTTON' ||
|
||||||
target.closest('a') !== null || target.closest('button') !== null ||
|
target.closest('a') !== null || target.closest('button') !== null ||
|
||||||
@@ -46,8 +92,7 @@ const Cursor: React.FC = () => {
|
|||||||
y: e.clientY,
|
y: e.clientY,
|
||||||
isPointer: isInteractive,
|
isPointer: isInteractive,
|
||||||
isOverBackground: target.tagName === 'CANVAS' ||
|
isOverBackground: target.tagName === 'CANVAS' ||
|
||||||
target.closest('canvas') !== null,
|
target.closest('canvas') !== null
|
||||||
isOverIframe: isOverIframe
|
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,15 +108,6 @@ const Cursor: React.FC = () => {
|
|||||||
setState(prev => ({ ...prev, x: -100, y: -100, isClicking: false }));
|
setState(prev => ({ ...prev, x: -100, y: -100, isClicking: false }));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle iframe mouse enter/leave
|
|
||||||
const handleFrameEnter = () => {
|
|
||||||
setState(prev => ({ ...prev, isOverIframe: true }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFrameLeave = () => {
|
|
||||||
setState(prev => ({ ...prev, isOverIframe: false }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Smooth cursor movement animation
|
// Smooth cursor movement animation
|
||||||
const animate = () => {
|
const animate = () => {
|
||||||
if (cursorRef.current) {
|
if (cursorRef.current) {
|
||||||
@@ -94,13 +130,6 @@ const Cursor: React.FC = () => {
|
|||||||
document.addEventListener('mouseup', handleMouseUp);
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
document.addEventListener('mouseleave', handleMouseLeave);
|
document.addEventListener('mouseleave', handleMouseLeave);
|
||||||
|
|
||||||
// Add iframe detection listeners
|
|
||||||
const iframes = document.getElementsByTagName('iframe');
|
|
||||||
Array.from(iframes).forEach(iframe => {
|
|
||||||
iframe.addEventListener('mouseenter', handleFrameEnter);
|
|
||||||
iframe.addEventListener('mouseleave', handleFrameLeave);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start animation
|
// Start animation
|
||||||
requestRef.current = requestAnimationFrame(animate);
|
requestRef.current = requestAnimationFrame(animate);
|
||||||
|
|
||||||
@@ -109,16 +138,11 @@ const Cursor: React.FC = () => {
|
|||||||
document.removeEventListener('mousedown', handleMouseDown);
|
document.removeEventListener('mousedown', handleMouseDown);
|
||||||
document.removeEventListener('mouseup', handleMouseUp);
|
document.removeEventListener('mouseup', handleMouseUp);
|
||||||
document.removeEventListener('mouseleave', handleMouseLeave);
|
document.removeEventListener('mouseleave', handleMouseLeave);
|
||||||
|
window.removeEventListener('resize', checkMobile);
|
||||||
// Remove iframe listeners
|
|
||||||
Array.from(iframes).forEach(iframe => {
|
|
||||||
iframe.removeEventListener('mouseenter', handleFrameEnter);
|
|
||||||
iframe.removeEventListener('mouseleave', handleFrameLeave);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (requestRef.current) {
|
if (requestRef.current) {
|
||||||
cancelAnimationFrame(requestRef.current);
|
cancelAnimationFrame(requestRef.current);
|
||||||
}
|
}
|
||||||
|
observer.disconnect();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -195,8 +219,8 @@ const Cursor: React.FC = () => {
|
|||||||
const cursorColor = getCursorColor();
|
const cursorColor = getCursorColor();
|
||||||
const scale = state.isClicking ? 0.8 : (state.isPointer ? 1.2 : 1);
|
const scale = state.isClicking ? 0.8 : (state.isPointer ? 1.2 : 1);
|
||||||
|
|
||||||
// Hide custom cursor when over iframe
|
// Hide cursor completely on mobile
|
||||||
if (state.isOverIframe) {
|
if (state.isMobile) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,18 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
/* Hide default cursor globally */
|
/* Hide default cursor globally on desktop */
|
||||||
* {
|
@media (min-width: 1025px) {
|
||||||
|
* {
|
||||||
cursor: none !important;
|
cursor: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Show default cursor on mobile and tablet */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
* {
|
||||||
|
cursor: auto !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Chrome, Edge, and Safari */
|
/* Chrome, Edge, and Safari */
|
||||||
|
|||||||
Reference in New Issue
Block a user