summaryrefslogblamecommitdiff
path: root/frontend/src/components/HeartLogo.tsx
blob: 2d407f72bf5b552f2361f11b1f19f8f3696a9096 (plain) (tree)













































































































































































































































































                                                                                                                                              
import React, { useState, useEffect } from 'react'

interface HeartLogoProps {
  size?: 'small' | 'medium' | 'large' | 'header' | 'header-no-rays'
  className?: string
  onClick?: () => void
}

export function HeartLogo({ size = 'small', className = '', onClick }: HeartLogoProps) {
  const [animationOffset, setAnimationOffset] = useState(0)
  const [isAnimating, setIsAnimating] = useState(false)

  // Click handler to toggle animation
  const handleClick = () => {
    setIsAnimating(!isAnimating)
    if (onClick) {
      onClick()
    }
  }

  // Animation for header beams
  useEffect(() => {
    if (size !== 'header-no-rays' || !isAnimating) return

    let animationId: number
    let startTime = Date.now()

    const animate = () => {
      const elapsed = Date.now() - startTime
      const rotationSpeed = 0.02 // Slow rotation speed
      const offset = (elapsed * rotationSpeed) % 360
      setAnimationOffset(offset)
      animationId = requestAnimationFrame(animate)
    }

    animationId = requestAnimationFrame(animate)

    return () => {
      if (animationId) {
        cancelAnimationFrame(animationId)
      }
    }
  }, [size, isAnimating])
  if (size === 'header') {
    // Header version with rays filling the entire header rectangle
    return (
      <div className={`heart-logo ${size} ${className}`}>
        <div className="heart-logo-rectangle">
          <div className="heart-logo-content">
            <div className="heart-logo-rays">
              <svg viewBox="0 0 100 100" className="heart-logo-rays-svg" preserveAspectRatio="none">
                {/* Header rays matching loading screen exactly */}
                <g transform="translate(50, 50)">
                  {[...Array(16)].map((_, i) => {
                    const angle = (i * 22.5);
                    const rayWidth = 2; // Much thinner rays

                    // Create triangular ray path - thin rays extending to header edges
                    const startAngle = angle - rayWidth;
                    const endAngle = angle + rayWidth;

                    const innerRadius = 0; // Start from center (heart center)
                    const outerRadius = 200; // Extend far beyond to reach all header edges

                    const x1 = Math.cos(startAngle * Math.PI / 180) * innerRadius;
                    const y1 = Math.sin(startAngle * Math.PI / 180) * innerRadius;
                    const x2 = Math.cos(endAngle * Math.PI / 180) * innerRadius;
                    const y2 = Math.sin(endAngle * Math.PI / 180) * innerRadius;
                    const x3 = Math.cos(startAngle * Math.PI / 180) * outerRadius;
                    const y3 = Math.sin(startAngle * Math.PI / 180) * outerRadius;
                    const x4 = Math.cos(endAngle * Math.PI / 180) * outerRadius;
                    const y4 = Math.sin(endAngle * Math.PI / 180) * outerRadius;

                    return (
                      <polygon
                        key={i}
                        points={`${x1},${y1} ${x2},${y2} ${x4},${y4} ${x3},${y3}`}
                        fill={i % 2 === 0 ? "#8B0000" : "#000000"}
                        opacity="0.9"
                      />
                    );
                  })}
                </g>
              </svg>
            </div>
            <div className="heart-logo-outline">
              <svg viewBox="0 0 100 100" className="heart-logo-svg">
                <path d="M50,85 C50,85 10,60 10,35 C10,18 20,8 35,8 C42,8 50,13 50,25 C50,13 58,8 65,8 C80,8 90,18 90,35 C90,60 50,85 50,85 Z"
                      fill="#8B0000"
                      stroke="#8B0000"
                      strokeWidth="2"/>
              </svg>
            </div>
          </div>
        </div>
      </div>
    )
  }

  if (size === 'header-no-rays') {
    // Header version with small red beams - compact sunlight effect
    return (
      <div className={`heart-logo ${size} ${className}`} onClick={handleClick} style={{ cursor: 'pointer' }}>
        <div className="heart-logo-content">
          <div className="heart-logo-rays">
            <svg viewBox="-200 -67 400 134" className="heart-logo-rays-svg" preserveAspectRatio="xMidYMid slice">
              {/* Red beams extending across entire header rectangle - optimized for wide screens */}
              <g>
                {[...Array(32)].map((_, i) => {
                  const angle = (i * 11.25) + animationOffset; // 32 rays, 11.25 degrees apart, animated
                  const rayWidth = 2; // Much narrower rays to show background between them

                  // Create triangular ray path
                  const startAngle = angle - rayWidth;
                  const endAngle = angle + rayWidth;

                  const innerRadius = 0; // Start from heart center

                  // Calculate intersection with rectangle bounds for wide header
                  const getIntersectionWithRect = (angleInDegrees: number) => {
                    const rad = angleInDegrees * Math.PI / 180;
                    const dx = Math.cos(rad);
                    const dy = Math.sin(rad);

                    // Header rectangle bounds (wide format ~3:1 ratio)
                    const rectBoundsX = 200; // Full width
                    const rectBoundsY = 67;  // Height to match header proportions

                    // Calculate intersection with each edge
                    let t = Infinity;

                    // Right edge (x = rectBoundsX)
                    if (dx > 0) {
                      t = Math.min(t, rectBoundsX / dx);
                    }
                    // Left edge (x = -rectBoundsX)
                    if (dx < 0) {
                      t = Math.min(t, -rectBoundsX / dx);
                    }
                    // Top edge (y = -rectBoundsY)
                    if (dy < 0) {
                      t = Math.min(t, -rectBoundsY / dy);
                    }
                    // Bottom edge (y = rectBoundsY)
                    if (dy > 0) {
                      t = Math.min(t, rectBoundsY / dy);
                    }

                    return { x: dx * t, y: dy * t };
                  };

                  const x1 = Math.cos(startAngle * Math.PI / 180) * innerRadius;
                  const y1 = Math.sin(startAngle * Math.PI / 180) * innerRadius;
                  const x2 = Math.cos(endAngle * Math.PI / 180) * innerRadius;
                  const y2 = Math.sin(endAngle * Math.PI / 180) * innerRadius;

                  const edge1 = getIntersectionWithRect(startAngle);
                  const edge2 = getIntersectionWithRect(endAngle);

                  return (
                    <polygon
                      key={i}
                      points={`${x1},${y1} ${x2},${y2} ${edge2.x},${edge2.y} ${edge1.x},${edge1.y}`}
                      fill={i % 2 === 0 ? "#DC2626" : "#B91C1C"}
                      opacity="0.6"
                    />
                  );
                })}
              </g>
            </svg>
          </div>
          <div className="heart-logo-outline">
            <svg viewBox="0 0 100 100" className="heart-logo-svg">
              <path d="M50,85 C50,85 10,60 10,35 C10,18 20,8 35,8 C42,8 50,13 50,25 C50,13 58,8 65,8 C80,8 90,18 90,35 C90,60 50,85 50,85 Z"
                    fill="#8B0000"
                    stroke="#8B0000"
                    strokeWidth="2"/>
            </svg>
          </div>
        </div>
      </div>
    )
  }

  // Original square version for other sizes
  return (
    <div className={`heart-logo ${size} ${className}`}>
      <div className="heart-logo-rectangle">
        <div className="heart-logo-content">
          <div className="heart-logo-rays">
            <svg viewBox="-100 -67 200 134" className="heart-logo-rays-svg">
              {/* Rising Sun flag style rays - triangular rays extending to rectangle edges */}
              <g>
                {[...Array(16)].map((_, i) => {
                  const angle = (i * 22.5);
                  const rayWidth = 11.25; // Half the angle between rays for triangular shape

                  // Create triangular ray path
                  const startAngle = angle - rayWidth;
                  const endAngle = angle + rayWidth;

                  const innerRadius = 0; // Start from center (heart center)

                  // Calculate intersection with rectangle bounds
                  // Rectangle aspect ratio 120:80 = 3:2, so use different bounds for x and y
                  const getIntersectionWithRect = (angleInDegrees: number) => {
                    const rad = angleInDegrees * Math.PI / 180;
                    const dx = Math.cos(rad);
                    const dy = Math.sin(rad);

                    // Rectangle bounds matching the 120x80 aspect ratio (3:2)
                    const rectBoundsX = 100; // Full width
                    const rectBoundsY = 67;  // 2/3 of width to maintain 3:2 ratio

                    // Calculate intersection with each edge
                    let t = Infinity;

                    // Right edge (x = rectBoundsX)
                    if (dx > 0) {
                      t = Math.min(t, rectBoundsX / dx);
                    }
                    // Left edge (x = -rectBoundsX)
                    if (dx < 0) {
                      t = Math.min(t, -rectBoundsX / dx);
                    }
                    // Top edge (y = -rectBoundsY)
                    if (dy < 0) {
                      t = Math.min(t, -rectBoundsY / dy);
                    }
                    // Bottom edge (y = rectBoundsY)
                    if (dy > 0) {
                      t = Math.min(t, rectBoundsY / dy);
                    }

                    return { x: dx * t, y: dy * t };
                  };

                  const x1 = Math.cos(startAngle * Math.PI / 180) * innerRadius;
                  const y1 = Math.sin(startAngle * Math.PI / 180) * innerRadius;
                  const x2 = Math.cos(endAngle * Math.PI / 180) * innerRadius;
                  const y2 = Math.sin(endAngle * Math.PI / 180) * innerRadius;

                  const edge1 = getIntersectionWithRect(startAngle);
                  const edge2 = getIntersectionWithRect(endAngle);

                  return (
                    <polygon
                      key={i}
                      points={`${x1},${y1} ${x2},${y2} ${edge2.x},${edge2.y} ${edge1.x},${edge1.y}`}
                      fill={i % 2 === 0 ? "#8B0000" : "#000000"}
                      opacity="0.9"
                    />
                  );
                })}
              </g>
            </svg>
          </div>
          <div className="heart-logo-outline">
            <svg viewBox="0 0 100 100" className="heart-logo-svg">
              <path d="M50,85 C50,85 10,60 10,35 C10,18 20,8 35,8 C42,8 50,13 50,25 C50,13 58,8 65,8 C80,8 90,18 90,35 C90,60 50,85 50,85 Z"
                    fill="#8B0000"
                    stroke="#8B0000"
                    strokeWidth="2"/>
            </svg>
          </div>
        </div>
      </div>
    </div>
  )
}