1- // GitHub Copilot 熟練應用展示
2- // 完整的待辦事項功能 + 進階特性
1+ // 完成課程後的待辦事項應用程式
2+ // 基本功能:新增、顯示待辦事項
33
44let todos = [ ] ;
5- let todoIdCounter = 1 ;
5+ let nextId = 1 ;
66
77// DOM 元素
88const todoInput = document . getElementById ( 'todoInput' ) ;
@@ -11,220 +11,57 @@ const todoList = document.getElementById('todoList');
1111
1212// 初始化
1313document . addEventListener ( 'DOMContentLoaded' , function ( ) {
14- showWelcomeMessage ( ) ;
15- setupEventListeners ( ) ;
16- setupKeyboardShortcuts ( ) ;
17- loadFromLocalStorage ( ) ;
18- renderTodos ( ) ;
19- } ) ;
20-
21- // 歡迎訊息
22- function showWelcomeMessage ( ) {
23- showNotification ( '🎉 歡迎使用 GitHub Copilot 熟練應用!' , 'success' ) ;
24- setTimeout ( ( ) => {
25- showNotification ( '💡 試試看 Ctrl+Enter 快速新增' , 'info' ) ;
26- } , 2000 ) ;
27- }
28-
29- // 設置事件監聽器
30- function setupEventListeners ( ) {
3114 addButton . addEventListener ( 'click' , addTodo ) ;
3215 todoInput . addEventListener ( 'keypress' , function ( e ) {
33- if ( e . key === 'Enter' ) addTodo ( ) ;
34- } ) ;
35-
36- // 批量操作
37- document . addEventListener ( 'keydown' , function ( e ) {
38- if ( e . ctrlKey && e . key === 'a' ) {
39- e . preventDefault ( ) ;
40- toggleAllTodos ( ) ;
41- }
42- if ( e . ctrlKey && e . key === 'd' ) {
43- e . preventDefault ( ) ;
44- deleteCompleted ( ) ;
45- }
46- } ) ;
47- }
48-
49- // 快捷鍵設置
50- function setupKeyboardShortcuts ( ) {
51- document . addEventListener ( 'keydown' , function ( e ) {
52- if ( e . ctrlKey && e . key === 'Enter' ) {
53- e . preventDefault ( ) ;
16+ if ( e . key === 'Enter' ) {
5417 addTodo ( ) ;
5518 }
5619 } ) ;
57- }
20+
21+ renderTodos ( ) ;
22+ } ) ;
5823
5924// 新增待辦事項
6025function addTodo ( ) {
6126 const text = todoInput . value . trim ( ) ;
6227 if ( ! text ) {
63- showNotification ( '⚠️ 請輸入待辦事項內容' , 'warning ') ;
28+ alert ( ' 請輸入待辦事項內容') ;
6429 return ;
6530 }
6631
6732 const todo = {
68- id : todoIdCounter ++ ,
33+ id : nextId ++ ,
6934 text : text ,
70- completed : false ,
71- createdAt : new Date ( ) . toISOString ( )
35+ completed : false
7236 } ;
7337
7438 todos . push ( todo ) ;
7539 todoInput . value = '' ;
76- saveToLocalStorage ( ) ;
7740 renderTodos ( ) ;
78- showNotification ( '✅ 已新增待辦事項' , 'success' ) ;
7941}
8042
8143// 渲染待辦事項列表
8244function renderTodos ( ) {
8345 todoList . innerHTML = '' ;
8446
8547 if ( todos . length === 0 ) {
86- todoList . innerHTML = '<li class="empty-message">🎯 還沒有待辦事項,開始新增一個吧!</li>' ;
48+ todoList . innerHTML = '<li class="empty-message">還沒有待辦事項,開始新增一個吧!</li>' ;
8749 return ;
8850 }
8951
9052 todos . forEach ( todo => {
9153 const li = document . createElement ( 'li' ) ;
92- li . className = ` todo-item ${ todo . completed ? 'completed' : '' } ` ;
54+ li . className = ' todo-item' ;
9355 li . innerHTML = `
94- <div class="todo-content">
95- <input type="checkbox" ${ todo . completed ? 'checked' : '' }
96- onchange="toggleTodo(${ todo . id } )">
97- <span class="todo-text">${ todo . text } </span>
98- <small class="todo-date">${ formatDate ( todo . createdAt ) } </small>
99- </div>
100- <div class="todo-actions">
101- <button onclick="editTodo(${ todo . id } )" class="edit-btn">✏️</button>
102- <button onclick="deleteTodo(${ todo . id } )" class="delete-btn">🗑️</button>
103- </div>
56+ <span class="todo-text">${ todo . text } </span>
57+ <button onclick="deleteTodo(${ todo . id } )" class="delete-button">刪除</button>
10458 ` ;
10559 todoList . appendChild ( li ) ;
10660 } ) ;
107-
108- updateStats ( ) ;
109- }
110-
111- // 切換待辦事項狀態
112- function toggleTodo ( id ) {
113- const todo = todos . find ( t => t . id === id ) ;
114- if ( todo ) {
115- todo . completed = ! todo . completed ;
116- saveToLocalStorage ( ) ;
117- renderTodos ( ) ;
118- showNotification ( todo . completed ? '✅ 已完成' : '🔄 已重新開啟' , 'info' ) ;
119- }
12061}
12162
12263// 刪除待辦事項
12364function deleteTodo ( id ) {
124- if ( confirm ( '確定要刪除這個待辦事項嗎?' ) ) {
125- todos = todos . filter ( t => t . id !== id ) ;
126- saveToLocalStorage ( ) ;
127- renderTodos ( ) ;
128- showNotification ( '🗑️ 已刪除待辦事項' , 'info' ) ;
129- }
130- }
131-
132- // 編輯待辦事項
133- function editTodo ( id ) {
134- const todo = todos . find ( t => t . id === id ) ;
135- if ( todo ) {
136- const newText = prompt ( '編輯待辦事項:' , todo . text ) ;
137- if ( newText && newText . trim ( ) ) {
138- todo . text = newText . trim ( ) ;
139- saveToLocalStorage ( ) ;
140- renderTodos ( ) ;
141- showNotification ( '✏️ 已更新待辦事項' , 'success' ) ;
142- }
143- }
144- }
145-
146- // 批量操作:全選/取消全選
147- function toggleAllTodos ( ) {
148- const allCompleted = todos . every ( t => t . completed ) ;
149- todos . forEach ( t => t . completed = ! allCompleted ) ;
150- saveToLocalStorage ( ) ;
65+ todos = todos . filter ( todo => todo . id !== id ) ;
15166 renderTodos ( ) ;
152- showNotification ( allCompleted ? '🔄 已全部重新開啟' : '✅ 已全部完成' , 'info' ) ;
153- }
154-
155- // 刪除已完成項目
156- function deleteCompleted ( ) {
157- const completedCount = todos . filter ( t => t . completed ) . length ;
158- if ( completedCount === 0 ) {
159- showNotification ( '💡 沒有已完成的項目' , 'info' ) ;
160- return ;
161- }
162-
163- if ( confirm ( `確定要刪除 ${ completedCount } 個已完成的項目嗎?` ) ) {
164- todos = todos . filter ( t => ! t . completed ) ;
165- saveToLocalStorage ( ) ;
166- renderTodos ( ) ;
167- showNotification ( `🗑️ 已刪除 ${ completedCount } 個項目` , 'success' ) ;
168- }
169- }
170-
171- // 更新統計
172- function updateStats ( ) {
173- const total = todos . length ;
174- const completed = todos . filter ( t => t . completed ) . length ;
175- const pending = total - completed ;
176-
177- document . title = `${ pending > 0 ? `(${ pending } ) ` : '' } GitHub Copilot 熟練應用展示` ;
178- }
179-
180- // 本地存儲
181- function saveToLocalStorage ( ) {
182- localStorage . setItem ( 'copilot-todos' , JSON . stringify ( todos ) ) ;
183- }
184-
185- function loadFromLocalStorage ( ) {
186- const saved = localStorage . getItem ( 'copilot-todos' ) ;
187- if ( saved ) {
188- todos = JSON . parse ( saved ) ;
189- todoIdCounter = Math . max ( ...todos . map ( t => t . id ) , 0 ) + 1 ;
190- }
191- }
192-
193- // 通知系統
194- function showNotification ( message , type = 'info' ) {
195- const notification = document . createElement ( 'div' ) ;
196- notification . className = `notification ${ type } ` ;
197- notification . textContent = message ;
198-
199- document . body . appendChild ( notification ) ;
200-
201- setTimeout ( ( ) => notification . classList . add ( 'show' ) , 100 ) ;
202- setTimeout ( ( ) => {
203- notification . classList . remove ( 'show' ) ;
204- setTimeout ( ( ) => notification . remove ( ) , 300 ) ;
205- } , 3000 ) ;
206- }
207-
208- // 格式化日期
209- function formatDate ( isoString ) {
210- const date = new Date ( isoString ) ;
211- const now = new Date ( ) ;
212- const diffMs = now - date ;
213- const diffMins = Math . floor ( diffMs / 60000 ) ;
214- const diffHours = Math . floor ( diffMins / 60 ) ;
215- const diffDays = Math . floor ( diffHours / 24 ) ;
216-
217- if ( diffMins < 1 ) return '剛剛' ;
218- if ( diffMins < 60 ) return `${ diffMins } 分鐘前` ;
219- if ( diffHours < 24 ) return `${ diffHours } 小時前` ;
220- if ( diffDays < 7 ) return `${ diffDays } 天前` ;
221-
222- return date . toLocaleDateString ( 'zh-TW' ) ;
223- }
224-
225- // 初始化示例數據
226- setTimeout ( ( ) => {
227- if ( todos . length === 0 ) {
228- showNotification ( '💡 提示:Ctrl+Enter 快速新增,Ctrl+A 全選,Ctrl+D 刪除已完成' , 'info' ) ;
229- }
230- } , 4000 ) ;
67+ }
0 commit comments