github-research-tool/practice-project/script.js
marketing-shibata50 1e2b71e1b3 feat: GitHub完全活用ガイド - 包括的な解説書とWebサイトを追加
🎯 主要機能:
- GitHub機能の網羅的解説書 (10章構成)
- 外部ツール代替戦略とコスト分析
- 実践的な設定例とベストプラクティス
- 実務ケーススタディと段階的移行計画

🌐 GitHub Pages Webサイト:
- Jekyll設定とレスポンシブデザイン
- 自動デプロイワークフロー
- 美しいランディングページ
- SEO最適化とモバイル対応

📊 期待効果:
- 年間37%のコスト削減
- 開発効率2倍向上
- セキュリティ強化

🚀 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-20 11:21:37 +09:00

412 lines
No EOL
14 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Personal Task Manager - GitHub学習用JavaScript
class TaskManager {
constructor() {
this.tasks = this.loadTasks();
this.taskIdCounter = this.getNextTaskId();
this.initializeApp();
}
// アプリケーション初期化
initializeApp() {
this.setupEventListeners();
this.renderTasks();
this.updateStats();
this.setupDragAndDrop();
}
// イベントリスナー設定
setupEventListeners() {
// タスク追加フォーム
document.getElementById('addTaskForm').addEventListener('submit', (e) => {
e.preventDefault();
this.addTask();
});
// フィルタ変更
document.getElementById('categoryFilter').addEventListener('change', () => this.applyFilters());
document.getElementById('statusFilter').addEventListener('change', () => this.applyFilters());
document.getElementById('priorityFilter').addEventListener('change', () => this.applyFilters());
// タスク操作(イベント委譲)
document.addEventListener('click', (e) => {
if (e.target.classList.contains('edit-btn')) {
this.editTask(e.target.closest('.task-card').dataset.taskId);
}
if (e.target.classList.contains('delete-btn')) {
this.deleteTask(e.target.closest('.task-card').dataset.taskId);
}
});
}
// タスク追加
addTask() {
const title = document.getElementById('taskTitle').value.trim();
const description = document.getElementById('taskDescription').value.trim();
const category = document.getElementById('taskCategory').value;
const priority = document.getElementById('taskPriority').value;
if (!title) {
alert('タスクタイトルを入力してください');
return;
}
const task = {
id: this.taskIdCounter++,
title,
description,
category,
priority,
status: 'todo',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
};
this.tasks.push(task);
this.saveTasks();
this.renderTasks();
this.updateStats();
this.clearForm();
// GitHub風の成功メッセージ実際のGitHubではIssue作成時に表示される
this.showNotification(`タスク #${task.id} を作成しました`, 'success');
}
// タスク編集
editTask(taskId) {
const task = this.tasks.find(t => t.id === parseInt(taskId));
if (!task) return;
const newTitle = prompt('タスクタイトル:', task.title);
if (newTitle === null) return;
const newDescription = prompt('タスク説明:', task.description);
if (newDescription === null) return;
task.title = newTitle.trim();
task.description = newDescription.trim();
task.updatedAt = new Date().toISOString();
this.saveTasks();
this.renderTasks();
this.showNotification(`タスク #${task.id} を更新しました`, 'info');
}
// タスク削除
deleteTask(taskId) {
const task = this.tasks.find(t => t.id === parseInt(taskId));
if (!task) return;
if (confirm(`タスク「${task.title}」を削除しますか?`)) {
this.tasks = this.tasks.filter(t => t.id !== parseInt(taskId));
this.saveTasks();
this.renderTasks();
this.updateStats();
this.showNotification(`タスク #${task.id} を削除しました`, 'warning');
}
}
// タスクレンダリング
renderTasks() {
const todoContainer = document.getElementById('todoTasks');
const inProgressContainer = document.getElementById('inProgressTasks');
const doneContainer = document.getElementById('doneTasks');
// コンテナをクリア
todoContainer.innerHTML = '';
inProgressContainer.innerHTML = '';
doneContainer.innerHTML = '';
// フィルタリングされたタスクを取得
const filteredTasks = this.getFilteredTasks();
// 各タスクをレンダリング
filteredTasks.forEach(task => {
const taskElement = this.createTaskElement(task);
switch (task.status) {
case 'todo':
todoContainer.appendChild(taskElement);
break;
case 'in-progress':
inProgressContainer.appendChild(taskElement);
break;
case 'done':
doneContainer.appendChild(taskElement);
break;
}
});
}
// タスク要素作成
createTaskElement(task) {
const template = document.getElementById('taskTemplate');
const taskElement = template.content.cloneNode(true);
const taskCard = taskElement.querySelector('.task-card');
taskCard.dataset.taskId = task.id;
taskCard.dataset.status = task.status;
// タスク情報を設定
taskElement.querySelector('.task-id').textContent = `#${task.id}`;
taskElement.querySelector('.task-title').textContent = task.title;
taskElement.querySelector('.task-description').textContent = task.description || '説明なし';
// 優先度設定
const priorityElement = taskElement.querySelector('.task-priority');
priorityElement.textContent = this.getPriorityLabel(task.priority);
priorityElement.className = `task-priority ${task.priority}`;
// カテゴリ設定
const categoryElement = taskElement.querySelector('.task-category');
categoryElement.textContent = this.getCategoryLabel(task.category);
categoryElement.className = `task-category ${task.category}`;
// 作成日時
taskElement.querySelector('.task-created').textContent =
new Date(task.createdAt).toLocaleDateString('ja-JP');
return taskElement;
}
// フィルタリング適用
applyFilters() {
this.renderTasks();
}
// フィルタリングされたタスク取得
getFilteredTasks() {
const categoryFilter = document.getElementById('categoryFilter').value;
const statusFilter = document.getElementById('statusFilter').value;
const priorityFilter = document.getElementById('priorityFilter').value;
return this.tasks.filter(task => {
const matchesCategory = categoryFilter === 'all' || task.category === categoryFilter;
const matchesStatus = statusFilter === 'all' || task.status === statusFilter;
const matchesPriority = priorityFilter === 'all' || task.priority === priorityFilter;
return matchesCategory && matchesStatus && matchesPriority;
});
}
// 統計更新
updateStats() {
const totalTasks = this.tasks.length;
const completedTasks = this.tasks.filter(t => t.status === 'done').length;
const inProgressTasks = this.tasks.filter(t => t.status === 'in-progress').length;
const completionRate = totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0;
document.getElementById('totalTasks').textContent = totalTasks;
document.getElementById('completedTasks').textContent = completedTasks;
document.getElementById('inProgressCount').textContent = inProgressTasks;
document.getElementById('completionRate').textContent = `${completionRate}%`;
}
// ドラッグ&ドロップ設定
setupDragAndDrop() {
// タスクカードのドラッグ開始
document.addEventListener('dragstart', (e) => {
if (e.target.classList.contains('task-card')) {
e.target.classList.add('dragging');
e.dataTransfer.setData('text/plain', e.target.dataset.taskId);
}
});
// ドラッグ終了
document.addEventListener('dragend', (e) => {
if (e.target.classList.contains('task-card')) {
e.target.classList.remove('dragging');
}
});
// ドロップゾーンの設定
document.querySelectorAll('.task-column').forEach(column => {
column.addEventListener('dragover', (e) => {
e.preventDefault();
column.classList.add('drag-over');
});
column.addEventListener('dragleave', (e) => {
if (!column.contains(e.relatedTarget)) {
column.classList.remove('drag-over');
}
});
column.addEventListener('drop', (e) => {
e.preventDefault();
column.classList.remove('drag-over');
const taskId = e.dataTransfer.getData('text/plain');
const newStatus = column.dataset.status;
this.updateTaskStatus(parseInt(taskId), newStatus);
});
});
}
// タスクステータス更新
updateTaskStatus(taskId, newStatus) {
const task = this.tasks.find(t => t.id === taskId);
if (!task || task.status === newStatus) return;
const oldStatus = task.status;
task.status = newStatus;
task.updatedAt = new Date().toISOString();
this.saveTasks();
this.renderTasks();
this.updateStats();
// GitHub風のステータス更新メッセージ
this.showNotification(
`タスク #${taskId}${this.getStatusLabel(oldStatus)} から ${this.getStatusLabel(newStatus)} に移動しました`,
'info'
);
}
// ユーティリティ関数
getPriorityLabel(priority) {
const labels = {
'high': '高',
'medium': '中',
'low': '低'
};
return labels[priority] || priority;
}
getCategoryLabel(category) {
const labels = {
'feature': '新機能',
'bug': 'バグ',
'improvement': '改善',
'documentation': 'ドキュメント'
};
return labels[category] || category;
}
getStatusLabel(status) {
const labels = {
'todo': 'TODO',
'in-progress': '進行中',
'done': '完了'
};
return labels[status] || status;
}
// 通知表示GitHub風
showNotification(message, type = 'info') {
// 簡易的な通知実装
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 16px;
background: #0366d6;
color: white;
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
z-index: 1000;
max-width: 300px;
animation: slideIn 0.3s ease-out;
`;
// タイプ別スタイル
const colors = {
'success': '#28a745',
'warning': '#ffd33d',
'error': '#d73a49',
'info': '#0366d6'
};
if (colors[type]) {
notification.style.background = colors[type];
}
document.body.appendChild(notification);
// 3秒後に削除
setTimeout(() => {
notification.remove();
}, 3000);
}
// フォームクリア
clearForm() {
document.getElementById('addTaskForm').reset();
}
// データ永続化
saveTasks() {
localStorage.setItem('github-learning-tasks', JSON.stringify(this.tasks));
localStorage.setItem('github-learning-task-counter', this.taskIdCounter.toString());
}
loadTasks() {
const saved = localStorage.getItem('github-learning-tasks');
return saved ? JSON.parse(saved) : [];
}
getNextTaskId() {
const saved = localStorage.getItem('github-learning-task-counter');
return saved ? parseInt(saved) : 1;
}
// デモデータ生成(学習用)
generateSampleTasks() {
const sampleTasks = [
{
id: this.taskIdCounter++,
title: 'GitHub Issues の基本操作を学習',
description: 'Issue の作成、編集、クローズの方法を実践で学ぶ',
category: 'documentation',
priority: 'high',
status: 'todo',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
},
{
id: this.taskIdCounter++,
title: 'Pull Request のワークフローを実践',
description: 'ブランチ作成からマージまでの一連の流れを体験',
category: 'feature',
priority: 'high',
status: 'in-progress',
createdAt: new Date(Date.now() - 86400000).toISOString(),
updatedAt: new Date().toISOString()
},
{
id: this.taskIdCounter++,
title: 'GitHub Actions でCI/CDを設定',
description: '自動テストとデプロイの仕組みを構築',
category: 'improvement',
priority: 'medium',
status: 'todo',
createdAt: new Date(Date.now() - 172800000).toISOString(),
updatedAt: new Date(Date.now() - 172800000).toISOString()
}
];
if (this.tasks.length === 0) {
this.tasks = sampleTasks;
this.saveTasks();
}
}
}
// アプリケーション開始
document.addEventListener('DOMContentLoaded', () => {
const taskManager = new TaskManager();
// デモデータ生成(初回のみ)
taskManager.generateSampleTasks();
taskManager.renderTasks();
taskManager.updateStats();
// グローバルに公開(デバッグ用)
window.taskManager = taskManager;
console.log('🎯 Personal Task Manager が起動しました!');
console.log('GitHub機能学習用のタスク管理アプリです。');
console.log('タスクを追加して、GitHub の各機能を実践的に学習しましょう!');
});