SRP Refactoring — FOPL Frontend

Applying the Single Responsibility Principle across the Friends of the Poway Library frontend — extracting duplicated nav, footer, styles, and shared JS from 13 pages into four shared files.

Single Responsibility Principle (SRP) Refactoring

Every function, class, or module should have one reason to change. We applied SRP across the FOPL frontend by extracting copy-pasted nav, footer, CSS, and JS that was duplicated in every page file into four dedicated shared files — without changing any visual appearance or behavior.


Overview: What Changed

File Type Changes
_includes/fopl-nav.html HTML Include (NEW) Shared nav extracted from all pages
_includes/fopl-footer.html HTML Include (NEW) Shared footer extracted from all pages
assets/css/fopl-shared.css Stylesheet (NEW) All shared styles in one file
assets/js/fopl-shared.js JavaScript (NEW) Auth dropdown, backend URL, game helpers
_layouts/fopl.html Layout Updated to include all shared files
13 page .md files Pages ~1,543 lines of duplicated code removed

The Problem: 13 Pages, All Identical Chrome

Every single FOPL page (home.md, catalog.md, history.md, puzzles.md, etc.) contained the full nav bar HTML, the footer HTML, all nav/footer CSS, the auth dropdown CSS, the Google Fonts import, and the auth dropdown JavaScript — copy-pasted identically. A change to the nav (adding a link, fixing a color, updating the auth logic) required editing every file individually.

BEFORE — a snippet of what lived at the top of every page’s <style> block:

/* Duplicated in home.md, catalog.md, history.md, puzzles.md ... */
@import url('https://fonts.googleapis.com/css2?family=Cabin:...');

*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: 'Lato', sans-serif; }

.fopl-nav {
  background: #023b0f;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 30px;
  flex-wrap: wrap;
}
.fopl-nav-links { display: flex; list-style: none; margin: 0; padding: 0; }
.fopl-nav-links li a {
  display: block; color: #fff; text-decoration: none;
  font-family: 'Cabin', sans-serif; font-size: 0.95rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 18px 20px; transition: background 0.2s;
}
/* ... nav dropdown CSS, auth pill CSS, footer CSS ...
   ~60 lines of identical CSS in every single file */

And the same nav HTML was also copy-pasted into every page’s body:

<!-- Duplicated nav HTML in every page -->
<nav class="fopl-nav">
  <div class="fopl-logo-wrap">
    <img src="/FOTPL/fopllogo.png" alt="Friends of the Poway Library" />
  </div>
  <ul class="fopl-nav-links">
    <li><a href="/home">Home</a></li>
    <li><a href="/history">History</a></li>
    <li><a href="/catalog">Catalog</a></li>
    <!-- ... more links ... -->
    <li id="nav-auth-item"><a href="/login" id="nav-auth-link">Sign In</a>
      <ul class="fopl-nav-dropdown" id="nav-auth-dropdown">
        <li><a href="/profile">Profile</a></li>
        <li><a href="#" id="nav-signout-btn">Sign Out</a></li>
      </ul>
    </li>
  </ul>
</nav>

Along with ~50 lines of auth dropdown JavaScript at the bottom of every page. In total, ~118 lines of identical code appeared in all 13 pages.


File 1: Shared Nav (_includes/fopl-nav.html) — NEW

Problem: Nav HTML was copy-pasted into all 13 pages

The nav bar had one job — render site navigation. But it lived inside every page file, meaning page content and nav structure had the same reason to change. Adding a new nav link required editing 13 files.

BEFORE — nav HTML duplicated inside each page’s body:

<!-- In home.md, catalog.md, history.md, puzzles.md ... (all 13 pages) -->
<nav class="fopl-nav">
  <div class="fopl-logo-wrap">
    <img src="/FOTPL/fopllogo.png" alt="Friends of the Poway Library" />
  </div>
  <ul class="fopl-nav-links">
    <li><a href="/home">Home</a></li>
    <li><a href="/history">History</a></li>
    <li><a href="/catalog">Catalog</a></li>
    <li><a href="/bookstore">Bookstore</a></li>
    <li><a href="/news">Newsletters</a></li>
    <li><a href="/puzzles">Puzzles</a></li>
    <li><a href="/contact">Contact Us</a></li>
    <li id="nav-auth-item"><a href="/login" id="nav-auth-link">Sign In</a>
      <ul class="fopl-nav-dropdown" id="nav-auth-dropdown">
        <li><a href="/profile">Profile</a></li>
        <li><a href="#" id="nav-signout-btn">Sign Out</a></li>
      </ul>
    </li>
  </ul>
</nav>

AFTER_includes/fopl-nav.html is the single source of truth for nav HTML:

<nav class="fopl-nav">
  <div class="fopl-logo-wrap">
    <img src="/FOTPL/fopllogo.png"
         alt="Friends of the Poway Library" />
  </div>
  <ul class="fopl-nav-links">
    <li><a href="/home">Home</a></li>
    <li><a href="/history">History</a></li>
    
    <li><a href="/bookstore">Bookstore</a></li>
    <li><a href="/news">Newsletters</a></li>
    <li><a href="/puzzles">Puzzles</a></li>
    <li><a href="/contact">Contact Us</a></li>
    <li id="nav-auth-item"><a href="/login" id="nav-auth-link">Sign In</a>
      <ul class="fopl-nav-dropdown" id="nav-auth-dropdown">
        <li><a href="/profile">Profile</a></li>
        <li><a href="#" id="nav-signout-btn">Sign Out</a></li>
      </ul>
    </li>
  </ul>
</nav>

Each page now sets fopl_nav_active: home (or history, catalog, etc.) in its front matter — the include handles the active class automatically. Each page only describes what it is, not how the nav works.

Why this is better: Adding or renaming a nav link is now one edit in one file. Pages no longer have any reason to change when the nav structure changes.


The footer is site-wide chrome — it has nothing to do with any individual page’s content. Yet it lived inside every page file.

BEFORE — footer HTML duplicated in every page:

<!-- Repeated in every .md page -->
<div class="fopl-footer">
  &copy; 2025 Friends of the Poway Library &mdash;
  <a href="https://powayfriends.org">powayfriends.org</a>
</div>

AFTER_includes/fopl-footer.html holds it once:

<div class="fopl-footer">
  &copy; 2025 Friends of the Poway Library &mdash;
  <a href="https://powayfriends.org">powayfriends.org</a>
</div>

Included automatically by _layouts/fopl.html — pages don’t even need to think about it.

Why this is better: Updating the copyright year or adding a footer link is a single-file change with zero risk of missing a page.


File 3: Shared Styles (assets/css/fopl-shared.css) — NEW

Problem: ~60 lines of nav/footer CSS were copy-pasted into every page

Every page’s <style> block started with the same Google Fonts import, the same nav layout rules, the same auth pill styles, the same footer styles, and the same responsive breakpoints. CSS that controls the nav had no business living inside a page about book puzzles.

BEFORE — the same ~60-line CSS block duplicated across all 13 pages:

/* This block appeared inside <style> in EVERY page */
@import url('https://fonts.googleapis.com/css2?family=Cabin:wght@400;600;700&family=Lato:wght@300;400;700&display=swap');
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: 'Lato', sans-serif; }

.fopl-nav { background: #023b0f; display: flex; ... }
.fopl-nav-links li a { color: #fff; font-family: 'Cabin', sans-serif; ... }
.fopl-nav-links li a:hover,
.fopl-nav-links li.active a { background: rgba(255,255,255,0.12); }

/* Nav dropdown */
.fopl-nav-dropdown { display: none; position: absolute; ... }
.fopl-nav-dropdown.open { display: block; }

/* Auth pill */
#nav-auth-item a#nav-auth-link {
  background: rgba(255,255,255,0.15);
  border: 1.5px solid rgba(255,255,255,0.45);
  border-radius: 20px; ...
}

/* Footer */
.fopl-footer { background: #023b0f; text-align: center; ... }

/* Responsive */
@media (max-width: 640px) {
  .fopl-nav { flex-direction: column; ... }
  .fopl-nav-links li a { padding: 12px 14px; ... }
}

AFTERassets/css/fopl-shared.css is the single source of truth for all shared styles:

/* ═══════════════════════════════════════════
   FOPL shared styles — nav, footer, auth pill
   Single source of truth for site-wide chrome
   ═══════════════════════════════════════════ */

@import url('https://fonts.googleapis.com/css2?family=Cabin:wght@400;600;700&family=Lato:wght@300;400;700&display=swap');

*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; font-family: 'Lato', sans-serif; }

/* ── Nav bar ── */
.fopl-nav { background: #023b0f; display: flex; align-items: center; ... }
.fopl-nav-links li a { color: #fff; font-family: 'Cabin', sans-serif; ... }
.fopl-nav-links li a:hover,
.fopl-nav-links li.active a { background: rgba(255,255,255,0.12); }

/* ── Nav dropdown ── */
.fopl-nav-dropdown { display: none; position: absolute; top: 100%; right: 0; ... }
.fopl-nav-dropdown.open { display: block; }

/* ── Auth nav pill ── */
#nav-auth-item a#nav-auth-link { background: rgba(255,255,255,0.15); border-radius: 20px; ... }

/* ── Footer ── */
.fopl-footer { background: #023b0f; text-align: center; padding: 22px 20px; ... }

/* ── Responsive nav ── */
@media (max-width: 640px) {
  .fopl-nav { flex-direction: column; ... }
  .fopl-nav-links li a { padding: 12px 14px; font-size: 0.85rem; }
}

Loaded once via _layouts/fopl.html — pages only define their own page-specific styles.

Why this is better: Changing the nav color, fixing a font size, or adding a hover effect is one edit in one file. Before this change, every CSS fix had to be applied to all 13 pages manually.


File 4: Shared JavaScript (assets/js/fopl-shared.js) — NEW

Problem: Auth dropdown JS was copy-pasted into every page; game helpers had no shared home

Every page ran the same 50-line auth nav dropdown setup (reading fopl_user from localStorage, toggling the dropdown, handling sign-out). The backend URL (http://127.0.0.1:8587) was also hardcoded individually in every page that made API calls. Game pages each reimplemented their own day-ID and progress-tracking logic.

BEFORE — identical auth script block at the bottom of all 13 pages:

// This ~50-line block was copy-pasted into EVERY page
(function() {
  var foplUser = JSON.parse(localStorage.getItem('fopl_user') || 'null');
  var authItem = document.getElementById('nav-auth-item');
  var authLink = document.getElementById('nav-auth-link');
  var dropdown = document.getElementById('nav-auth-dropdown');
  var signoutBtn = document.getElementById('nav-signout-btn');

  if (foplUser && authLink) {
    authItem.classList.add('fopl-nav-has-dropdown');
    authLink.textContent = foplUser.name.split(' ')[0];
    authLink.href = '#';
    authLink.onclick = function(e) {
      e.preventDefault();
      dropdown.classList.toggle('open');
    };
    document.addEventListener('click', function(e) {
      if (!authItem.contains(e.target)) dropdown.classList.remove('open');
    });
    signoutBtn.onclick = async function(e) {
      e.preventDefault();
      await fetch('http://127.0.0.1:8587/api/fopl/login', { // hardcoded in every page
        method: 'DELETE', credentials: 'include'
      }).catch(function() {});
      localStorage.removeItem('fopl_user');
      window.location.href = '/home';
    };
  }
})();

AFTERassets/js/fopl-shared.js owns all shared JS in clearly separated sections:

/* ═══════════════════════════════════════════
   FOPL shared JavaScript
   Auth nav dropdown, backend URL, game helpers
   ═══════════════════════════════════════════ */

// Shared backend URL — single source of truth
window.FOPL_BACKEND = 'http://127.0.0.1:8587';

// ── Auth nav dropdown (runs on every page) ──
(function initAuthNav() {
  var foplUser = JSON.parse(localStorage.getItem('fopl_user') || 'null');
  // ... same logic, but references window.FOPL_BACKEND instead of a hardcoded URL
})();

// ── Day-ID helper (shared across all daily games) ──
window.foplGetDayId = function() {
  var epoch = new Date('2024-01-01T00:00:00');
  var today = new Date();
  today.setHours(0, 0, 0, 0);
  return String(Math.floor((today - epoch) / 86400000));
};

// ── Overall game-progress tracker (shared across all games) ──
window.foplAddOverallProgress = function(game, points, won) {
  var overall = JSON.parse(
    localStorage.getItem('fopl_games_overall_v1') || '{"xp":0,"sessions":0,"wins":0,"byGame":{}}'
  );
  overall.xp = Number(overall.xp || 0) + Math.max(0, Number(points || 0));
  // ... updates wins, sessions, byGame breakdown ...
  localStorage.setItem('fopl_games_overall_v1', JSON.stringify(overall));
};

// ── Post puzzle result to backend (shared across all games) ──
window.foplPostResult = async function(game, won, guesses) {
  var user = JSON.parse(localStorage.getItem('fopl_user') || 'null');
  if (!user) return;
  await fetch(window.FOPL_BACKEND + '/api/fopl/puzzle/stats', {
    method: 'POST', credentials: 'include',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ game, won: !!won, guesses })
  });
};

Game pages now call window.foplGetDayId(), window.foplAddOverallProgress(), and window.foplPostResult() instead of reimplementing them.

Why this is better: Changing the backend URL is one line. Fixing a sign-out bug is one edit in one file. Adding a new shared game helper has a clear home — it doesn’t belong in any single game page.


File 5: Layout (_layouts/fopl.html) — UPDATED

Problem: The layout didn’t include any shared resources

The layout rendered page content but left every page responsible for loading its own fonts, nav, footer, and scripts.

BEFORE_layouts/fopl.html only injected `

Poway Woman's Club

Modernizing a 65-year-old community nonprofit's web presence with member portals, online payments, and a fresh UI — while preserving the heart of the original site.

Poway Woman's Club — Website Refurbishment Capstone
View Project
In Development
Project Leads Evan S, Maya D, Cyrus Z

Poway Woman's Club

Bringing a Legacy Nonprofit Into the Modern Web

Fix broken email button — replace with a working contact form
Full UI redesign with softer, cohesive color palette
Clarify the club's purpose with better visual hierarchy and messaging
Member login system with user profiles and personal dashboards
Interactive event calendar with RSVP functionality
Online membership payment portal
Admin panel for managing content, members, and events
Comment system / mini-blog for member interaction
Member activity and engagement tracking
Modern Responsive Frontend User Authentication & Profiles Event Calendar System Payment Integration Admin Dashboard Messaging / Comment Engine Data Tracking

About

A design-based research capstone that rebuilds the Poway Woman's Club website from the ground up. The club is a 501(c)(3) nonprofit founded in 1960 and affiliated with the General Federation of Women's Clubs International. For over six decades it has served Poway through scholarships, art exhibits, library support, and youth leadership programs — but its current site is a table-based layout with clashing colors, a broken email link, and no clear communication of its mission. This project delivers a modern, welcoming interface that makes the club's purpose obvious at a glance, lets new members sign up and pay dues online, gives existing members a space to interact through comments and calendars, and provides administrators with a dashboard to manage everything without touching code.

Impact

Makes the club's purpose and community work immediately clear to visitors
Removes friction from joining — members can sign up and pay online
Gives members a space to interact, comment, and stay connected between meetings
Provides administrators with a dashboard to manage events, members, and content
Modernizes a 65-year-old organization's digital presence while respecting its legacy
Preserves existing strengths: working navigation, meeting schedule, and contact info
Learn More

`:

<!DOCTYPE html>
<html>
<head>
  <title>SRP Refactoring — FOPL Frontend</title>
  <meta name="description" content="Applying the Single Responsibility Principle across the Friends of the Poway Library frontend — extracting duplicated nav, footer, styles, and shared JS from 13 pages into four shared files.">
  <link rel="icon" type="image/png" href="/FOTPL/fopllogo.png">
  <!-- no shared CSS -->
</head>
<body style="margin:0;padding:0;">
  












<style>
  /* === Post Header === */
  .post-header h3 {
    font-size: 1.8rem;
    font-weight: 600;
    margin-top: 0.5rem;
    margin-bottom: 0.5rem;
    line-height: 1.3;
  }

  .page-description {
    font-size: 1rem;
    color: #555;
    margin-bottom: 1rem;
  }

  /* === Meta Info (date, author, reading time) === */
  .post-meta {
    font-size: 0.9rem;
    color: #666;
    margin-bottom: 0.5rem;
  }

  .post-meta time {
    font-weight: 500;
  }

  /* === Category & Breadcrumb Links === */
  .category-tags-link {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    margin: 0.1rem;
    font-size: 0.85rem;
    background: #f5f5f5;
    border-radius: 999px;
    color: #333;
    text-decoration: none;
    transition: background 0.2s ease;
  }

  .category-tags-link:hover {
    background: #e0e0e0;
  }

  .post-header {
    margin-bottom: 1rem;
  }

  .post-header a.category-tags-link {
    margin-right: 0.3rem;
  }

  /* === Main Content Styling === */
  .post-content {
    line-height: 1.7;
    font-size: 1rem;
  }

  .post-content h2,
  .post-content h3 {
    margin-top: 1.5rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid #eee;
    padding-bottom: 0.3rem;
  }

  /* === Comments Section Separator === */
  .post-content+div,
  .post-content+section {
    margin-top: 2rem;
    padding-top: 1rem;
    border-top: 1px solid #ddd;
  }

  /* Assignment Submission Widget */
  .assignment-submission {
    margin-top: 48px;
    padding: 24px;
    background: #f9f9f9;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
  }

  .assignment-submission h3 {
    color: #333;
    font-size: 1.25rem;
    margin: 0 0 16px 0;
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .assignment-submission-icon {
    color: #2563eb;
  }

  .submission-options {
    display: flex;
    gap: 12px;
    margin-bottom: 20px;
    flex-wrap: wrap;
  }

  .submission-tab {
    padding: 8px 16px;
    background: white;
    border: 1px solid #d0d0d0;
    border-radius: 6px;
    color: #555;
    cursor: pointer;
    transition: all 0.2s;
  }

  .submission-tab:hover {
    background: #f0f0f0;
    color: #333;
  }

  .submission-tab.active {
    background: #2563eb;
    color: white;
    border-color: #2563eb;
  }

  .submission-form {
    display: none;
  }

  .submission-form.active {
    display: block;
  }

  .form-group {
    margin-bottom: 16px;
  }

  .form-group label {
    display: block;
    color: #333;
    font-size: 14px;
    margin-bottom: 8px;
    font-weight: 500;
  }

  .form-group input[type="text"],
  .form-group input[type="url"],
  .form-group textarea {
    width: 100%;
    padding: 10px 12px;
    background: white;
    border: 1px solid #d0d0d0;
    border-radius: 6px;
    color: #333;
    font-size: 14px;
    font-family: inherit;
  }

  .form-group input:focus,
  .form-group textarea:focus {
    outline: none;
    border-color: #2563eb;
  }

  .form-group textarea {
    min-height: 100px;
    resize: vertical;
  }

  .file-upload-area {
    border: 2px dashed #d0d0d0;
    border-radius: 8px;
    padding: 32px;
    text-align: center;
    cursor: pointer;
    transition: all 0.2s;
    background: white;
  }

  .file-upload-area:hover {
    border-color: #2563eb;
    background: #f0f7ff;
  }

  .file-upload-area.dragover {
    border-color: #2563eb;
    background: #f0f7ff;
  }

  .file-upload-icon {
    font-size: 48px;
    color: #2563eb;
    margin-bottom: 12px;
  }

  .file-upload-text {
    color: #555;
    margin-bottom: 8px;
  }

  .file-upload-hint {
    color: #999;
    font-size: 12px;
  }

  .file-list {
    margin-top: 16px;
  }

  .file-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px;
    background: white;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    margin-bottom: 8px;
  }

  .file-info {
    display: flex;
    align-items: center;
    gap: 12px;
  }

  .file-name {
    color: #333;
    font-size: 14px;
  }

  .file-size {
    color: #999;
    font-size: 12px;
  }

  .remove-file {
    background: transparent;
    border: none;
    color: #999;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 4px;
    transition: all 0.2s;
  }

  .remove-file:hover {
    background: #fee;
    color: #dc2626;
  }

  .submit-btn {
    padding: 12px 24px;
    background: #2563eb;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.2s;
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }

  .submit-btn:hover {
    background: #1d4ed8;
  }

  .submit-btn:disabled {
    background: #d0d0d0;
    color: #999;
    cursor: not-allowed;
  }

  .submission-status {
    margin-top: 16px;
    padding: 12px;
    border-radius: 6px;
    display: none;
  }

  .submission-status.success {
    display: block;
    background: #dbeafe;
    border: 1px solid #2563eb;
    color: #1e40af;
  }

  .submission-status.error {
    display: block;
    background: #fee2e2;
    border: 1px solid #dc2626;
    color: #991b1b;
  }
</style>

<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

  <header class="post-header">
    
    
    <p class="post-meta post-meta-title"><time class="dt-published" datetime="2026-03-09T00:00:00+00:00" itemprop="datePublished">
        Mar 9, 2026
      </time><span class="read-time" title="Estimated read time">
    
     1 min read  </span></p>
    <h3>Poway Woman&#39;s Club</h3><p class="page-description">Modernizing a 65-year-old community nonprofit's web presence with member portals, online payments, and a fresh UI — while preserving the heart of the original site.</p></header>

  <div class="post-content e-content" itemprop="articleBody">
<div class="wp-infograph">
 <!-- Header Section -->
 <div class="wp-header">
   <div class="wp-badge">Design-Based Research Capstone</div>
   <h1 class="wp-title">Poway Woman's Club — Website Refurbishment</h1>
   <p class="wp-description">Modernizing a 65-year-old community nonprofit's web presence with member portals, online payments, and a fresh UI — while preserving the heart of the original site.</p>
 </div>


 <!-- Project Cards -->
 
 <div class="wp-card">
   <div class="wp-card-grid">
    
     <!-- Left: Image & Status -->
     <div class="wp-visual">
       <a href="/capstone/poway-womans-club/" class="wp-image-link">
         <img src="/images/capstone/pwc_logo.png" alt="Poway Woman's Club — Website Refurbishment Capstone" class="wp-image" />
         <div class="wp-overlay">
           <span>View Project</span>
         </div>
       </a>
       <div class="wp-status">In Development</div>
       <div class="wp-team">
         <span class="wp-team-label">Project Leads</span>
         <span class="wp-team-name">Evan S, Maya D, Cyrus Z</span>
       </div>
     </div>


     <!-- Center: Key Points -->
     <div class="wp-content">
       <h2 class="wp-project-title">Poway Woman's Club</h2>
       <p class="wp-subtitle">Bringing a Legacy Nonprofit Into the Modern Web</p>
      
       <div class="wp-keypoints">
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Fix broken email button — replace with a working contact form</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Full UI redesign with softer, cohesive color palette</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Clarify the club's purpose with better visual hierarchy and messaging</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Member login system with user profiles and personal dashboards</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Interactive event calendar with RSVP functionality</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Online membership payment portal</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Admin panel for managing content, members, and events</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Comment system / mini-blog for member interaction</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Member activity and engagement tracking</span>
         </div>
         
       </div>


       <div class="wp-tech-stack">
         
         <span class="wp-tech-tag">Modern Responsive Frontend</span>
         
         <span class="wp-tech-tag">User Authentication &amp; Profiles</span>
         
         <span class="wp-tech-tag">Event Calendar System</span>
         
         <span class="wp-tech-tag">Payment Integration</span>
         
         <span class="wp-tech-tag">Admin Dashboard</span>
         
         <span class="wp-tech-tag">Messaging / Comment Engine</span>
         
         <span class="wp-tech-tag">Data Tracking</span>
         
       </div>
     </div>


     <!-- Right: Description & Impact -->
     <div class="wp-details">
       <h3 class="wp-section-title">About</h3>
       <p class="wp-about">A design-based research capstone that rebuilds the Poway Woman's Club website from the ground up. The club is a 501(c)(3) nonprofit founded in 1960 and affiliated with the General Federation of Women's Clubs International. For over six decades it has served Poway through scholarships, art exhibits, library support, and youth leadership programs — but its current site is a table-based layout with clashing colors, a broken email link, and no clear communication of its mission. This project delivers a modern, welcoming interface that makes the club's purpose obvious at a glance, lets new members sign up and pay dues online, gives existing members a space to interact through comments and calendars, and provides administrators with a dashboard to manage everything without touching code.</p>
      
       <h3 class="wp-section-title">Impact</h3>
       <div class="wp-impact-list">
         
         <div class="wp-impact-item">Makes the club's purpose and community work immediately clear to visitors</div>
         
         <div class="wp-impact-item">Removes friction from joining — members can sign up and pay online</div>
         
         <div class="wp-impact-item">Gives members a space to interact, comment, and stay connected between meetings</div>
         
         <div class="wp-impact-item">Provides administrators with a dashboard to manage events, members, and content</div>
         
         <div class="wp-impact-item">Modernizes a 65-year-old organization's digital presence while respecting its legacy</div>
         
         <div class="wp-impact-item">Preserves existing strengths: working navigation, meeting schedule, and contact info</div>
         
       </div>


       <a href="/capstone/poway-womans-club/" class="wp-btn">Learn More</a>
     </div>


   </div>
 </div>
 
</div>


    
  </div><a class="u-url" href="/capstone/poway-womans-club/" hidden></a>

  <!-- Enhanced Analytics Tracking -->
  <script type="module">
    import { pythonURI, javaURI } from '/assets/js/api/config.js';
    window.pythonURI = pythonURI;
    window.javaURI = javaURI;
  </script>
  <script src="/assets/js/ocs-analytics-enhanced.js"></script>
  <script src="/assets/js/code-runner-analytics.js"></script>
  <script src="/assets/js/lesson-completion.js"></script>
  <script src="/assets/js/lesson-completion-bigsix.js"></script>
</article>


  <!-- no nav, no footer, no shared JS -->
</body>
</html>

AFTER — the layout is the single place that wires everything together:

<!DOCTYPE html>
<html>
<head>
  <title>SRP Refactoring — FOPL Frontend</title>
  <meta name="description" content="Applying the Single Responsibility Principle across the Friends of the Poway Library frontend — extracting duplicated nav, footer, styles, and shared JS from 13 pages into four shared files.">
  <link rel="icon" type="image/png" href="/FOTPL/fopllogo.png">
  <link rel="stylesheet" href="/assets/css/fopl-shared.css">
</head>
<body style="margin:0;padding:0;">
  <nav class="fopl-nav">
  <div class="fopl-logo-wrap">
    <img src="/FOTPL/Images/fopllogo.png"
         alt="Friends of the Poway Library" />
  </div>
  <ul class="fopl-nav-links">
    <li><a href="/home">Home</a></li>
    <li><a href="/history">History</a></li>
    
    <li><a href="/bookstore">Bookstore</a></li>
    <li><a href="/news">Newsletters</a></li>
    <li><a href="/puzzles">Puzzles</a></li>
    <li><a href="/contact">Contact Us</a></li>
    <li id="nav-auth-item"><a href="/login" id="nav-auth-link">Sign In</a>
      <ul class="fopl-nav-dropdown" id="nav-auth-dropdown">
        <li><a href="/profile">Profile</a></li>
        <li><a href="#" id="nav-signout-btn">Sign Out</a></li>
      </ul>
    </li>
  </ul>
</nav>

  












<style>
  /* === Post Header === */
  .post-header h3 {
    font-size: 1.8rem;
    font-weight: 600;
    margin-top: 0.5rem;
    margin-bottom: 0.5rem;
    line-height: 1.3;
  }

  .page-description {
    font-size: 1rem;
    color: #555;
    margin-bottom: 1rem;
  }

  /* === Meta Info (date, author, reading time) === */
  .post-meta {
    font-size: 0.9rem;
    color: #666;
    margin-bottom: 0.5rem;
  }

  .post-meta time {
    font-weight: 500;
  }

  /* === Category & Breadcrumb Links === */
  .category-tags-link {
    display: inline-block;
    padding: 0.2rem 0.6rem;
    margin: 0.1rem;
    font-size: 0.85rem;
    background: #f5f5f5;
    border-radius: 999px;
    color: #333;
    text-decoration: none;
    transition: background 0.2s ease;
  }

  .category-tags-link:hover {
    background: #e0e0e0;
  }

  .post-header {
    margin-bottom: 1rem;
  }

  .post-header a.category-tags-link {
    margin-right: 0.3rem;
  }

  /* === Main Content Styling === */
  .post-content {
    line-height: 1.7;
    font-size: 1rem;
  }

  .post-content h2,
  .post-content h3 {
    margin-top: 1.5rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid #eee;
    padding-bottom: 0.3rem;
  }

  /* === Comments Section Separator === */
  .post-content+div,
  .post-content+section {
    margin-top: 2rem;
    padding-top: 1rem;
    border-top: 1px solid #ddd;
  }

  /* Assignment Submission Widget */
  .assignment-submission {
    margin-top: 48px;
    padding: 24px;
    background: #f9f9f9;
    border: 1px solid #e0e0e0;
    border-radius: 12px;
  }

  .assignment-submission h3 {
    color: #333;
    font-size: 1.25rem;
    margin: 0 0 16px 0;
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .assignment-submission-icon {
    color: #2563eb;
  }

  .submission-options {
    display: flex;
    gap: 12px;
    margin-bottom: 20px;
    flex-wrap: wrap;
  }

  .submission-tab {
    padding: 8px 16px;
    background: white;
    border: 1px solid #d0d0d0;
    border-radius: 6px;
    color: #555;
    cursor: pointer;
    transition: all 0.2s;
  }

  .submission-tab:hover {
    background: #f0f0f0;
    color: #333;
  }

  .submission-tab.active {
    background: #2563eb;
    color: white;
    border-color: #2563eb;
  }

  .submission-form {
    display: none;
  }

  .submission-form.active {
    display: block;
  }

  .form-group {
    margin-bottom: 16px;
  }

  .form-group label {
    display: block;
    color: #333;
    font-size: 14px;
    margin-bottom: 8px;
    font-weight: 500;
  }

  .form-group input[type="text"],
  .form-group input[type="url"],
  .form-group textarea {
    width: 100%;
    padding: 10px 12px;
    background: white;
    border: 1px solid #d0d0d0;
    border-radius: 6px;
    color: #333;
    font-size: 14px;
    font-family: inherit;
  }

  .form-group input:focus,
  .form-group textarea:focus {
    outline: none;
    border-color: #2563eb;
  }

  .form-group textarea {
    min-height: 100px;
    resize: vertical;
  }

  .file-upload-area {
    border: 2px dashed #d0d0d0;
    border-radius: 8px;
    padding: 32px;
    text-align: center;
    cursor: pointer;
    transition: all 0.2s;
    background: white;
  }

  .file-upload-area:hover {
    border-color: #2563eb;
    background: #f0f7ff;
  }

  .file-upload-area.dragover {
    border-color: #2563eb;
    background: #f0f7ff;
  }

  .file-upload-icon {
    font-size: 48px;
    color: #2563eb;
    margin-bottom: 12px;
  }

  .file-upload-text {
    color: #555;
    margin-bottom: 8px;
  }

  .file-upload-hint {
    color: #999;
    font-size: 12px;
  }

  .file-list {
    margin-top: 16px;
  }

  .file-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px;
    background: white;
    border: 1px solid #e0e0e0;
    border-radius: 6px;
    margin-bottom: 8px;
  }

  .file-info {
    display: flex;
    align-items: center;
    gap: 12px;
  }

  .file-name {
    color: #333;
    font-size: 14px;
  }

  .file-size {
    color: #999;
    font-size: 12px;
  }

  .remove-file {
    background: transparent;
    border: none;
    color: #999;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 4px;
    transition: all 0.2s;
  }

  .remove-file:hover {
    background: #fee;
    color: #dc2626;
  }

  .submit-btn {
    padding: 12px 24px;
    background: #2563eb;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.2s;
    display: inline-flex;
    align-items: center;
    gap: 8px;
  }

  .submit-btn:hover {
    background: #1d4ed8;
  }

  .submit-btn:disabled {
    background: #d0d0d0;
    color: #999;
    cursor: not-allowed;
  }

  .submission-status {
    margin-top: 16px;
    padding: 12px;
    border-radius: 6px;
    display: none;
  }

  .submission-status.success {
    display: block;
    background: #dbeafe;
    border: 1px solid #2563eb;
    color: #1e40af;
  }

  .submission-status.error {
    display: block;
    background: #fee2e2;
    border: 1px solid #dc2626;
    color: #991b1b;
  }
</style>

<article class="post h-entry" itemscope itemtype="http://schema.org/BlogPosting">

  <header class="post-header">
    
    
    <p class="post-meta post-meta-title"><time class="dt-published" datetime="2026-03-09T00:00:00+00:00" itemprop="datePublished">
        Mar 9, 2026
      </time><span class="read-time" title="Estimated read time">
    
     1 min read  </span></p>
    <h3>Poway Woman&#39;s Club</h3><p class="page-description">Modernizing a 65-year-old community nonprofit's web presence with member portals, online payments, and a fresh UI — while preserving the heart of the original site.</p></header>

  <div class="post-content e-content" itemprop="articleBody">
<div class="wp-infograph">
 <!-- Header Section -->
 <div class="wp-header">
   <div class="wp-badge">Design-Based Research Capstone</div>
   <h1 class="wp-title">Poway Woman's Club — Website Refurbishment</h1>
   <p class="wp-description">Modernizing a 65-year-old community nonprofit's web presence with member portals, online payments, and a fresh UI — while preserving the heart of the original site.</p>
 </div>


 <!-- Project Cards -->
 
 <div class="wp-card">
   <div class="wp-card-grid">
    
     <!-- Left: Image & Status -->
     <div class="wp-visual">
       <a href="/capstone/poway-womans-club/" class="wp-image-link">
         <img src="/images/capstone/pwc_logo.png" alt="Poway Woman's Club — Website Refurbishment Capstone" class="wp-image" />
         <div class="wp-overlay">
           <span>View Project</span>
         </div>
       </a>
       <div class="wp-status">In Development</div>
       <div class="wp-team">
         <span class="wp-team-label">Project Leads</span>
         <span class="wp-team-name">Evan S, Maya D, Cyrus Z</span>
       </div>
     </div>


     <!-- Center: Key Points -->
     <div class="wp-content">
       <h2 class="wp-project-title">Poway Woman's Club</h2>
       <p class="wp-subtitle">Bringing a Legacy Nonprofit Into the Modern Web</p>
      
       <div class="wp-keypoints">
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Fix broken email button — replace with a working contact form</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Full UI redesign with softer, cohesive color palette</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Clarify the club's purpose with better visual hierarchy and messaging</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Member login system with user profiles and personal dashboards</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Interactive event calendar with RSVP functionality</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Online membership payment portal</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Admin panel for managing content, members, and events</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Comment system / mini-blog for member interaction</span>
         </div>
         
         <div class="wp-keypoint">
           <span class="wp-check"></span>
           <span>Member activity and engagement tracking</span>
         </div>
         
       </div>


       <div class="wp-tech-stack">
         
         <span class="wp-tech-tag">Modern Responsive Frontend</span>
         
         <span class="wp-tech-tag">User Authentication &amp; Profiles</span>
         
         <span class="wp-tech-tag">Event Calendar System</span>
         
         <span class="wp-tech-tag">Payment Integration</span>
         
         <span class="wp-tech-tag">Admin Dashboard</span>
         
         <span class="wp-tech-tag">Messaging / Comment Engine</span>
         
         <span class="wp-tech-tag">Data Tracking</span>
         
       </div>
     </div>


     <!-- Right: Description & Impact -->
     <div class="wp-details">
       <h3 class="wp-section-title">About</h3>
       <p class="wp-about">A design-based research capstone that rebuilds the Poway Woman's Club website from the ground up. The club is a 501(c)(3) nonprofit founded in 1960 and affiliated with the General Federation of Women's Clubs International. For over six decades it has served Poway through scholarships, art exhibits, library support, and youth leadership programs — but its current site is a table-based layout with clashing colors, a broken email link, and no clear communication of its mission. This project delivers a modern, welcoming interface that makes the club's purpose obvious at a glance, lets new members sign up and pay dues online, gives existing members a space to interact through comments and calendars, and provides administrators with a dashboard to manage everything without touching code.</p>
      
       <h3 class="wp-section-title">Impact</h3>
       <div class="wp-impact-list">
         
         <div class="wp-impact-item">Makes the club's purpose and community work immediately clear to visitors</div>
         
         <div class="wp-impact-item">Removes friction from joining — members can sign up and pay online</div>
         
         <div class="wp-impact-item">Gives members a space to interact, comment, and stay connected between meetings</div>
         
         <div class="wp-impact-item">Provides administrators with a dashboard to manage events, members, and content</div>
         
         <div class="wp-impact-item">Modernizes a 65-year-old organization's digital presence while respecting its legacy</div>
         
         <div class="wp-impact-item">Preserves existing strengths: working navigation, meeting schedule, and contact info</div>
         
       </div>


       <a href="/capstone/poway-womans-club/" class="wp-btn">Learn More</a>
     </div>


   </div>
 </div>
 
</div>


    
  </div><a class="u-url" href="/capstone/poway-womans-club/" hidden></a>

  <!-- Enhanced Analytics Tracking -->
  <script type="module">
    import { pythonURI, javaURI } from '/assets/js/api/config.js';
    window.pythonURI = pythonURI;
    window.javaURI = javaURI;
  </script>
  <script src="/assets/js/ocs-analytics-enhanced.js"></script>
  <script src="/assets/js/code-runner-analytics.js"></script>
  <script src="/assets/js/lesson-completion.js"></script>
  <script src="/assets/js/lesson-completion-bigsix.js"></script>
</article>


  <div class="fopl-deco-scene" aria-hidden="true">
  <img class="deco-palm" src="/FOTPL/Images/PalmTree.png" alt="">
  <img class="deco-palm" src="/FOTPL/Images/PalmTree.png" alt="" style="height:115px;animation-delay:0.8s;">
  <img class="deco-book-mascot" src="/FOTPL/Images/bookclipart.png" alt="">
  <img class="deco-palm deco-palm--right" src="/FOTPL/Images/PalmTree.png" alt="" style="height:115px;animation-delay:1.2s;">
  <img class="deco-palm deco-palm--right" src="/FOTPL/Images/PalmTree.png" alt="">
</div>

<div class="fopl-footer">
  &copy; 2025 Friends of the Poway Library &mdash;
  <a href="https://powayfriends.org">powayfriends.org</a>
</div>

  <script src="/assets/js/fopl-shared.js"></script>
</body>
</html>

Pages set layout: fopl and get nav + footer + shared styles + shared JS automatically.

Why this is better: The layout’s one job is page assembly. Adding a new shared resource (e.g., a new analytics script) to all pages is now a single line in _layouts/fopl.html.


Key Takeaways

  • Zero visual changes — every page looks and behaves identically after the refactor
  • 1,543 lines removed across 13 page files — all of it duplicated code
  • 4 shared files added — each with exactly one job: nav HTML, footer HTML, shared CSS, shared JS
  • Pages now only contain page content — no nav, no footer, no shared styles, no auth logic
  • One change = one file — updating the nav, fixing a font, or changing the backend URL now requires editing exactly one file instead of all 13

Files Changed Summary

File Path Lines Before Lines After Notes
_includes/fopl-nav.html 21 NEW — shared nav HTML
_includes/fopl-footer.html 4 NEW — shared footer HTML
assets/css/fopl-shared.css 136 NEW — all shared styles
assets/js/fopl-shared.js 79 NEW — auth dropdown, backend URL, game helpers
_layouts/fopl.html 11 15 +shared CSS link, nav include, footer include, JS script
13 × FOTPL/*.md pages ~118 ea. page-only ~1,543 lines of duplicated chrome removed