Todos os componentes

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.

Abrir no catálogo

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

index.tsx
"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>
  );
}

Componentes parecidos