DomesticSummary.tsx 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import './domestic-summary.scss';
  2. import { moveDir, formatFlucRate, formatIndexClose } from '@/types/worldIndex';
  3. import { type DomesticIndexRow, formatIndexChange, formatNet, formatCount, netDir } from '@/types/domesticSummary';
  4. // 국내 증시 요약 — 코스피/코스닥/KOSPI200 카드. 지수·등락 + 투자자별 순매수(Phase 2 "–") + 등락종목수(코스피/코스닥) / 베이시스(KOSPI200).
  5. type Props = {
  6. rows: DomesticIndexRow[];
  7. };
  8. const ARROW = { up: '▲', down: '▼', flat: '–' } as const;
  9. export default function DomesticSummary({ rows }: Props)
  10. {
  11. if (rows.length === 0) {
  12. return null;
  13. }
  14. return (
  15. <section className='dsum' aria-label='국내 증시 요약'>
  16. <div className='dsum__grid'>
  17. {rows.map((row) => {
  18. const dir = moveDir(row.flucRateBp);
  19. const isKospi200 = row.key === 'kospi200';
  20. return (
  21. <div key={row.key} className='dsum__card'>
  22. <div className='dsum__name'>{row.name}</div>
  23. <div className='dsum__price'>
  24. <span className={`dsum__value dsum__value--${dir}`}>{formatIndexClose(row.close)}</span>
  25. <span className={`dsum__chg dsum__chg--${dir}`}>
  26. <i className='dsum__arrow' aria-hidden='true'>{ARROW[dir]}</i>
  27. {formatIndexChange(row.changeVal)}
  28. <em className='dsum__rate'>{formatFlucRate(row.flucRateBp)}</em>
  29. </span>
  30. </div>
  31. <div className='dsum__investors'>
  32. <div className='dsum__inv'>
  33. <span className='dsum__inv-k'>개인</span>
  34. <span className={`dsum__inv-v dsum__inv-v--${netDir(row.individualNet)}`}>{formatNet(row.individualNet)}</span>
  35. </div>
  36. <div className='dsum__inv'>
  37. <span className='dsum__inv-k'>외국인</span>
  38. <span className={`dsum__inv-v dsum__inv-v--${netDir(row.foreignNet)}`}>{formatNet(row.foreignNet)}</span>
  39. </div>
  40. <div className='dsum__inv'>
  41. <span className='dsum__inv-k'>기관</span>
  42. <span className={`dsum__inv-v dsum__inv-v--${netDir(row.institutionNet)}`}>{formatNet(row.institutionNet)}</span>
  43. </div>
  44. <div className='dsum__inv'>
  45. <span className='dsum__inv-k'>프로그램</span>
  46. <span className={`dsum__inv-v dsum__inv-v--${netDir(row.programNet)}`}>{formatNet(row.programNet)}</span>
  47. </div>
  48. </div>
  49. {isKospi200 ? (
  50. <div className='dsum__foot'>
  51. <span className='dsum__basis-k'>베이시스</span>
  52. <span className='dsum__basis-v'>{row.basis !== null && row.basis !== undefined ? row.basis.toFixed(2) : '–'}</span>
  53. </div>
  54. ) : (
  55. <div className='dsum__breadth'>
  56. <span className='dsum__b'>상한 <em className='dsum__b--up'>{formatCount(row.limitUp)}</em></span>
  57. <span className='dsum__b'>상승 <em className='dsum__b--up'>{formatCount(row.advances)}</em></span>
  58. <span className='dsum__b'>보합 <em>{formatCount(row.unchanged)}</em></span>
  59. <span className='dsum__b'>하락 <em className='dsum__b--down'>{formatCount(row.declines)}</em></span>
  60. <span className='dsum__b'>하한 <em className='dsum__b--down'>{formatCount(row.limitDown)}</em></span>
  61. </div>
  62. )}
  63. </div>
  64. );
  65. })}
  66. </div>
  67. </section>
  68. );
  69. }