LostBoard 프로젝트

[LostBoard 프로젝트] 현황판 화면 디자인 수정

qweasd5123 2025. 9. 21. 01:10

기존 현황판 화면

🎯  문제점 분석

현황판 화면은 LostBoard의 핵심 페이지이지만, 여러 문제점들이 있었습니다.

 

1. 시각적 가독성 문제

// 기존 코드 - 단순한 이미지 표시
<img src={`${process.env.PUBLIC_URL}/class_logo/${characterInfo.CharacterClassName}.png`}
  width="30%" alt={characterInfo.CharacterClassName} />
  • 캐릭터 정보가 평면적으로 나열되어 중요도 파악 어려움
  • 캐릭터 간 구분이 어려움

2. 정보 과부하

  • 한 화면에 너무 많은 정보가 동시에 표시
  • 캐릭터별 구분이 명확하지 않음
  • 시각적 계층 구조 부족

3. 구식 UI 요소

// 기존 체크박스 - 밋밋한 디자인
<Checkbox
  checked={checkedValues[characterIndex]?.[raidIndex] || false}
  onChange={(e) => handleCheckboxChange(e, characterIndex, raidIndex)}
/>
<span>{raidName}</span>
  • 기본 체크박스로 재미없는 인터페이스
  • 상태 변화에 대한 시각적 피드백 부족

4. 코드 복잡성

  • 현황판 페이지 코드가 300줄 이상으로 유지보수 어려움
  • 모든 로직이 한 파일에 집중
  • 재사용 가능한 컴포넌트 부족

🛠 단계별 개선 과정

1단계: 캐릭터 카드 컴포넌트 분리

개선 목표

  • 캐릭터 정보를 카드 형태로 구조화
  • 직업 로고 가독성 개선
  • 아이템 레벨별 시각적 구분

새로운 CharacterCard 컴포넌트

const CharacterAvatar = styled(Avatar)(({ theme }) => ({
  width: 80,
  height: 80,
  border: '3px solid var(--primary-gold)',
  boxShadow: '0 0 20px var(--primary-gold-glow)',
  background: 'var(--bg-tertiary)',
  
  '& img': {
    filter: 'drop-shadow(0 0 10px rgba(212, 175, 55, 0.3))',
  }
}));

const ItemLevelChip = styled(Chip)(({ itemlevel }) => {
  const getColorByLevel = (level) => {
    if (level >= 1700) return { bg: '#FF6B6B', color: '#FFF' };
    if (level >= 1640) return { bg: '#4ECDC4', color: '#FFF' };
    if (level >= 1580) return { bg: '#45B7D1', color: '#FFF' };
    if (level >= 1490) return { bg: '#96CEB4', color: '#FFF' };
    return { bg: '#FFEAA7', color: '#2D3436' };
  };
  // ...
});

 

개선 효과:

  • ✅ 금색 테두리로 직업 로고 가독성 대폭 개선
  • ✅ 아이템 레벨별 색상 구분으로 한눈에 파악 가능
  • ✅ 카드 형태로 캐릭터별 명확한 구분

2단계: 인터랙티브 레이드 아이템 컴포넌트

개선 목표

  • 클래식한 체크박스를 모던한 인터페이스로 교체
  • 상태별 시각적 피드백 강화
  • 사용자 경험 개선

새로운 RaidItem 컴포넌트

const RaidContainer = styled(Box)(({ ischecked, isgoldselected }) => ({
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'space-between',
  padding: '16px 20px',
  background: ischecked === 'true' 
    ? 'linear-gradient(135deg, var(--bg-tertiary), var(--bg-secondary))' 
    : 'var(--bg-tertiary)',
  border: `2px solid ${
    ischecked === 'true' 
      ? 'var(--primary-gold)' 
      : 'var(--border-color)'
  }`,
  borderRadius: '12px',
  transition: 'all 0.3s ease',
  
  '&:hover': {
    borderColor: 'var(--primary-gold)',
    transform: 'translateX(4px)',
    boxShadow: '0 4px 20px rgba(212, 175, 55, 0.2)',
  },
}));

 

인터렉티브 버튼

// 클리어 상태 토글
<IconButton onClick={onRaidToggle}>
  {isChecked ? <CheckCircleIcon /> : <RadioButtonUncheckedIcon />}
</IconButton>

// 골드 획득 버튼
<GoldButton isselected={isGoldSelected.toString()} disabled={isGoldDisabled}>
  <PaidIcon />
</GoldButton>

// 더보기 보상 버튼  
<GoldButton isselected={isAdditionalSelected.toString()} disabled={isAdditionalDisabled}>
  <AddIcon />
</GoldButton>

 

개선 효과:

  • ✅ 체크박스 → 직관적인 아이콘 버튼으로 변경
  • ✅ 호버 시 슬라이드 애니메이션으로 반응성 증대
  • ✅ 상태별 색상 변화로 명확한 피드백
  • ✅ 툴팁으로 기능 설명 추가

 

3단계: Board.js 리팩토링

개선 목표

  • 코드 간소화
  • 컴포넌트 분리로 가독성 향상
  • 재사용 가능한 구조로 변경

기존 복잡한 구조

// 기존 - 모든 로직이 한 곳에
return (
  <div className='content'>
    {sortedData.map((characterInfo, characterIndex) => (
      <Grid container spacing={3} key={characterIndex}>
        <Grid size="grow">
          {/* 캐릭터 정보 */}
        </Grid>
        <Grid size="grow">
          {/* 복잡한 레이드 목록 로직 */}
          {filteredRaidName[characterIndex].map((raidName, raidIndex) => {
            // 50줄 이상의 복잡한 로직...
          })}
        </Grid>
        <Grid size="grow">
          {/* 재료 정보 */}
        </Grid>
      </Grid>
    ))}
  </div>
);

 

개선된 구조

// 개선 후 - 컴포넌트 분리로 깔끔하게
return (
  <div className='content'>
    <Container maxWidth="lg">
      {sortedData.map((characterInfo, characterIndex) => (
        <Fade in={true} timeout={300 + characterIndex * 100} key={characterIndex}>
          <CharacterCard characterInfo={characterInfo}>
            {filteredRaidName[characterIndex]?.map((raidName, raidIndex) => (
              <RaidItem
                key={raidIndex}
                raidName={raidName}
                isChecked={checkedValues[characterIndex]?.[raidIndex] || false}
                // ... 기타 props
                onRaidToggle={(e) => handleCheckboxChange(e, characterIndex, raidIndex)}
              />
            ))}
            <Material /* ... props */ />
          </CharacterCard>
        </Fade>
      ))}
    </Container>
  </div>
);

 

개선 효과:

  • ✅ 코드 라인 수 50% 감소
  • ✅ 컴포넌트별 책임 분리
  • ✅ 재사용 가능한 구조
  • ✅ 유지보수성 대폭 향상

 

4단계: 시각적 개선 및 애니메이션

페이드 인 애니메이션

<Fade in={true} timeout={300 + characterIndex * 100} key={characterIndex}>
  <CharacterCard>
    {/* 컨텐츠 */}
  </CharacterCard>
</Fade>

 

호버 효과

.character-card:hover {
  border-color: var(--primary-gold);
  box-shadow: var(--shadow-gold);
  transform: translateY(-4px);
}

.raid-item:hover {
  transform: translateX(4px);
  box-shadow: 0 4px 20px rgba(212, 175, 55, 0.2);
}

 

📊 개선 결과 비교

Before (기존)

  • 😞 평면적인 정보 나열
  • 😞 밋밋한 체크박스 UI
  • 😞 300줄의 복잡한 코드
  • 😞 반응성 부족

After (개선 후)

  • ✅ 금색 테두리로 명확한 구분
  • ✅ 카드 기반 구조화된 정보
  • ✅ 인터랙티브한 버튼 UI
  • ✅ 150줄의 깔끔한 코드
  • ✅ 부드러운 애니메이션

 

💡 배운 점

이번 디자인 개선을 통해 깨달은 것들

1. 사용자 경험 우선 사고

  • 기능이 작동하는 것과 사용하기 편한 것은 다름
  • 시각적 피드백의 중요성

2. 컴포넌트 분리의 중요성

  • 하나의 거대한 컴포넌트보다 작은 단위로 분리하는 것이 유지보수에 유리
  • 각 컴포넌트가 단일 책임을 가지도록 설계