From 4f993f1daa544faf6b7f2be62f7d1de674b4ec72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B0=A8=EC=A4=80=ED=98=B8?= Date: Mon, 12 Oct 2026 10:03:48 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(mobile):=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=20=ED=91=9C=EA=B0=80=20=EB=AA=A8=EB=B0=94=EC=9D=BC=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EA=B0=80=EB=A1=9C=EB=A1=9C=20=EB=B0=80=EB=A6=AC?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EA=B2=83=20=EB=93=B1=20?= =?UTF-8?q?=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EC=A0=90=EA=B2=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 2026-10-06 Web 56개 화면을 360·390px 로 전수 점검하며 고친 것. - 관리자 표 카드(ADMIN_TABLE_CARD)가 overflow-hidden 이라 오른쪽 열이 잘린 채 스와이프도 안 됐다(Users·Members·Core 지원서·Core 출석). overflow-x-auto + 표 min-w-max. 360px 터치 스와이프로 Users 표가 201px 밀리는 것을 확인 — 같은 카드를 overflow-hidden 으로 되돌리면 0. - Core 출석: 그리드 아이템 min-w-0 누락으로 문서가 409px 로 넘침. - 관리자 입력칸 13~15px → iOS 포커스 확대. mobile:text-base. - 온보딩 헤더: LEAD 로그인 시 「지원하기」가 잘림 → 「콘텐츠 관리」를 모바일에서 숨김. - 신청자 표 이름이 한 글자씩 꺾임 → 고정 열 whitespace-nowrap. 링크 첨부 말줄임. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01Ji3KHVeQmBERyUWeWzTzDM --- src/app/dashboard/club/review/page.tsx | 2 +- src/app/dashboard/club/team/page.tsx | 2 +- src/app/dashboard/core-applications/page.tsx | 2 +- src/app/dashboard/core/attendance/page.tsx | 6 +++--- src/app/dashboard/events/applicants/page.tsx | 14 +++++++++---- src/app/dashboard/events/form/page.tsx | 2 +- src/app/dashboard/members/page.tsx | 2 +- src/app/dashboard/page.tsx | 4 ++-- src/app/dashboard/users/page.tsx | 12 +++++------ src/components/admin/dashboard/adminStyles.ts | 21 +++++++++++++------ src/components/board/AttachmentList.tsx | 5 +++-- src/components/club/admin/ClubTermCard.tsx | 2 +- .../eventApplication/QuestionEditor.tsx | 2 +- .../landing/onboarding/LandingHeader.tsx | 6 +++++- 14 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/app/dashboard/club/review/page.tsx b/src/app/dashboard/club/review/page.tsx index 3ee87ca..e378205 100644 --- a/src/app/dashboard/club/review/page.tsx +++ b/src/app/dashboard/club/review/page.tsx @@ -235,7 +235,7 @@ export default function ClubReviewPage() { maxLength={1000} onChange={(e) => setReason(e.target.value)} placeholder="예: 모임 장면이 보이는 사진을 추가해 주세요" - className="resize-y rounded-xl border border-admin-line bg-admin-base px-4 py-3 text-[14px] text-admin-ink outline-none focus:border-admin-accent" + className="resize-y rounded-xl border border-admin-line bg-admin-base px-4 py-3 text-[14px] mobile:text-base text-admin-ink outline-none focus:border-admin-accent" />
diff --git a/src/app/dashboard/club/team/page.tsx b/src/app/dashboard/club/team/page.tsx index 479e2e3..fa4c2fe 100644 --- a/src/app/dashboard/club/team/page.tsx +++ b/src/app/dashboard/club/team/page.tsx @@ -50,7 +50,7 @@ const STATE_CLASS: Record = { const CARD = 'flex flex-col gap-3 rounded-[20px] border border-admin-line-soft bg-admin-card p-[22px] shadow-admin' const FIELD = - 'resize-y rounded-xl border border-admin-line bg-admin-base px-4 py-3 text-[14px] text-admin-ink outline-none focus:border-admin-accent' + 'resize-y rounded-xl border border-admin-line bg-admin-base px-4 py-3 text-[14px] mobile:text-base text-admin-ink outline-none focus:border-admin-accent' /** * 팀 상세·완주 확정 (C 담당). 계산상 미충족이어도 확정할 수 있다 — 확정 전에 한 번 더 묻는다. diff --git a/src/app/dashboard/core-applications/page.tsx b/src/app/dashboard/core-applications/page.tsx index a136d9c..e2c6a12 100644 --- a/src/app/dashboard/core-applications/page.tsx +++ b/src/app/dashboard/core-applications/page.tsx @@ -384,7 +384,7 @@ export default function DashboardCoreApplicationsPage() {
- +
{['이름', '학과 · 학번', '지원 팀', '상태', '제출 시각'].map((label) => ( diff --git a/src/app/dashboard/core/attendance/page.tsx b/src/app/dashboard/core/attendance/page.tsx index f600107..aaff091 100644 --- a/src/app/dashboard/core/attendance/page.tsx +++ b/src/app/dashboard/core/attendance/page.tsx @@ -526,7 +526,7 @@ export default function DashboardCoreAttendancePage() { aria-label="추가할 일정 날짜" value={newDate} onChange={(e) => setNewDate(e.target.value)} - className="rounded-full border border-admin-line bg-admin-card px-3.5 py-1.5 text-[13px] text-admin-ink outline-none transition-colors duration-200 focus:border-admin-accent" + className="rounded-full border border-admin-line bg-admin-card px-3.5 py-1.5 text-[13px] mobile:text-base text-admin-ink outline-none transition-colors duration-200 focus:border-admin-accent" />
+
{['이름', '팀', '상태', '최종 수정'].map((label) => ( diff --git a/src/app/dashboard/events/applicants/page.tsx b/src/app/dashboard/events/applicants/page.tsx index cfc9d50..e926502 100644 --- a/src/app/dashboard/events/applicants/page.tsx +++ b/src/app/dashboard/events/applicants/page.tsx @@ -243,7 +243,7 @@ export default function EventApplicantsPage() { ) : ( applicants.map((applicant) => ( - - - - + + +
+ {applicant.name} {applicant.userId == null && ( (비로그인) @@ -252,9 +252,15 @@ export default function EventApplicantsPage() { (취소) )} {applicant.studentId}{formatMajorLabel(applicant.major)}{formatDate(applicant.appliedAt)} + {applicant.studentId} + + {formatMajorLabel(applicant.major)} + + {formatDate(applicant.appliedAt)} +
+
{['이름', '학과 · 학번', '지원 학기', '제출 시각', '전화번호', '회비'].map( diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 4bfd737..4b11b25 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -252,7 +252,7 @@ export default function DashboardIndexPage() { value={query} onChange={(event) => setQuery(event.target.value)} placeholder="페이지 검색 ( / 키로 이동 )" - className="min-w-0 flex-1 border-0 bg-transparent text-[15px] text-admin-ink outline-none" + className="min-w-0 flex-1 border-0 bg-transparent text-[15px] mobile:text-base text-admin-ink outline-none" /> @@ -262,7 +262,7 @@ export default function DashboardIndexPage() {
+
+
{['ID', '이름', '이메일', '학과 · 학번', '권한', '팀'].map((label) => ( diff --git a/src/components/admin/dashboard/adminStyles.ts b/src/components/admin/dashboard/adminStyles.ts index 84a766c..249b606 100644 --- a/src/components/admin/dashboard/adminStyles.ts +++ b/src/components/admin/dashboard/adminStyles.ts @@ -9,23 +9,28 @@ export const ADMIN_PILL = 'flex items-center gap-2.5 rounded-full border border-admin-line bg-admin-card px-4 py-2.5' -/** 알약 안에 들어가는 네이티브 셀렉트 */ +/** + * 알약 안에 들어가는 네이티브 셀렉트. + * + * 입력 컨트롤은 모바일에서 16px 이상이어야 한다 — iOS Safari 는 그보다 작은 칸에 포커스하면 + * 화면을 확대하고 되돌리지 않는다. + */ export const ADMIN_PILL_SELECT = - 'cursor-pointer border-0 bg-transparent text-[15px] text-admin-ink outline-none' + 'cursor-pointer border-0 bg-transparent text-[15px] mobile:text-base text-admin-ink outline-none' /** 셀렉트 옵션 — 브라우저가 배경을 상속하지 않아 직접 준다 */ export const ADMIN_OPTION = 'bg-admin-card text-admin-ink' /** 표 안에서 쓰는 셀렉트 */ export const ADMIN_CELL_SELECT = - 'w-full min-w-[96px] cursor-pointer rounded-[10px] border border-admin-line bg-admin-card px-2.5 py-2 text-[14px] text-admin-ink outline-none transition-colors duration-200 hover:border-admin-accent disabled:cursor-not-allowed disabled:opacity-40' + 'w-full min-w-[96px] cursor-pointer rounded-[10px] border border-admin-line bg-admin-card px-2.5 py-2 text-[14px] mobile:text-base text-admin-ink outline-none transition-colors duration-200 hover:border-admin-accent disabled:cursor-not-allowed disabled:opacity-40' /** 검색 필드를 감싸는 라벨 */ export const ADMIN_SEARCH_FIELD = 'flex min-w-0 flex-1 basis-[300px] items-center gap-2.5 rounded-full border border-admin-line bg-admin-card px-4 py-2.5 shadow-admin transition duration-[250ms] focus-within:border-admin-accent focus-within:shadow-admin-ring' export const ADMIN_SEARCH_INPUT = - 'min-w-0 flex-1 border-0 bg-transparent text-[15px] text-admin-ink outline-none' + 'min-w-0 flex-1 border-0 bg-transparent text-[15px] mobile:text-base text-admin-ink outline-none' /** 강조 버튼 (저장 등) */ export const ADMIN_ACCENT_BUTTON = @@ -39,9 +44,13 @@ export const ADMIN_ACCENT_BUTTON_SM = export const ADMIN_GHOST_BUTTON = 'whitespace-nowrap rounded-full border border-admin-line px-[18px] py-2 text-[13px] text-admin-ink-muted transition-colors duration-200 hover:border-admin-accent hover:text-admin-ink disabled:cursor-not-allowed disabled:opacity-40' -/** 표를 감싸는 카드 — `overflow-hidden` 이 라운드를 지킨다 */ +/** + * 표를 감싸는 카드. `overflow-x-auto` 가 라운드를 지키면서 좁은 화면에서 가로 스크롤을 준다 — + * `overflow-hidden` 이던 때는 모바일에서 오른쪽 열이 잘린 채 밀어도 움직이지 않았다. + * 안의 표는 `min-w-max` 등으로 폭을 지켜야 열이 찌그러지지 않는다. + */ export const ADMIN_TABLE_CARD = - 'overflow-hidden rounded-[20px] border border-admin-line-soft bg-admin-card shadow-admin' + 'overflow-x-auto rounded-[20px] border border-admin-line-soft bg-admin-card shadow-admin' /** * 표 헤더 셀. `top-0` 이어야 한다 — 68px 을 주면 첫 행과 겹친다. diff --git a/src/components/board/AttachmentList.tsx b/src/components/board/AttachmentList.tsx index 443d70f..c4a109f 100644 --- a/src/components/board/AttachmentList.tsx +++ b/src/components/board/AttachmentList.tsx @@ -59,9 +59,10 @@ export function AttachmentList({ attachments }: AttachmentListProps) { href={href ?? '#'} target="_blank" rel="noreferrer" - className="flex items-center gap-2 overflow-hidden text-ellipsis whitespace-nowrap rounded-[10px] bg-[rgba(240,234,228,0.06)] px-4 py-[9px] text-[15px] text-tag-info underline transition-colors hover:bg-[rgba(240,234,228,0.11)]" + className="flex items-center gap-2 rounded-[10px] bg-[rgba(240,234,228,0.06)] px-4 py-[9px] text-[15px] text-tag-info underline transition-colors hover:bg-[rgba(240,234,228,0.11)]" > - {attachment.url} + {/* flex 컨테이너에 직접 둔 텍스트에는 말줄임이 안 걸려 긴 URL 이 오른쪽 여백까지 잘린다. */} + {attachment.url} ) diff --git a/src/components/club/admin/ClubTermCard.tsx b/src/components/club/admin/ClubTermCard.tsx index 49d4fa9..7d7f284 100644 --- a/src/components/club/admin/ClubTermCard.tsx +++ b/src/components/club/admin/ClubTermCard.tsx @@ -16,7 +16,7 @@ import { cn } from '@/utils/cn' const CARD = 'flex flex-col gap-3 rounded-[20px] border border-admin-line-soft bg-admin-card p-[22px] shadow-admin' const FIELD = - 'rounded-xl border border-admin-line bg-admin-base px-4 py-3 text-[14px] text-admin-ink outline-none focus:border-admin-accent' + 'rounded-xl border border-admin-line bg-admin-base px-4 py-3 text-[14px] mobile:text-base text-admin-ink outline-none focus:border-admin-accent' /** * 기수 설정 (C 담당) — `/dashboard/club/leaders` 오른쪽 칸. 이름과 참석 비율만 있다. 활동 기간은 소모임마다 둔다. diff --git a/src/components/eventApplication/QuestionEditor.tsx b/src/components/eventApplication/QuestionEditor.tsx index 4309cfe..d02658c 100644 --- a/src/components/eventApplication/QuestionEditor.tsx +++ b/src/components/eventApplication/QuestionEditor.tsx @@ -20,7 +20,7 @@ import { } from '@/types/eventApplication' const INPUT = - 'w-full rounded-[10px] border border-admin-line bg-admin-card px-3 py-2 text-[14px] text-admin-ink outline-none transition-colors duration-200 focus:border-admin-accent disabled:cursor-not-allowed disabled:opacity-40' + 'w-full rounded-[10px] border border-admin-line bg-admin-card px-3 py-2 text-[14px] mobile:text-base text-admin-ink outline-none transition-colors duration-200 focus:border-admin-accent disabled:cursor-not-allowed disabled:opacity-40' const LABEL = 'shrink-0 whitespace-nowrap text-[12px] tracking-[0.06em] text-admin-ink-dim' diff --git a/src/components/landing/onboarding/LandingHeader.tsx b/src/components/landing/onboarding/LandingHeader.tsx index d13e0ac..c9b0c97 100644 --- a/src/components/landing/onboarding/LandingHeader.tsx +++ b/src/components/landing/onboarding/LandingHeader.tsx @@ -67,8 +67,12 @@ export default function LandingHeader() { - + ) } diff --git a/src/components/ui/design-system/GdgSiteNav.types.ts b/src/components/ui/design-system/GdgSiteNav.types.ts index 804bc4e..786107b 100644 --- a/src/components/ui/design-system/GdgSiteNav.types.ts +++ b/src/components/ui/design-system/GdgSiteNav.types.ts @@ -1,4 +1,6 @@ export type GdgMenuLink = { label: string url: string + /** 모바일 탭 줄처럼 폭이 좁은 곳에서 쓰는 짧은 이름 */ + shortLabel?: string } diff --git a/src/utils/auth/role.ts b/src/utils/auth/role.ts index 381eac5..1879263 100644 --- a/src/utils/auth/role.ts +++ b/src/utils/auth/role.ts @@ -12,6 +12,15 @@ export const hasAtLeast = ( minimumRole: UserRoleValue ): boolean => rankOf(currentRole) >= rankOf(minimumRole) +/** + * 운영진 대시보드(`/dashboard`)에 들어갈 수 있는 최소 역할. + * 대시보드 가드와 헤더의 「운영」 버튼이 같이 본다 — 따로 적으면 버튼은 보이는데 열면 막히는 일이 생긴다. + */ +export const DASHBOARD_MIN_ROLE: UserRoleValue = 'CORE' + +export const canOpenDashboard = (currentRole: string | undefined | null): boolean => + hasAtLeast(currentRole, DASHBOARD_MIN_ROLE) + /** * 부원 정보를 고칠 수 있는가 — 서버 LEAD_OR_HR_RULE 과 같은 규칙이다. * CORE 는 조회만 되므로 쓰기 버튼은 이 판정으로 막는다.