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 122 123 124 125 126 127 128 129 | 1x 53x 53x 53x | import React from 'react';
/**
* Props for the LoadingState component.
*
* @property progress Loading progress as a percentage (0-100), or undefined for indeterminate.
* @property message Custom loading message to display.
* @default '로드 중 | Loading...'
* @property stage Current loading stage, determines the stage-specific message.
* Possible values:
* - 'assets': Loading game assets
* - 'audio': Initializing audio system
* - 'initialization': Preparing game
* - 'complete': Loading complete
* @default 'initialization'
*/
export interface LoadingStateProps {
/**
* Loading progress as a percentage (0-100), or undefined for indeterminate
*/
readonly progress?: number;
/**
* Custom loading message to display
* @default '로드 중 | Loading...'
*/
readonly message?: string;
/**
* Current loading stage, determines the stage-specific message
* - assets: Loading game assets
* - audio: Initializing audio system
* - initialization: Preparing game
* - complete: Loading complete
* @default 'initialization'
*/
readonly stage?: 'assets' | 'audio' | 'initialization' | 'complete';
}
/**
* LoadingState component with progress indication.
* Provides user feedback during asset loading and initialization with Korean/English bilingual support.
*
* @example
* ```tsx
* <LoadingState
* progress={50}
* message="로드 중 | Loading..."
* stage="audio"
* />
* ```
*/
export const LoadingState: React.FC<LoadingStateProps> = ({
progress,
message = '로드 중 | Loading...',
stage = 'initialization',
}) => {
const stageText = {
assets: '자산 로드 중 | Loading Assets',
audio: '오디오 초기화 | Initializing Audio',
initialization: '게임 준비 중 | Preparing Game',
complete: '완료 | Complete',
};
const progressValue = progress !== undefined && !Number.isNaN(progress)
? Math.min(100, Math.max(0, progress))
: undefined;
return (
<div
className="loading-state"
role="status"
aria-live="polite"
aria-busy="true"
aria-label={progressValue !== undefined ? `Loading progress: ${progressValue}%` : 'Loading...'}
data-testid="loading-state"
>
<div className="loading-state__logo">
<svg
width="150"
height="150"
viewBox="0 0 150 150"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-label="Black Trigram Logo"
>
{/* Black Trigram Symbol */}
<rect x="50" y="30" width="20" height="90" fill="#00ffff" />
<rect x="80" y="30" width="20" height="90" fill="#ffd700" />
</svg>
</div>
<h1 className="loading-state__title">
흑괘 | BLACK TRIGRAM
</h1>
<div
className="loading-state__progress"
role="progressbar"
aria-valuenow={progressValue}
aria-valuemin={0}
aria-valuemax={100}
aria-label={progressValue !== undefined ? `Loading progress: ${progressValue}%` : 'Loading...'}
data-testid="loading-progress-bar"
>
<div
className={`loading-state__progress-bar${progressValue === undefined ? ' loading-state__progress-bar--indeterminate' : ''}`}
style={progressValue !== undefined ? { width: `${progressValue}%` } : undefined}
/>
</div>
<p className="loading-state__stage">
{stageText[stage]}
</p>
{message && (
<p className="loading-state__message">
{message}
</p>
)}
<div
className="loading-state__spinner"
aria-label="Loading spinner"
/>
</div>
);
};
|