VibeCoderzVibeCoderz
Telegram
All Prompts
Custom Range Slider preview
sliderrangeinteractiveanimatedforminputcontrolcustom

Custom Range Slider

Настраиваемый слайдер диапазона с двумя ползунками. Для выбора значений в формах и интерактивных элементах. Поддерживает клавиатуру и анимацию.

Prompt

<div class="flex justify-center p-8 bg-black text-5xl rounded-full">
  <style class="text-5xl rounded-full">@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');</style>
  <div class="relative select-none transition-transform duration-300 ease-out text-5xl rounded-full" id="slider-container" style="width: 400px; height: 70px; transform: rotate(-2.76deg)">
    <div class="absolute inset-0 border border-yellow-500 pointer-events-none text-5xl rounded-full"></div>
    <button type="button" aria-label="Adjust start" class="z-20 absolute top-0 h-full w-7 border border-yellow-500 flex items-center justify-center cursor-ew-resize focus:outline-none focus:ring-2 focus:ring-yellow-400 transition-transform duration-150 ease-in-out opacity-100 hover:scale-110 bg-gray-200 text-5xl rounded-full" id="left-handle" style="left: 0px; touch-action: none">
      <span class="w-1 h-8 bg-yellow-500 text-5xl rounded-full"></span>
    </button>
    <button type="button" aria-label="Adjust end" class="z-20 absolute top-0 h-full w-7 border border-yellow-500 flex items-center justify-center cursor-ew-resize focus:outline-none focus:ring-2 focus:ring-yellow-400 transition-transform duration-150 ease-in-out opacity-100 hover:scale-110 bg-gray-200 text-5xl rounded-full" id="right-handle" style="left: 372px; touch-action: none">
      <span class="w-1 h-8 bg-yellow-500 text-5xl rounded-full"></span>
    </button>
    <div class="flex z-10 items-center justify-center w-full h-full px-4 overflow-hidden pointer-events-none font-bold tracking-tighter text-white text-5xl rounded-full" id="slider-text" style="clip-path: inset(0 0px 0 0px round 1rem); font-family: 'Inter', 'Helvetica Neue', sans-serif">NewSide News</div>
  </div>
  <script class="text-5xl rounded-full">(() => {const MIN_RANGE = 50;const ROTATION_DEG = -2.76;const THETA = ROTATION_DEG * (Math.PI / 180);const COS_THETA = Math.cos(THETA);const SIN_THETA = Math.sin(THETA);const clamp = (v, min, max) => Math.min(Math.max(v, min), max);const container = document.getElementById('slider-container');const leftHandle = document.getElementById('left-handle');const rightHandle = document.getElementById('right-handle');const sliderText = document.getElementById('slider-text');let width = 400;let left = 0;let right = width;let draggingHandle = null;let dragRef = null;function updateSlider() {const handleMidpoint = (left + right) / 2;const sliderCenter = width / 2;const deviationFactor = (handleMidpoint - sliderCenter) / sliderCenter;const maxAdditionalTilt = 3;const newRotation = ROTATION_DEG + (deviationFactor * maxAdditionalTilt);container.style.transform = `rotate(${newRotation}deg)`;leftHandle.style.left = `${left}px`;rightHandle.style.left = `${right - 28}px`;sliderText.style.clipPath = `inset(0 ${width - right}px 0 ${left}px round 1rem)`;}function startDrag(handle, e) {e.preventDefault();e.currentTarget.setPointerCapture(e.pointerId);dragRef = {handle,startX: e.clientX,startY: e.clientY,initialLeft: left,initialRight: right};draggingHandle = handle;e.currentTarget.classList.add('scale-125');e.currentTarget.classList.remove('hover:scale-110');}function moveDrag(e) {if (!dragRef) return;const { handle, startX, startY, initialLeft, initialRight } = dragRef;const dX = e.clientX - startX;const dY = e.clientY - startY;const projected = dX * COS_THETA + dY * SIN_THETA;if (handle === 'left') {left = clamp(initialLeft + projected, 0, right - MIN_RANGE);} else {right = clamp(initialRight + projected, left + MIN_RANGE, width);}updateSlider();}function endDrag() {if (draggingHandle) {const handle = draggingHandle === 'left' ? leftHandle : rightHandle;handle.classList.remove('scale-125');handle.classList.add('hover:scale-110');}dragRef = null;draggingHandle = null;}function nudgeHandle(handle, e) {if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return;e.preventDefault();const delta = e.key === 'ArrowLeft' ? -10 : 10;if (handle === 'left') {left = clamp(left + delta, 0, right - MIN_RANGE);} else {right = clamp(right + delta, left + MIN_RANGE, width);}updateSlider();}leftHandle.addEventListener('pointerdown', (e) => startDrag('left', e));rightHandle.addEventListener('pointerdown', (e) => startDrag('right', e));leftHandle.addEventListener('keydown', (e) => nudgeHandle('left', e));rightHandle.addEventListener('keydown', (e) => nudgeHandle('right', e));window.addEventListener('pointermove', moveDrag);window.addEventListener('pointerup', endDrag);window.addEventListener('pointercancel', endDrag);updateSlider();})();</script>
</div>
All Prompts