728x90
Chat GPT4 를 활용해서 웹 일정관리 캘린더를 만들어 보았습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Schedule Dashboard</title>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container mt-5">
<div class="card shadow">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<button id="prevMonth" class="btn btn-primary">< Prev</button>
<h3 id="currentMonth"></h3>
<button id="nextMonth" class="btn btn-primary">Next ></button>
</div>
<div class="calendar" id="calendar"></div>
</div>
</div>
</div>
<!-- Modal for Event Details -->
<div id="eventModal" class="modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 id="modalTitle" class="modal-title"></h5>
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<form id="eventForm">
<input type="hidden" id="eventId">
<div class="form-group">
<label for="eventDate">Date:</label>
<input type="date" id="eventDate" class="form-control" required>
</div>
<div class="form-group">
<label for="eventTitle">Title:</label>
<input type="text" id="eventTitle" class="form-control" required>
</div>
<div class="form-group">
<label for="eventDescription">Description:</label>
<textarea id="eventDescription" class="form-control" required></textarea>
</div>
<button type="submit" id="saveButton" class="btn btn-success">Save</button>
<button type="button" id="deleteButton" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script src="script.js"></script>
</body>
</html>
body {
font-family: Arial, sans-serif;
}
.card {
border-radius: 10px;
}
.calendar {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 1px;
border: 1px solid #ddd;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.day {
border: 1px solid #ddd;
padding: 10px;
min-height: 100px;
position: relative;
transition: background-color 0.3s ease;
}
.day:hover {
background-color: #f0f0f0;
}
.today {
background-color: #ffeb3b;
}
.day .events {
margin-top: 10px;
}
.event {
background-color: #007BFF;
color: #fff;
padding: 5px;
margin-top: 5px;
cursor: pointer;
border-radius: 3px;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.event:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.modal {
display: none;
}
@keyframes slideIn {
from {
transform: translateY(-20px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.new-event {
animation: slideIn 0.3s ease;
}
document.addEventListener("DOMContentLoaded", () => {
const calendar = document.getElementById('calendar');
const modal = new bootstrap.Modal(document.getElementById('eventModal'));
const closeBtn = document.querySelector(".close");
const eventForm = document.getElementById('eventForm');
const saveButton = document.getElementById('saveButton');
const deleteButton = document.getElementById('deleteButton');
const modalTitle = document.getElementById('modalTitle');
const eventId = document.getElementById('eventId');
const eventDate = document.getElementById('eventDate');
const eventTitle = document.getElementById('eventTitle');
const eventDescription = document.getElementById('eventDescription');
const currentMonthEl = document.getElementById('currentMonth');
const prevMonthBtn = document.getElementById('prevMonth');
const nextMonthBtn = document.getElementById('nextMonth');
let events = [
{ id: 1, date: '2024-07-30', title: 'Event 1', description: 'Event 1 Description' },
{ id: 2, date: '2024-07-30', title: 'Event 2', description: 'Event 2 Description' },
{ id: 3, date: '2024-07-31', title: 'Event 3', description: 'Event 3 Description' },
];
let currentMonth = new Date().getMonth();
let currentYear = new Date().getFullYear();
function renderCalendar() {
calendar.innerHTML = '';
const firstDayOfMonth = new Date(currentYear, currentMonth, 1).getDay();
const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();
currentMonthEl.innerText = `${currentYear}년 ${currentMonth + 1}월`;
for (let i = 0; i < firstDayOfMonth; i++) {
const emptyDiv = document.createElement('div');
emptyDiv.classList.add('day');
calendar.appendChild(emptyDiv);
}
for (let i = 1; i <= daysInMonth; i++) {
const dayDiv = document.createElement('div');
dayDiv.classList.add('day');
dayDiv.innerHTML = `<div>${i}</div><div class="events"></div>`;
const dateStr = `${currentYear}-${(currentMonth + 1).toString().padStart(2, '0')}-${i.toString().padStart(2, '0')}`;
if (dateStr === new Date().toISOString().split('T')[0]) {
dayDiv.classList.add('today');
}
const dayEvents = events.filter(event => event.date === dateStr);
const eventsDiv = dayDiv.querySelector('.events');
dayEvents.forEach(event => {
const eventDiv = document.createElement('div');
eventDiv.classList.add('event', 'new-event');
eventDiv.innerText = event.title;
eventDiv.addEventListener('click', (e) => {
e.stopPropagation();
openModal(event, true);
});
eventsDiv.appendChild(eventDiv);
});
dayDiv.addEventListener('dblclick', () => openModal({ date: dateStr }, false));
calendar.appendChild(dayDiv);
}
}
function openModal(event, isEdit) {
modal.show();
eventId.value = isEdit ? event.id : '';
eventDate.value = event.date;
eventTitle.value = isEdit ? event.title : '';
eventDescription.value = isEdit ? event.description : '';
modalTitle.innerText = isEdit ? 'Edit Event' : 'Add Event';
deleteButton.style.display = isEdit ? 'block' : 'none';
}
function closeModal() {
modal.hide();
}
function saveEvent(e) {
e.preventDefault();
const id = eventId.value;
const date = eventDate.value;
const title = eventTitle.value;
const description = eventDescription.value;
if (id) {
const eventIndex = events.findIndex(event => event.id == id);
events[eventIndex].date = date;
events[eventIndex].title = title;
events[eventIndex].description = description;
} else {
const newEvent = {
id: events.length ? Math.max(...events.map(event => event.id)) + 1 : 1,
date,
title,
description
};
events.push(newEvent);
}
closeModal();
renderCalendar();
}
function deleteEvent() {
const id = eventId.value;
events = events.filter(event => event.id != id);
closeModal();
renderCalendar();
}
function prevMonth() {
if (currentMonth === 0) {
currentMonth = 11;
currentYear--;
} else {
currentMonth--;
}
renderCalendar();
}
function nextMonth() {
if (currentMonth === 11) {
currentMonth = 0;
currentYear++;
} else {
currentMonth++;
}
renderCalendar();
}
closeBtn.onclick = closeModal;
window.onclick = event => {
if (event.target === modal._element) {
closeModal();
}
};
eventForm.onsubmit = saveEvent;
deleteButton.onclick = deleteEvent;
prevMonthBtn.onclick = prevMonth;
nextMonthBtn.onclick = nextMonth;
renderCalendar();
});

감사합니다.
'한국 20대 개발자의 성장기' 카테고리의 다른 글
| Haut(How Are U Today ?) 앱 개발을 시작합니다. (0) | 2025.06.10 |
|---|---|
| 작업표시줄 새로고침 / 작업탐색기 프로세스 재시작 (1) | 2024.09.23 |
| 전력 요금 계산하기 (스크래핑 활용) (1) | 2024.06.22 |
| HTTPS ? HTTP ? CORS / XMLHttpRequest Error ?? (0) | 2024.04.10 |
| 쇼핑몰 구매수량 추출 프로그램/웹 스크래핑 프로그램 문의 (0) | 2024.02.27 |