- -
-
+ +
+
📅
-
예정된 회의
-
3
+
0
+
예정된 회의
-
+
-
진행 중 Todo
-
1
+
0
+
나의 Todo
-
-
📈
-
Todo 완료율
-
33%
-
-
+

최근 회의

- 전체 보기 →
- +
-

할당된 Todo

+

나의 Todo

전체 보기 →
@@ -515,10 +584,10 @@
- +
-

내 회의록

+

나의 회의록

전체 보기 →
@@ -570,19 +639,25 @@ const currentUser = getFromStorage('currentUser') || CURRENT_USER; /** - * 최근 회의 렌더링 + * 최근 회의 렌더링 (회의록 미생성 먼저, 빠른 일시 순으로 3개) */ function renderRecentMeetings() { const container = $('#recent-meetings'); - // 진행중 우선, 날짜순 정렬 + // 회의록 미생성(scheduled, ongoing) 먼저, 빠른 일시 순 정렬 const meetings = [...SAMPLE_MEETINGS] .sort((a, b) => { - if (a.status === 'ongoing' && b.status !== 'ongoing') return -1; - if (a.status !== 'ongoing' && b.status === 'ongoing') return 1; - return new Date(b.date + ' ' + b.time) - new Date(a.date + ' ' + a.time); + // 회의록 미생성 회의 우선 + const aNoMinutes = a.status === 'scheduled' || a.status === 'ongoing'; + const bNoMinutes = b.status === 'scheduled' || b.status === 'ongoing'; + + if (aNoMinutes && !bNoMinutes) return -1; + if (!aNoMinutes && bNoMinutes) return 1; + + // 동일 그룹 내에서는 빠른 일시 순 (오름차순) + return new Date(a.date + ' ' + a.time) - new Date(b.date + ' ' + b.time); }) - .slice(0, 3); + .slice(0, 3); // 상위 3개만 표시 container.innerHTML = meetings.map(meeting => { const statusInfo = getMeetingStatusInfo(meeting); @@ -591,16 +666,12 @@ return `
-
- ${createBadge(statusInfo.badgeText, statusInfo.badgeType)} - ${isCreator ? ' 👑' : ''} -
+ ${createBadge(statusInfo.badgeText, statusInfo.badgeType)} +

${meeting.title}${isCreator ? ' 👑' : ''}

-

${meeting.title}

-
📅 ${formatDate(meeting.date)} ${formatTime(meeting.time)}
+
📅 ${formatDate(meeting.date)} ${formatTime(meeting.time)} 👥 ${meeting.participants.length}명
📍 ${meeting.location}
-
👥 ${meeting.participants.length}명
${meeting.status === 'ongoing' @@ -633,7 +704,7 @@ } /** - * 내 Todo 렌더링 + * 내 Todo 렌더링 (09-Todo관리.html과 동일한 정렬 기준) */ function renderMyTodos() { const container = $('#my-todos'); @@ -641,10 +712,12 @@ const myTodos = SAMPLE_TODOS .filter(todo => todo.assignee.id === currentUser.id) .sort((a, b) => { - const priorityOrder = { overdue: 0, in_progress: 1, not_started: 2, completed: 3 }; - return priorityOrder[a.status] - priorityOrder[b.status]; + // 09-Todo관리.html과 동일한 정렬: 완료되지 않은 것 우선, 마감일 순 + if (a.status === 'completed' && b.status !== 'completed') return 1; + if (a.status !== 'completed' && b.status === 'completed') return -1; + return new Date(a.dueDate) - new Date(b.dueDate); }) - .slice(0, 5); + .slice(0, 3); // 상위 3개만 표시 if (myTodos.length === 0) { container.innerHTML = '

할당된 Todo가 없습니다

'; @@ -652,61 +725,122 @@ } container.innerHTML = myTodos.map(todo => { - const statusInfo = getTodoStatusInfo(todo); - const isOverdue = calculateDday(todo.dueDate) < 0 && todo.status !== 'completed'; + const dday = calculateDday(todo.dueDate); + const isCompleted = todo.status === 'completed'; + const isOverdue = dday < 0 && !isCompleted; + + // D-day 배지 + let ddayBadge = ''; + let ddayClass = ''; + if (isCompleted) { + ddayBadge = '완료'; + ddayClass = 'badge-complete'; + } else if (isOverdue) { + ddayBadge = `D+${Math.abs(dday)} (지연)`; + ddayClass = 'badge-overdue'; + } else if (dday === 0) { + ddayBadge = 'D-DAY'; + ddayClass = 'badge-warning'; + } else if (dday <= 3) { + ddayBadge = `D-${dday}`; + ddayClass = 'badge-warning'; + } else if (dday <= 7) { + ddayBadge = `D-${dday}`; + ddayClass = 'badge-primary'; + } else { + ddayBadge = `D-${dday}`; + ddayClass = ''; + } + + // 우선순위 배지 + const priorityText = todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음'; + const priorityClass = `badge-${todo.priority}`; return ` -
-
-

${todo.title}

- ${createBadge(statusInfo.badgeText, statusInfo.badgeType)} -
-
- 마감: ${formatDate(todo.dueDate)} - ${createBadge(todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음', todo.priority)} -
-
- ${createProgressBar(todo.progress)} +
+
+
+ +
+
+
+ ${ddayBadge} + ${priorityText} +
+
${todo.title}
+
+ + 🔗 ${todo.meetingTitle} + + ${formatDate(todo.dueDate)} +
+
+ ${!isCompleted ? ` +
+ +
+ ` : ''}
`; }).join(''); - // Todo 항목 클릭 시 해당 회의록 상세로 이동 - $$('.todo-item').forEach(item => { - item.addEventListener('click', () => { - const meetingId = item.dataset.meetingId; - const todoId = item.dataset.todoId; - // 회의록 상세 페이지로 이동 (Todo ID를 파라미터로 전달) + // Todo 카드 클릭 시 해당 회의록 상세로 이동 (체크박스와 버튼 제외) + $$('.todo-card').forEach(card => { + card.addEventListener('click', (e) => { + // 체크박스나 버튼 클릭은 무시 + if (e.target.classList.contains('todo-checkbox') || + e.target.classList.contains('icon-btn') || + e.target.closest('.icon-btn')) { + return; + } + const meetingId = card.dataset.meetingId; + const todoId = card.dataset.todoId; navigateTo(`10-회의록상세조회.html?meetingId=${meetingId}&todoId=${todoId}`); }); }); } /** - * 내 회의록 렌더링 + * 나의 회의록 렌더링 (참여자 또는 생성자로 등록된 회의록, 최신순 정렬) */ function renderMyMinutes() { const container = $('#my-minutes'); - const myMeetings = SAMPLE_MEETINGS - .filter(m => m.participants.some(p => p.id === currentUser.id && p.role === 'creator')) - .slice(0, 3); + const myMinutes = SAMPLE_MINUTES + .filter(m => m.participants.some(p => p.id === currentUser.id)) // 참여자 또는 생성자 모두 포함 + .sort((a, b) => new Date(b.date + ' ' + b.time) - new Date(a.date + ' ' + a.time)) // 최신순 정렬 + .slice(0, 3); // 상위 3개만 표시 - if (myMeetings.length === 0) { - container.innerHTML = '
📝

작성한 회의록이 없습니다

'; + if (myMinutes.length === 0) { + container.innerHTML = '
📝

참여한 회의록이 없습니다

'; return; } - container.innerHTML = myMeetings.map(meeting => { - const statusInfo = getMeetingStatusInfo(meeting); + container.innerHTML = myMinutes.map(minutes => { + // 상태 배지 정보 + const statusBadge = minutes.status === 'complete' + ? { text: '확정완료', type: 'complete' } + : { text: '작성중', type: 'draft' }; + + // 생성자 여부 확인 + const isCreator = minutes.participants.some(p => p.id === currentUser.id && p.role === 'creator'); + return ` -
-

${meeting.title}

-
- 📅 ${formatDate(meeting.date)} - 👥 ${meeting.participants.length}명 - ${createBadge(statusInfo.badgeText, statusInfo.badgeType)} +
+
+
+ ${createBadge(statusBadge.text, statusBadge.type)} +
+

${minutes.title}

+ ${isCreator ? '👑' : ''} +
+
+ 📅 ${formatDate(minutes.date)} ${formatTime(minutes.time)} + 👥 ${minutes.participantCount}명 + ${minutes.status === 'draft' ? `${minutes.completionRate}% 완료` : ''}
`; @@ -717,15 +851,14 @@ * 통계 업데이트 */ function updateStats() { + // 예정된 회의 개수 (예정 + 진행중) const scheduled = SAMPLE_MEETINGS.filter(m => m.status === 'scheduled' || m.status === 'ongoing').length; - const todos = SAMPLE_TODOS.filter(t => t.assignee.id === currentUser.id && t.status !== 'completed').length; - const totalTodos = SAMPLE_TODOS.filter(t => t.assignee.id === currentUser.id).length; - const completedTodos = SAMPLE_TODOS.filter(t => t.assignee.id === currentUser.id && t.status === 'completed').length; - const completion = totalTodos > 0 ? Math.round((completedTodos / totalTodos) * 100) : 0; + + // 나의 Todo 개수 (전체) + const myTodos = SAMPLE_TODOS.filter(t => t.assignee.id === currentUser.id).length; $('#stat-scheduled').textContent = scheduled; - $('#stat-todos').textContent = todos; - $('#stat-completion').textContent = completion + '%'; + $('#stat-todos').textContent = myTodos; } /** @@ -827,6 +960,50 @@ } } + /** + * Todo 완료 토글 + * @param {string} todoId - Todo ID + * @param {boolean} isChecked - 체크박스 상태 + */ + function toggleTodoComplete(todoId, isChecked) { + if (isChecked) { + // 완료 처리 + if (confirm('완료 처리하시겠습니까?')) { + const todo = SAMPLE_TODOS.find(t => t.id === todoId); + if (todo) { + todo.status = 'completed'; + showToast('Todo가 완료되었습니다', 'success'); + updateStats(); + renderMyTodos(); + } + } else { + event.target.checked = false; + } + } else { + // 미완료로 되돌리기 + if (confirm('미완료로 변경하시겠습니까?')) { + const todo = SAMPLE_TODOS.find(t => t.id === todoId); + if (todo) { + todo.status = 'incomplete'; + showToast('미완료로 변경되었습니다', 'info'); + updateStats(); + renderMyTodos(); + } + } else { + event.target.checked = true; + } + } + } + + /** + * Todo 편집 (간이 버전 - 09-Todo관리.html로 이동) + * @param {string} todoId - Todo ID + */ + function editTodo(todoId) { + // Todo 관리 화면으로 이동하여 편집 + navigateTo(`09-Todo관리.html?todoId=${todoId}`); + } + init(); diff --git a/design/uiux/prototype/09-Todo관리.html b/design/uiux/prototype/09-Todo관리.html index 6281fdd..6eeeae8 100644 --- a/design/uiux/prototype/09-Todo관리.html +++ b/design/uiux/prototype/09-Todo관리.html @@ -268,114 +268,14 @@ border-color: var(--primary); } - /* Todo 카드 - 컴팩트 디자인 */ - .todo-card { - position: relative; - background: var(--white); - padding: var(--space-md); - border-radius: var(--radius-lg); - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); - margin-bottom: var(--space-sm); - transition: all var(--transition-normal); - border: 1px solid var(--gray-200); - } - - .todo-card:hover { - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12); - border-color: var(--primary); - } - - .todo-card.completed { - opacity: 0.5; - background: var(--gray-50); - } - - .todo-card.completed .todo-title { - text-decoration: line-through; - color: var(--gray-500); - } - - /* 레이아웃: 체크박스 + 콘텐츠 */ - .todo-top { - display: flex; - gap: var(--space-md); - align-items: flex-start; - position: relative; - } - - .todo-checkbox-wrapper { - flex-shrink: 0; - padding-top: 2px; - } - - .todo-checkbox { - width: 24px; - height: 24px; - border: 2px solid var(--gray-400); - border-radius: 6px; - cursor: pointer; - transition: all var(--transition-fast); - } - - .todo-checkbox:checked { - background: var(--success); - border-color: var(--success); - } - - .todo-content-wrapper { - flex: 1; - min-width: 0; /* 텍스트 오버플로우 방지 */ - } - - /* 배지 영역 */ - .todo-badges { - display: flex; - gap: var(--space-xs); - flex-wrap: wrap; - margin-bottom: var(--space-xs); - } - - /* Todo 제목 */ - .todo-title { - font-size: var(--font-body); - font-weight: var(--font-weight-regular); - color: var(--gray-900); - margin-bottom: var(--space-xs); - line-height: 1.5; - } - - /* 하단 메타 정보 */ - .todo-meta-row { - display: flex; - align-items: center; - gap: var(--space-sm); - font-size: var(--font-small); - color: var(--gray-500); - flex-wrap: wrap; - } - - .todo-meeting-link { - display: inline-flex; - align-items: center; - gap: 4px; - color: #4CAF50; /* 연한 초록색 */ - text-decoration: none; - font-size: var(--font-small); - cursor: pointer; - transition: color var(--transition-fast); - } - - .todo-meeting-link:hover { - color: #388E3C; - text-decoration: underline; - } + /* Todo 카드 스타일은 common.css에서 공통 관리 */ /* 담당자 정보 숨김 (간결한 디자인) */ .todo-assignee { display: none; } - /* 액션 버튼 영역 - 우측 상단에 배치 */ + /* 액션 버튼 영역 - 09-Todo관리 페이지 전용: 우측 상단에 배치 */ .todo-actions { position: absolute; top: var(--space-md); diff --git a/design/uiux/prototype/10-회의록상세조회.html b/design/uiux/prototype/10-회의록상세조회.html index 035674d..2664362 100644 --- a/design/uiux/prototype/10-회의록상세조회.html +++ b/design/uiux/prototype/10-회의록상세조회.html @@ -540,6 +540,217 @@ margin-bottom: var(--space-xs); } + /* 원형 진행 바 - 모바일에서 축소 */ + .circular-progress { + width: 60px; + height: 60px; + margin: 0 auto; + position: relative; + } + + .circular-progress svg { + width: 80px; + height: 80px; + transform: rotate(-90deg); + } + + .circular-progress circle { + fill: none; + stroke-width: 6; + } + + .circular-progress .bg-circle { + stroke: var(--gray-300); + } + + .circular-progress .progress-circle { + stroke: var(--primary); + stroke-linecap: round; + transition: stroke-dashoffset 1s ease; + } + + .circular-progress-text { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: var(--font-h3); + font-weight: var(--font-weight-bold); + color: var(--primary); + } + + /* 데스크톱에서 원형 진행 바 크기 복원 */ + @media (min-width: 768px) { + .circular-progress { + width: 80px; + height: 80px; + margin-bottom: var(--space-sm); + } + + .circular-progress svg { + width: 100px; + height: 100px; + } + + .circular-progress circle { + stroke-width: 8; + } + } + + /* Todo 진행상황 - 09-Todo관리 스타일 적용 */ + .todo-filters { + display: flex; + gap: var(--space-sm); + margin-bottom: var(--space-md); + overflow-x: auto; + } + + .filter-btn { + padding: 8px 16px; + border: 1px solid var(--gray-300); + background: var(--white); + border-radius: 20px; + font-size: var(--font-small); + color: var(--gray-700); + cursor: pointer; + white-space: nowrap; + transition: all var(--transition-fast); + } + + .filter-btn.active { + background: var(--primary); + color: var(--white); + border-color: var(--primary); + } + + .todo-card { + position: relative; + background: var(--white); + padding: var(--space-md); + border-radius: var(--radius-lg); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); + margin-bottom: var(--space-sm); + transition: all var(--transition-normal); + border: 1px solid var(--gray-200); + } + + .todo-card:hover { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12); + border-color: var(--primary); + } + + .todo-card.completed { + opacity: 0.5; + background: var(--gray-50); + } + + .todo-card.completed .todo-title { + text-decoration: line-through; + color: var(--gray-500); + } + + .todo-top { + display: flex; + gap: var(--space-md); + align-items: flex-start; + position: relative; + } + + .todo-checkbox-wrapper { + flex-shrink: 0; + padding-top: 2px; + } + + .todo-checkbox { + width: 24px; + height: 24px; + border: 2px solid var(--gray-400); + border-radius: 6px; + cursor: pointer; + transition: all var(--transition-fast); + } + + .todo-checkbox:checked { + background: var(--success); + border-color: var(--success); + } + + .todo-content-wrapper { + flex: 1; + min-width: 0; + } + + .todo-badges { + display: flex; + gap: var(--space-xs); + flex-wrap: wrap; + margin-bottom: var(--space-xs); + } + + .todo-title { + font-size: var(--font-body); + font-weight: var(--font-weight-regular); + color: var(--gray-900); + margin-bottom: var(--space-xs); + line-height: 1.5; + } + + .todo-meta-row { + display: flex; + align-items: center; + gap: var(--space-sm); + font-size: var(--font-small); + color: var(--gray-500); + flex-wrap: wrap; + } + + .todo-meeting-link { + display: inline-flex; + align-items: center; + gap: 4px; + color: #4CAF50; + text-decoration: none; + font-size: var(--font-small); + cursor: pointer; + transition: color var(--transition-fast); + } + + .todo-meeting-link:hover { + color: #388E3C; + text-decoration: underline; + } + + .todo-actions { + position: absolute; + top: var(--space-md); + right: var(--space-md); + } + + .icon-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + padding: 0; + background: none; + border: none; + border-radius: var(--radius-md); + font-size: 20px; + cursor: pointer; + transition: all var(--transition-fast); + } + + .icon-btn:hover { + background: var(--gray-100); + transform: scale(1.1); + } + + .icon-btn:active { + background: var(--gray-200); + transform: scale(1); + } + /* 하단 액션 바 - common.css에서 기본 스타일 적용됨 */ /* 탭 콘텐츠 토글 */ @@ -915,6 +1126,21 @@

📋 Todo 진행상황

+ +
+
+ + + + +
40%
+
+
+ 2 / 5 완료 +
+
+
@@ -923,125 +1149,114 @@
- -
-
-
- 이준호 (2) -
- -
-
- API 명세서 작성 - 높음 + +
+
+
+
-
- D-2 - 2025-10-23 마감 -
-
-
- 진행률 - 60% +
+
+ D+1 (지연) + 높음
-
-
+
데이터베이스 스키마 설계
+
+ 담당자: 이준호 + 2025-10-20 마감
-
- -
-
- 데이터베이스 스키마 설계 - 높음 -
-
- D+1 (지연) - 2025-10-20 마감 -
-
-
- 진행률 - 80% -
-
-
-
+
+
- -
-
-
- 최유진 (1) -
- -
-
- UI 프로토타입 디자인 - 보통 +
+
+
+
-
- D-7 - 2025-10-28 마감 +
+
+ D-2 + 높음 +
+
API 명세서 작성
+
+ 담당자: 이준호 + 2025-10-23 마감 +
-
-
- 진행률 - 0% -
-
-
-
+
+
- -
-
-
- 김민준 (2) -
- -
-
- 예산 편성안 검토 - 높음 +
+
+
+
-
- D-1 - 2025-10-22 마감 +
+
+ D-1 + 높음 +
+
예산 편성안 검토
+
+ 담당자: 김민준 + 2025-10-22 마감 +
-
-
- 진행률 - 40% -
-
-
-
+
+
+
-
-
- 사용자 피드백 분석 - 보통 +
+
+
+
-
- 완료 - 2025-10-19 마감 -
-
-
- 진행률 - 100% +
+
+ D-7 + 보통
-
-
+
UI 프로토타입 디자인
+
+ 담당자: 최유진 + 2025-10-28 마감 +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ 완료 + 보통 +
+
사용자 피드백 분석
+
+ 담당자: 김민준 + 2025-10-19 마감
@@ -1098,8 +1313,194 @@
+ + + + + + diff --git a/design/uiux/prototype/common.css b/design/uiux/prototype/common.css index c05c433..4fbb6fc 100644 --- a/design/uiux/prototype/common.css +++ b/design/uiux/prototype/common.css @@ -1759,3 +1759,132 @@ input[type="date"]::-webkit-calendar-picker-indicator { .layout-none { /* 특별한 스타일 불필요, body만 있음 */ } + +/* ======================================== + Todo Card - 공통 컴포넌트 + ======================================== */ +/* Todo 카드 - 09-Todo관리, 02-대시보드 등에서 공통 사용 */ +.todo-card { + position: relative; + background: var(--white); + padding: var(--space-md); + border-radius: var(--radius-lg); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); + margin-bottom: var(--space-sm); + transition: all var(--transition-normal); + border: 1px solid var(--gray-200); + cursor: pointer; +} + +.todo-card:hover { + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.12); + border-color: var(--primary); +} + +.todo-card.completed { + opacity: 0.5; + background: var(--gray-50); +} + +/* 레이아웃: 체크박스 + 콘텐츠 */ +.todo-top { + display: flex; + gap: var(--space-md); + align-items: flex-start; + position: relative; +} + +.todo-checkbox-wrapper { + flex-shrink: 0; + padding-top: 2px; +} + +.todo-checkbox { + width: 24px; + height: 24px; + border: 2px solid var(--gray-400); + border-radius: 6px; + cursor: pointer; + transition: all var(--transition-fast); +} + +.todo-checkbox:checked { + background: var(--success); + border-color: var(--success); +} + +.todo-content-wrapper { + flex: 1; + min-width: 0; /* 텍스트 오버플로우 방지 */ +} + +/* 배지 영역 */ +.todo-badges { + display: flex; + gap: var(--space-xs); + flex-wrap: wrap; + margin-bottom: var(--space-xs); +} + +/* Todo 제목 */ +.todo-title { + font-size: var(--font-body); + font-weight: var(--font-weight-medium); + color: var(--gray-900); + margin-bottom: var(--space-xs); + line-height: 1.5; +} + +.todo-card.completed .todo-title { + text-decoration: line-through; + color: var(--gray-500); +} + +/* 하단 메타 정보 */ +.todo-meta-row { + display: flex; + align-items: center; + gap: var(--space-sm); + font-size: var(--font-small); + color: var(--gray-500); + flex-wrap: wrap; +} + +/* 회의 링크 */ +.todo-meeting-link { + display: inline-flex; + align-items: center; + gap: 4px; + color: #4CAF50; + text-decoration: none; + font-size: var(--font-small); + cursor: pointer; + transition: color var(--transition-fast); +} + +.todo-meeting-link:hover { + color: #388E3C; + text-decoration: underline; +} + +/* 액션 버튼 */ +.todo-actions { + flex-shrink: 0; + display: flex; + gap: var(--space-xs); +} + +.icon-btn { + background: transparent; + border: none; + font-size: 18px; + color: var(--gray-600); + cursor: pointer; + padding: var(--space-xs); + transition: color var(--transition-fast); + line-height: 1; +} + +.icon-btn:hover { + color: var(--primary); +} diff --git a/design/uiux/prototype/common.js b/design/uiux/prototype/common.js index 834729c..0862488 100644 --- a/design/uiux/prototype/common.js +++ b/design/uiux/prototype/common.js @@ -65,10 +65,205 @@ const SAMPLE_MEETINGS = [ ], sections: 4, todos: 3 + }, + // 김민준이 생성한 다양한 상태의 회의 추가 + { + id: 'meeting-004', + title: '경영진 보고 회의', + date: '2025-10-26', + time: '16:00', + duration: 120, + location: '본사 1층 경영진 회의실', + status: 'scheduled', + participants: [ + { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green', role: 'creator' }, + { id: 'user-005', name: '정도현', avatar: '정', avatarColor: 'purple' } + ], + sections: 0, + todos: 0 + }, + { + id: 'meeting-005', + title: '영업 전략 회의', + date: '2025-10-18', + time: '13:00', + duration: 60, + location: 'Google Meet', + status: 'completed', + participants: [ + { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green', role: 'creator' }, + { id: 'user-002', name: '박서연', avatar: '박', avatarColor: 'blue' }, + { id: 'user-004', name: '최유진', avatar: '최', avatarColor: 'pink' } + ], + sections: 5, + todos: 6 + }, + { + id: 'meeting-006', + title: '월간 회고 미팅', + date: '2025-10-20', + time: '11:00', + duration: 90, + location: '본사 4층 라운지', + status: 'completed', + participants: [ + { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green', role: 'creator' }, + { id: 'user-003', name: '이준호', avatar: '이', avatarColor: 'yellow' }, + { id: 'user-005', name: '정도현', avatar: '정', avatarColor: 'purple' } + ], + sections: 3, + todos: 4 + } +]; + +// 샘플 회의록 데이터 (완료된 회의의 회의록만 포함) +// participantCount: 참여자 총 인원수 (회의록 작성자 포함) +const SAMPLE_MINUTES = [ + { + id: 'minutes-001', + meetingId: 'meeting-001', + title: '2025년 1분기 제품 기획 회의', + date: '2025-10-25', + time: '14:00', + status: 'draft', // complete(확정완료), draft(작성중) + participants: [ + { id: 'user-001', name: '김민준', role: 'creator' }, + { id: 'user-002', name: '박서연' }, + { id: 'user-003', name: '이준호' }, + { id: 'user-004', name: '최유진' } + ], + participantCount: 4, + lastUpdated: '2025-10-23', + completionRate: 75, + sections: 3, + todos: 5 + }, + { + id: 'minutes-002', + meetingId: 'meeting-002', + title: '주간 스크럼 회의', + date: '2025-10-21', + time: '10:00', + status: 'complete', + participants: [ + { id: 'user-002', name: '박서연', role: 'creator' }, + { id: 'user-001', name: '김민준' }, + { id: 'user-005', name: '정도현' } + ], + participantCount: 3, + lastUpdated: '2025-10-21', + sections: 2, + todos: 8 + }, + { + id: 'minutes-003', + meetingId: 'meeting-003', + title: 'AI 기능 개선 회의', + date: '2025-10-23', + time: '15:00', + status: 'complete', + participants: [ + { id: 'user-003', name: '이준호', role: 'creator' }, + { id: 'user-001', name: '김민준' } + ], + participantCount: 2, + lastUpdated: '2025-10-23', + sections: 4, + todos: 3 + }, + { + id: 'minutes-004', + meetingId: 'meeting-007', + title: '개발 리소스 계획 회의', + date: '2025-10-22', + time: '11:00', + status: 'draft', + participants: [ + { id: 'user-002', name: '박서연', role: 'creator' }, + { id: 'user-001', name: '김민준' }, + { id: 'user-003', name: '이준호' }, + { id: 'user-004', name: '최유진' }, + { id: 'user-005', name: '정도현' } + ], + participantCount: 5, + lastUpdated: '2025-10-22', + completionRate: 50, + sections: 5, + todos: 7 + }, + { + id: 'minutes-005', + meetingId: 'meeting-005', + title: '영업 전략 회의', + date: '2025-10-18', + time: '13:00', + status: 'complete', + participants: [ + { id: 'user-001', name: '김민준', role: 'creator' }, + { id: 'user-002', name: '박서연' }, + { id: 'user-004', name: '최유진' } + ], + participantCount: 3, + lastUpdated: '2025-10-18', + sections: 5, + todos: 6 + }, + { + id: 'minutes-006', + meetingId: 'meeting-006', + title: '월간 회고 미팅', + date: '2025-10-20', + time: '11:00', + status: 'complete', + participants: [ + { id: 'user-001', name: '김민준', role: 'creator' }, + { id: 'user-003', name: '이준호' }, + { id: 'user-005', name: '정도현' } + ], + participantCount: 3, + lastUpdated: '2025-10-20', + sections: 3, + todos: 4 + }, + { + id: 'minutes-007', + meetingId: 'meeting-008', + title: 'UI/UX 디자인 검토 회의', + date: '2025-10-19', + time: '14:00', + status: 'complete', + participants: [ + { id: 'user-004', name: '최유진', role: 'creator' }, + { id: 'user-001', name: '김민준' }, + { id: 'user-002', name: '박서연' }, + { id: 'user-003', name: '이준호' } + ], + participantCount: 4, + lastUpdated: '2025-10-19', + sections: 4, + todos: 5 + }, + { + id: 'minutes-008', + meetingId: 'meeting-009', + title: '경쟁사 분석 회의', + date: '2025-10-20', + time: '10:00', + status: 'complete', + participants: [ + { id: 'user-001', name: '김민준', role: 'creator' }, + { id: 'user-002', name: '박서연' }, + { id: 'user-005', name: '정도현' } + ], + participantCount: 3, + lastUpdated: '2025-10-20', + sections: 3, + todos: 2 } ]; // 샘플 Todo 데이터 +// status: not_started(미시작), completed(완료)만 사용 const SAMPLE_TODOS = [ { id: 'todo-001', @@ -76,8 +271,7 @@ const SAMPLE_TODOS = [ assignee: { id: 'user-003', name: '이준호', avatar: '이', avatarColor: 'yellow' }, dueDate: '2025-10-23', priority: 'high', - status: 'in_progress', - progress: 60, + status: 'not_started', meetingId: 'meeting-001', meetingTitle: '2025년 1분기 제품 기획 회의' }, @@ -87,8 +281,7 @@ const SAMPLE_TODOS = [ assignee: { id: 'user-003', name: '이준호', avatar: '이', avatarColor: 'yellow' }, dueDate: '2025-10-20', priority: 'high', - status: 'overdue', - progress: 80, + status: 'not_started', meetingId: 'meeting-001', meetingTitle: '2025년 1분기 제품 기획 회의' }, @@ -99,7 +292,6 @@ const SAMPLE_TODOS = [ dueDate: '2025-10-28', priority: 'medium', status: 'not_started', - progress: 0, meetingId: 'meeting-001', meetingTitle: '2025년 1분기 제품 기획 회의' }, @@ -109,8 +301,7 @@ const SAMPLE_TODOS = [ assignee: { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green' }, dueDate: '2025-10-22', priority: 'high', - status: 'in_progress', - progress: 40, + status: 'not_started', meetingId: 'meeting-002', meetingTitle: '주간 스크럼 회의' }, @@ -121,7 +312,37 @@ const SAMPLE_TODOS = [ dueDate: '2025-10-19', priority: 'medium', status: 'completed', - progress: 100, + meetingId: 'meeting-002', + meetingTitle: '주간 스크럼 회의' + }, + // 김민준에게 할당된 다양한 상태의 Todo 추가 + { + id: 'todo-006', + title: '고객사 제안서 작성', + assignee: { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green' }, + dueDate: '2025-10-19', + priority: 'high', + status: 'not_started', + meetingId: 'meeting-003', + meetingTitle: '영업 전략 회의' + }, + { + id: 'todo-007', + title: '분기 성과 보고서 검토', + assignee: { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green' }, + dueDate: '2025-10-30', + priority: 'medium', + status: 'not_started', + meetingId: 'meeting-004', + meetingTitle: '경영진 보고 회의' + }, + { + id: 'todo-008', + title: '시스템 보안 점검', + assignee: { id: 'user-001', name: '김민준', avatar: '김', avatarColor: 'green' }, + dueDate: '2025-10-18', + priority: 'low', + status: 'completed', meetingId: 'meeting-002', meetingTitle: '주간 스크럼 회의' } diff --git a/design/uiux/uiux.md b/design/uiux/uiux.md index adeacbb..e3fb6c7 100644 --- a/design/uiux/uiux.md +++ b/design/uiux/uiux.md @@ -4,7 +4,7 @@ - **작성일**: 2025-10-21 - **최종 수정일**: 2025-10-23 - **작성자**: 이미준 (서비스 기획자) -- **버전**: 1.4.8 +- **버전**: 1.4.10 - **설계 철학**: Mobile First Design --- @@ -1321,9 +1321,13 @@ graph TD - 각 카드: 결정 내용 + 결정자 + 시간 + 배경 설명 - **Todo 진행상황 섹션** (📋) + - **전체 진행률 표시**: 상단에 원형 진행 바 (완료 Todo 개수 / 전체 Todo 개수) + - 진행률 퍼센트 중앙 표시 (예: "60%") + - 색상: Primary 색상 (#4DD5A7) + - 크기: 80px (Desktop), 60px (Mobile) - 상태별 필터 탭 (전체/시작 전/진행 중/완료) - 담당자별 그룹화 - - 각 Todo: 제목 + 진행률 바 + 마감일 + 우선순위 배지 + - 각 Todo: 제목 + 마감일 + 우선순위 배지 (개별 진행률 바 제거) - **참고자료 섹션** (📚) - 참고자료 탭 (관련 회의록/프로젝트 문서/이슈 트래커/위키 페이지) @@ -2075,6 +2079,8 @@ graph TD | 1.4.6 | 2025-10-23 | 강지수 | 검증완료 섹션 잠금해제 정책 단순화
- **정책 변경**: 검증완료 섹션은 회의 생성자만 잠금 해제 후 수정 가능 (참석자는 수정 불가)
- **제거**: 참석자용 잠금해제 요청 기능 완전 제거 (공수 절감)
- **11-회의록수정**: 검증완료 섹션에 "🔒 읽기 전용" 배지 표시 (참석자 화면)
- 잠금해제요청 버튼 제거
- unlockSection() 함수 제거
- 읽기 전용 안내 텍스트 추가: "(잠금됨 · 회의 생성자만 수정 가능)"
- **06-검증완료**: 회의 생성자용 잠금해제 버튼 유지 (변경 없음)
- **인터랙션**: "3. 섹션 잠금 해제" → "3. 검증완료 섹션 (권한별 차등 표시)"로 수정
- **유저스토리**: UFR-MEET-055, UFR-COLLAB-030 권한 제어 명확화 | | 1.4.7 | 2025-10-23 | 강지수, 도그냥 | Todo 및 회의록 관련 UI/UX 재정의
- **09-Todo관리**: "Todo수정" → "Todo관리" 기능 확장
- 통계 블록: 전체(미완료), 마감임박(3일 이내), 지연(기한 경과)
- 필터 탭 개수 표시: 전체(개수), 지연(개수), 마감임박(개수), 완료(개수)
- 편집 모달: 제목, 담당자, 마감일, 우선순위 수정
- 체크박스 확인 모달: 완료/미완료 전환 시 확인
- 프로토타입: 09-Todo관리.html (통계, 필터, 모달 구현)
- **10-회의록상세조회**: 탭 순서 및 기본 노출 변경
- 탭 순서: 대시보드 → 회의록 (기존: 회의록 → 대시보드)
- 기본 활성 탭: 대시보드 (Desktop/Mobile 공통)
- 프로토타입: 10-회의록상세조회.html (탭 순서 변경, active 클래스 이동)
- **11-회의록수정**: 진입 경로 및 권한 제어 명확화
- 진입 경로: 10-회의록상세조회 → "수정" 버튼 클릭
- 권한 제어: 검증완료 전(모든 참석자), 검증완료 후(회의 생성자만)
- 회의 일시/장소: 읽기 전용 표시 추가 "(읽기 전용)"
- UI 구성: 회의록 리스트 제거, 직접 편집 화면으로 시작
- 프로토타입: 11-회의록수정.html (권한 코멘트 추가, readonly 표시) | | 1.4.8 | 2025-10-23 | 강지수 | Todo 관리 화면 UI/UX 개선 (컴팩트 디자인 및 시각적 계층 차별화)
- **09-Todo관리**: 통계 블록 및 Todo 카드 디자인 전면 개선
- **통계 블록**: 정보 표시 전용 디자인으로 변경
- 그라데이션 제거 → 모던한 단색 배경 + 좌측 4px 액센트 라인
- 상태별 연한 단색 배경 (블루 #F8FBFF / 오렌지 #FFFBF5 / 레드 #FFF8F8)
- 호버 효과 추가: 살짝 떠오르는 애니메이션 (translateY -2px)
- 미묘한 그림자로 깊이감 표현 (0 1px 3px rgba(0,0,0,0.05))
- 모바일에서도 3개 블록 한 줄 유지 (grid-template-columns: repeat(3, 1fr))
- 큰 숫자 + 작은 레이블로 정보 계층 명확화
- **Todo 카드**: 컴팩트 레이아웃으로 재설계
- 레이아웃: [체크박스] [배지] [배지] [✏️] / [제목] / [🔗 링크] [마감일]
- 편집 버튼: 우측 상단 절대 위치, ✏️ 이모지 아이콘 사용 (32×32px)
- 담당자 정보 제거 (간결한 디자인)
- 얇은 테두리 + 얇은 그림자로 인터랙티브 의도 명확화
- **Todo 편집 모달**: 모바일 전체화면 모드로 변경
- 모바일: 전체화면 (100vh), 헤더/바디/푸터 flexbox 구조
- 바디 영역만 스크롤 가능 (overflow-y: auto, -webkit-overflow-scrolling: touch)
- 데스크톱: 중앙 모달 (max-width: 600px, max-height: 90vh)
- 버튼 크기 확대 (40px) 및 가로 균등 배치 (flex: 1)
- **시각적 차별화**: 정보 블록 vs 인터랙티브 블록
- 통계 블록: 정보 표시 + 부드러운 호버 효과
- Todo 카드: 인터랙티브 (호버 시 테두리/그림자 변경)
- **프로토타입**: design/uiux/prototype/09-Todo관리.html 전면 개선 | +| 1.4.9 | 2025-10-23 | 강지수 | 회의록 상세조회 화면 Todo 진행상황 섹션 정책 추가
- **10-회의록상세조회**: Todo 진행상황 섹션에 전체 진행률 표시 추가
- **전체 진행률**: 원형 진행 바로 완료 Todo / 전체 Todo 비율 표시
- 진행률 퍼센트 중앙 표시 (예: "60%")
- 색상: Primary 색상 (#4DD5A7)
- 크기: 80px (Desktop), 60px (Mobile)
- **개별 Todo 진행률 바 제거**: Todo는 완료/미완료 상태만 존재하므로 개별 진행률 표시 불필요
- Todo 카드 구성: 제목 + 마감일 + 우선순위 배지만 표시
- **이유**: 회의록에 포함된 Todo의 전체 완료 상황을 한눈에 파악하기 위함 | +| 1.4.10 | 2025-10-23 | 강지수 | 대시보드 카드 디자인 통일 및 Todo 카드 스타일 공통화
- **02-대시보드**: 모든 카드 레이아웃 일관성 개선 (배지 우선 배치)
- **나의 Todo 카드**: 담당자 정보 제거 → 회의록 링크로 변경
- 메타 정보: 🔗 회의 제목 + 마감일 (담당자 정보 제거, 나의 Todo이므로 불필요)
- 09-Todo관리.html과 동일한 구조 적용
- **나의 회의록 카드**: 배지 + 제목 + 👑 레이아웃 통일
- 1줄: [상태배지] 제목 👑
- 2줄: 📅 날짜/시간 👥 인원수 완료율%
- **최근 회의 카드**: 배지 + 제목👑 + 메타정보 3줄 구조
- 1줄: [상태배지] 제목👑
- 2줄: 📅 날짜/시간 👥 인원수
- 3줄: 📍 장소
- **공통 스타일 관리**: Todo 카드 스타일 common.css로 이동
- common.css 1767-1890 라인에 Todo 카드 공통 스타일 추가
- 02-대시보드.html, 09-Todo관리.html에서 중복 스타일 제거 (~240줄 절감)
- 페이지별 전용 스타일만 개별 파일에 유지
- **샘플 데이터 개선**: common.js 샘플 데이터 정책 명확화
- SAMPLE_TODOS: status는 not_started/completed만 사용, progress 항목 제거
- SAMPLE_MINUTES: lastUpdated를 날짜 형식으로 변경, participantCount 의미 주석 추가, draft 상태 최소 1개 보장
- **유지보수성 향상**: 모든 화면에서 동일한 Todo 카드 디자인, 중앙 관리로 일관성 보장
- **프로토타입**: 02-대시보드.html, 09-Todo관리.html, common.css, common.js 수정 | ---