diff --git a/app/index.tsx b/app/index.tsx index e355023..a499f31 100644 --- a/app/index.tsx +++ b/app/index.tsx @@ -1,7 +1,8 @@ import { HamburgerIcon, SearchIcon, ThingoLogoSmall } from '@/components/icons'; import { Text } from '@/components/ui/text'; +import { Link } from 'expo-router'; import * as React from 'react'; -import { Dimensions, Keyboard, ScrollView, View } from 'react-native'; +import { Dimensions, Keyboard, ScrollView, TouchableOpacity, View } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Page1 } from './_components/Page1'; import AllScreen from './_components/all-screen'; @@ -11,9 +12,8 @@ import { Page4 } from './_components/Page4'; import NoticeScreen from './_components/notice-screen'; import { Page6 } from './_components/Page6'; import { Page7 } from './_components/Page7'; -import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; -import clsx from 'clsx'; +import { TabBar } from '@/components/ui/tab-bar'; const { width } = Dimensions.get('window'); const TABS = ['ALL', '학식', '게시판', '명지도', '공지사항', '학사일정', '명대신문', '명대뉴스']; @@ -23,7 +23,6 @@ export default function Screen() { const insets = useSafeAreaInsets(); const scrollRef = React.useRef(null); const [currentTab, setCurrentTab] = React.useState(TABS[INITIAL_PAGE]); - const [searchQuery, setSearchQuery] = React.useState(''); React.useEffect(() => { scrollRef.current?.scrollTo({ x: width * INITIAL_PAGE, animated: false }); @@ -47,15 +46,12 @@ export default function Screen() { - - - - + + + + 검색어를 입력하세요 + + - ))} - - + {/* 스와이프 페이지 */} prev.filter((k) => k !== keyword)); + } + + function onSuggestedSearchPress(keyword: string): void { + setQuery(keyword); + } + + function onPopularSearchPress(keyword: string): void { + setQuery(keyword); + } + + function onNoticeMorePress(): void {} + + function onCommunityMorePress(): void {} + + function onNewspaperMorePress(): void {} + + return ( + + + + router.back()}> + + + + {/* 검색바 */} + + + + {!!query && ( + setQuery('')}> + + + )} + + + + {/* 검색어 없는 경우 */} + {!query && ( + + {/* 최근 검색어 */} + + + 최근 검색어 + onClearRecentSearchHistoryPress()}> + 전체 삭제 + + + + {recentSearches.map((keyword) => ( + + onRecentSearchPress(keyword)}> + + {keyword} + + + onDeleteRecentSearchPress(keyword)}> + + + + ))} + + + + {/* 추천 검색어 */} + + 추천 검색어 + + {SUGGESTED_SEARCHES.map((keyword) => ( + onSuggestedSearchPress(keyword)}> + + {keyword} + + + ))} + + + + {/* 인기 검색어 */} + + 인기 검색어 + String(index)} + contentContainerStyle={{ paddingHorizontal: 16, gap: 10 }} + columnWrapperStyle={{ gap: 4 }} + renderItem={({ item, index }) => ( + onPopularSearchPress(item)}> + + {index + 1} + {item} + + + )} + /> + + + )} + + {/* 검색어 있는 경우 */} + {!!query && ( + + setCurrentTab(TABS[i])} + /> + + {/* ai 요약 검색 결과 */} + + + AI 요약 검색 결과 + + {AI_SUMMARY} + + {AI_SOURCES.map((source) => ( + + {source.title} + + + + + + + ))} + + + + + {/* 공지사항 검색 결과*/} + + + 공지사항 + onNoticeMorePress()}> + + + + {NOTICE_RESULTS.map((item) => ( + + + + {item.category} + + {item.title} + + {item.date} + + + + ))} + + + {/* 커뮤니티 검색 결과*/} + + + 커뮤니티 + onCommunityMorePress()}> + + + + {COMMUNITY_RESULTS.map((item) => ( + + + + {item.title} + + {item.preview} + + + + + {item.likes} + + {item.comments} + + {item.date} + + + + + ))} + + + {/* 명대신문 검색 결과*/} + + + 명대신문 + onNewspaperMorePress()}> + + + + {/* */} + + {NEWSPAPER_RESULTS.map((item) => ( + + + + + + + {item.title} + + + {item.preview} + + + {item.author} + + + {item.date} + + + + + + ))} + + + + )} + + + ); +} + +const RECENT_SEARCHES = [ + '수강신청', + '장학금 신청', + '도서관 열람실', + '학식 메뉴', + '졸업 요건', + '소프트웨어 라이선스', +]; + +const SUGGESTED_SEARCHES = [ + '수강신청 일정', + '장학금 종류', + '학식 오늘', + '도서관 좌석', + '졸업논문 제출', + '학생증 발급', + '버스 시간표', + '교내 동아리', +]; + +const POPULAR_SEARCHES = [ + '수강신청', + '장학금', + '도서관 좌석', + '학식 메뉴', + '졸업 요건', + '학생증 발급', +]; + +const AI_SUMMARY = + '명지대학교 2025학년도 1학기 수강신청은 2월 17일(월)부터 21일(금)까지 진행됩니다. 재학생은 학년별로 신청 기간이 나뉘며, 포털 시스템(mjportal.mju.ac.kr)에서 신청할 수 있습니다. 수강 정원 초과 시 대기 신청이 가능하며, 개강 후 2주 이내에 수강 변경 기간이 별도로 운영됩니다. 장학금·학점 등 조건에 따라 신청 가능 학점 수가 달라지므로 학생처 공지사항을 반드시 확인하세요.'; + +const AI_SOURCES: { id: number; title: string; url: string }[] = [ + { + id: 1, + title: '[학사공지] 2025학년도 1학기 수강신청 일정 안내', + url: 'https://www.mju.ac.kr/mjukr/255/subview.do', + }, + { + id: 2, + title: '[학사공지] 수강신청 유의사항 및 정원 초과 대기 방법', + url: 'https://www.mju.ac.kr/mjukr/255/subview.do', + }, + { + id: 3, + title: '[장학처] 성적 기준 장학금 신청 가능 학점 안내', + url: 'https://www.mju.ac.kr/mjukr/259/subview.do', + }, + { + id: 4, + title: '[학사공지] 개강 후 수강 변경 기간 운영 안내', + url: 'https://www.mju.ac.kr/mjukr/255/subview.do', + }, +]; + +const NOTICE_RESULTS: { id: number; category: string; title: string; date: string; url: string }[] = + [ + { + id: 1, + category: '학사공지', + title: + '2025학년도 1학기 수강신청 일정 및 유의사항 안내 — 신청 기간·정원 초과 대기 방법·수강 변경 기간 포함', + date: '2025.01.15', + url: 'https://www.mju.ac.kr/mjukr/255/subview.do', + }, + { + id: 2, + category: '장학공지', + title: + '2025학년도 1학기 국가장학금(한국장학재단) 신청 안내 — 소득분위 산정 기준 및 제출 서류 목록 포함 (1차 신청)', + date: '2025.01.10', + url: 'https://www.mju.ac.kr/mjukr/259/subview.do', + }, + { + id: 3, + category: '학사공지', + title: '개강 후 수강 변경(정정) 기간 운영 안내 — 변경 가능 과목 범위 및 포털 신청 방법 안내', + date: '2025.01.08', + url: 'https://www.mju.ac.kr/mjukr/255/subview.do', + }, + ]; + +const COMMUNITY_RESULTS: { + id: number; + title: string; + preview: string; + likes: number; + comments: number; + date: string; +}[] = [ + { + id: 1, + title: '수강신청 꿀팁 공유합니다', + preview: + '저는 매번 수강신청 때 이 방법으로 성공했어요. 특히 인기 강의는 미리 즐겨찾기 해두는 게 핵심입니다.', + likes: 42, + comments: 18, + date: '2025.01.14', + }, + { + id: 2, + title: '1학기 장학금 신청 같이 하실 분?', + preview: + '국가장학금 서류 준비하다가 헷갈리는 부분 있어서 같이 스터디 하실 분 구합니다. 카톡 오픈채팅으로 연락주세요.', + likes: 27, + comments: 9, + date: '2025.01.12', + }, + { + id: 3, + title: '도서관 열람실 자리 잡는 타이밍', + preview: '오전 8시 이전에 가면 거의 항상 자리 있더라고요. 시험기간에는 7시 30분도 빠듯합니다.', + likes: 61, + comments: 33, + date: '2025.01.09', + }, +]; + +const NEWSPAPER_RESULTS: { + id: number; + title: string; + preview: string; + author: string; + date: string; + url: string; +}[] = [ + { + id: 1, + title: '2025년 명지대, 글로벌 캠퍼스 확장 추진', + preview: + '명지대학교가 올해 해외 자매결연 대학을 기존 120개에서 150개로 확대하는 글로벌 캠퍼스 프로젝트를 본격 추진한다고 밝혔다.', + author: '김명지 기자', + date: '2025.01.13', + url: 'https://www.mju.ac.kr/mjukr/267/subview.do', + }, + { + id: 2, + title: '학생 복지관 리모델링, 3월 완공 예정', + preview: + '노후화된 학생 복지관이 전면 리모델링을 거쳐 오는 3월 초 새롭게 문을 열 예정이다. 카페테리아와 휴게 공간이 대폭 확충된다.', + author: '이한솔 기자', + date: '2025.01.07', + url: 'https://www.mju.ac.kr/mjukr/267/subview.do', + }, + { + id: 3, + title: '명지대 창업동아리, 스타트업 경진대회 대상 수상', + preview: + '명지대학교 창업동아리 \"테크브릿지\"가 지난달 열린 전국 대학생 스타트업 경진대회에서 대상을 수상하며 주목받고 있다.', + author: '박수현 기자', + date: '2025.01.03', + url: 'https://www.mju.ac.kr/mjukr/267/subview.do', + }, +]; diff --git a/components/icons/close.tsx b/components/icons/close.tsx index 4d1a000..3125e90 100644 --- a/components/icons/close.tsx +++ b/components/icons/close.tsx @@ -13,9 +13,11 @@ interface CloseIconProps { export default function CloseIcon({ size = 24, className = 'text-[#CDD0D4]' }: CloseIconProps) { return ( - + diff --git a/components/icons/index.ts b/components/icons/index.ts index ec0ea32..15b817b 100644 --- a/components/icons/index.ts +++ b/components/icons/index.ts @@ -12,3 +12,5 @@ export { default as SearchIcon } from './search'; export { default as DiningIcon } from './dining'; export { default as ThingoLogoLarge } from './thingo-logo-large'; export { default as ThingoLogoSmall } from './thingo-logo-small'; +export { default as XIcon } from './x'; +export { default as LinkIcon } from './link'; diff --git a/components/icons/link.tsx b/components/icons/link.tsx new file mode 100644 index 0000000..8cafd12 --- /dev/null +++ b/components/icons/link.tsx @@ -0,0 +1,26 @@ +import { cssInterop } from 'nativewind'; +import Svg, { Circle, Path } from 'react-native-svg'; + +const StyledSvg = cssInterop(Svg, { + className: { target: 'style', nativeStyleToProp: { color: true } }, +}); + +interface LinkIconProps { + size?: number; + className?: string; +} + +export default function LinkIcon({ size = 24, className = 'text-[#1778FF]' }: LinkIconProps) { + return ( + + + + + ); +} diff --git a/components/icons/x.tsx b/components/icons/x.tsx new file mode 100644 index 0000000..00e2a8d --- /dev/null +++ b/components/icons/x.tsx @@ -0,0 +1,24 @@ +import { cssInterop } from 'nativewind'; +import Svg, { Path } from 'react-native-svg'; + +const StyledSvg = cssInterop(Svg, { + className: { target: 'style', nativeStyleToProp: { color: true } }, +}); + +interface XIconProps { + size?: number; + className?: string; +} + +export default function XIcon({ size = 24, className = 'text-black' }: XIconProps) { + return ( + + + + ); +} diff --git a/components/ui/tab-bar.tsx b/components/ui/tab-bar.tsx new file mode 100644 index 0000000..4132a32 --- /dev/null +++ b/components/ui/tab-bar.tsx @@ -0,0 +1,37 @@ +import { Button } from '@/components/ui/button'; +import { Text } from '@/components/ui/text'; +import clsx from 'clsx'; +import { ScrollView, View } from 'react-native'; + +type Props = { + tabs: string[]; + currentTab: string; + onTabPress: (index: number) => void; +}; + +export function TabBar({ tabs, currentTab, onTabPress }: Props) { + return ( + + + {tabs.map((label, index) => ( + + ))} + + + ); +}