mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 06:46:24 +00:00
Merge pull request #31 from hwanny1128/wip/cleanup-uiux-files
UI/UX 문서 정리: 불필요한 백업 파일 및 참조 이미지 삭제
This commit is contained in:
commit
3bcc4d4f6b
@ -1,832 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>대시보드 - 회의록 서비스</title>
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
/* Mobile 프로필 버튼 (데스크톱에서 숨김) */
|
||||
.mobile-profile-btn {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.mobile-profile-btn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* 프로필 드롭다운 */
|
||||
.profile-dropdown {
|
||||
position: fixed;
|
||||
top: 64px;
|
||||
right: 16px;
|
||||
width: 280px;
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-lg);
|
||||
box-shadow: var(--shadow-lg);
|
||||
padding: var(--space-md);
|
||||
z-index: 2001;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.profile-dropdown.show {
|
||||
display: block;
|
||||
animation: slideDown 0.2s ease;
|
||||
}
|
||||
|
||||
.profile-dropdown-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: var(--space-md);
|
||||
border-bottom: 1px solid var(--gray-300);
|
||||
}
|
||||
|
||||
.profile-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 2000;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.profile-overlay.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop에서 프로필 드롭다운 숨김 */
|
||||
@media (min-width: 768px) {
|
||||
.profile-dropdown,
|
||||
.profile-overlay {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 대시보드 헤더 커스터마이징 */
|
||||
.header-title {
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.header-title {
|
||||
font-size: var(--font-h2);
|
||||
}
|
||||
|
||||
.header-title img {
|
||||
width: 28px !important;
|
||||
height: 28px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.header-subtitle {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.header-subtitle {
|
||||
font-size: var(--font-small);
|
||||
}
|
||||
}
|
||||
|
||||
/* 통계 카드 - common.css의 공통 스타일 사용 */
|
||||
.stat-icon {
|
||||
font-size: 24px;
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: var(--font-h2);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
/* 섹션 헤더 */
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: var(--font-h3);
|
||||
font-weight: var(--font-weight-bold);
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
.section-link {
|
||||
font-size: var(--font-small);
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.section-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 회의 카드 */
|
||||
.meeting-grid {
|
||||
display: grid;
|
||||
gap: var(--space-md);
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.meeting-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.meeting-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1440px) {
|
||||
.meeting-grid {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
.meeting-card {
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-lg);
|
||||
box-shadow: var(--shadow-sm);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.meeting-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.meeting-card.ongoing {
|
||||
border-left: 4px solid var(--ongoing);
|
||||
}
|
||||
|
||||
.meeting-card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
.meeting-card-title {
|
||||
font-size: var(--font-body);
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-900);
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.meeting-card-meta {
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
.meeting-card-meta-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.meeting-card-actions {
|
||||
display: flex;
|
||||
gap: var(--space-sm);
|
||||
margin-top: var(--space-md);
|
||||
}
|
||||
|
||||
/* Todo 리스트 */
|
||||
.todo-list {
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
.todo-item {
|
||||
padding: var(--space-md);
|
||||
border-bottom: 1px solid var(--gray-200);
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast);
|
||||
}
|
||||
|
||||
.todo-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.todo-item:hover {
|
||||
background: var(--gray-50);
|
||||
}
|
||||
|
||||
.todo-item.overdue {
|
||||
border-left: 4px solid var(--error);
|
||||
padding-left: calc(var(--space-md) - 4px);
|
||||
}
|
||||
|
||||
.todo-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
.todo-title {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-900);
|
||||
}
|
||||
|
||||
.todo-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-md);
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
.todo-progress {
|
||||
margin-top: var(--space-sm);
|
||||
}
|
||||
|
||||
/* 회의록 리스트 */
|
||||
.minutes-list {
|
||||
background: var(--white);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--space-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
.minutes-item {
|
||||
padding: var(--space-md);
|
||||
border-bottom: 1px solid var(--gray-200);
|
||||
cursor: pointer;
|
||||
transition: background var(--transition-fast);
|
||||
}
|
||||
|
||||
.minutes-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.minutes-item:hover {
|
||||
background: var(--gray-50);
|
||||
}
|
||||
|
||||
.minutes-item-title {
|
||||
font-weight: var(--font-weight-medium);
|
||||
color: var(--gray-900);
|
||||
margin-bottom: var(--space-xs);
|
||||
}
|
||||
|
||||
.minutes-item-meta {
|
||||
font-size: var(--font-small);
|
||||
color: var(--gray-500);
|
||||
display: flex;
|
||||
gap: var(--space-md);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 빈 상태 */
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: var(--space-xxl);
|
||||
color: var(--gray-500);
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
section {
|
||||
margin-bottom: var(--space-xl);
|
||||
}
|
||||
|
||||
/* 플로팅 액션 메뉴 */
|
||||
.fab-menu {
|
||||
position: fixed;
|
||||
bottom: 160px; /* 모바일: FAB 버튼(88px) + FAB 높이(56px) + 여백(16px) */
|
||||
right: var(--space-lg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-md);
|
||||
z-index: 999;
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
pointer-events: none;
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.fab-menu.active {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
/* FAB 메뉴 아이템 & FAB 버튼 공통 스타일 */
|
||||
.fab-menu-item,
|
||||
.fab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 100px;
|
||||
height: 56px;
|
||||
background: var(--primary);
|
||||
border: none;
|
||||
border-radius: 28px;
|
||||
padding: 0 var(--space-md);
|
||||
cursor: pointer;
|
||||
transition: all var(--transition-fast);
|
||||
color: var(--white);
|
||||
font-size: 14px;
|
||||
font-weight: var(--font-weight-semibold);
|
||||
box-shadow: var(--shadow-fab);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.fab-menu-item:hover,
|
||||
.fab:hover {
|
||||
background: var(--primary-dark);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.fab-menu-item:active,
|
||||
.fab:active {
|
||||
transform: translateY(0) scale(0.98);
|
||||
}
|
||||
|
||||
/* FAB 회전 효과 제거 */
|
||||
.fab.active {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
/* 오버레이 */
|
||||
.fab-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
z-index: 998;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: opacity var(--transition-normal);
|
||||
}
|
||||
|
||||
.fab-overlay.active {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
/* 데스크톱에서 위치 조정 */
|
||||
@media (min-width: 768px) {
|
||||
.fab-menu {
|
||||
bottom: 96px; /* 데스크톱: FAB 버튼(24px) + FAB 높이(56px) + 여백(16px) */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="layout-sidebar-header">
|
||||
<!-- 사이드바 (데스크톱) -->
|
||||
<aside class="sidebar">
|
||||
<a href="02-대시보드.html" class="sidebar-logo">
|
||||
<img src="img/cicle.png" alt="로고" class="sidebar-logo-icon-img">
|
||||
<div class="sidebar-logo-text">회의록 서비스</div>
|
||||
</a>
|
||||
|
||||
<nav class="sidebar-nav">
|
||||
<a href="12-회의록목록조회.html" class="sidebar-nav-item">
|
||||
<span class="sidebar-nav-icon"><img src="img/edit.png" width="32"></span>
|
||||
<span>회의 목록</span>
|
||||
</a>
|
||||
<a href="09-Todo관리.html" class="sidebar-nav-item">
|
||||
<span class="sidebar-nav-icon"><img src="img/list.png" width="32"></span>
|
||||
<span>Todo 관리</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- 사용자 정보 영역 (Desktop) -->
|
||||
<div class="sidebar-user">
|
||||
<div class="avatar avatar-green">김</div>
|
||||
<div class="sidebar-user-info">
|
||||
<div class="sidebar-user-name">김민준</div>
|
||||
<div class="sidebar-user-email">minjun.kim@company.com</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-ghost" style="width: calc(100% - 32px); margin: 0 16px 16px;" onclick="logout()">로그아웃</button>
|
||||
</aside>
|
||||
|
||||
<!-- 헤더 -->
|
||||
<header class="header">
|
||||
<div class="header-left">
|
||||
<h1 class="header-title"><img src="img/hi.png" alt="" style="width: 18px; height: 18px; vertical-align: middle; margin-right: 6px;">안녕하세요, 김민준님!</h1>
|
||||
<p class="header-subtitle">오늘의 일정을 확인하세요</p>
|
||||
</div>
|
||||
<!-- Mobile 프로필 아이콘 -->
|
||||
<button class="icon-btn mobile-profile-btn" onclick="toggleProfileMenu()" title="프로필">
|
||||
👤
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<!-- Mobile 프로필 드롭다운 -->
|
||||
<div class="profile-dropdown" id="profileDropdown">
|
||||
<div class="profile-dropdown-header">
|
||||
<div class="avatar avatar-green">김</div>
|
||||
<div style="margin-left: 12px;">
|
||||
<div style="font-weight: 600; font-size: 14px; color: var(--gray-900);">김민준</div>
|
||||
<div style="font-size: 12px; color: var(--gray-500);">minjun.kim@company.com</div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-ghost" style="width: 100%; margin-top: 12px;" onclick="logout()">로그아웃</button>
|
||||
</div>
|
||||
<div class="profile-overlay" id="profileOverlay" onclick="toggleProfileMenu()"></div>
|
||||
|
||||
<!-- 메인 콘텐츠 -->
|
||||
<main class="main-content">
|
||||
|
||||
<!-- 통계 -->
|
||||
<section class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">📅</div>
|
||||
<div class="stat-label">예정된 회의</div>
|
||||
<div class="stat-value" id="stat-scheduled">3</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">✅</div>
|
||||
<div class="stat-label">진행 중 Todo</div>
|
||||
<div class="stat-value" id="stat-todos">1</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon">📈</div>
|
||||
<div class="stat-label">Todo 완료율</div>
|
||||
<div class="stat-value" id="stat-completion">33%</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 최근 회의 -->
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">최근 회의</h2>
|
||||
<a href="12-회의록목록조회.html" class="section-link">전체 보기 →</a>
|
||||
</div>
|
||||
<div class="meeting-grid" id="recent-meetings">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 할당된 Todo -->
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">할당된 Todo</h2>
|
||||
<a href="09-Todo관리.html" class="section-link">전체 보기 →</a>
|
||||
</div>
|
||||
<div class="todo-list" id="my-todos">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 내 회의록 -->
|
||||
<section>
|
||||
<div class="section-header">
|
||||
<h2 class="section-title">내 회의록</h2>
|
||||
<a href="12-회의록목록조회.html" class="section-link">전체 보기 →</a>
|
||||
</div>
|
||||
<div class="minutes-list" id="my-minutes">
|
||||
<!-- 동적 생성 -->
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<!-- 하단 네비게이션 (모바일) -->
|
||||
<nav class="bottom-nav">
|
||||
<a href="02-대시보드.html" class="nav-item active">
|
||||
<img src="img/home.png" alt="홈" style="width: 45px;">
|
||||
</a>
|
||||
<a href="12-회의록목록조회.html" class="nav-item">
|
||||
<img src="img/edit.png" alt="회의록" style="width: 45px;">
|
||||
</a>
|
||||
<a href="09-Todo관리.html" class="nav-item">
|
||||
<img src="img/list.png" alt="Todo" style="width: 45px;">
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<!-- FAB 오버레이 -->
|
||||
<div class="fab-overlay" id="fabOverlay"></div>
|
||||
|
||||
<!-- FAB 확장 메뉴 (단일 버튼) -->
|
||||
<div class="fab-menu" id="fabMenu">
|
||||
<button class="fab-menu-item" id="quickStartBtn" title="바로 시작">
|
||||
바로시작
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- FAB (Floating Action Button) - 회의 예약 -->
|
||||
<button class="fab" id="fabButton" title="회의 예약">
|
||||
회의예약
|
||||
</button>
|
||||
|
||||
<script src="common.js"></script>
|
||||
<script>
|
||||
/**
|
||||
* 대시보드 초기화
|
||||
*/
|
||||
|
||||
// 로그인 체크
|
||||
if (!getFromStorage('isLoggedIn')) {
|
||||
navigateTo('01-로그인.html');
|
||||
}
|
||||
|
||||
const currentUser = getFromStorage('currentUser') || CURRENT_USER;
|
||||
|
||||
/**
|
||||
* 최근 회의 렌더링
|
||||
*/
|
||||
function renderRecentMeetings() {
|
||||
const container = $('#recent-meetings');
|
||||
|
||||
// 진행중 우선, 날짜순 정렬
|
||||
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);
|
||||
})
|
||||
.slice(0, 3);
|
||||
|
||||
container.innerHTML = meetings.map(meeting => {
|
||||
const statusInfo = getMeetingStatusInfo(meeting);
|
||||
const isCreator = meeting.participants.some(p => p.id === currentUser.id && p.role === 'creator');
|
||||
|
||||
return `
|
||||
<div class="meeting-card ${meeting.status === 'ongoing' ? 'ongoing' : ''}" data-id="${meeting.id}">
|
||||
<div class="meeting-card-header">
|
||||
<div>
|
||||
${createBadge(statusInfo.badgeText, statusInfo.badgeType)}
|
||||
${isCreator ? ' <span>👑</span>' : ''}
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="meeting-card-title">${meeting.title}</h3>
|
||||
<div class="meeting-card-meta">
|
||||
<div class="meeting-card-meta-item">📅 ${formatDate(meeting.date)} ${formatTime(meeting.time)}</div>
|
||||
<div class="meeting-card-meta-item">📍 ${meeting.location}</div>
|
||||
<div class="meeting-card-meta-item">👥 ${meeting.participants.length}명</div>
|
||||
</div>
|
||||
<div class="meeting-card-actions">
|
||||
${meeting.status === 'ongoing'
|
||||
? `<button class="btn btn-primary btn-sm" onclick="navigateTo('05-회의진행.html'); event.stopPropagation();">참여하기</button>`
|
||||
: meeting.status === 'scheduled' && isCreator
|
||||
? `<button class="btn btn-secondary btn-sm" onclick="navigateTo('03-회의예약.html'); event.stopPropagation();">수정</button>`
|
||||
: `<button class="btn btn-ghost btn-sm" onclick="navigateTo('10-회의록상세조회.html'); event.stopPropagation();">보기</button>`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
// 클릭 이벤트
|
||||
$$('.meeting-card').forEach(card => {
|
||||
card.addEventListener('click', (e) => {
|
||||
if (e.target.tagName !== 'BUTTON') {
|
||||
const meetingId = card.dataset.id;
|
||||
const meeting = SAMPLE_MEETINGS.find(m => m.id === meetingId);
|
||||
if (meeting.status === 'ongoing') {
|
||||
navigateTo('05-회의진행.html');
|
||||
} else if (meeting.status === 'completed') {
|
||||
navigateTo('10-회의록상세조회.html');
|
||||
} else {
|
||||
navigateTo('03-회의예약.html');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 내 Todo 렌더링
|
||||
*/
|
||||
function renderMyTodos() {
|
||||
const container = $('#my-todos');
|
||||
|
||||
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];
|
||||
})
|
||||
.slice(0, 5);
|
||||
|
||||
if (myTodos.length === 0) {
|
||||
container.innerHTML = '<div class="empty-state"><div class="empty-icon">✅</div><p>할당된 Todo가 없습니다</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = myTodos.map(todo => {
|
||||
const statusInfo = getTodoStatusInfo(todo);
|
||||
const isOverdue = calculateDday(todo.dueDate) < 0 && todo.status !== 'completed';
|
||||
|
||||
return `
|
||||
<div class="todo-item ${isOverdue ? 'overdue' : ''}" data-todo-id="${todo.id}" data-meeting-id="${todo.meetingId}">
|
||||
<div class="todo-header">
|
||||
<h4 class="todo-title">${todo.title}</h4>
|
||||
${createBadge(statusInfo.badgeText, statusInfo.badgeType)}
|
||||
</div>
|
||||
<div class="todo-meta">
|
||||
<span>마감: ${formatDate(todo.dueDate)}</span>
|
||||
${createBadge(todo.priority === 'high' ? '높음' : todo.priority === 'medium' ? '보통' : '낮음', todo.priority)}
|
||||
</div>
|
||||
<div class="todo-progress">
|
||||
${createProgressBar(todo.progress)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
// Todo 항목 클릭 시 해당 회의록 상세로 이동
|
||||
$$('.todo-item').forEach(item => {
|
||||
item.addEventListener('click', () => {
|
||||
const meetingId = item.dataset.meetingId;
|
||||
const todoId = item.dataset.todoId;
|
||||
// 회의록 상세 페이지로 이동 (Todo ID를 파라미터로 전달)
|
||||
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);
|
||||
|
||||
if (myMeetings.length === 0) {
|
||||
container.innerHTML = '<div class="empty-state"><div class="empty-icon">📝</div><p>작성한 회의록이 없습니다</p></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = myMeetings.map(meeting => {
|
||||
const statusInfo = getMeetingStatusInfo(meeting);
|
||||
return `
|
||||
<div class="minutes-item" onclick="navigateTo('10-회의록상세조회.html')">
|
||||
<h4 class="minutes-item-title">${meeting.title}</h4>
|
||||
<div class="minutes-item-meta">
|
||||
<span>📅 ${formatDate(meeting.date)}</span>
|
||||
<span>👥 ${meeting.participants.length}명</span>
|
||||
${createBadge(statusInfo.badgeText, statusInfo.badgeType)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* 통계 업데이트
|
||||
*/
|
||||
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;
|
||||
|
||||
$('#stat-scheduled').textContent = scheduled;
|
||||
$('#stat-todos').textContent = todos;
|
||||
$('#stat-completion').textContent = completion + '%';
|
||||
}
|
||||
|
||||
/**
|
||||
* 초기화
|
||||
*/
|
||||
function init() {
|
||||
updateStats();
|
||||
renderRecentMeetings();
|
||||
renderMyTodos();
|
||||
renderMyMinutes();
|
||||
|
||||
console.log('대시보드 초기화 완료');
|
||||
}
|
||||
|
||||
/**
|
||||
* FAB 메뉴 토글
|
||||
*/
|
||||
let fabMenuOpen = false;
|
||||
|
||||
function toggleFabMenu() {
|
||||
fabMenuOpen = !fabMenuOpen;
|
||||
const fabButton = $('#fabButton');
|
||||
const fabMenu = $('#fabMenu');
|
||||
const fabOverlay = $('#fabOverlay');
|
||||
|
||||
if (fabMenuOpen) {
|
||||
fabButton.classList.add('active');
|
||||
fabMenu.classList.add('active');
|
||||
fabOverlay.classList.add('active');
|
||||
} else {
|
||||
fabButton.classList.remove('active');
|
||||
fabMenu.classList.remove('active');
|
||||
fabOverlay.classList.remove('active');
|
||||
}
|
||||
}
|
||||
|
||||
function closeFabMenu() {
|
||||
if (fabMenuOpen) {
|
||||
toggleFabMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FAB 오버레이 클릭 시 메뉴 닫기
|
||||
*/
|
||||
$('#fabOverlay').addEventListener('click', () => {
|
||||
closeFabMenu();
|
||||
});
|
||||
|
||||
/**
|
||||
* play 버튼 (새 회의 시작) 클릭
|
||||
*/
|
||||
$('#quickStartBtn').addEventListener('click', () => {
|
||||
closeFabMenu();
|
||||
// 새 회의 생성 화면으로 이동
|
||||
navigateTo('04-템플릿선택.html');
|
||||
});
|
||||
|
||||
/**
|
||||
* FAB 버튼 (add 이미지) 클릭
|
||||
* - 메뉴 닫혀있을 때: play 버튼 확장
|
||||
* - 메뉴 열려있을 때: 회의 예약 화면으로 이동
|
||||
*/
|
||||
$('#fabButton').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (fabMenuOpen) {
|
||||
// 이미 메뉴가 열려있으면 회의 예약 화면으로 이동
|
||||
closeFabMenu();
|
||||
navigateTo('03-회의예약.html');
|
||||
} else {
|
||||
// 메뉴가 닫혀있으면 play 버튼 표시
|
||||
toggleFabMenu();
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 프로필 메뉴 토글 (Mobile)
|
||||
*/
|
||||
function toggleProfileMenu() {
|
||||
const dropdown = $('#profileDropdown');
|
||||
const overlay = $('#profileOverlay');
|
||||
|
||||
dropdown.classList.toggle('show');
|
||||
overlay.classList.toggle('show');
|
||||
}
|
||||
|
||||
/**
|
||||
* 로그아웃
|
||||
*/
|
||||
function logout() {
|
||||
if (confirm('로그아웃 하시겠습니까?')) {
|
||||
// 로컬 스토리지 초기화
|
||||
localStorage.removeItem('isLoggedIn');
|
||||
localStorage.removeItem('currentUser');
|
||||
|
||||
// 로그인 페이지로 이동
|
||||
navigateTo('01-로그인.html');
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 43 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB |
2167
design/uiux/uiux.md
2167
design/uiux/uiux.md
File diff suppressed because it is too large
Load Diff
1139
design/userstory.md
1139
design/userstory.md
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user