Building A PWA Template: Structure, Styling And Core UI

Learning Lab
My Journey Through Books, Discoveries, and Ideas

Building a PWA Template: structure, styling and core UI

This is the first part of a series detailing the creation of a generic Progressive Web Application (PWA) template. The goal is to build a reusable foundation packed with common features needed for modern web apps. This part focuses on the foundational elements: HTML structure, CSS styling, core application logic, local storage, and basic UI components.

HTML structure

The application uses two main HTML files: index.html for the main interface and help/index.html for a separate help page. Both leverage Bootstrap 5 for layout and core components.

index.html sets up the primary view:

  • Offcanvas Sidebar: A collapsible sidebar (#offcanvasSidebar) for file management (listing files, add/rename/delete buttons).
  • Main Content Area: Contains the header with controls and the primary content display area.
    • Header: Includes a button to toggle the sidebar, the current file name (#currentFileNameHeader), a language switcher, sync status indicator, Dropbox button, and help link.
    • Content Placeholder: An area (#main-content-area) for application-specific UI, pre-filled with examples of the template’s UI components.
  • Modals: Bootstrap modals for user interactions (add/rename/delete files, sync conflicts).

<!-- Snippet from index.html Header -->
<div class="pt-3 pb-2 mb-3 border-bottom d-flex justify-content-between align-items-center flex-wrap">
  <div class="d-flex align-items-center me-3 mb-2 mb-md-0">
    <button class="btn btn-light me-3" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasSidebar">...</button>
    <h1 class="h2 mb-0" id="currentFileNameHeader" data-i18n="main.header.currentFile">Current File</h1>
  </div>
  <div class="d-flex align-items-center">
    <!-- Language Dropdown -->
    <div class="dropdown me-2">...</div>
    <!-- Sync Status -->
    <span id="syncStatusIndicator" class="me-2 text-muted small"></span>
    <!-- Dropbox Button -->
    <button type="button" id="dropboxAuthButton" class="btn btn-light p-1 btn-fa me-2">...</button>
    <!-- Help Link -->
    <a href="help/" class="btn btn-light btn-fa p-1">...</a>
  </div>
</div>

This structure provides a clean and adaptable base for various PWA applications.

CSS styling

Styling relies heavily on Bootstrap 5. Customizations are added via:

  • TEMPLATE.css: Contains general overrides, theme colors (primary #0083B3, complementary #FF4030), button styling, layout adjustments, and styles for the file list sidebar and Dropbox button. It also includes a simple mechanism to prevent Flash of Unstyled Content (FOUC).
  • Component CSS (assets/css/ui/, assets/css/notif.min.css): Minified CSS for the datepicker, switch, and notification toasts.

/* Example Theme Variables in TEMPLATE.css */
.btn-primary {
  --bs-btn-color:#FFF;
  --bs-btn-bg:#0083B3;
  --bs-btn-border-color:#0083B3;
  /* ... hover, active, disabled states ... */
}

.btn-complementary {
  --bs-btn-color: #FFF;
  --bs-btn-bg: #FF4030;
  --bs-btn-border-color: #FF4030;
  /* ... hover, active, disabled states ... */
}

/* FOUC Prevention */
body {
  opacity: 0; /* Initially hidden */
  transition: opacity 0.4s ease-in-out;
}
body.localized {
  opacity: 1; /* Visible once i18next is ready */
}

The styling aims for a clean, modern look that’s easily customizable.

JavaScript implementation: core logic and storage

The application logic is modularized for maintainability.

Core application logic

This script acts as the main entry point for UI interactions.

  • Initialization: Calls initializeDropboxSync() (covered in Part 2) and sets up listeners for file management buttons.
  • Modal Handling: Manages the opening of Bootstrap modals for file operations, populating necessary data and initializing event listeners dynamically.
Storage system

Handles data persistence using localStorage and file management logic.

  • storage.js: Provides low-level access to localStorage. Manages:
    • A list of known files (knownFiles).
    • The currently active file (activeFile).
    • Content and metadata for each file using dynamic keys.
    • Ensures a default file exists.
    • Dispatches a localDataChanged event on save.
  • files.js: Implements higher-level file operations triggered by the UI.
    • Updates the file list UI in the sidebar.
    • Handles adding, renaming, and deleting files locally and initiates corresponding Dropbox actions.

// Simplified storage structure in localStorage
// knownFiles: [{"name": "default.txt", "path": "/default.txt"}, ...]
// activeFile: "/default.txt"
// content_/default.txt: "File content here"
// lastModified_/default.txt: 1678886400000
// lastSync_/default.txt: 1678886400000

JavaScript implementation: UI components

Reusable UI components enhance the user experience.

  • datepicker.js: Initializes the Bootstrap Datepicker on .date-picker elements.
  • switch.js: Initializes Bootstrap switches, setting labels based on state and data-checked/data-unchecked attributes.
  • notif.js: Provides functions to show notifications and contains logic to initialize switches with i18n support (more on i18n in Part 2).
  • notif-flash.min.js: Displays notifications based on URL parameters and defines the global showNotification function for Bootstrap Toasts.

// Example: Initializing a datepicker
$('.date-picker').datepicker({
    format: 'yyyy-mm-dd',
    autoclose: true,
    // ... other options
});

// Example: Showing a notification
showNotification('File saved successfully!', 'success');

You can access the full source code, at the GitHub repository here.

For more insights into this topic, you can find the details here.