diff --git a/app/_components/Page2.tsx b/app/_components/Page2.tsx
index 102bcb0..ddbe4b6 100644
--- a/app/_components/Page2.tsx
+++ b/app/_components/Page2.tsx
@@ -44,7 +44,7 @@ export function Page2() {
-
+
diff --git a/app/_components/notice-page.tsx b/app/_components/notice-page.tsx
index 5d03b31..40bfa88 100644
--- a/app/_components/notice-page.tsx
+++ b/app/_components/notice-page.tsx
@@ -6,7 +6,7 @@ import { Linking, Pressable, ScrollView, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { Footer } from './footer';
-export function NoticePage() {
+export function NoticeScreen() {
const categories = ['전체', '일반', '학사', '장학', '진로', '학생활동', '학칙개정'];
const [selectedCategory, setSelectedCategory] = React.useState('전체');
const [currentPage, setCurrentPage] = React.useState(1);
diff --git a/app/boards/[boardId]/index.tsx b/app/boards/[boardId]/index.tsx
deleted file mode 100644
index 2b885f5..0000000
--- a/app/boards/[boardId]/index.tsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Text, View } from 'react-native';
-
-export default function BoardDetailScreen() {
- return (
-
- 게시판 상세보기 페이지 입니다
-
- );
-}
diff --git a/app/index.tsx b/app/index.tsx
index bbb9a0e..ea5a08d 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -8,7 +8,7 @@ import { Page2 } from './_components/Page2';
import { Page3 } from './_components/Page3';
import MealSection from './_components/meal';
import { Page4 } from './_components/Page4';
-import { NoticePage } from './_components/notice-page';
+import { NoticeScreen } from './_components/notice-page';
import { Page6 } from './_components/Page6';
import { Page7 } from './_components/Page7';
import { Input } from '@/components/ui/input';
@@ -100,7 +100,7 @@ export default function Screen() {
-
+
diff --git a/app/posts/[postId]/index.tsx b/app/posts/[postId]/index.tsx
new file mode 100644
index 0000000..70b0134
--- /dev/null
+++ b/app/posts/[postId]/index.tsx
@@ -0,0 +1,250 @@
+import { Footer } from '@/app/_components/footer';
+import { HeartIcon } from '@/components/icons';
+import { Button } from '@/components/ui/button';
+import { Text } from '@/components/ui/text';
+import { router } from 'expo-router';
+import { ChevronLeft } from 'lucide-react-native';
+import { useState } from 'react';
+import { ScrollView, TextInput, TouchableOpacity, View } from 'react-native';
+import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import Svg, { Circle, Line, Path } from 'react-native-svg';
+
+export default function BoardDetailScreen() {
+ const insets = useSafeAreaInsets();
+ const [commentText, setCommentText] = useState('');
+
+ function onPostLikeClick(): void {}
+
+ function onCommentSubmitClick(): void {}
+
+ function onCommentDeleteClick(): void {}
+
+ return (
+
+ {/* header */}
+
+ router.back()}
+ className="flex-row items-center gap-1 self-start">
+
+ 이전
+
+
+
+ {/* content */}
+
+ {POST.title}
+
+
+ {POST.createdAt}
+
+ {POST.author}
+
+
+
+ {POST.likeCount}
+
+
+ {POST.commentCount}
+
+
+
+
+ {POST.content}
+
+
+ {/* like button */}
+
+ onPostLikeClick()}
+ className="flex-row items-center self-start">
+ 좋아요
+
+
+
+
+
+ {/* comments section */}
+ {false ? (
+
+ 댓글
+
+
+ 로그인 후 이용 가능합니다
+
+
+
+
+ ) : (
+
+
+ 댓글
+
+
+ onCommentSubmitClick()}
+ className="absolute bottom-2 right-2">
+
+
+
+
+ {commentText.length}/300
+
+
+
+ {/* comments */}
+ {COMMENTS.map((comment) => (
+
+
+
+
+ {comment.author}
+ {comment.createdAt}
+
+ {comment.isOwner && (
+ onCommentDeleteClick()}>
+
+
+ )}
+
+ {comment.content}
+
+
+ {comment.likeCount}
+
+
+ {comment.replyCount}
+
+
+ ))}
+
+ )}
+
+
+
+ );
+}
+
+// dummy
+const COMMENTS = [
+ {
+ id: 1,
+ author: '이서연',
+ createdAt: '2026.04.25 09:12',
+ content:
+ '요즘 세상 돌아가는 거 보면 진짜 어이없음. 뉴스 켜면 맨날 똑같은 얘기고, 전문가라는 사람들은 나와서 서로 반대 말만 하고, 댓글창은 또 난리고. 근데 신기한 건 다들 이렇게 피곤하다고 하면서 또 뉴스 봄. 나 포함.',
+ likeCount: 14,
+ replyCount: 3,
+ isOwner: false,
+ },
+ {
+ id: 2,
+ author: '박준혁',
+ createdAt: '2026.04.25 10:34',
+ content:
+ 'AI 에이전트 얘기 진짜 공감돼요. 저도 요즘 개발할 때 방향 제시만 하고 나머지는 AI한테 맡기는 경우가 많아졌어요.',
+ likeCount: 7,
+ replyCount: 1,
+ isOwner: true,
+ },
+ {
+ id: 3,
+ author: '최다은',
+ createdAt: '2026.04.25 11:58',
+ content: '좋은 글 잘 읽었습니다. 결국 AI를 어떻게 활용하느냐의 문제라는 말이 가장 와닿네요.',
+ likeCount: 5,
+ replyCount: 0,
+ isOwner: false,
+ },
+];
+
+const POST = {
+ title: '2026년, AI는 이미 "도구"가 아니다 — 우리가 몰랐던 변화의 속도',
+ author: '김민준',
+ createdAt: '2026.04.25',
+ likeCount: 42,
+ commentCount: 8,
+ content: `2026년, AI는 이미 '도구'가 아니다 — 우리가 몰랐던 변화의 속도
+요즘 들어 부쩍 이런 말을 자주 듣는다. "AI가 내 일자리를 빼앗는 건 아닐까?" 혹은 반대로 "AI, 써봤는데 별거 없던데?" 두 반응 모두 이해한다. 하지만 2026년 현재, 이 두 시선 모두 조금씩 빗나가 있다. AI는 이미 우리의 일상과 산업 깊숙이 스며들었고, 그 방식은 우리가 상상했던 것보다 훨씬 조용하고, 훨씬 빠르다.
+
+"AI 시대가 온다"는 말은 이미 과거형이다
+2023년, ChatGPT가 세상에 나왔을 때 많은 사람들은 이것을 '신기한 챗봇' 정도로 여겼다. 몇 가지 질문을 던져보고, 틀린 답변에 실망하고, 결국 탭을 닫았다. 그로부터 불과 3년이 지난 지금, 상황은 완전히 달라졌다.
+전 세계 수억 명의 사람들이 매일 AI와 대화하며 글을 쓰고, 코드를 짜고, 의사결정을 내린다. 기업들은 고객 서비스, 법률 검토, 재무 분석, 마케팅 카피 작성에 AI를 전면 도입했다. 병원에서는 AI가 영상 판독을 보조하고, 법원에서는 판례 분석에 AI가 활용된다. 이제 AI는 "쓸 것인가 말 것인가"의 문제가 아니라 "어떻게 잘 쓸 것인가"의 문제가 됐다.
+
+에이전트 AI: 단순 대화를 넘어선 '행동하는 AI'
+2025~2026년의 가장 큰 변화는 단연 **AI 에이전트(Agentic AI)**의 부상이다. 기존의 AI가 질문에 답하는 수동적인 도구였다면, 에이전트 AI는 스스로 계획을 세우고, 도구를 사용하고, 결과를 검토하며 목표를 달성한다.
+예를 들어 이런 식이다. 당신이 "다음 달 도쿄 출장 준비해줘"라고 말하면, 에이전트 AI는 항공권을 검색하고, 숙소를 비교하고, 일정을 정리해 캘린더에 등록하고, 필요한 서류 체크리스트까지 만들어 이메일로 보내준다. 사람이 중간에 개입하지 않아도 된다.
+이 기술은 이미 소프트웨어 개발 분야에서 두드러지게 나타나고 있다. 개발자들은 AI에게 기능 구현을 맡기고, AI는 코드를 작성하고 테스트하고 오류를 수정하는 전 과정을 자율적으로 수행한다. 개발자의 역할은 '코드를 짜는 사람'에서 '방향을 제시하고 결과를 검토하는 사람'으로 빠르게 이동하고 있다.
+
+멀티모달의 일상화: 텍스트, 이미지, 소리, 영상이 하나로
+또 하나의 거대한 흐름은 멀티모달(Multimodal) AI의 일상화다. 이제 AI는 텍스트만 처리하지 않는다. 사진을 보고 상황을 설명하고, 음성을 듣고 감정을 분석하며, 영상을 보고 요약문을 만든다. 반대로 텍스트 설명만으로 고품질의 이미지와 영상을 생성하기도 한다.
+이 변화가 가져온 파급력은 콘텐츠 산업에서 가장 극적으로 드러났다. 1인 크리에이터가 AI를 활용해 드라마 수준의 영상을 혼자 제작하고, 소규모 스타트업이 대형 광고 대행사와 맞먹는 품질의 광고 영상을 만들어낸다. 진입장벽이 낮아지면서 창작의 민주화가 빠르게 진행되고 있다.
+물론 이 과정에서 저작권, 딥페이크 악용, 가짜 정보 생성 같은 어두운 면도 함께 부상하고 있다. 기술의 속도를 제도가 따라가지 못하는 전형적인 문제다.
+
+AI와 일자리: 공포보다 복잡한 현실
+"AI가 일자리를 빼앗는다"는 공포는 여전히 유효하지만, 현실은 더 복잡하다. 단순 반복 업무는 분명히 AI로 대체되고 있다. 하지만 동시에, AI를 잘 활용하는 사람은 혼자서 이전에 팀 전체가 해내던 일을 처리할 수 있게 됐다. 생산성의 격차가 개인 단위에서 극적으로 벌어지고 있는 것이다.
+직종별로 보면 영향은 제각각이다. 회계사, 번역가, 콜센터 직원처럼 규칙 기반의 반복 업무가 많은 직종은 빠르게 자동화 압력을 받고 있다. 반면 인간 고유의 감성, 윤리 판단, 물리적 상호작용이 필요한 직종 — 사회복지사, 간호사, 배관공, 교사 — 은 당분간 AI의 위협으로부터 비교적 안전하다.
+중요한 건 "AI에게 대체될 것인가"가 아니라 "AI를 활용할 수 있는가"다. 이미 많은 기업이 채용 공고에 'AI 툴 활용 능력'을 필수 역량으로 명시하기 시작했다.
+
+소버린 AI와 규제: 각국의 AI 주도권 경쟁
+기술 패권 경쟁도 빼놓을 수 없다. 미국과 중국을 중심으로 AI 주도권 경쟁이 치열하게 벌어지는 가운데, 유럽은 세계 최초의 포괄적 AI 규제법인 EU AI Act를 본격 시행하며 '규제 선도국'의 역할을 자처하고 있다. 한국, 일본, 인도 등도 자국 언어와 문화에 특화된 AI 모델 개발에 박차를 가하고 있다.
+이른바 소버린 AI(Sovereign AI) — 자국의 데이터와 인프라로 운영되는 독립적 AI — 가 국가 전략의 핵심 키워드로 떠올랐다. 단순한 기술 경쟁을 넘어, AI는 이제 국가 안보와 경제 자립의 문제가 됐다.
+
+우리에게 필요한 것: 속도보다 방향
+변화의 속도는 분명 숨 막힐 정도로 빠르다. 하지만 속도에 압도되어서는 안 된다. 중요한 건 방향이다.
+AI가 더 강력해질수록, 우리가 스스로에게 던져야 할 질문도 깊어진다. 이 기술을 누가 통제하는가. 누가 혜택을 받고 누가 소외되는가. AI의 판단을 어디까지 믿을 것인가. 기술의 발전을 환영하되, 그것을 비판적으로 바라보는 시선을 잃지 않는 것 — 그것이 지금 이 시대를 살아가는 우리 모두에게 필요한 태도일 것이다.
+AI 시대는 이미 왔다. 이제 문제는 우리가 이 시대를 어떻게 살아갈 것인가다.`,
+ isLiked: true,
+};
diff --git a/components/ui/button.tsx b/components/ui/button.tsx
index e05c743..b3a6352 100644
--- a/components/ui/button.tsx
+++ b/components/ui/button.tsx
@@ -5,85 +5,52 @@ import { Platform, Pressable } from 'react-native';
const buttonVariants = cva(
cn(
- 'group shrink-0 flex-row items-center justify-center gap-2 rounded-md shadow-none',
+ 'group shrink-0 flex-row items-center justify-center gap-2 rounded-lg shadow-none active:opacity-80',
+ 'px-4 py-2.5',
Platform.select({
- web: "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
+ web: "aria-invalid:ring-destructive/20 aria-invalid:border-destructive whitespace-nowrap outline-none transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
})
),
{
variants: {
variant: {
- default: cn(
- 'bg-primary shadow-sm shadow-black/5 active:bg-primary/90',
- Platform.select({ web: 'hover:bg-primary/90' })
- ),
+ default: cn('bg-blue-35', Platform.select({ web: 'hover:opacity-80' })),
+ secondary: cn('bg-grey-40', Platform.select({ web: 'hover:opacity-80' })),
+ muted: cn('bg-grey-02', Platform.select({ web: 'hover:opacity-80' })),
destructive: cn(
- 'bg-destructive shadow-sm shadow-black/5 active:bg-destructive/90 dark:bg-destructive/60',
+ 'bg-error',
Platform.select({
- web: 'hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
+ web: 'focus-visible:ring-error/40 hover:opacity-80',
})
),
outline: cn(
- 'border border-border bg-background shadow-sm shadow-black/5 active:bg-accent dark:border-input dark:bg-input/30 dark:active:bg-input/50',
- Platform.select({
- web: 'hover:bg-accent dark:hover:bg-input/50',
- })
+ 'border border-border bg-background',
+ Platform.select({ web: 'hover:bg-accent' })
),
- secondary: cn(
- 'bg-secondary shadow-sm shadow-black/5 active:bg-secondary/80',
- Platform.select({ web: 'hover:bg-secondary/80' })
- ),
- ghost: cn(
- 'active:bg-accent dark:active:bg-accent/50',
- Platform.select({ web: 'hover:bg-accent dark:hover:bg-accent/50' })
- ),
- link: '',
- },
- size: {
- default: cn('h-10 px-4 py-2 sm:h-9', Platform.select({ web: 'has-[>svg]:px-3' })),
- sm: cn('h-9 gap-1.5 rounded-md px-3 sm:h-8', Platform.select({ web: 'has-[>svg]:px-2.5' })),
- lg: cn('h-11 rounded-md px-6 sm:h-10', Platform.select({ web: 'has-[>svg]:px-4' })),
- icon: 'h-10 w-10 sm:h-9 sm:w-9',
+ ghost: cn('', Platform.select({ web: 'hover:bg-grey-02' })),
},
},
defaultVariants: {
variant: 'default',
- size: 'default',
},
}
);
const buttonTextVariants = cva(
- cn(
- 'text-sm font-medium text-foreground',
- Platform.select({ web: 'pointer-events-none transition-colors' })
- ),
+ cn('text-body05', Platform.select({ web: 'pointer-events-none transition-colors' })),
{
variants: {
variant: {
- default: 'text-primary-foreground',
+ default: 'text-white',
+ secondary: 'text-white',
+ muted: 'text-grey-40',
destructive: 'text-white',
- outline: cn(
- 'group-active:text-accent-foreground',
- Platform.select({ web: 'group-hover:text-accent-foreground' })
- ),
- secondary: 'text-secondary-foreground',
- ghost: 'group-active:text-accent-foreground',
- link: cn(
- 'text-primary group-active:underline',
- Platform.select({ web: 'underline-offset-4 hover:underline group-hover:underline' })
- ),
- },
- size: {
- default: '',
- sm: '',
- lg: '',
- icon: '',
+ outline: cn('', Platform.select({ web: 'group-hover:text-accent-foreground' })),
+ ghost: '',
},
},
defaultVariants: {
variant: 'default',
- size: 'default',
},
}
);
@@ -92,11 +59,11 @@ type ButtonProps = React.ComponentProps &
React.RefAttributes &
VariantProps;
-function Button({ className, variant, size, ...props }: ButtonProps) {
+function Button({ className, variant, ...props }: ButtonProps) {
return (
-
+