এই পর্যন্ত আমরা Advanced HTML সিরিজে শিখেছি — Web Storage, Canvas, SVG, Accessibility, আর Meta Tags/SEO। এই শেষ পর্বে আমরা সবকিছু একসাথে করে একটা বাস্তব প্রজেক্ট বানাব — একটা নোট-অ্যাপ, যেটা localStorage দিয়ে ডেটা ধরে রাখবে আর সম্পূর্ণভাবে কীবোর্ড-অ্যাক্সেসিবল হবে।
প্রজেক্টের ফিচারগুলো
- নতুন নোট যোগ করা
- নোট মুছে ফেলা
- নোট এডিট করা
- রিফ্রেশ করলেও নোট থেকে যাওয়া (localStorage দিয়ে)
- সম্পূর্ণ কীবোর্ড দিয়ে ব্যবহারযোগ্য
- স্ক্রিন রিডার-ফ্রেন্ডলি (ARIA লেবেল আর live region)
HTML স্ট্রাকচার
প্রথমে সেমান্টিক আর অ্যাক্সেসিবল HTML বানাই — <label>, aria-live, আর সঠিক <button> ব্যবহার করে।
<main>
<h1>আমার নোট</h1>
<form id="noteForm">
<label for="noteInput">নতুন নোট লিখুন</label>
<input
id="noteInput"
placeholder="যেমন: বাজার করতে হবে"
required
type="text"
/>
<button type="submit">যোগ করো</button>
</form>
<p aria-live="polite" class="sr-status" id="statusMsg"></p>
<ul aria-label="নোট তালিকা" id="noteList"></ul>
</main>
aria-live="polite" খুব গুরুত্বপূর্ণ — এতে যখনই statusMsg-এর টেক্সট পাল্টাবে ("নোট যোগ হয়েছে", "নোট মোছা হয়েছে"), স্ক্রিন রিডার স্বয়ংক্রিয়ভাবে সেটা পড়ে শোনাবে — ব্যবহারকারীকে আলাদা করে জানার দরকার নেই কিছু ঘটেছে কিনা।
JavaScript — localStorage দিয়ে ডেটা ম্যানেজ করা
নোটগুলো একটা অ্যারে হিসেবে রাখা হবে, আর প্রতিবার পরিবর্তনের পর JSON.stringify() দিয়ে localStorage-এ সেভ হবে — এটা আমাদের পর্ব ১-এর টেকনিক।
const form = document.getElementById("noteForm");
const input = document.getElementById("noteInput");
const list = document.getElementById("noteList");
const status = document.getElementById("statusMsg");
// পেজ লোড হওয়ার সময় সেভ করা নোট নিয়ে আসা
let notes = JSON.parse(localStorage.getItem("myNotes")) || [];
function saveNotes() {
localStorage.setItem("myNotes", JSON.stringify(notes));
}
function renderNotes() {
list.innerHTML = "";
notes.forEach((note, index) => {
const li = document.createElement("li");
const span = document.createElement("span");
span.textContent = note;
const deleteBtn = document.createElement("button");
deleteBtn.textContent = "মুছো";
deleteBtn.setAttribute("aria-label", `"${note}" নোটটি মুছুন`);
deleteBtn.addEventListener("click", () => deleteNote(index));
li.appendChild(span);
li.appendChild(deleteBtn);
list.appendChild(li);
});
}
function addNote(text) {
notes.push(text);
saveNotes();
renderNotes();
status.textContent = "নতুন নোট যোগ হয়েছে";
}
function deleteNote(index) {
const removed = notes[index];
notes.splice(index, 1);
saveNotes();
renderNotes();
status.textContent = `"${removed}" মুছে ফেলা হয়েছে`;
}
form.addEventListener("submit", (e) => {
e.preventDefault();
const text = input.value.trim();
if (text === "") return;
addNote(text);
input.value = "";
input.focus(); // এড করার পর আবার ইনপুটেই ফোকাস থাকা উচিত
});
renderNotes(); // পেজ লোড হলেই আগের নোট দেখানো
এখানে খেয়াল করো — form-এর submit ইভেন্ট ব্যবহার করা হয়েছে, শুধু বাটনের click না — এতে ব্যবহারকারী Enter চাপলেও নোট যোগ হয়ে যায়, যা কীবোর্ড ব্যবহারকারীদের জন্য স্বাভাবিক আচরণ।
CSS দিয়ে সাজানো
main {
max-width: 500px;
margin: 40px auto;
font-family: sans-serif;
}
#noteForm {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
#noteInput {
flex: 1;
padding: 8px 10px;
border: 1px solid #ccc;
border-radius: 6px;
}
/* ফোকাস রিং স্পষ্টভাবে দেখানো — অ্যাক্সেসিবিলিটির জন্য জরুরি */
#noteInput:focus, button:focus {
outline: 3px solid #2563eb;
outline-offset: 2px;
}
#noteList li {
display: flex;
justify-content: space-between;
align-items: center;
background: #f1f5f9;
padding: 10px 12px;
border-radius: 6px;
margin-bottom: 8px;
}
/* স্ক্রিন রিডারের জন্য থাকা কিন্তু চোখে অদৃশ্য টেক্সট */
.sr-status {
font-size: 12px;
color: #16a34a;
}
টিপস: outline: none দিয়ে ফোকাস রিং কখনো লুকিও না — এটা কীবোর্ড ব্যবহারকারীদের জন্য এলিমেন্ট কোথায় আছে বোঝার একমাত্র উপায়।
লাইভ ডেমো — নিজেই চালিয়ে দেখো
নিচে সম্পূর্ণ কাজ করা নোট-অ্যাপটা আছে। নোট যোগ করে পেজ রিফ্রেশ করেও দেখো — নোট থেকে যাবে। শুধু কীবোর্ড দিয়েও ট্রাই করো (Tab দিয়ে ইনপুটে যাও, লিখে Enter চাপো)।
SEO/Meta যোগ করা (ঐচ্ছিক)
যদি এই নোট-অ্যাপটা একটা আলাদা স্ট্যান্ডঅ্যালোন পেজ (যেমন Pathok Ghar-এর মতো Cloudflare Pages-এ) হিসেবে হোস্ট করো, তাহলে পর্ব ৫-এ শেখা মেটা ট্যাগও যোগ করতে পারো:
<title>আমার নোট - সহজ ও দ্রুত</title> <meta content="ব্রাউজারেই সেভ হওয়া একটা সহজ নোট অ্যাপ" name="description" /> <meta content="আমার নোট অ্যাপ" property="og:title" />
পরবর্তী উন্নতির আইডিয়া
Exercise: প্রজেক্টটা আরও ভালো করার জন্য নিজে চেষ্টা করো —
- নোট এডিট করার ফিচার যোগ করো (ক্লিক করলে ইনপুটে বদলে যাবে)।
- প্রতিটা নোটের সাথে একটা টাইমস্ট্যাম্প (কখন লেখা হয়েছে) সেভ করো ও দেখাও।
- নোটগুলো ড্র্যাগ করে পুনর্বিন্যাস করার ফিচার যোগ করো — এটা আমাদের সিরিজের বাইরের একটা টপিক থেকে ধারণা নিতে পারো (Drag and Drop API)।
- "সব মুছে ফেলো" বাটন যোগ করো, কিন্তু নিশ্চিত করার জন্য একটা
confirm()ডায়ালগ দেখাও। - পুরো অ্যাপটা কীবোর্ড দিয়ে (মাউস স্পর্শ না করে) ব্যবহার করে দেখো — কোথাও আটকে যাচ্ছ কিনা যাচাই করো।
সিরিজ শেষ!
এই ছয় পর্বে আমরা Web Storage, Canvas, SVG, Accessibility, আর SEO Meta Tags শিখেছি, আর সবশেষে সেগুলো মিলিয়ে একটা কাজ করা প্রজেক্ট বানিয়েছি। এখন থেকে তোমার যেকোনো প্রজেক্টে এই টেকনিকগুলো প্রয়োগ করতে পারো।