All files / components/screens/training/components/hud TrainingLeftHUD.tsx

100% Statements 4/4
100% Branches 1/1
100% Functions 1/1
100% Lines 4/4

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121                                                                                                          2x                     88x                 88x   88x                                                                                          
/**
 * TrainingLeftHUD - Left side HUD for training screen
 *
 * Contains:
 * - Anatomy Display controls
 * - Guard Indicator
 *
 * Gaming Layout Best Practice:
 * - Width: Resolution-based 14-18% of screen
 * - Height: 100% minus top/bottom HUD heights
 * - When combined with the right HUD, leaves roughly 64–72% center width for the arena depending on resolution
 *
 * Responsible for sizing and positioning all left-side UI elements.
 * Now uses shared HUD utilities with resolution-based sizing.
 *
 * @korean 훈련화면 왼쪽 HUD - 해부학 표시 및 가드 표시기
 */
 
import React from "react";
import { useHUDLayout } from "../../../../../hooks/useHUDLayout";
import { TRIGRAM_STANCES_ORDER } from "../../../../../systems/trigram/types";
import { TrigramStance } from "../../../../../types/common";
import { BaseHUDContainer } from "../../../../shared/ui/BaseHUDContainer";
import { GuardIndicator } from "../../../../shared/three/indicators/GuardIndicator";
import AnatomyControlsOverlayHtml from "../AnatomyControlsOverlayHtml";
import type { AnatomyLayer } from "../AnatomyOverlay3D";
 
export interface TrainingLeftHUDProps {
  /** Screen width for layout calculations */
  readonly width: number;
  /** Screen height for layout calculations */
  readonly height: number;
  /** Whether mobile controls should be shown (NOT for sizing) */
  readonly isMobile?: boolean;
  /** Position scale multiplier for large displays */
  readonly positionScale: number;
  /** Currently visible anatomy layers */
  readonly visibleAnatomyLayers: readonly AnatomyLayer[];
  /** Handler for toggling anatomy layers */
  readonly onAnatomyLayerToggle: (layer: AnatomyLayer) => void;
  /** Current stance index (0-7) */
  readonly currentStanceIndex: number;
  /** Whether player is in guard stance */
  readonly isInGuard: boolean;
}
 
/**
 * TrainingLeftHUD Component
 *
 * Left side of the training screen containing anatomy controls and guard indicator.
 * Uses resolution-based sizing for smooth scaling across all screen sizes.
 * Uses shared HUD utilities for consistent layout and styling.
 */
export const TrainingLeftHUD: React.FC<TrainingLeftHUDProps> = ({
  width,
  height,
  isMobile = false,
  positionScale,
  visibleAnatomyLayers,
  onAnatomyLayerToggle,
  currentStanceIndex,
  isInGuard,
}) => {
  // Use shared HUD layout hook
  const layout = useHUDLayout(
    width,
    height,
    positionScale,
    'left',
    'training'
  );
 
  const currentStance: TrigramStance =
    TRIGRAM_STANCES_ORDER[currentStanceIndex];
 
  return (
    <BaseHUDContainer
      position="left"
      width={layout.hudWidth}
      height={layout.availableHeight}
      topOffset={layout.topOffset}
      padding={layout.padding}
      gap={layout.gap}
      dataTestId="training-left-hud"
    >
      {/* Anatomy Controls */}
      <div
        style={{
          pointerEvents: "all",
          display: "flex",
          flexDirection: "column",
          gap: `${layout.gap}px`,
          maxWidth: "100%",
        }}
        data-testid="training-left-hud-anatomy-section"
      >
        <AnatomyControlsOverlayHtml
          visibleLayers={visibleAnatomyLayers as AnatomyLayer[]}
          onLayerToggle={onAnatomyLayerToggle}
          isMobile={isMobile}
        />
      </div>
 
      {/* Guard Indicator */}
      <div
        style={{ pointerEvents: "none", maxWidth: "100%" }}
        data-testid="training-left-hud-guard-section"
      >
        <GuardIndicator
          currentStance={currentStance}
          isInGuard={isInGuard}
          position="left"
          isMobile={isMobile}
        />
      </div>
    </BaseHUDContainer>
  );
};
 
export default TrainingLeftHUD;