Coding Diary: Building a Static Learning Portal in 7 Days
Coding Diary: Building a Static Learning Portal in 7 Days
A client of mine named Lisa runs a local community learning hub. She offers weekend classes like woodworking, bread making, and basic coding. Her old WordPress site was constantly getting hacked because she forgot to update the plugins, and she was tired of paying expensive monthly hosting bills for a simple site that only gets updated once a month.
She came to me asking for a simple, fast website where people could browse her course list and read teacher bios. Since the content rarely changes, I suggested going with a static website. It is incredibly secure, loads instantly, and can be hosted for free on platforms like Netlify. I advised her that we should start with a polished, pre-made HTML Template to save time. We picked the Edomi - Bootstrap 5 Education, Learning Courses HTML Template because it already had the clean layout cards we needed for her class lists.
Here is my daily developer journal of how I built this school portal, fixed a mobile layout bug, and optimized it for fast loading times.
---
Day 1: Auditing and Cleaning the Source Files
On my first day, I downloaded the source folder and inspected the directory. The layout is built with Bootstrap 5, which means it is fully responsive and uses modern CSS variables. This made it much easier for me to customize the branding colors to match Lisa’s logo.
To view my changes on the fly, I configured a simple development environment on my computer using Node.js and BrowserSync. I set up a project folder and ran this command in my terminal:
browser-sync start --server --files "*.html, css/*.css, js/*.js"The template came with over forty different pages, including complex shopping carts, checkout forms, and multiple homepage variations. Lisa does not take payments online; her students pay in cash or via bank transfers. I spent the afternoon deleting the unused HTML pages, clearing out extra image placeholders, and stripping out third-party scripts we did not need. This clean-up made our final code directory small and easy to manage.
---
Day 3: Fixing the Mobile Category Tab Glitch
On Day 3, I ran into my first real technical friction point while testing the course list page on my phone. The template has a beautiful tab system that lets users toggle between course categories (like "Cooking," "Coding," and "Art").
On desktop, the tabs worked beautifully. But on mobile screens, we faced two annoying issues. First, when a user clicked a category, the screen abruptly jumped, cutting off the top of the course list under Lisa’s sticky navigation header. Second, on older iOS browsers, the active tab’s text became invisible because the active text color and the active background color both defaulted to white due to a CSS specificity bug.
To fix this, I overrode the default Bootstrap tab trigger in my CSS and wrote a short JavaScript helper to smoothly scroll the active course grid into view, taking the height of the sticky header into account.
/* CSS specificity fix for mobile active tabs */
.course-tabs-nav .nav-link.active {
background-color: #3b82f6 !important; /* Force custom theme blue */
color: #ffffff !important; /* Force white text visibility */
}
@media (max-width: 768px) {
.course-tabs-nav {
display: flex;
overflow-x: auto; /* Enable horizontal scrolling for tabs on mobile */
white-space: nowrap;
}
}// Smooth scroll helper for active mobile tabs
const tabLinks = document.querySelectorAll('.course-tabs-nav .nav-link');
const headerHeight = document.querySelector('.sticky-header').offsetHeight;
tabLinks.forEach(link => {
link.addEventListener('shown.bs.tab', (e) => {
const targetId = e.target.getAttribute('data-bs-target');
const targetElement = document.querySelector(targetId);
if (window.innerWidth < 768 && targetElement) {
const elementPosition = targetElement.getBoundingClientRect().top + window.pageYOffset;
const offsetPosition = elementPosition - headerHeight - 20; // Add 20px padding
window.scrollTo({
top: offsetPosition,
behavior: 'smooth'
});
}
});
});Implementing these code fixes resolved our mobile navigation issues. The tabs became easily scrollable on small screens, and clicking a category now smoothly brings the courses into view without getting cut off by the header.
---
Day 5: Adding a Simple JSON Course Scheduler
On Day 5, I wanted to make the website easier for Lisa to manage in the future. I did not want her to have to open complex HTML files and copy-paste rows of code every time she added a new weekend class.
Since this is a static website, I wrote a small vanilla JavaScript script that reads course data from a simple, clean JSON file and dynamically builds the course cards on the homepage. This way, Lisa only has to edit a simple text file to update her schedule.
Here is the JSON structure and the fetch script I wrote:
[
{
"title": "Sourdough Bread Making for Beginners",
"category": "cooking",
"date": "Saturday, October 10",
"price": "$45",
"teacher": "Chef Pierre"
},
{
"title": "Introduction to Web Development",
"category": "coding",
"date": "Sunday, October 11",
"price": "$60",
"teacher": "Dev Sarah"
}
]// Fetch and render classes from JSON
fetch('assets/data/courses.json')
.then(response => response.json())
.then(courses => {
const grid = document.getElementById('courses-display-grid');
if (!grid) return;
grid.innerHTML = courses.map(course => `
<div class="col-md-6 col-lg-4 course-card" data-category="${course.category}">
<div class="card p-3 shadow-sm">
<span class="badge bg-secondary mb-2">${course.category}</span>
<h3>${course.title}</h3>
<p class="text-muted">Instructor: ${course.teacher}</p>
<div class="d-flex justify-content-between align-items-center">
<span class="fw-bold text-primary">${course.price}</span>
<small>${course.date}</small>
</div>
</div>
</div>
`).join('');
})
.catch(err => console.error('Error loading course schedule:', err));This simple JavaScript trick keeps the site static and secure, while giving Lisa an incredibly easy way to update her schedule without breaking any page layout elements.
---
Day 7: Performance Polish and Netlify Launch
On the final day, I focused on speed optimization and publishing the site. Since many of Lisa's students check the schedule on their phones while on slow public connections, loading speed was critical.
I compressed the images used on the site, turning them into the WebP format. This reduced our overall image size by about 60% without affecting the quality of the teacher profile pictures. I then deployed the site to Netlify and created a custom configuration file to set up browser caching and Brotli compression.
Here is the netlify.toml configuration I used to speed up the site delivery:
# Netlify static hosting header optimization
[[headers]]
for = "/*"
[headers.values]
X-Frame-Options = "DENY"
X-XSS-Protection = "1; mode=block"
X-Content-Type-Options = "nosniff"
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"When I ran the final site through Google PageSpeed Insights, the performance score was 97 on mobile devices and 99 on desktop. The homepage loads in under 0.8 seconds. It is incredibly quick and responsive.
---
Objective Pros and Cons
After working closely with this template for a full week, here is my balanced review of the product:
The Pros:
Excellent Layouts: The pre-designed course cards and bio pages are beautiful and required very few stylistic adjustments.
Bootstrap 5 Base: The code structure is modern and clean, making color customization simple using standard CSS variables.
Responsive Grids: The elements scale down beautifully, keeping the content readable on small viewports.
The Cons:
Tab Styling Bug: The active tab states had minor text contrast issues on mobile iOS screens, requiring manual CSS specificity updates.
Too Many Demo Assets: The initial download bundle was quite heavy, and you have to spend time cleaning out the unused files to keep your project light.
---
The Result
Using a solid pre-made framework was a great decision for this project. Instead of spending my time drawing basic grids and headers from scratch, I was able to focus on resolving mobile responsiveness issues, building the JSON scheduler, and configuring the server for speed.
Lisa's learning hub now has a beautiful, secure, and fast website. The pages load instantly, the mobile menu works correctly, and she can easily update her classes using a simple text file. It is a highly practical, low-maintenance solution that will save her money for years to come.
Replies