diff --git a/styles/base.css b/styles/base.css new file mode 100644 index 0000000..792282e --- /dev/null +++ b/styles/base.css @@ -0,0 +1,78 @@ +/** + * Base Styles - 基礎樣式 + * 包含 CSS 變數定義、CSS Reset、全域樣式 + */ + +/* ==================== CSS Variables ==================== */ +:root { + /* 主題色 */ + --primary: #1a5276; + --primary-light: #2980b9; + --primary-dark: #0e3a53; + --accent: #e67e22; + --accent-light: #f39c12; + --green: #27ae60; + --green-dark: #1e8449; + + /* 背景色 */ + --bg-main: #f4f6f9; + --bg-card: #ffffff; + --border: #d5dbdf; + + /* 文字顏色 */ + --text-primary: #2c3e50; + --text-secondary: #5d6d7e; + + /* 語義化顏色 */ + --success: #27ae60; + --warning: #f39c12; + --danger: #e74c3c; + + /* 陰影與圓角 */ + --shadow: 0 4px 20px rgba(26, 82, 118, 0.12); + --radius: 8px; +} + +/* ==================== CSS Reset ==================== */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +/* ==================== Global Styles ==================== */ +body { + font-family: 'Noto Sans TC', -apple-system, BlinkMacSystemFont, sans-serif; + background: linear-gradient(135deg, #e8f4fc 0%, #f4f6f9 100%); + min-height: 100vh; + color: var(--text-primary); +} + +/* ==================== Animations ==================== */ +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(8px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes modalIn { + from { + opacity: 0; + transform: scale(0.9); + } + to { + opacity: 1; + transform: scale(1); + } +} diff --git a/styles/components.css b/styles/components.css new file mode 100644 index 0000000..420a109 --- /dev/null +++ b/styles/components.css @@ -0,0 +1,562 @@ +/** + * Components Styles - 元件樣式 + * 包含按鈕、表單、卡片、頁籤、彈窗、Toast 等可重用元件 + */ + +/* ==================== Tabs ==================== */ +.tabs { + display: flex; + background: #f8fafc; + border-bottom: 2px solid var(--border); +} + +.tab-btn { + padding: 16px 32px; + border: none; + background: transparent; + font-family: inherit; + font-size: 0.95rem; + font-weight: 500; + color: var(--text-secondary); + cursor: pointer; + position: relative; + transition: all 0.3s ease; +} + +.tab-btn:hover { + color: var(--primary); + background: rgba(26, 82, 118, 0.05); +} + +.tab-btn.active { + color: var(--primary); + background: var(--bg-card); +} + +.tab-btn.active::after { + content: ''; + position: absolute; + bottom: -2px; + left: 0; + right: 0; + height: 3px; + background: var(--primary); + border-radius: 2px 2px 0 0; +} + +.tab-content { + display: none; + padding: 28px; + animation: fadeIn 0.3s ease; +} + +.tab-content.active { + display: block; +} + +/* ==================== Form Elements ==================== */ +.form-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 20px 32px; +} + +.form-grid.three-cols { + grid-template-columns: repeat(3, 1fr); +} + +.form-group { + display: flex; + flex-direction: column; + gap: 6px; +} + +.form-group.full-width { + grid-column: 1 / -1; +} + +.form-group label { + font-size: 0.875rem; + font-weight: 500; + color: var(--text-secondary); + display: flex; + align-items: center; + gap: 4px; +} + +.form-group label .required { + color: var(--danger); + font-weight: 600; +} + +.input-wrapper { + display: flex; + gap: 8px; + align-items: center; +} + +input[type="text"], +input[type="number"], +input[type="date"], +select, +textarea { + width: 100%; + padding: 10px 14px; + border: 1.5px solid var(--border); + border-radius: 6px; + font-family: inherit; + font-size: 0.9rem; + color: var(--text-primary); + background: #fafbfc; + transition: all 0.2s ease; +} + +input:focus, +select:focus, +textarea:focus { + outline: none; + border-color: var(--primary-light); + background: #ffffff; + box-shadow: 0 0 0 3px rgba(41, 128, 185, 0.1); +} + +input:read-only { + background: #f0f3f5; + color: var(--text-secondary); + cursor: default; +} + +textarea { + min-height: 100px; + resize: vertical; +} + +select { + cursor: pointer; + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%235d6d7e' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 12px center; + padding-right: 36px; +} + +/* ==================== Buttons ==================== */ +.btn { + padding: 12px 24px; + border: none; + border-radius: 6px; + font-family: inherit; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + transition: all 0.2s ease; +} + +.btn-primary { + background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); + color: white; + box-shadow: 0 2px 8px rgba(26, 82, 118, 0.3); +} + +.btn-primary:hover { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(26, 82, 118, 0.4); +} + +.btn-secondary { + background: white; + color: var(--primary); + border: 1.5px solid var(--primary); +} + +.btn-secondary:hover { + background: rgba(26, 82, 118, 0.05); +} + +.btn-cancel { + background: #f0f3f5; + color: var(--text-secondary); +} + +.btn-cancel:hover { + background: #e5e9ec; +} + +.btn svg { + width: 18px; + height: 18px; + fill: currentColor; +} + +.btn-lookup { + padding: 10px 16px; + border: 1.5px solid var(--border); + border-radius: 6px; + background: #f8fafc; + color: var(--text-secondary); + font-size: 0.85rem; + cursor: pointer; + transition: all 0.2s ease; + white-space: nowrap; +} + +.btn-lookup:hover { + background: var(--primary); + color: white; + border-color: var(--primary); +} + +.btn-icon { + width: 38px; + height: 38px; + border: 1.5px solid var(--border); + border-radius: 6px; + background: #f8fafc; + color: var(--text-secondary); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; +} + +.btn-icon:hover { + background: var(--primary); + color: white; + border-color: var(--primary); +} + +.btn-icon svg { + width: 18px; + height: 18px; + fill: currentColor; +} + +.nav-buttons { + display: flex; + gap: 8px; +} + +.nav-btn { + width: 36px; + height: 36px; + border: 1.5px solid var(--border); + border-radius: 6px; + background: white; + color: var(--text-secondary); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; +} + +.nav-btn:hover { + border-color: var(--primary); + color: var(--primary); +} + +.nav-btn svg { + width: 16px; + height: 16px; + fill: currentColor; +} + +/* ==================== AI Button ==================== */ +.ai-generate-btn { + display: flex; + align-items: center; + gap: 8px; + padding: 12px 24px; + margin-bottom: 24px; + background: linear-gradient(135deg, #9b59b6 0%, #8e44ad 100%); + color: white; + border: none; + border-radius: var(--radius); + font-family: inherit; + font-size: 0.95rem; + font-weight: 600; + cursor: pointer; + box-shadow: 0 4px 15px rgba(155, 89, 182, 0.3); + transition: all 0.3s ease; +} + +.ai-generate-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(155, 89, 182, 0.4); +} + +.ai-generate-btn:disabled { + opacity: 0.7; + cursor: not-allowed; + transform: none; +} + +.ai-generate-btn svg { + width: 20px; + height: 20px; + fill: currentColor; +} + +.ai-generate-btn .spinner { + width: 20px; + height: 20px; + border: 2px solid rgba(255, 255, 255, 0.3); + border-top-color: white; + border-radius: 50%; + animation: spin 0.8s linear infinite; +} + +/* ==================== Form Actions ==================== */ +.form-actions { + display: flex; + justify-content: space-between; + align-items: center; + padding: 20px 28px; + background: #f8fafc; + border-top: 1px solid var(--border); +} + +.action-buttons { + display: flex; + gap: 12px; +} + +/* ==================== Toggle Switch ==================== */ +.toggle-group { + display: flex; + align-items: center; + gap: 12px; +} + +.toggle-switch { + position: relative; + width: 52px; + height: 28px; +} + +.toggle-switch input { + opacity: 0; + width: 0; + height: 0; +} + +.toggle-slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + transition: 0.3s; + border-radius: 28px; +} + +.toggle-slider:before { + position: absolute; + content: ""; + height: 22px; + width: 22px; + left: 3px; + bottom: 3px; + background-color: white; + transition: 0.3s; + border-radius: 50%; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.toggle-switch input:checked + .toggle-slider { + background-color: var(--success); +} + +.toggle-switch input:checked + .toggle-slider:before { + transform: translateX(24px); +} + +.toggle-label { + font-size: 0.9rem; + color: var(--text-secondary); +} + +/* ==================== Toast Notification ==================== */ +.toast { + position: fixed; + top: 24px; + right: 24px; + padding: 16px 24px; + background: var(--success); + color: white; + border-radius: var(--radius); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); + display: flex; + align-items: center; + gap: 12px; + transform: translateX(120%); + transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55); + z-index: 1000; +} + +.toast.show { + transform: translateX(0); +} + +.toast svg { + width: 24px; + height: 24px; + fill: currentColor; +} + +/* ==================== Modal ==================== */ +.modal-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.5); + display: none; + align-items: center; + justify-content: center; + z-index: 100; + backdrop-filter: blur(4px); +} + +.modal-overlay.show { + display: flex; +} + +.modal { + background: white; + border-radius: var(--radius); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); + width: 90%; + max-width: 500px; + animation: modalIn 0.3s ease; +} + +.modal-header { + padding: 20px 24px; + border-bottom: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: center; +} + +.modal-header h3 { + font-size: 1.1rem; + font-weight: 600; +} + +.modal-close { + width: 32px; + height: 32px; + border: none; + background: #f0f3f5; + border-radius: 6px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; +} + +.modal-close:hover { + background: var(--danger); + color: white; +} + +.modal-body { + padding: 24px; +} + +.modal-footer { + padding: 16px 24px; + border-top: 1px solid var(--border); + display: flex; + justify-content: flex-end; + gap: 12px; +} + +/* ==================== Checkbox Group ==================== */ +.checkbox-group { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 12px; +} + +.checkbox-item { + display: flex; + align-items: center; + gap: 8px; + padding: 10px 12px; + border: 1.5px solid var(--border); + border-radius: 6px; + cursor: pointer; + transition: all 0.2s ease; +} + +.checkbox-item:hover { + border-color: var(--primary-light); + background: rgba(41, 128, 185, 0.05); +} + +.checkbox-item input { + width: 18px; + height: 18px; + accent-color: var(--primary); +} + +.checkbox-item label { + cursor: pointer; + font-size: 0.9rem; +} + +/* ==================== Special Fields ==================== */ +.confidential-field { + position: relative; +} + +.confidential-field input { + padding-left: 32px; +} + +.confidential-field::before { + content: '🔒'; + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); + font-size: 14px; +} + +.numbered-textarea { + font-family: inherit; + line-height: 1.8; +} + +/* ==================== Data Preview ==================== */ +.data-preview { + margin-top: 24px; + padding: 20px; + background: #f8fafc; + border-radius: var(--radius); + border: 1px solid var(--border); +} + +.data-preview h4 { + font-size: 0.9rem; + color: var(--text-secondary); + margin-bottom: 12px; +} + +.data-preview pre { + font-family: 'Monaco', 'Consolas', monospace; + font-size: 0.8rem; + background: #2c3e50; + color: #ecf0f1; + padding: 16px; + border-radius: 6px; + overflow-x: auto; + max-height: 300px; +} diff --git a/styles/layout.css b/styles/layout.css new file mode 100644 index 0000000..ad32518 --- /dev/null +++ b/styles/layout.css @@ -0,0 +1,257 @@ +/** + * Layout Styles - 布局樣式 + * 包含容器、整體布局、Header、模組切換器 + */ + +/* ==================== Container ==================== */ +.app-container { + max-width: 1200px; + margin: 0 auto; + padding: 24px; +} + +/* ==================== User Info Bar ==================== */ +.user-info-bar { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + border-radius: var(--radius); + padding: 12px 20px; + margin-bottom: 20px; + display: flex; + justify-content: space-between; + align-items: center; + box-shadow: var(--shadow); +} + +.user-info { + display: flex; + align-items: center; + gap: 12px; + color: #ffffff; +} + +.user-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.2); + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 1.1rem; +} + +.user-details { + display: flex; + flex-direction: column; +} + +.user-name { + font-weight: 600; + font-size: 1rem; +} + +.user-role { + font-size: 0.85rem; + opacity: 0.9; +} + +.logout-btn { + padding: 8px 20px; + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 6px; + background: rgba(255, 255, 255, 0.1); + color: #ffffff; + font-family: inherit; + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + transition: all 0.3s ease; +} + +.logout-btn:hover { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.5); + transform: translateY(-2px); +} + +.logout-btn svg { + width: 18px; + height: 18px; + fill: currentColor; +} + +/* ==================== Module Selector ==================== */ +.module-selector { + display: flex; + gap: 12px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.module-btn { + flex: 1; + min-width: 200px; + padding: 14px 20px; + border: 2px solid var(--border); + border-radius: var(--radius); + background: var(--bg-card); + font-family: inherit; + font-size: 0.95rem; + font-weight: 500; + color: var(--text-secondary); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + transition: all 0.3s ease; +} + +.module-btn:hover { + border-color: var(--primary-light); + color: var(--primary); + transform: translateY(-2px); + box-shadow: var(--shadow); +} + +.module-btn.active { + background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); + border-color: var(--primary); + color: white; + box-shadow: 0 4px 15px rgba(26, 82, 118, 0.3); +} + +.module-btn.active.job-active { + background: linear-gradient(135deg, var(--accent) 0%, #d35400 100%); + border-color: var(--accent); + box-shadow: 0 4px 15px rgba(230, 126, 34, 0.3); +} + +.module-btn.active.desc-active { + background: linear-gradient(135deg, var(--green) 0%, var(--green-dark) 100%); + border-color: var(--green); + box-shadow: 0 4px 15px rgba(39, 174, 96, 0.3); +} + +.module-btn svg { + width: 22px; + height: 22px; + fill: currentColor; +} + +.module-content { + display: none; +} + +.module-content.active { + display: block; + animation: fadeIn 0.3s ease; +} + +/* ==================== App Header ==================== */ +.app-header { + display: flex; + align-items: center; + gap: 16px; + margin-bottom: 24px; + padding: 20px 28px; + background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%); + border-radius: var(--radius); + box-shadow: var(--shadow); +} + +.app-header.job-header { + background: linear-gradient(135deg, var(--accent) 0%, #d35400 100%); +} + +.app-header.desc-header { + background: linear-gradient(135deg, var(--green) 0%, var(--green-dark) 100%); +} + +.app-header .icon { + width: 48px; + height: 48px; + background: rgba(255, 255, 255, 0.15); + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; +} + +.app-header .icon svg { + width: 28px; + height: 28px; + fill: #ffffff; +} + +.app-header h1 { + color: #ffffff; + font-size: 1.5rem; + font-weight: 600; +} + +.app-header .subtitle { + color: rgba(255, 255, 255, 0.7); + font-size: 0.875rem; + margin-top: 2px; +} + +/* ==================== Form Card ==================== */ +.form-card { + background: var(--bg-card); + border-radius: var(--radius); + box-shadow: var(--shadow); + overflow: hidden; +} + +/* ==================== Sections ==================== */ +.section-box { + background: #f8fafc; + border: 1px solid var(--border); + border-radius: var(--radius); + margin-bottom: 20px; +} + +.section-header { + padding: 12px 16px; + background: linear-gradient(135deg, #e8f4fc 0%, #f0f4f8 100%); + border-bottom: 1px solid var(--border); + font-weight: 600; + font-size: 0.9rem; + color: var(--primary); +} + +.section-header.green { + background: linear-gradient(135deg, #e8f8f0 0%, #f0f8f4 100%); + color: var(--green-dark); +} + +.section-body { + padding: 20px; +} + +.section-divider { + grid-column: 1 / -1; + display: flex; + align-items: center; + gap: 12px; + margin: 8px 0; +} + +.section-divider span { + font-size: 0.85rem; + font-weight: 600; + color: var(--primary); + white-space: nowrap; +} + +.section-divider::after { + content: ''; + flex: 1; + height: 1px; + background: linear-gradient(to right, var(--border), transparent); +} diff --git a/styles/modules.css b/styles/modules.css new file mode 100644 index 0000000..8dc5bf6 --- /dev/null +++ b/styles/modules.css @@ -0,0 +1,27 @@ +/** + * Modules Styles - 模組專屬樣式 + * 包含各個頁籤/模組的特定樣式需求 + */ + +/* ==================== 崗位基礎資料模組 ==================== */ +/* (目前使用共用元件,無特殊樣式) */ + +/* ==================== 職務基礎資料模組 ==================== */ +/* (目前使用共用元件,無特殊樣式) */ + +/* ==================== 部門職責模組 ==================== */ +/* (目前使用共用元件,無特殊樣式) */ + +/* ==================== 崗位描述模組 ==================== */ +/* (目前使用共用元件,無特殊樣式) */ + +/* ==================== 崗位清單模組 ==================== */ +/* (目前使用共用元件,無特殊樣式) */ + +/* ==================== 管理者頁面模組 ==================== */ +/* (目前使用共用元件,無特殊樣式) */ + +/* + * 注意:如果未來各模組需要特定樣式,可在此添加 + * 例如:特殊的表格樣式、卡片佈局等 + */ diff --git a/styles/utilities.css b/styles/utilities.css new file mode 100644 index 0000000..057ddde --- /dev/null +++ b/styles/utilities.css @@ -0,0 +1,56 @@ +/** + * Utilities Styles - 工具類別與響應式設計 + * 包含快速工具類別、響應式斷點 + */ + +/* ==================== Utility Classes ==================== */ +/* (可按需添加工具類別,如 .mt-1, .text-center 等) */ + +/* ==================== Responsive Design ==================== */ +@media (max-width: 768px) { + /* Form Grid */ + .form-grid, + .form-grid.three-cols { + grid-template-columns: 1fr; + } + + /* Form Actions */ + .form-actions { + flex-direction: column; + gap: 16px; + } + + .action-buttons { + width: 100%; + flex-direction: column; + } + + .btn { + justify-content: center; + } + + /* Module Selector */ + .module-selector { + flex-direction: column; + } + + .module-btn { + min-width: 100%; + } + + /* User Info Bar */ + .user-info-bar { + flex-direction: column; + gap: 12px; + text-align: center; + } + + .user-info { + justify-content: center; + } + + .logout-btn { + width: 100%; + justify-content: center; + } +}