WEBLEB
Home
Editor
Accedi
Pro
Italiano
English
Français
Español
Português
Deutsch
Italiano
हिंदी
Manopole del volume
19
kevekıbhack
Apri nell'Editor
Pubblica il Tuo Codice
Consigliato
19 May 2025
menu della barra di navigazione
31 July 2025
Modello HTML della pagina di accesso Liquid Drop
28 June 2025
Modello HTML per il sito web di noleggio biciclette a Miami
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; };