Uxui Review And Fix Svelte Rails

Rails + Svelte 앱 UX/UI 전수 점검 및 개선 기록

Rails 8 + Inertia.js + Svelte 5 조합으로 만든 웹앱을 운영하다가, 기능은 돌아가는데 세부 UX가 들쭉날쭉하다는 걸 느꼈다. 이번 글은 전수 점검 후 우선순위 높은 4가지를 직접 고친 기록이다. 문제 발견: 같은 기능인데 UI가 다르다 가장 먼저 눈에 띈 건 시작일 입력 UI가 화면마다 다르게 동작하는 문제였다. 앱에는 할일을 만들 수 있는 진입점이 4곳이다. 대시보드 빠른 추가 모달(생성) 전체 페이지 생성 모달(수정) 위치 시작일 동작 대시보드 빠른추가 피커가 항상 노출 + + 시작일 버튼도 따로 존재 생성 모달 마감일 설정 후 + 시작일 추가 버튼 클릭 시 피커 표시 전체 페이지 피커 항상 노출 수정 모달 피커 항상 노출 생성 모달만 UX가 깔끔했고, 나머지 3곳은 피커가 항상 보여서 폼이 불필요하게 복잡해 보였다. + 시작일 버튼이 있는데 피커도 이미 떠 있으니 버튼의 의미가 모호했다. ...

2026-03-06 · 4분 소요 · Seunghan
Calendar Print Browser Print Bug Paper Sizes

웹 캘린더 인쇄 기능의 함정: window.print()는 off-screen 엘리먼트를 무시한다

웹에서 캘린더를 출력하는 기능을 만들었다. PDF와 PNG 다운로드는 완벽한데, 브라우저 인쇄 버튼만 누르면 이미지 위치가 전혀 반영되지 않았다. 같은 데이터를 쓰는데 왜 결과가 다를까? 구조: 프리뷰와 숨겨진 내보내기 타겟 캘린더 출력 페이지의 구조는 이렇다: ┌─ 화면에 보이는 영역 ─────────────────┐ │ [설정 패널] [프리뷰 영역] │ │ - 기간 선택 캘린더 미리보기 │ │ - 테마/색상 │ │ - 이미지 위치 슬라이더 │ └──────────────────────────────────────┘ ┌─ 숨겨진 내보내기 타겟 ───────────────┐ │ <div class="fixed -left-[9999px]"> │ ← 화면 밖 │ <PrintableCalendar ... /> │ │ </div> │ └──────────────────────────────────────┘ 프리뷰는 축소된 미리보기고, 실제 내보내기용 캘린더는 원본 크기로 화면 밖(-left-[9999px])에 렌더링된다. PDF/PNG는 이 숨겨진 엘리먼트를 캡처한다. ...

2026-01-20 · 4분 소요 · Seunghan
Flutter Bloc Infinite Scroll Pagination

Flutter BLoC 무한스크롤 구현 — 외부 패키지 없이 레이어별로 설계하기

목록을 처음에 전부 로드하면 느리다. 사용자가 스크롤할수록 자연스럽게 다음 데이터를 불러오는 무한스크롤이 필요했다. infinite_scroll_pagination 같은 패키지도 있지만, 기존 BLoC 구조에 그대로 얹으려면 상태 설계를 패키지 방식에 맞춰야 해서 오히려 복잡해지는 경우가 있다. 외부 의존 없이 ScrollController만으로도 충분히 만들 수 있어서 그 방향으로 구현했다. 왜 Offset 기반인가 페이지네이션 방식은 두 가지다. Offset 기반 (page 번호) GET /items?page=1&per_page=20 GET /items?page=2&per_page=20 Cursor 기반 (마지막 아이템 ID) GET /items?cursor=abc123&per_page=20 Cursor 방식이 “데이터가 중간에 삽입/삭제돼도 중복/누락 없다"는 점에서 이론적으로 더 우수하다. 하지만 대상 데이터가 법령/규정처럼 자주 바뀌지 않는 정적 문서라면 Offset 방식으로 충분하다. ...

2025-09-20 · 5분 소요 · Seunghan
Flutter Bloc Complex State Management

Flutter BLoC - Q&A 세션처럼 상태가 복잡할 때 설계하기

목록을 불러오고 보여주는 수준의 BLoC는 어렵지 않다. 문제는 세션 기반의 흐름, 예를 들어 “세션을 만들고 → 질문을 추가하고 → 답변을 받고 → 완료” 같은 단계적 워크플로우를 BLoC 하나로 관리할 때다. 상태를 먼저 그려라 BLoC를 코딩하기 전에 상태부터 정의하는 게 순서다. 이 워크플로우에서 UI가 보여줘야 하는 상태를 나열하면: 초기 (아무것도 없음) 세션 목록 로딩 중 세션 목록 표시 새 세션 생성 중 세션 상세 로딩 중 세션 상세 표시 (질문 목록 포함) 질문 추가 중 답변 입력 중 오류 abstract class ReviewQaState {} class ReviewQaInitial extends ReviewQaState {} class ReviewQaLoading extends ReviewQaState {} class ReviewQaSessionListLoaded extends ReviewQaState { final List<QaSession> sessions; ReviewQaSessionListLoaded(this.sessions); } class ReviewQaSessionLoaded extends ReviewQaState { final QaSession session; final List<ReviewQuestion> questions; ReviewQaSessionLoaded({required this.session, required this.questions}); } class ReviewQaQuestionAdded extends ReviewQaState { final ReviewQuestion question; ReviewQaQuestionAdded(this.question); } class ReviewQaError extends ReviewQaState { final String message; ReviewQaError(this.message); } 상태 클래스를 이렇게 구체적으로 나눠야 UI에서 if (state is ReviewQaSessionLoaded) 처럼 명확하게 분기할 수 있다. ...

2025-07-06 · 3분 소요 · Seunghan
개인정보처리방침 문의