WEBLEB
Inicio
Editora de código
Iniciar sesión
Pro
Español
English
Français
Español
Português
Deutsch
Italiano
हिंदी
diales de volumen
16
kevekıbhack
Abrir en el editor
Publica tu código
Recomendado
17 May 2024
Página de destino
7 November 2024
Texto con degradado de neón
3 April 2024
Plantilla de sitio web HTML y CSS
HTML
Copy
CSS
Copy
/* :root kısmına yeni renkler ekleyin */ :root { /* ...diğer değişkenler... */ --purple: hsl(270, 90%, 60%); --pink: hsl(330, 90%, 60%); --yellow: hsl(60, 90%, 60%); --cyan: hsl(180, 90%, 60%); } /* Yeni renk sınıfları ekleyin */ .volume--rainbow .volume__dot--filled { --dot-color: var(--red); animation: rainbow 5s linear infinite; } .volume--gradient .volume__dot--filled { --dot-color: var(--blue); animation: gradientGlow 3s ease-in-out infinite alternate; } .volume--pastel .volume__dot--filled { --dot-color: var(--green); filter: brightness(1.2); } /* Animasyonlar */ @keyframes rainbow { 0% { background-color: var(--red); } 14% { background-color: var(--orange); } 28% { background-color: var(--yellow); } 42% { background-color: var(--green); } 57% { background-color: var(--blue); } 71% { background-color: var(--indigo); } 85% { background-color: var(--purple); } 100% { background-color: var(--red); } } @keyframes gradientGlow { 0% { box-shadow: 0 0 5px var(--blue); } 100% { box-shadow: 0 0 15px var(--cyan); } }
JS
Copy
import React, { StrictMode, useEffect, useRef, useState } from "https://esm.sh/react"; import { createRoot } from "https://esm.sh/react-dom/client"; import gsap from "https://esm.sh/gsap"; import { useGSAP } from "https://esm.sh/@gsap/react"; import { Draggable } from "https://esm.sh/gsap/Draggable"; gsap.registerPlugin(useGSAP, Draggable); createRoot(document.getElementById("root")!).render( <StrictMode> <main> <VolumeDial ticks={24} color="rainbow" volume={0.7} label="Party Mode" /> <VolumeDial ticks={16} color="gradient" volume={0.4} label="Neon Glow" /> <VolumeDial ticks={12} color="pastel" volume={0.2} label="Soft Tones" /> </main> </StrictMode> ); function VolumeDial({ color, ticks, volume = 0, label = "Volume", children }: VolumeDialProps) { const [isKeyDown, setIsKeydown] = useState(false); const dialRef = useRef<HTMLButtonElement>(null); const rootClass = `volume${color ? ` volume--${color}` : ''}`; // volume state const [vol, setVol] = useState(volume); const maxTick = Math.max(1, ticks) || 1; const tick = Math.max(0, vol * maxTick); const percent = `${Math.round(vol * 100)}%`; // dial angle const minAngle = -135; const maxAngle = 135; const angleSpan = maxAngle - minAngle; const startAngle = minAngle + vol * angleSpan; const [angle, setAngle] = useState(startAngle); // dots const dotSectorAngle = angleSpan / maxTick; const dotSectorAngleOffset = -angleSpan / 2 + dotSectorAngle / 2; const dotTickOffset = 0.5; const dotFillArray: boolean[] = []; for (let t = 0; t < ticks; ++t) { dotFillArray.push(t < tick - dotTickOffset); } // Color schemes const colorSchemes = { rainbow: [ '#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#0000FF', '#4B0082', '#9400D3' ], gradient: [ '#FF00FF', '#FF007F', '#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF' ], pastel: [ '#FFD1DC', '#FFECB8', '#B5EAD7', '#C7CEEA', '#E2F0CB', '#FFDAC1', '#B5EAD7', '#F8B195' ], default: ['var(--dot-color)'] }; const getDotColor = (index: number) => { const scheme = colorSchemes[color as keyof typeof colorSchemes] || colorSchemes.default; return scheme[index % scheme.length]; }; // set the volume useEffect(() => { setVol((angle - minAngle) / angleSpan); }, [angle]); // initiate the draggable useEffect(() => { Draggable.create(dialRef.current, { type: "rotation", bounds: { minRotation: minAngle, maxRotation: maxAngle }, onDrag: function() { setAngle(this.rotation); } }); }, []); // run a transition when adjusting using arrow keys useGSAP(() => { if (isKeyDown) { gsap.to(dialRef.current, { rotation: angle, duration: 0.15 }); } }, [angle]); // starting angle useGSAP(() => { gsap.to(dialRef.current, { rotation: startAngle, duration: 0 }); }, []); function keyboardAction(e: React.KeyboardEvent<HTMLButtonElement>) { const up = e.code === "ArrowUp" || e.code === "ArrowRight"; const down = e.code === "ArrowDown" || e.code === "ArrowLeft"; if (up || down) { e.preventDefault(); setIsKeydown(true); } if (up) { setAngle(minAngle + Math.min(tick + 1, maxTick) / maxTick * angleSpan); } else if (down) { setAngle(minAngle + Math.max(0, tick - 1) / maxTick * angleSpan); } } return ( <div className={rootClass}> <div className="volume__control"> {dotFillArray.map((filled, i) => { const angle = dotSectorAngle * i + dotSectorAngleOffset; return ( <VolumeDialDot key={i} angle={angle} filled={filled} color={getDotColor(i)} /> ) })} <div className="volume__dial-wrap"> <button className="volume__dial" type="button" ref={dialRef} onKeyDown={keyboardAction} onKeyUp={() => setIsKeydown(false)} aria-description={percent} > <span className="volume__dial-label">{label}</span> </button> </div> </div> <div className="volume__content"> {children || <div className="volume__display">{percent}</div>} </div> </div> ); } function VolumeDialDot({ angle = 0, filled = false, color = '' }: VolumeDialDotProps) { const filledClass = filled ? " volume__dot--filled" : ""; const dotClass = `volume__dot${filledClass}`; const dotStyle = { transform: `rotate(${angle}deg)`, ...(color && filled ? { '--dot-color': color } : {}) }; return ( <div className={dotClass} style={dotStyle}></div> ); } interface VolumeDialProps { ticks: number; volume?: number; color?: string; label?: string; children?: React.ReactNode; }; interface VolumeDialDotProps { angle?: number; filled?: boolean; color?: string; };