🎯 系列目標:用 30 天時間,從零開始打造一個專屬輔大學生的課表生成 Chrome 擴充功能
💻 作者:輔大智慧資安 412580084
📅 Day 24:課表HTML模板與基礎樣式
昨天 Day 23 我們建立了完整的 Chrome Storage 儲存機制,今天我們要開始設計課表的視覺介面,建立 HTML 模板和基礎樣式系統。
今天我們要完成:
這裡我們選擇使用 table 元素來更好管理 DOM :
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>輔大課表 - 個人化課程表</title>
<link rel="stylesheet" href="schedule-styles.css">
</head>
<body>
<div class="schedule-container">
<!-- 控制面板 -->
<div class="controls-panel">
<button id="refreshDataBtn" class="control-btn">
🔄 重新載入
</button>
<select id="themeSelector" class="theme-selector">
<option value="default">🌟 預設主題</option>
<option value="forest">🌲 森林主題</option>
<option value="ocean">🌊 海洋主題</option>
</select>
<button id="exportBtn" class="control-btn">
📥 匯出課表
</button>
</div>
<!-- 學生資訊區域 -->
<section class="student-info-section">
<div class="student-card">
<h2 class="student-title">學生資訊</h2>
<div class="student-details" id="studentDetails">
<div class="info-item">
<span class="info-label">學期:</span>
<span class="info-value" id="semesterInfo">載入中...</span>
</div>
<div class="info-item">
<span class="info-label">系級:</span>
<span class="info-value" id="departmentInfo">載入中...</span>
</div>
<div class="info-item">
<span class="info-label">學號:</span>
<span class="info-value" id="studentIdInfo">載入中...</span>
</div>
</div>
</div>
</section>
<!-- 課表主體 -->
<section class="schedule-section">
<h2 class="schedule-title">我的課表</h2>
<div class="schedule-wrapper">
<table class="schedule-table" id="scheduleTable">
<thead>
<tr class="schedule-header">
<th class="time-header">時間</th>
<th class="day-header">週一</th>
<th class="day-header">週二</th>
<th class="day-header">週三</th>
<th class="day-header">週四</th>
<th class="day-header">週五</th>
</tr>
</thead>
<tbody id="scheduleBody">
<!-- 課表內容將由 JavaScript 動態生成 -->
</tbody>
</table>
</div>
</section>
</div>
<script src="schedule-renderer.js"></script>
</body>
</html>
這裡使用:root
以為了之後的變換主題樣式的設計
/* CSS 變數定義與主題系統 */
:root {
/* 主要色彩 */
--primary-color: #2563eb;
--primary-hover: #1d4ed8;
--primary-light: #dbeafe;
/* 背景色彩 */
--background-main: #ffffff;
--background-secondary: #f8fafc;
--background-card: #ffffff;
/* 文字色彩 */
--text-primary: #1e293b;
--text-secondary: #64748b;
/* 間距系統 */
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
/* 圓角設定 */
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
/* 陰影效果 */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
}
/* 森林主題 */
[data-theme="forest"] {
--primary-color: #16a34a;
--primary-hover: #15803d;
--background-main: #f0fdf4;
}
/* 海洋主題 */
[data-theme="ocean"] {
--primary-color: #0891b2;
--primary-hover: #0e7490;
--background-main: #f0f9ff;
}
這裡可以根據自己的想法設計:
/* 基礎重置與全域樣式 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Microsoft JhengHei', sans-serif;
background-color: var(--background-main);
color: var(--text-primary);
line-height: 1.6;
}
/* 主容器 */
.schedule-container {
max-width: 1200px;
margin: 0 auto;
padding: var(--spacing-lg);
background-color: var(--background-main);
}
/* 控制面板樣式 */
.controls-panel {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--spacing-md);
margin-bottom: var(--spacing-xl);
padding: var(--spacing-md);
background-color: var(--background-card);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
}
.control-btn {
padding: var(--spacing-sm) var(--spacing-md);
background-color: var(--primary-color);
color: white;
border: none;
border-radius: var(--radius-md);
cursor: pointer;
transition: all 0.2s ease;
}
.control-btn:hover {
background-color: var(--primary-hover);
transform: translateY(-1px);
}
/* 學生資訊卡片 */
.student-card {
background-color: var(--background-card);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
box-shadow: var(--shadow-md);
margin-bottom: var(--spacing-xl);
}
.student-details {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: var(--spacing-md);
}
.info-item {
display: flex;
gap: var(--spacing-sm);
}
.info-label {
font-weight: 500;
color: var(--text-secondary);
}
.info-value {
font-weight: 600;
color: var(--text-primary);
}
/* 課表樣式 */
.schedule-table {
width: 100%;
border-collapse: collapse;
background-color: var(--background-card);
border-radius: var(--radius-lg);
overflow: hidden;
box-shadow: var(--shadow-md);
}
.schedule-table th,
.schedule-table td {
padding: var(--spacing-md);
text-align: center;
border: 1px solid #e2e8f0;
}
.schedule-header {
background-color: var(--primary-color);
color: white;
}
.schedule-table tbody tr:nth-child(even) {
background-color: var(--background-secondary);
}
.schedule-table tbody tr:hover {
background-color: var(--primary-light);
}
/* 響應式設計 */
@media (max-width: 768px) {
.controls-panel {
flex-direction: column;
gap: var(--spacing-sm);
}
.student-details {
grid-template-columns: 1fr;
}
.schedule-table {
font-size: 0.875rem;
}
}
建立簡單的 JavaScript 測試器來驗證模板:
// 簡單的模板測試器
class ScheduleTemplateTest {
constructor() {
this.log('📋 課表模板測試器初始化');
}
// 測試模板載入
testTemplateLoad() {
console.log('🧪 開始測試模板載入');
// 檢查必要元素
const requiredElements = [
'refreshDataBtn',
'themeSelector',
'studentDetails',
'scheduleTable'
];
requiredElements.forEach(id => {
const element = document.getElementById(id);
if (element) {
console.log(`✅ 元素 ${id} 載入成功`);
} else {
console.error(`❌ 元素 ${id} 載入失敗`);
}
});
}
// 測試主題切換
testThemeSwitch() {
const themeSelector = document.getElementById('themeSelector');
if (themeSelector) {
themeSelector.addEventListener('change', (e) => {
document.documentElement.setAttribute('data-theme', e.target.value);
console.log(`🎨 主題切換至: ${e.target.value}`);
});
}
}
// 測試時間段配置(與 schedule.js 一致)
testPeriodConfiguration() {
const periods = ['1', '2', '3', '4', 'DN', '5', '6', '7', '8', 'E0'];
const periodTimeMap = {
'1': '1<br>08:10-09:00',
'2': '2<br>09:10-10:00',
'3': '3<br>10:10-11:00',
'4': '4<br>11:10-12:00',
'DN': 'DN<br>12:10-13:00 <br>or <br> 12:40-13:30',
'5': '5<br>13:40-14:30',
'6': '6<br>14:40-15:30',
'7': '7<br>15:40-16:30',
'8': '8<br>16:40-17:30',
'E0': 'E0<br>17:40-18:30'
};
console.log('🕒 測試時間段配置:');
periods.forEach(period => {
console.log(`${period}: ${periodTimeMap[period].replace(/<br>/g, ' ')}`);
});
}
log(message) {
console.log(`[TemplateTest] ${message}`);
}
}
// 執行測試
document.addEventListener('DOMContentLoaded', () => {
const tester = new ScheduleTemplateTest();
tester.testTemplateLoad();
tester.testThemeSwitch();
tester.testPeriodConfiguration();
});
之後我們在輔大學生入口網中點擊我的課表
會看到schedule.html
顯示:
今天我們建立了完整的HTML模板和樣式基礎,明天我們要實現課表渲染引擎與資料綁定