Skip to content

Instantly share code, notes, and snippets.

@fabiobrasileiroo
Created January 5, 2026 13:57
Show Gist options
  • Select an option

  • Save fabiobrasileiroo/b33643761b9f3f29abf72d6b81361d93 to your computer and use it in GitHub Desktop.

Select an option

Save fabiobrasileiroo/b33643761b9f3f29abf72d6b81361d93 to your computer and use it in GitHub Desktop.
<!-- como usar -->
<!-- {process.env.NODE_ENV === 'development' && <ScreenSizeButton />}
'use client';
-->
import { useEffect, useState, useRef } from 'react';
type ScreenSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl';
interface Position {
x: number;
y: number;
}
const ScreenSizeButton: React.FC = () => {
const [screenSize, setScreenSize] = useState<ScreenSize | any>('sm');
const [widthSize, setWidthSize] = useState<number | null>(null);
const [heightSize, setHeightSize] = useState<number | null>(null);
const [position, setPosition] = useState<Position>({ x: 20, y: 20 });
const [isDragging, setIsDragging] = useState(false);
const [dragStart, setDragStart] = useState<Position>({ x: 0, y: 0 });
const [showTooltip, setShowTooltip] = useState(false);
const buttonRef = useRef<HTMLButtonElement>(null);
const handleResize = (): void => {
const width = window.innerWidth;
const height = window.innerHeight;
setWidthSize(width);
setHeightSize(height);
if (width < 640) {
setScreenSize('sm');
} else if (width >= 640 && width < 768) {
setScreenSize('md');
} else if (width >= 768 && width < 1024) {
setScreenSize('lg');
} else if (width >= 1024 && width < 1280) {
setScreenSize('xl');
} else {
setScreenSize('2xl');
}
};
// Carregar posição do localStorage
useEffect(() => {
const savedPosition = localStorage.getItem('screenSizeButtonPosition');
if (savedPosition) {
try {
const parsed = JSON.parse(savedPosition);
setPosition(parsed);
} catch (error) {
console.warn('Erro ao carregar posição do localStorage:', error);
}
}
}, []);
// Salvar posição no localStorage
const savePosition = (newPosition: Position) => {
localStorage.setItem(
'screenSizeButtonPosition',
JSON.stringify(newPosition)
);
};
// Restringir posição dentro da tela
const clampPosition = (pos: Position): Position => {
if (!buttonRef.current) return pos;
const buttonRect = buttonRef.current.getBoundingClientRect();
const maxX = window.innerWidth - buttonRect.width - 20; // margem de 20px
const maxY = window.innerHeight - buttonRect.height - 20;
return {
x: Math.max(20, Math.min(pos.x, maxX)), // mínimo 20px da borda
y: Math.max(20, Math.min(pos.y, maxY))
};
};
const handleMouseDown = (e: React.MouseEvent) => {
setIsDragging(true);
setDragStart({
x: e.clientX - position.x,
y: e.clientY - position.y
});
};
const handleMouseMove = (e: MouseEvent) => {
if (!isDragging) return;
const newPosition = {
x: e.clientX - dragStart.x,
y: e.clientY - dragStart.y
};
setPosition(clampPosition(newPosition));
};
const handleMouseUp = () => {
if (isDragging) {
setIsDragging(false);
savePosition(position);
}
};
const handleMouseEnter = () => {
setShowTooltip(true);
};
const handleMouseLeave = () => {
setShowTooltip(false);
};
useEffect(() => {
handleResize(); // Executa no carregamento
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
useEffect(() => {
if (isDragging) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
} else {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
}
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging]);
return (
<>
{showTooltip && (
<div
className='pointer-events-none fixed z-1000 rounded-md bg-black/80 px-3 py-1 text-xs whitespace-nowrap text-white'
style={{
left: `${position.x + (buttonRef.current?.offsetWidth || 0) / 2}px`,
top: `${position.y - 28}px`,
transform: 'translateX(-50%)',
boxShadow:
'0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)'
}}
>
Clique e arraste para mover
<div className='absolute top-full left-1/2 h-0 w-0 -translate-x-1/2 transform border-t-4 border-r-4 border-l-4 border-transparent border-t-black/80'></div>
</div>
)}
<button
ref={buttonRef}
onMouseDown={handleMouseDown}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
className={`fixed z-999 transform rounded-full bg-zinc-800/80 px-4 py-2 text-xs text-white shadow-lg drop-shadow-lg transition-transform hover:scale-105 hover:bg-zinc-700 sm:text-base md:text-sm ${
isDragging ? 'scale-105 cursor-grabbing' : 'cursor-grab'
}`}
style={{
right: 'auto',
bottom: 'auto',
left: `${position.x}px`,
top: `${position.y}px`,
userSelect: 'none'
}}
>
{`${widthSize}x-${heightSize}y `}{' '}
<span className='font-bold'>{`${screenSize}`}</span>
</button>
</>
);
};
export default ScreenSizeButton;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment