From 74f11d3bd41a2d9c9dfc73ee5a10a102f787fd15 Mon Sep 17 00:00:00 2001 From: Taehoon Date: Mon, 16 Mar 2026 17:41:46 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=8C=80=EC=8B=9C=EB=B3=B4=EB=93=9C=20?= =?UTF-8?q?=EA=B2=BD=EA=B3=A0=20=EB=B0=8F=20=EC=9C=84=ED=97=98=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=8A=A4=ED=83=80=EC=9D=BC=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/dashboard.js | 28 +++- style/common.css | 325 ++++++++++++++++------------------------------- 2 files changed, 130 insertions(+), 223 deletions(-) diff --git a/js/dashboard.js b/js/dashboard.js index 7d43ba6..b5ff1b8 100644 --- a/js/dashboard.js +++ b/js/dashboard.js @@ -120,14 +120,21 @@ function createProjectHtml(p) { const isNoFiles = (files === 0 || files === null); const statusClass = isNoFiles ? "status-error" : ""; - // 로그 텍스트 스타일 결정 (기록 없음 이거나 폴더자동삭제인 경우) - const logStyleClass = (recentLog === '기록 없음' || isStaleLog) ? 'warning-text' : ''; + // 로그 텍스트 스타일 결정 + // 폴더자동삭제는 위험(error), 기록 없음은 주의(warning) + let logStyleClass = ""; + if (isStaleLog) { + logStyleClass = "error-text"; + } else if (recentLog === "기록 없음") { + logStyleClass = "warning-text"; + } + const logBoldStyle = isStaleLog ? 'font-weight: 800;' : ''; return `
-
${name}
${dept}
${admin}
${files || 0}
${recentLog}
+
${name}
${dept}
${admin}
${files || 0}
${recentLog}
@@ -170,14 +177,25 @@ function showActivityDetails(status) { modal.style.display = 'flex'; } -function closeActivityModal() { document.getElementById('activityDetailModal').style.display = 'none'; } +function closeActivityModal() { + const modal = document.getElementById('activityDetailModal'); + if (modal) modal.style.display = 'none'; +} + +function closeAuthModal() { + const modal = document.getElementById('authModal'); + if (modal) modal.style.display = 'none'; +} function scrollToProject(name) { closeActivityModal(); const target = Array.from(document.querySelectorAll('.repo-title')).find(t => t.innerText.trim() === name.trim())?.closest('.accordion-header'); if (target) { let p = target.parentElement; - while (p && p !== document.body) { if (p.classList.contains('continent-group') || p.classList.contains('country-group')) p.classList.add('active'); p = p.parentElement; } + while (p && p !== document.body) { + if (p.classList.contains('continent-group') || p.classList.contains('country-group')) p.classList.add('active'); + p = p.parentElement; + } target.parentElement.classList.add('active'); const pos = target.getBoundingClientRect().top + window.pageYOffset - 220; window.scrollTo({ top: pos, behavior: 'smooth' }); diff --git a/style/common.css b/style/common.css index 090f80c..3ccba6a 100644 --- a/style/common.css +++ b/style/common.css @@ -1,80 +1,70 @@ :root { - /* Design Tokens */ + /* 1. Core Colors */ --primary-color: #1E5149; - --primary-lv-0: #e9eeed; - --primary-lv-1: #D2DCDB; + --primary-hover: #163b36; + --primary-lv-0: #f0f7f4; + --primary-lv-1: #e1eee9; --primary-lv-8: #193833; + --bg-default: #FFFFFF; --bg-muted: #F9FAFB; - --text-main: #2D3748; - --text-sub: #718096; - --border-color: #E2E8F0; --hover-bg: #F7FAFC; + + --text-main: #111827; + --text-sub: #6B7280; + --error-color: #F21D0D; + --border-color: #E2E8F0; + + /* 2. Gradients */ --header-gradient: linear-gradient(90deg, #193833 0%, #1e5149 100%); --ai-gradient: linear-gradient(180deg, #da8cf1 0%, #8bb1f2 100%); + + /* 3. Spacing & Radius */ --space-xs: 4px; --space-sm: 8px; --space-md: 16px; --space-lg: 32px; - --space-xl: 64px; --radius-sm: 4px; + --radius-md: 6px; --radius-lg: 8px; + --radius-xl: 12px; + + /* 4. Typography */ --fz-h1: 20px; --fz-h2: 16px; --fz-body: 13px; - --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); + --fz-small: 11px; + + /* 5. Shadows */ + --box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05); --box-shadow-lg: 0 10px 20px rgba(0, 0, 0, 0.1); + --box-shadow-modal: 0 25px 50px -12px rgba(0,0,0,0.5); + + /* 6. Layout Constants */ + --topbar-h: 36px; } /* Base Reset */ -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - +* { margin: 0; padding: 0; box-sizing: border-box; } body { - font-family: 'Pretendard', sans-serif; + font-family: 'Pretendard', -apple-system, sans-serif; font-size: var(--fz-body); color: var(--text-main); background: var(--bg-default); min-height: 100vh; } -/* 메일 관리자 전용: 전체 스크롤 방지 */ -body:has(.mail-wrapper) { - height: 100vh; - overflow: hidden; -} +/* Page Specific Overrides */ +body:has(.mail-wrapper) { height: 100vh; overflow: hidden; } -input, select, textarea, button { - font-family: 'Pretendard', sans-serif; -} +input, select, textarea, button { font-family: inherit; } +a { text-decoration: none; color: inherit; } +button { cursor: pointer; border: none; transition: all 0.2s ease; } -a { - text-decoration: none; - color: inherit; -} - -button { - cursor: pointer; - border: none; - font-family: inherit; - transition: all 0.2s ease; -} - -/* Layout Utilities */ -.flex-center { - display: flex; - align-items: center; - justify-content: center; -} - -.flex-between { - display: flex; - align-items: center; - justify-content: space-between; -} +/* Utilities */ +.flex-center { display: flex; align-items: center; justify-content: center; } +.flex-between { display: flex; align-items: center; justify-content: space-between; } +.text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* Components: Topbar */ .topbar { @@ -84,198 +74,97 @@ button { padding: 0 var(--space-lg); position: fixed; top: 0; - height: 36px; + height: var(--topbar-h); display: flex; align-items: center; - z-index: 1000; -} - -.topbar-header { - margin-right: 60px; - font-weight: 700; -} - -.topbar-header h2 { - font-size: 16px; - color: white; -} - -.nav-list { - display: flex; - list-style: none; - gap: var(--space-sm); -} - -.nav-item { - padding: 4px 8px; - border-radius: 4px; - color: rgba(255, 255, 255, 0.8); - transition: 0.2s; - font-size: 14px; - cursor: pointer; -} - -.nav-item:hover { - background: var(--primary-lv-1); - color: #fff; -} - -.nav-item.active { - background: var(--primary-lv-0); - color: var(--primary-color) !important; - font-weight: 700; -} - -/* Modals */ -.modal-overlay { - display: none; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.6); z-index: 2000; - justify-content: center; - align-items: center; } +.topbar-header h2 { font-size: 16px; color: white; margin-right: 60px; font-weight: 700; } +.nav-list { display: flex; list-style: none; gap: var(--space-sm); } +.nav-item { + padding: 4px 12px; border-radius: var(--radius-sm); + color: rgba(255, 255, 255, 0.8); font-size: 14px; +} +.nav-item:hover { background: var(--primary-lv-8); color: #fff; } +.nav-item.active { background: var(--primary-lv-0); color: var(--primary-color) !important; font-weight: 700; } +/* Components: Modals */ +.modal-overlay { + display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; + background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); + z-index: 3000; justify-content: center; align-items: center; +} .modal-content { - background: white; - padding: 24px; - border-radius: 12px; - width: 90%; - max-width: 500px; - box-shadow: var(--box-shadow-lg); + background: white; padding: 24px; border-radius: var(--radius-xl); + width: 90%; max-width: 500px; box-shadow: var(--box-shadow-modal); } - .modal-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 20px; - border-bottom: 1px solid var(--border-color); - padding-bottom: 12px; + display: flex; justify-content: space-between; align-items: center; + margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 12px; } +.modal-header h3 { margin: 0; font-size: 16px; color: var(--primary-color); font-weight: 700; } +.modal-close { cursor: pointer; font-size: 24px; color: var(--text-sub); line-height: 1; } +.modal-close:hover { color: var(--text-main); } -.modal-header h3 { - margin: 0; - font-size: 16px; -} +/* Components: Data Tables */ +.data-table { width: 100%; border-collapse: collapse; font-size: 12px; } +.data-table th, .data-table td { padding: 10px 8px; border-bottom: 1px solid var(--border-color); text-align: left; } +.data-table th { color: var(--text-sub); font-weight: 600; background: var(--bg-muted); } +.data-table tr:hover { background: var(--hover-bg); } -.modal-close { - cursor: pointer; - font-size: 20px; +/* Components: Buttons (Unified) */ +.btn { + display: inline-flex; align-items: center; justify-content: center; gap: 8px; + padding: 8px 16px; border-radius: var(--radius-lg); font-weight: 600; font-size: 13px; } +.btn-primary { background: var(--primary-color); color: #fff; } +.btn-primary:hover { background: var(--primary-hover); transform: translateY(-1px); } +.btn-secondary { background: #f1f3f5; color: #495057; } +.btn-secondary:hover { background: #e9ecef; } +.btn-danger { background: #fee2e2; color: #dc2626; } +.btn-danger:hover { background: #fecaca; } -/* Modal Form Elements */ -.select-group { - margin-bottom: 16px; - text-align: left; -} +/* Existing Utils - Compatibility */ +._button-small { @extend .btn; padding: 6px 14px; font-size: 12px; background: var(--primary-color); color: #fff; border-radius: 6px; } +._button-medium { @extend .btn; padding: 10px 20px; background: var(--primary-color); color: #fff; border-radius: 6px; font-weight: 700; } +.sync-btn { background: var(--primary-color); color: #fff; padding: 8px 16px; border-radius: 8px; font-size: 13px; font-weight: 600; } -.select-group label { - display: block; - font-size: 12px; - font-weight: 700; - color: var(--text-sub); - margin-bottom: 6px; -} +/* Badges */ +.badge { padding: 2px 8px; border-radius: 20px; font-size: 11px; font-weight: 700; display: inline-block; background: #eee; } -.modal-select { - width: 100%; - padding: 10px; - border: 1px solid var(--border-color); - border-radius: 6px; - font-size: 14px; - background: #fff; - outline: none; -} +/* Status Colors (Common) */ +.bg-success { background: #e8f5e9; color: #2e7d32; } +.bg-warning { background: #fff8e1; color: #FFBF00; } +.bg-danger { background: #ffebee; color: #dc2626; } +.bg-info { background: #e3f2fd; color: #1565c0; } -.modal-select:focus { - border-color: var(--primary-color); -} +.status-error { background: #fee9e7; } +.status-warning { background: #fff9e6; } -/* Data Tables inside Modals */ -.data-table { - width: 100%; - border-collapse: collapse; - font-size: 12px; -} - -.data-table th, -.data-table td { - padding: 10px 8px; - border-bottom: 1px solid var(--border-color); - text-align: left; -} - -.data-table th { - color: var(--text-sub); - font-weight: 600; - background: var(--bg-muted); -} - -.data-table tr:hover { - background: var(--hover-bg); -} - -/* Utils: Buttons */ -._button-xsmall { - padding: 2px 8px; - font-size: 11px; - border-radius: 4px; - background: var(--bg-muted); - border: 1px solid var(--border-color); -} - -._button-small { - padding: 6px 14px; - font-size: 12px; - border-radius: 6px; - background: var(--primary-color); - color: #fff; - font-weight: 600; -} - -._button-medium { - padding: 10px 20px; - background: var(--primary-color); - color: #fff; - border-radius: 6px; - font-weight: 700; -} - -.btn-confirm { - width: 100%; - padding: 12px; - background: var(--primary-color); - color: white; - border: none; - border-radius: 8px; - font-weight: 700; - cursor: pointer; - margin-top: 10px; -} +.warning-text { color: #FFBF00; font-weight: 600; } +.error-text { color: #F21D0D !important; font-weight: 700; } /* Spinner */ .spinner { - display: none; - width: 16px; - height: 16px; - border: 2px solid rgba(255, 255, 255, .3); - border-radius: 50%; - border-top-color: #fff; - animation: spin 1s ease-in-out infinite; + display: none; width: 16px; height: 16px; border: 2px solid rgba(255, 255, 255, .3); + border-radius: 50%; border-top-color: #fff; animation: spin 1s ease-in-out infinite; } +@keyframes spin { to { transform: rotate(360deg); } } -@keyframes spin { - to { transform: rotate(360deg); } +/* Modals (Refined) */ +.modal-overlay { + display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; + background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(4px); + z-index: 3000; justify-content: center; align-items: center; } - -.badge { - background: #eee; - padding: 2px 6px; - border-radius: 4px; - font-size: 11px; +.modal-content { + background: white; padding: 24px; border-radius: var(--radius-xl); + width: 90%; max-width: 500px; box-shadow: var(--box-shadow-modal); } +.modal-header { + display: flex; justify-content: space-between; align-items: center; + margin-bottom: 20px; border-bottom: 1px solid var(--border-color); padding-bottom: 12px; +} +.modal-header h3 { margin: 0; font-size: 16px; color: var(--primary-color); font-weight: 700; } +.modal-close { cursor: pointer; font-size: 24px; color: var(--text-sub); line-height: 1; transition: 0.2s; } +.modal-close:hover { color: var(--text-main); }