Features Implemented
Layout & Design
- Clean, centered daily planner interface with modern UI
- Uses Inter font from Google Fonts
- Responsive design that works on desktop, tablet, and mobile
- Soft shadows, proper padding, and clean typography
Functionality
- Date selector at the top with "Today" button
- To-Do list section with:
- Add/remove tasks
- Checkboxes to mark tasks complete
- Editable task fields
- Schedule section with hourly time blocks (6 AM to 9 PM)
- Notes section with multiline textarea
- "Download as PDF" button using html2pdf.js
Optional Enhancements
- Auto-saves data to localStorage
- Auto-fills today's date
- Dark/light theme toggle
Technical
- Uses html2pdf.js via CDN
- Clean, well-commented code
- Responsive design with CSS Grid and Flexbox
- Fully functional copy-paste ready code
How to Use :
- Simply copy and paste the entire code into an HTML file
- Open the file in any modern browser
- No additional dependencies needed (all CDN links are included)
The planner will automatically save your data to localStorage, so when you return to the page, your plans will still be there. You can download your planner as a PDF at any time by clicking the "Download PDF" button.
:root {
--primary-color: #4a6fa5;
--secondary-color: #6b8cae;
--text-color: #333;
--light-gray: #f5f5f5;
--medium-gray: #e0e0e0;
--dark-gray: #666;
--white: #fff;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--border-radius: 8px;
}
[data-theme="dark"] {
--primary-color: #5d8acd;
--secondary-color: #7fa3d1;
--text-color: #f0f0f0;
--light-gray: #2a2a2a;
--medium-gray: #3a3a3a;
--dark-gray: #999;
--white: #1a1a1a;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Inter', sans-serif;
line-height: 1.6;
color: var(--text-color);
background-color: var(--light-gray);
padding: 20px;
transition: all 0.3s ease;
}
.container {
max-width: 900px;
margin: 0 auto;
background-color: var(--white);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
padding: 30px;
transition: all 0.3s ease;
}
h1 {
text-align: center;
margin-bottom: 20px;
color: var(--primary-color);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
flex-wrap: wrap;
gap: 15px;
}
.date-picker {
display: flex;
align-items: center;
gap: 10px;
}
.date-picker input {
padding: 8px 12px;
border: 1px solid var(--medium-gray);
border-radius: var(--border-radius);
font-family: inherit;
font-size: 16px;
background-color: var(--white);
color: var(--text-color);
}
.actions {
display: flex;
gap: 10px;
}
button {
padding: 8px 16px;
background-color: var(--primary-color);
color: white;
border: none;
border-radius: var(--border-radius);
cursor: pointer;
font-family: inherit;
font-weight: 500;
transition: background-color 0.2s;
}
button:hover {
background-color: var(--secondary-color);
}
button.secondary {
background-color: var(--medium-gray);
color: var(--text-color);
}
button.secondary:hover {
background-color: var(--dark-gray);
}
.section {
margin-bottom: 25px;
}
.section-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 15px;
color: var(--primary-color);
display: flex;
justify-content: space-between;
align-items: center;
}
.todo-list {
list-style: none;
}
.todo-item {
display: flex;
align-items: center;
padding: 10px;
border-bottom: 1px solid var(--medium-gray);
}
.todo-item:last-child {
border-bottom: none;
}
.todo-checkbox {
margin-right: 10px;
transform: scale(1.2);
}
.todo-text {
flex-grow: 1;
padding: 8px;
border: 1px solid transparent;
border-radius: 4px;
font-size: 16px;
background-color: var(--white);
color: var(--text-color);
}
.todo-text:focus {
outline: none;
border-color: var(--primary-color);
}
.todo-delete {
background: none;
border: none;
color: var(--dark-gray);
cursor: pointer;
font-size: 18px;
margin-left: 10px;
padding: 0 5px;
}
.todo-delete:hover {
color: #ff4444;
}
.completed .todo-text {
text-decoration: line-through;
color: var(--dark-gray);
}
.add-todo {
display: flex;
margin-top: 10px;
}
.add-todo input {
flex-grow: 1;
padding: 8px 12px;
border: 1px solid var(--medium-gray);
border-radius: var(--border-radius) 0 0 var(--border-radius);
font-family: inherit;
font-size: 16px;
background-color: var(--white);
color: var(--text-color);
}
.add-todo button {
border-radius: 0 var(--border-radius) var(--border-radius) 0;
}
.schedule {
display: grid;
grid-template-columns: 80px 1fr;
gap: 10px;
}
.time-block {
display: contents;
}
.time-label {
padding: 8px;
text-align: right;
font-weight: 500;
align-self: center;
}
.time-input {
padding: 8px 12px;
border: 1px solid var(--medium-gray);
border-radius: var(--border-radius);
font-family: inherit;
font-size: 16px;
margin-bottom: 5px;
background-color: var(--white);
color: var(--text-color);
width: 100%;
}
.time-input:focus {
outline: none;
border-color: var(--primary-color);
}
.notes {
width: 100%;
min-height: 150px;
padding: 12px;
border: 1px solid var(--medium-gray);
border-radius: var(--border-radius);
font-family: inherit;
font-size: 16px;
resize: vertical;
background-color: var(--white);
color: var(--text-color);
}
.notes:focus {
outline: none;
border-color: var(--primary-color);
}
@media (max-width: 768px) {
.container {
padding: 20px;
}
.header {
flex-direction: column;
align-items: stretch;
}
.date-picker {
justify-content: space-between;
}
.actions {
justify-content: flex-end;
}
.schedule {
grid-template-columns: 60px 1fr;
}
}
@media (max-width: 480px) {
body {
padding: 10px;
}
.container {
padding: 15px;
}
.time-label {
font-size: 14px;
}
}
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const dateInput = document.getElementById('date-input');
const todayBtn = document.getElementById('today-btn');
const themeToggle = document.getElementById('theme-toggle');
const downloadBtn = document.getElementById('download-btn');
const todoList = document.getElementById('todo-list');
const newTodoInput = document.getElementById('new-todo');
const addTodoBtn = document.getElementById('add-todo-btn');
const schedule = document.getElementById('schedule');
const notes = document.getElementById('notes');
const planner = document.getElementById('planner');
// Initialize the app
init();
function init() {
// Set today's date
setTodayDate();
// Initialize time blocks
createTimeBlocks();
// Load saved data
loadData();
// Set up event listeners
setupEventListeners();
}
function setTodayDate() {
const today = new Date();
const formattedDate = formatDate(today);
dateInput.value = formattedDate;
}
function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
function createTimeBlocks() {
const hours = [];
// Create time blocks from 6 AM to 9 PM
for (let hour = 6; hour <= 21; hour++) {
const timeLabel = formatHour(hour);
const timeBlock = document.createElement('div');
timeBlock.className = 'time-block';
const labelElement = document.createElement('div');
labelElement.className = 'time-label';
labelElement.textContent = timeLabel;
const inputElement = document.createElement('input');
inputElement.className = 'time-input';
inputElement.type = 'text';
inputElement.placeholder = `Plan for ${timeLabel}`;
inputElement.dataset.hour = hour;
timeBlock.appendChild(labelElement);
timeBlock.appendChild(inputElement);
schedule.appendChild(timeBlock);
}
}
function formatHour(hour) {
const period = hour >= 12 ? 'PM' : 'AM';
const displayHour = hour > 12 ? hour - 12 : hour;
return `${displayHour}:00 ${period}`;
}
function setupEventListeners() {
// Date picker
dateInput.addEventListener('change', saveData);
// Today button
todayBtn.addEventListener('click', function() {
setTodayDate();
saveData();
});
// Theme toggle
themeToggle.addEventListener('click', toggleTheme);
// Download PDF
downloadBtn.addEventListener('click', downloadPDF);
// Add new todo
addTodoBtn.addEventListener('click', addTodo);
newTodoInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
addTodo();
}
});
// Save data on input changes
notes.addEventListener('input', saveData);
// Auto-save when leaving the page
window.addEventListener('beforeunload', saveData);
}
function addTodo() {
const text = newTodoInput.value.trim();
if (text) {
const todoItem = createTodoItem(text);
todoList.appendChild(todoItem);
newTodoInput.value = '';
saveData();
}
}
function createTodoItem(text, isCompleted = false) {
const li = document.createElement('li');
li.className = 'todo-item' + (isCompleted ? ' completed' : '');
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.className = 'todo-checkbox';
checkbox.checked = isCompleted;
checkbox.addEventListener('change', function() {
li.classList.toggle('completed', this.checked);
saveData();
});
const span = document.createElement('input');
span.type = 'text';
span.className = 'todo-text';
span.value = text;
span.addEventListener('input', saveData);
const deleteBtn = document.createElement('button');
deleteBtn.className = 'todo-delete';
deleteBtn.innerHTML = '×';
deleteBtn.addEventListener('click', function() {
li.remove();
saveData();
});
li.appendChild(checkbox);
li.appendChild(span);
li.appendChild(deleteBtn);
return li;
}
function toggleTheme() {
const currentTheme = document.documentElement.getAttribute('data-theme');
if (currentTheme === 'dark') {
document.documentElement.removeAttribute('data-theme');
themeToggle.textContent = 'Dark Mode';
} else {
document.documentElement.setAttribute('data-theme', 'dark');
themeToggle.textContent = 'Light Mode';
}
saveData();
}
function downloadPDF() {
// Temporarily hide the download button to avoid it appearing in the PDF
downloadBtn.style.visibility = 'hidden';
const opt = {
margin: 10,
filename: `daily-planner-${dateInput.value}.pdf`,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 2 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
};
html2pdf().set(opt).from(planner).save().then(() => {
downloadBtn.style.visibility = 'visible';
});
}
function saveData() {
const data = {
date: dateInput.value,
theme: document.documentElement.getAttribute('data-theme') || 'light',
todos: [],
schedule: {},
notes: notes.value
};
// Save todos
document.querySelectorAll('.todo-item').forEach(item => {
data.todos.push({
text: item.querySelector('.todo-text').value,
completed: item.querySelector('.todo-checkbox').checked
});
});
// Save schedule
document.querySelectorAll('.time-input').forEach(input => {
data.schedule[input.dataset.hour] = input.value;
});
localStorage.setItem('dailyPlannerData', JSON.stringify(data));
}
function loadData() {
const savedData = localStorage.getItem('dailyPlannerData');
if (savedData) {
const data = JSON.parse(savedData);
// Set date
if (data.date) {
dateInput.value = data.date;
}
// Set theme
if (data.theme === 'dark') {
document.documentElement.setAttribute('data-theme', 'dark');
themeToggle.textContent = 'Light Mode';
}
// Load todos
if (data.todos && data.todos.length > 0) {
todoList.innerHTML = '';
data.todos.forEach(todo => {
const todoItem = createTodoItem(todo.text, todo.completed);
todoList.appendChild(todoItem);
});
}
// Load schedule
if (data.schedule) {
document.querySelectorAll('.time-input').forEach(input => {
const hour = input.dataset.hour;
if (data.schedule[hour]) {
input.value = data.schedule[hour];
}
});
}
// Load notes
if (data.notes) {
notes.value = data.notes;
}
}
}
});
إرسال تعليق
Thank you
Learning robo team