Nemůžete vyplnit toto pole

měsíc

Tvůj měsíc v jednom pohledu.

Měsíční přehledy ti dají jasnou strukturu – kde jsou priority, co můžeš posunout a kde máš prostor na oddych.

Naplánuj si měsíc tak, aby fungoval pro tebe, ne proti tobě.

Řazení produktů

Výpis produktů

produktové fotky BOLD 47
ZDARMAZDARMA
Doprava zdarma

Ovládací prvky výpisu

2 položek celkem
Dárek zdarma
Dárek zdarma
Ke každé objednávce
Garance doručení
nepoškozeného zboží
Přes 3000 výdejních míst
po celé ČR
Doručení do druhého dne
na jakékoliv místo
'use client'; import React, { useEffect, useRef } from 'react'; interface BubbleCursorProps { wrapperElement?: HTMLElement; } class Particle { lifeSpan: number; initialLifeSpan: number; velocity: { x: number; y: number }; position: { x: number; y: number }; baseDimension: number; constructor(x: number, y: number) { this.initialLifeSpan = Math.floor(Math.random() * 60 + 60); this.lifeSpan = this.initialLifeSpan; this.velocity = { x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 10), y: -0.4 + Math.random() * -1, }; this.position = { x, y }; this.baseDimension = 4; } update(context: CanvasRenderingContext2D) { this.position.x += this.velocity.x; this.position.y += this.velocity.y; this.velocity.x += ((Math.random() < 0.5 ? -1 : 1) * 2) / 75; this.velocity.y -= Math.random() / 600; this.lifeSpan--; const scale = 0.2 + (this.initialLifeSpan - this.lifeSpan) / this.initialLifeSpan; context.fillStyle = '#e6f1f7'; context.strokeStyle = '#3a92c5'; context.beginPath(); context.arc( this.position.x - (this.baseDimension / 2) * scale, this.position.y - this.baseDimension / 2, this.baseDimension * scale, 0, 2 * Math.PI ); context.stroke(); context.fill(); context.closePath(); } } const BubbleCursor: React.FC = ({ wrapperElement }) => { const canvasRef = useRef(null); const particlesRef = useRef([]); const cursorRef = useRef({ x: 0, y: 0 }); const animationFrameRef = useRef(null); useEffect(() => { const prefersReducedMotion = window.matchMedia( '(prefers-reduced-motion: reduce)' ); let canvas: HTMLCanvasElement | null = null; let context: CanvasRenderingContext2D | null = null; let width = window.innerWidth; let height = window.innerHeight; const init = () => { if (prefersReducedMotion.matches) { console.log( 'This browser has prefers reduced motion turned on, so the cursor did not init' ); return false; } canvas = canvasRef.current; if (!canvas) return; context = canvas.getContext('2d'); if (!context) return; canvas.style.top = '0px'; canvas.style.left = '0px'; canvas.style.pointerEvents = 'none'; if (wrapperElement) { canvas.style.position = 'absolute'; wrapperElement.appendChild(canvas); canvas.width = wrapperElement.clientWidth; canvas.height = wrapperElement.clientHeight; } else { canvas.style.position = 'fixed'; document.body.appendChild(canvas); canvas.width = width; canvas.height = height; } bindEvents(); loop(); }; const bindEvents = () => { const element = wrapperElement || document.body; element.addEventListener('mousemove', onMouseMove); element.addEventListener('touchmove', onTouchMove, { passive: true }); element.addEventListener('touchstart', onTouchMove, { passive: true }); window.addEventListener('resize', onWindowResize); }; const onWindowResize = () => { width = window.innerWidth; height = window.innerHeight; if (!canvasRef.current) return; if (wrapperElement) { canvasRef.current.width = wrapperElement.clientWidth; canvasRef.current.height = wrapperElement.clientHeight; } else { canvasRef.current.width = width; canvasRef.current.height = height; } }; const onTouchMove = (e: TouchEvent) => { if (e.touches.length > 0) { for (let i = 0; i < e.touches.length; i++) { addParticle(e.touches[i].clientX, e.touches[i].clientY); } } }; const onMouseMove = (e: MouseEvent) => { if (wrapperElement) { const boundingRect = wrapperElement.getBoundingClientRect(); cursorRef.current.x = e.clientX - boundingRect.left; cursorRef.current.y = e.clientY - boundingRect.top; } else { cursorRef.current.x = e.clientX; cursorRef.current.y = e.clientY; } addParticle(cursorRef.current.x, cursorRef.current.y); }; const addParticle = (x: number, y: number) => { particlesRef.current.push(new Particle(x, y)); }; const updateParticles = () => { if (!canvas || !context) return; if (particlesRef.current.length === 0) { return; } context.clearRect(0, 0, canvas.width, canvas.height); // Update for (let i = 0; i < particlesRef.current.length; i++) { particlesRef.current[i].update(context); } // Remove dead particles for (let i = particlesRef.current.length - 1; i >= 0; i--) { if (particlesRef.current[i].lifeSpan < 0) { particlesRef.current.splice(i, 1); } } if (particlesRef.current.length === 0) { context.clearRect(0, 0, canvas.width, canvas.height); } }; const loop = () => { updateParticles(); animationFrameRef.current = requestAnimationFrame(loop); }; init(); return () => { if (canvas) { canvas.remove(); } if (animationFrameRef.current) { cancelAnimationFrame(animationFrameRef.current); } const element = wrapperElement || document.body; element.removeEventListener('mousemove', onMouseMove); element.removeEventListener('touchmove', onTouchMove); element.removeEventListener('touchstart', onTouchMove); window.removeEventListener('resize', onWindowResize); }; }, [wrapperElement]); return ; }; export default BubbleCursor;