uwksa.ca (Frontend)¶
UWKSA 메인 웹사이트(uwksa.ca)의 프론트엔드 프로젝트 문서입니다.
기술 스택¶
| 분류 | 기술 |
|---|---|
| Framework | React 18 + TypeScript |
| Build Tool | Vite 6 |
| UI 라이브러리 | Radix UI + shadcn/ui |
| 스타일링 | Tailwind CSS |
| 아이콘 | Lucide React |
| 애니메이션 | Motion |
| 테마 | next-themes (다크/라이트 모드) |
| 패키지 매니저 | npm |
개발 환경 설정¶
| 항목 | 값 |
|---|---|
| 개발 서버 포트 | 3000 (npm run dev 시 브라우저 자동 열림) |
| 빌드 출력 | build/ |
| Path Alias | @ → ./src |
Path Alias @¶
이 프로젝트는 @를 ./src 폴더의 alias로 사용합니다. import 시 상대 경로 대신 @/를 사용하세요:
// Good
import { Button } from "@/components/ui/button"; // = src/components/ui/button
import { useLanguage } from "@/contexts/AppContext"; // = src/contexts/AppContext
// Bad - 깊은 상대 경로는 피하세요
import { Button } from "../../../components/ui/button";
프로젝트 구조¶
uwksa.ca/
├── src/
│ ├── App.tsx # 메인 앱 컴포넌트 (hash 라우팅 + lazy loading)
│ ├── main.tsx # 엔트리 포인트
│ ├── index.css # 글로벌 스타일
│ ├── components/ # 재사용 가능한 컴포넌트
│ │ ├── ui/ # shadcn/ui 컴포넌트 (40개 이상)
│ │ ├── Header.tsx # 네비게이션 헤더 (한/영 메뉴)
│ │ ├── Footer.tsx # 푸터
│ │ ├── TeamSection.tsx # 팀원 소개 섹션
│ │ ├── CursorMascot.tsx # 마스코트 커서 효과
│ │ ├── ImageWithFallback.tsx # 이미지 로딩 실패 시 폴백
│ │ └── ThemeToggle.tsx # 다크/라이트 모드 토글
│ ├── pages/ # 페이지 컴포넌트
│ │ ├── HomePage.tsx # 메인 페이지 (이벤트 포함)
│ │ ├── MembershipPage.tsx # 멤버십 + 제휴 식당
│ │ ├── EventsPage.tsx # 이벤트 목록 (이벤트 포함)
│ │ ├── GalleryPage.tsx # 갤러리
│ │ └── ContactPage.tsx # 연락처
│ ├── contexts/ # React Context
│ │ └── AppContext.tsx # 언어/테마 상태 관리
│ ├── data/ # 정적 데이터
│ │ ├── teamData.ts # 팀원 정보 + 프로필 사진 매핑
│ │ └── socialLinks.ts # 소셜 미디어 링크
│ ├── types/ # TypeScript 타입 정의
│ ├── hooks/ # 커스텀 React hooks
│ └── assets/ # 이미지 등 정적 자산 (프로필 사진)
├── public/ # 정적 파일
├── index.html # HTML 엔트리
├── package.json
├── vite.config.ts # Vite 설정 (path alias 포함)
└── .gitignore
상태 관리¶
src/contexts/AppContext.tsx에서 3가지 hook을 제공합니다:
| Hook | 반환값 | 설명 |
|---|---|---|
useApp() |
전체 Context | 언어 + 테마 전체 접근 |
useLanguage() |
{ language, setLanguage, toggleLanguage } |
언어 전환 ('ko' / 'en', 기본값 'ko', 새로고침 시 초기화) |
useTheme() |
{ isDark, setIsDark, toggleTheme } |
다크/라이트 모드 (localStorage에 저장, 유지됨) |
사용 예시:
import { useLanguage } from '@/contexts/AppContext';
export function MyComponent() {
const { language } = useLanguage();
return <p>{language === 'ko' ? '안녕하세요' : 'Hello'}</p>;
}
주요 특징¶
Hash 기반 라우팅¶
#/, #/membership, #/events, #/gallery, #/contact
다국어 지원¶
한국어(KO) / 영어(EN) 전환 가능. 다국어 텍스트는 LocalizedContent<T> 타입을 사용하여 관리합니다:
type LocalizedContent<T> = {
ko: T;
en: T;
};
이벤트 데이터는 예외
이벤트 데이터는 LocalizedContent 타입 대신 페이지 내부에서 content = { ko: { events: [...] }, en: { events: [...] } } 형태로 직접 정의합니다. 자세한 내용은 자주 하는 작업 - 이벤트 업데이트를 참고하세요.
다크/라이트 모드¶
시스템 설정 감지 + 수동 전환. localStorage에 저장되어 새로고침 후에도 유지됩니다.
Lazy Loading¶
React Suspense를 이용한 페이지별 코드 스플리팅. Named export + .then() 패턴을 사용합니다.
브랜드 색상¶
| 색상 | 코드 | 용도 |
|---|---|---|
| UWKSA Gold | #FDB813 |
Footer 배경, 로딩 스피너, 로고 등 |