Power Off Slide
Power Off Slide é um componente para React e Tailwind CSS, da biblioteca SmoothUI, com licença MIT. Copia e cola no teu projeto.
SmoothUI
MIT
other
O que é
Power Off Slide é um componente para React e Tailwind CSS, da biblioteca SmoothUI, com licença MIT. Copia e cola no teu projeto.
Como usar
Abre o componente no catálogo, carrega em copiar, e cola no teu projeto. O prompt copiado leva o código e as regras para o teu agente o reproduzir sem alterar nada.
Cinco cópias grátis por mês. Sem cartão.
Precisa de
npm i motion lucide-react
Licença
Este componente vem de SmoothUI e é redistribuído sob a licença MIT, que permite uso comercial. O aviso de copyright viaja com o código.
Power Off Slide
"use client";
import { Power } from "lucide-react";
import {
motion,
useAnimation,
useAnimationFrame,
useMotionValue,
useReducedMotion,
} from "motion/react";
import { type RefObject, useRef, useState } from "react";
const SLIDE_THRESHOLD = 160;
const SLIDE_MAX_DISTANCE = 168;
const PERCENTAGE_MULTIPLIER = 100;
export interface PowerOffSlideProps {
className?: string;
disabled?: boolean;
duration?: number;
label?: string;
onPowerOff?: () => void;
}
export default function PowerOffSlide({
onPowerOff,
label = "Slide to power off",
className = "",
duration = 2000,
disabled = false,
}: PowerOffSlideProps) {
const [isPoweringOff, setIsPoweringOff] = useState(false);
const x = useMotionValue(0);
const controls = useAnimation();
const constraintsRef = useRef(null);
const textRef: RefObject<HTMLDivElement | null> = useRef(null);
const shouldReduceMotion = useReducedMotion();
useAnimationFrame((t) => {
if (shouldReduceMotion) {
return;
}
const animDuration = duration;
const progress = (t % animDuration) / animDuration;
if (textRef.current) {
textRef.current.style.setProperty(
"--x",
`${(1 - progress) * PERCENTAGE_MULTIPLIER}%`
);
}
});
const handleDragEnd = async () => {
if (disabled) {
return;
}
const dragDistance = x.get();
if (dragDistance > SLIDE_THRESHOLD) {
await controls.start({ x: SLIDE_MAX_DISTANCE });
setIsPoweringOff(true);
if (onPowerOff) {
onPowerOff();
}
setTimeout(() => {
setIsPoweringOff(false);
controls.start({ x: 0 });
x.set(0);
}, duration);
} else {
controls.start({ x: 0 });
}
};
return (
<div className={`flex h-auto items-center justify-center ${className}`}>
<div className="w-56">
{isPoweringOff ? (
<div className="text-center text-foreground">
<p className="mb-2 font-light text-xl">Shutting down...</p>
</div>
) : (
<div
className="relative h-14 overflow-hidden rounded-full border bg-secondary"
ref={constraintsRef}
>
<div className="absolute inset-0 left-8 z-0 flex items-center justify-center overflow-hidden">
<div className="loading-shimmer relative w-full select-none text-center font-normal text-foreground text-md">
{label}
</div>
</div>
<motion.div
animate={controls}
aria-disabled={disabled}
className={`absolute top-1 left-1 z-10 flex h-12 w-12 items-center justify-center rounded-full bg-background shadow-md ${disabled ? "cursor-not-allowed opacity-50" : "cursor-grab active:cursor-grabbing"}`}
drag={disabled || shouldReduceMotion ? false : "x"}
dragConstraints={{ left: 0, right: SLIDE_MAX_DISTANCE }}
dragElastic={0}
dragMomentum={false}
onDragEnd={handleDragEnd}
style={{ x }}
tabIndex={disabled ? -1 : 0}
transition={
shouldReduceMotion
? { duration: 0 }
: { duration: 0.25, type: "spring" as const }
}
>
<Power className="text-red-600" size={32} />
</motion.div>
</div>
)}
</div>
</div>
);
}