PVR Tech Studio

Layout

The page shell — header, sidebar, main content area and footer — how it's composed from PUG mixins, and the sticky-header and responsive behavior.

3 min read
Updated June 21, 2026

Every page is built from the same shell: a top header/navbar, a left sidebar, the main content area (with a sticky page header), and a footer. In the canonical HTML edition the shell is assembled in PUG from reusable mixins, then compiled to static HTML. This page documents both — the mixins you call and the markup they produce.

How the shell is composed (PUG)

A page template includes the common partials and calls four mixins. The header, sidebar, page header and footer each come from a mixin; your content goes inside main, in .pageWrapper:

include common_pages/mainInclude
include common_pages/pageHeader
include common_pages/mixins/panelCard
include common_pages/mixins/colLayout
 
+headSection({ title: 'My Page | Taxi CRM', canonical: 'myPage.html' })
+loadingScreen()
+headerSection({ showPrimaryNav: false })          // top navbar
+sidebarSection()                                  // left rail
main.d-flex.flex-column.has-sticky-header
    +pageHeader({ currentPage: 'myPage.html', fixed: true })   // title + breadcrumb
    .d-flex.flex-column.pageWrapper
        // ▼ YOUR PAGE CONTENT ▼
 
include common_pages/notifications
include common_pages/chatApp
+footerSection()                                   // footer

Mixin config flags drive the layout variants (showPrimaryNav, fixedNav, fixed, fixedFooter, bodyClass) — see Page Layouts.

Page shell — compiled markup

The mixins above compile to this structure:

<!-- 1. Header / top navbar (wrapped in #app-main) -->
<div class="d-flex flex-column app-main" id="app-main">
  <header class="d-flex app-page flex-column"> … </header>
</div>
 
<!-- 2. Sidebar -->
<aside class="app-sidebar flex-column drawer drawer-start"> … </aside>
 
<!-- 3. Main content -->
<main class="d-flex flex-column has-sticky-header">
  <div class="page-header page-header-default page-header-fixed"> … </div>
  <div class="d-flex flex-column pageWrapper">
    <!-- ▼ YOUR PAGE CONTENT ▼ -->
  </div>
</main>
 
<!-- 4. Footer -->
<footer class="app-footer"> … </footer>

Key hooks:

ElementClass / idPurpose
App wrapper#app-main / .app-mainFlex container the headerSection mixin wraps the header in.
Main areamain.has-sticky-headerReserves space for the pinned navbar and enables the sticky page-header behavior.
Page header.page-header.page-header-default.page-header-fixedTitle + breadcrumb bar (page-header-fixed makes it sticky).
Content slot.pageWrapperPut your page content here.

Header / top navbar

<header class="d-flex app-page flex-column">
  <!-- Slide-down search -->
  <form class="site-search" method="get">
    <input type="text" name="site_search" placeholder="Type to search..." autocomplete="off">
    <div class="search-tools">
      <span class="clear-search">Clear</span>
      <span class="close-search"><span class="material-symbols-sharp">close</span></span>
    </div>
  </form>
 
  <nav class="navbar navbar-expand-md fixed-top">
    <div class="container-fluid ps-0 pe-0">
      <!-- Brand (mobile) -->
      <div class="d-flex align-items-center" id="mobileBrandingLink">
        <a class="d-flex align-items-center text-decoration-none" href="dashboard.html">
          <img alt="Taxi CRM Logo" height="38" src="assets/img/logo/logo.png" width="38">
          <span class="text-nowrap fs-4 ms-2">Taxi CRM</span>
        </a>
      </div>
 
      <!-- Sidebar toggle (mobile) -->
      <div class="me-1 me-md-2" id="sidebarTrigger">
        <span class="material-symbols-sharp btn btn-primary btn-sm">menu</span>
      </div>
      <!-- Minify sidebar (desktop) -->
      <div class="d-lg-flex me-1 me-md-2" id="minifySidebar">
        <span class="material-symbols-sharp btn btn-primary btn-sm">menu</span>
      </div>
 
      <!-- Primary nav (optional quick-access dropdowns) -->
      <div class="collapse navbar-collapse" id="primaryNav">
        <ul class="navbar-nav align-items-center"> … </ul>
      </div>
 
      <!-- Right-side actions -->
      <div class="collapse navbar-collapse" id="navbarActions">
        <ul class="navbar-nav">
          <li class="nav-item languageSwitcher w-auto"> … </li>   <!-- language switcher -->
          <li class="nav-item">
            <button class="header-nav-link btn border-0 btn-lg btn-icons theme-toggle" id="themeToggle" type="button">
              <span class="material-symbols-sharp">dark_mode</span>
            </button>
          </li>
          <li class="nav-item searchBar"> … </li>                 <!-- opens .site-search -->
          <li class="nav-item appItems"> … </li>                  <!-- apps dropdown -->
          <li class="nav-item dropdown notification" data-bs-toggle="offcanvas" data-bs-target="#notificationsOffcanvas">
            <span class="notification-count">8</span> …
          </li>
          <li class="nav-item" data-bs-toggle="offcanvas" data-bs-target="#chat-app"> … </li> <!-- messages -->
          <li class="nav-item">
            <button class="header-nav-link btn border-0 btn-lg btn-icons" id="toggleFullScreen" type="button">
              <span class="material-symbols-sharp">fullscreen</span>
            </button>
          </li>
          <li class="nav-item userProfile"> … </li>               <!-- user/profile dropdown -->
        </ul>
      </div>
    </div>
  </nav>
</header>

The header behaviors (theme toggle via #themeToggle, language switcher, fullscreen, search, sidebar minify) are wired up automatically by assets/js/core/app.js — see JavaScript. The notifications and chat panels live in shared offcanvas markup pulled in by include common_pages/notifications and include common_pages/chatApp (#notificationsOffcanvas, #chat-app).

<aside class="app-sidebar flex-column drawer drawer-start">
  <div class="d-flex" id="brandingLink">
    <a class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-decoration-none" href="dashboard.html">
      <img alt="Taxi CRM Logo" height="44" src="assets/img/logo/logo.png" width="44">
      <span class="text-nowrap">Taxi CRM</span>
    </a>
  </div>
 
  <div class="d-flex flex-column flex-shrink-0" id="navigations">
    <ul class="nav nav-pills flex-row mb-auto addSlimScroll">
      <div class="nav-hover-bg"></div>
      <div class="nav-active-bg"></div>
 
      <!-- Section divider -->
      <li class="nav-item divider">
        <span class="text">Taxi Booking</span>
        <span class="material-symbols-sharp">filter_list</span>
      </li>
 
      <!-- Collapsible group with children -->
      <li class="nav-item nav-accordion active">
        <span class="nav-link">
          <span class="make_icon material-symbols-sharp">database</span>
          <span class="nav-title">Masters</span>
          <span class="nav-arrow"></span>
        </span>
        <div class="nav-sub nav-sub-accordion">
          <div class="nav-item-sub active">
            <a class="nav-link" href="roleMaster.html"><span class="nav-title">Role Master</span></a>
            <a class="nav-add-icon" href="addRoleMaster.html" title="Add Role">
              <span class="material-symbols-sharp">add</span>
            </a>
          </div>
          <!-- more .nav-item-sub … -->
        </div>
      </li>
 
      <!-- Plain item with no children -->
      <li class="nav-item no-child">
        <a class="nav-link" href="faqPage.html">
          <span class="make_icon material-symbols-sharp">help</span>
          <span class="nav-title">FAQ Page</span>
        </a>
      </li>
    </ul>
  </div>
</aside>

Sidebar class reference:

ClassRole
nav-accordionCollapsible menu group (shows the nav-arrow chevron). Add active to expand/highlight.
nav-sub / nav-sub-accordionThe submenu container, revealed when the group is open.
nav-item-subA single submenu entry (link + optional nav-add-icon).
no-childA top-level item that links directly (no submenu).
make_icon + material-symbols-sharpThe leading menu icon.
nav-titleThe menu label (translate with data-i18n).
dividerA section heading inside the menu.
addSlimScrollApplies the slim-scroll plugin to the menu list.

In the HTML edition the whole menu is data-driven: aside.pug iterates the ITEMS menu structure (asideItems.pug) to emit these .nav-accordion / .nav-item-sub / .no-child items, sets active automatically by matching the current page, and pulls "Add" shortcuts from ADD_PAGE_MAP. The markup above is what one entry compiles to.

To highlight the current page (in plain compiled HTML): add active to its .nav-item-sub (and to the parent .nav-accordion), or to its .nav-item.no-child.

<footer class="app-footer">
  <nav class="navbar navbar-expand-lg fixed-bottom">
    <div class="container-fluid navbar-brand">
      <div class="d-flex flex-column">
        <ul class="navbar-nav">
          <li class="nav-item"><a class="nav-link active" aria-current="page" href="dashboard.html">Home</a></li>
          <li class="nav-item"><a class="nav-link" href="javascript:void(0)">Website</a></li>
          <li class="nav-item"><a class="nav-link" href="javascript:void(0)">Portfolio</a></li>
          <li class="nav-item"><a class="nav-link" href="javascript:void(0)">Terms</a></li>
          <li class="nav-item"><a class="nav-link" href="javascript:void(0)">License</a></li>
          <li class="nav-item"><a class="nav-link" href="javascript:void(0)">Privacy Policy</a></li>
        </ul>
      </div>
      <div class="text-dark pb-0">
        <span class="me-2">© 2026</span>
        <a class="text-dark me-0" href="http://www.pvrtechstudio.com/">PVR Tech Studio</a>
      </div>
    </div>
  </nav>
</footer>

The footer mixin takes fixedFooter (default true) — set +footerSection({ fixedFooter: false }) to drop fixed-bottom.

Page header (title + breadcrumb)

The page header is generated by the pageHeader / autoPageHeader mixin. You pass the current page and it auto-resolves the title and breadcrumb by looking the page up in the ITEMS menu structure; it can also render a right-aligned stats strip (Bookings / Drivers / Revenue with sparklines) when showStats is on:

+pageHeader({ currentPage: 'roleMaster.html', fixed: true })

That compiles to:

<div class="page-header page-header-default page-header-fixed">
  <div class="page-header-content d-flex justify-content-between align-items-end">
    <div class="page-title">
      <h5><span class="fw-bold">Role Master</span><span> - </span><span>Masters</span></h5>
      <ul class="breadcrumb d-flex flex-wrap list-unstyled mb-0">
        <li><a class="text-primary text-decoration-none" href="dashboard.html">Home</a></li>
        <li><a class="text-primary text-decoration-none" href="javascript:void(0)">Masters</a></li>
        <li class="active text-secondary"><span>Role Master</span></li>
      </ul>
    </div>
    <!-- optional: #breadcrumb-right stats with .sparkline -->
  </div>
</div>

fixed: true adds page-header-fixed (sticky); fixed: false lets the bar scroll away.

Responsive & mobile behavior

The sidebar is a drawer drawer-start rail. On wide screens it sits beside the content; below the navbar's navbar-expand-md breakpoint the hamburger (#sidebarTrigger, in the header) slides it in as an off-canvas drawer. On desktop, #minifySidebar toggles the icon-only minified state, which simply reduces --app-width-lhs from 16.5625rem to 5.625rem. Loading a page with <body class="minSidebar"> starts in that collapsed state.

Breakpoints come from 01-variable.less (500 / 767 / 799 / 991 / 992 / 1149 / 1150px and more) — see CSS System.

Layout variants

The kit ships demo pages showing different header / footer / sidebar modes, each produced by flipping a mixin config flag (showPrimaryNav, fixedNav, fixed, fixedFooter, bodyClass). For the full list of variants, the exact flags, and which classes they emit, see Page Layouts.

Was this page helpful?