Local or Online Development
local: install Visual Studio Code. – Youtube Link
online: browse to https://vscode.dev/
Step One: Create a Project Folder
– File – Open Folder – ****
locate your code folder and create a subfolder for your project (to-do-list) and create a subfolder in that (v1)
Step Two: Create the FOUR files
- index.html
- style.css
- script.js
- mytasks.json
Step Three: Copy the code from below into the files
Step Four: Run your app
using local vscode – press F5 or click the run button.
using vscode online – open a browser and navigate to your code folder and open the html file.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSON File To-Do List</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<h2>Task Manager</h2>
<div class="file-controls">
<button id="open-btn">Open JSON File</button>
<button id="save-btn" disabled>Save Changes</button>
</div>
<div class="input-group">
<input type="text" id="todo-input" placeholder="New task..." disabled>
<button id="add-btn" disabled>Add</button>
</div>
<ul id="todo-list"></ul>
<p id="status-msg">Please open a .json file to begin.</p>
</div>
<script src="script.js"></script>
</body>
</html>CSS
/* 1. Global Styles & Typography */
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f8f9fa;
color: #333;
display: flex;
justify-content: center;
padding: 60px 20px;
margin: 0;
}
/* 2. Main Container */
.container {
background: #ffffff;
width: 100%;
max-width: 450px;
padding: 30px;
border-radius: 16px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
}
h2 {
font-size: 1.5rem;
margin-bottom: 25px;
text-align: center;
color: #2c3e50;
font-weight: 600;
}
/* 3. File Controls Section */
.file-controls {
display: flex;
justify-content: space-between;
gap: 12px;
margin-bottom: 25px;
padding-bottom: 20px;
border-bottom: 1px solid #edf2f7;
}
/* 4. Inputs and Buttons */
.input-group {
display: flex;
gap: 10px;
margin-bottom: 25px;
}
input[type="text"] {
flex: 1;
padding: 12px 16px;
border: 2px solid #e2e8f0;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.2s ease;
}
input[type="text"]:focus {
outline: none;
border-color: #3182ce;
}
button {
padding: 12px 20px;
font-size: 0.95rem;
font-weight: 500;
border: none;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
}
button:active {
transform: translateY(1px);
}
/* Specific Button Colors */
#open-btn { background-color: #3182ce; color: white; flex: 1; }
#open-btn:hover { background-color: #2b6cb0; }
#save-btn { background-color: #805ad5; color: white; flex: 1; }
#save-btn:hover { background-color: #6b46c1; }
#add-btn { background-color: #38a169; color: white; }
#add-btn:hover { background-color: #2f855a; }
button:disabled {
background-color: #cbd5e0 !important;
cursor: not-allowed;
opacity: 0.7;
}
/* 5. The Task List */
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 16px;
margin-bottom: 10px;
background-color: #fdfdfd;
border: 1px solid #edf2f7;
border-radius: 8px;
transition: background-color 0.2s;
}
li:hover {
background-color: #f7fafc;
}
.del-btn {
background-color: #fed7d7;
color: #c53030;
padding: 6px 12px;
font-size: 0.85rem;
}
.del-btn:hover {
background-color: #feb2b2;
}
/* 6. Status Messages */
#status-msg {
margin-top: 20px;
font-size: 0.85rem;
color: #718096;
text-align: center;
font-style: italic;
}Java Script
let fileHandle;
let tasks = [];
const openBtn = document.getElementById('open-btn');
const saveBtn = document.getElementById('save-btn');
const addBtn = document.getElementById('add-btn');
const input = document.getElementById('todo-input');
const todoList = document.getElementById('todo-list');
const statusMsg = document.getElementById('status-msg');
// 1. Open and Read the JSON File
openBtn.addEventListener('click', async () => {
try {
[fileHandle] = await window.showOpenFilePicker({
types: [{ description: 'JSON Files', accept: { 'application/json': ['.json'] } }],
multiple: false
});
const file = await fileHandle.getFile();
const content = await file.text();
// Parse JSON content (handle empty files with empty array)
tasks = content ? JSON.parse(content) : [];
enableApp(file.name);
renderTasks();
} catch (err) {
console.error("File access denied or closed", err);
}
});
// 2. Save the array back to the JSON File
saveBtn.addEventListener('click', async () => {
if (!fileHandle) return;
const writable = await fileHandle.createWritable();
await writable.write(JSON.stringify(tasks, null, 2));
await writable.close();
statusMsg.innerText = "Changes saved to file!";
setTimeout(() => statusMsg.innerText = `Editing: ${fileHandle.name}`, 2000);
});
// 3. UI Logic
function renderTasks() {
todoList.innerHTML = '';
tasks.forEach((task, index) => {
const li = document.createElement('li');
li.innerHTML = `<span>${task}</span><button class="del-btn" onclick="deleteTask(${index})">x</button>`;
todoList.appendChild(li);
});
}
function deleteTask(index) {
tasks.splice(index, 1);
renderTasks();
}
addBtn.addEventListener('click', () => {
if (input.value.trim()) {
tasks.push(input.value.trim());
input.value = '';
renderTasks();
}
});
function enableApp(fileName) {
input.disabled = false;
addBtn.disabled = false;
saveBtn.disabled = false;
statusMsg.innerText = `Editing: ${fileName}`;
}json data
[
"Review Year 10 Science for Friday",
"Daily Goal: Reach 10,000 steps",
"Eat a health breakfast",
"Buy chocolate from IGA",
"Get uniform washed before work"
]