Page templates
Global layout
The global layout can be used for inner pages on the City of Winnipeg website. It uses the global header , global footer , breadcrumbs , a search bar and sidebar navigation . Inner page content would vary based on need.
Template structure
The global page layout uses the body class of global
along with the following elements for the general page structure.
<!DOCTYPE html>
<html lang= "en" >
<head>
<title> Page title</title>
</head>
<body class= "global" >
<!-- Insert global header here -->
<div class= "container" >
<div class= "mt-4 mb-4" >
<!-- Insert breadcrumbs here -->
</div>
<div class= "row" >
<div class= "col-12 col-md-12 col-lg-3 col-xl-3" >
<div class= "sidebar" >
<!-- Optional search bar -->
<div class= "form-group sm search-group mb-4" >
<input type= "search" class= "form-control form-control-sm google-search" placeholder= "Search 311 City Services" aria-label= "Search 311 City Services" >
<button type= "submit" aria-label= "Search 311 City Services" class= "btn btn-sm btn-search" ><i aria-hidden= "true" class= "far fa-search" ></i></button>
</div>
<!-- Insert side navigation here -->
</div>
</div>
<main class= "col-12 col-sm-12 col-lg-9 col-xl-9" >
<div class= "cw-content" >
<!-- Page content -->
</div>
</main>
</div>
</div>
<!-- Insert global footer here -->
</body>
</html>
Sample pages
These sample pages have been pre-built including all default design system CSS and JavaScript .
How it works
The following JavaScript for initializing Bootstrap components and for custom component functionality has also been included (assets/js/global.js
):
$ ( document ). ready ( function () {
/* ==================== Global header =================== */
// Search bar
$ ( '#globalSearchInput' ). keyup ( function (){
if ( $ ( this ). val () === '' ){
$ ( '#globalSearchBtn' ). attr ( "disabled" , true );
} else {
$ ( '#globalSearchBtn' ). attr ( "disabled" , false );
}
});
// Mobile menu
function openMenu (){
$ ( 'html' ). scrollTop ( 0 );
$ ( '.headerGradient' ). fadeIn ( 200 );
$ ( '.headerGradient' ). addClass ( 'menuOpen' );
$ ( 'nav.main-nav' ). addClass ( 'in' );
$ ( 'body' ). css ({ 'position' : 'fixed' , 'left' : 0 , 'right' : 0 , 'top' : 0 });
}
function closeMenu (){
$ ( '.headerGradient' ). fadeOut ( 200 );
$ ( '.headerGradient' ). removeClass ( 'menuOpen' );
$ ( 'nav.main-nav' ). removeClass ( 'in' );
$ ( 'body' ). css ({ 'position' : 'initial' , 'left' : 'auto' , 'right' : 'auto' , 'top' : 'auto' });
}
$ ( '.menuBtn' ). click ( function () {
openMenu ();
})
// Mobile search
function openSearch (){
$ ( 'html' ). scrollTop ( 0 );
$ ( '.headerGradient' ). fadeIn ( 200 );
$ ( '.global-header .search-group-container' ). addClass ( 'in' );
$ ( '.global-header .search-group-container input' ). focus ();
$ ( 'body' ). css ({ 'position' : 'fixed' , 'left' : 0 , 'right' : 0 , 'top' : 0 });
}
function closeSearch (){
$ ( '.headerGradient' ). fadeOut ( 200 );
$ ( '.global-header .search-group-container' ). removeClass ( 'in' );
$ ( 'body' ). css ({ 'position' : 'initial' , 'left' : 'auto' , 'right' : 'auto' , 'top' : 'auto' });
}
$ ( '.searchBtn' ). click ( function () {
openSearch ();
})
// Close search and menu on gradient click
$ ( '.headerGradient, .headerCloseBtn' ). click ( function () {
closeMenu ();
closeSearch ();
})
/* ==================== Enable tooltips =================== */
$ ( '[data-toggle="tooltip"]' ). tooltip ();
// Dark styled
$ ( '.dark-tooltip' ). tooltip ({
'template' : '<div class="tooltip dark" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
});
/* ==================== Datepicker - https://bootstrap-datepicker.readthedocs.io/en/stable/ =================== */
//----- Enable single date picker
$ ( '.datePicker' ). datepicker ({
format : 'mm/dd/yyyy' ,
startDate : '-3d' ,
todayHighlight : true ,
daysOfWeekDisabled : '0,6'
});
// Single date picker trigger
$ ( '.datePickerTrigger' ). click ( function () {
$ ( this ). closest ( '.input-group' ). find ( '.datePicker' ). datepicker ( 'show' );
})
//----- Enable date range
$ ( '.dateRange' ). datepicker ({
inputs : $ ( '.dateRangeInput' )
});
// Date range trigger
$ ( '.dateRangeTrigger' ). click ( function () {
$ ( this ). closest ( '.input-group' ). find ( '.dateRangeInput' ). datepicker ( 'show' );
})
/* ==================== Accordions =================== */
$ ( '.accordion .heading' ). click ( function () {
// Toggle the icon
$ ( this ). find ( 'i' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
})
$ ( '.collapse' ). on ( 'hidden.bs.collapse' , function () {
// Toggle the icon
$ ( this ). find ( 'i.fa-chevron-up' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
// Disable the expand all link
var id = $ ( this ). closest ( '.accordion' ). attr ( 'id' );
$ ( '.expandAll[data-target="#' + id + '"]' ). removeClass ( 'disabled' );
// If all items are hidden then disable the collapse link
if ( $ ( this ). closest ( '.accordion' ). find ( '.collapse.show' ). length == 0 ) {
$ ( '.collapseAll[data-target="#' + id + '"]' ). addClass ( 'disabled' );
}
})
$ ( '.collapse' ). on ( 'shown.bs.collapse' , function () {
// Toggle the icon
$ ( this ). find ( 'i.fa-chevron-down' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
// Disable the collapse all link
var id = $ ( this ). closest ( '.accordion' ). attr ( 'id' );
$ ( '.collapseAll[data-target="#' + id + '"]' ). removeClass ( 'disabled' );
// If all items are shown then disable the expand link
if ( $ ( this ). closest ( '.accordion' ). find ( '.collapse:not(.show)' ). length == 0 ) {
$ ( '.expandAll[data-target="#' + id + '"]' ). addClass ( 'disabled' );
}
})
$ ( '.expandAll' ). click ( function () {
// Disable the expand all link
var id = $ ( this ). attr ( 'data-target' );
$ ( this ). addClass ( 'disabled' );
// Enable the collapse all link
$ ( '.collapseAll[data-target="' + id + '"]' ). removeClass ( 'disabled' );
// Show all items
$ ( id + ' .collapse' ). collapse ( 'show' );
// Toggle the icons
$ ( id ). find ( 'i.fa-chevron-down' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
})
$ ( '.collapseAll' ). click ( function () {
// Disable the collapse all link
var id = $ ( this ). attr ( 'data-target' );
$ ( this ). addClass ( 'disabled' );
// Enable the expand all link
$ ( '.expandAll[data-target="' + id + '"]' ). removeClass ( 'disabled' );
// Hide all items
$ ( id + ' .collapse' ). collapse ( 'hide' );
// Toggle the icons
$ ( id ). find ( 'i.fa-chevron-up' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
})
/* ==================== Dropdown toggles - Sidebar navigation =================== */
$ ( '.sidebarBtn' ). click ( function () {
$ ( this ). find ( 'i' ). toggleClass ( 'fa-chevron-up fa-chevron-down' );
if ( $ ( this ). attr ( 'aria-expanded' ) == true ){
$ ( this ). attr ({ 'aria-expanded' : false });
} else {
$ ( this ). attr ({ 'aria-expanded' : true });
}
$ ( this ). next ( 'ul' ). slideToggle ();
});
})
The vertical header layout uses the vertical header and includes a secondary navigation (‘Jump to’ menu on the right) as well as a footer.
Template structure
This template uses a body class of vertical-layout
along with the following elements for the general page layout.
<!DOCTYPE html>
<html lang= "en" >
<head>
<title> Page title</title>
</head>
<body class= "vertical-layout" >
<!-- Insert vertical header here -->
<div class= "container-fluid" >
<main class= "clearfix" >
<div class= "cw-content" >
<!-- Page content here -->
</div>
<div class= "secondary-nav-container" >
<div class= "secondary-nav" id= "secondaryNav" >
<!-- Secondary navigation dynamically generated here -->
</div>
</div>
</main>
</div>
<!-- Footer -->
<footer class= "vertical-layout-footer" >
<div class= "container-fluid" >
<div class= "guide-footer-inner small" >
<p> Copyright or any other important information can be added inside the footer, maybe a link to <a href= "#" > contact us</a> .</p>
</div>
</div>
</footer>
</body>
</html>
Sample pages
These sample pages have been pre-built including all default design system CSS and JavaScript .
How it works
The following JavaScript for initializing Bootstrap components and for custom component functionality has also been included (assets/js/vertical-layout.js
):
Secondary navigation
The secondary sidebar navigation (‘Jump to’ menu) is dynamically inserted into #secondaryNav
using JavaScript based on the h2
and h3
headings within .cw-content
. You must add an id
attribute to each h2
and h3
for the scroll functionality. Add the class no-scroll
to any h2
or h3
headings that you don’t want to appear in the menu.
/* ==========================================================================
Vertical layout JS
========================================================================== */
function makeArray ( list ) {
return []. slice . call ( list )
}
function getUrlParameter ( name ) {
name = name . replace ( / [\[] / , ' \\ [' ). replace ( / [\]] / , ' \\ ]' );
var regex = new RegExp ( '[ \\ ?&]' + name + '=([^&#]*)' );
var results = regex . exec ( location . search );
return results === null ? '' : decodeURIComponent ( results [ 1 ]. replace ( / \+ /g , ' ' ));
};
$ ( document ). ready ( function () {
/* ==================== Vertical header =================== */
// Search form
// $('#searchInput').keyup(function(){
// if($(this).val() === ''){
// $('#searchBtn').attr("disabled", true);
// }else{
// $('#searchBtn').attr("disabled", false);
// }
// });
// Dropdown toggles
$ ( '.sidebarBtn' ). click ( function () {
$ ( this ). find ( 'i' ). toggleClass ( 'fa-chevron-up fa-chevron-down' );
if ( $ ( this ). attr ( 'aria-expanded' ) == true ){
$ ( this ). attr ({ 'aria-expanded' : false });
} else {
$ ( this ). attr ({ 'aria-expanded' : true });
}
$ ( this ). next ( 'ul' ). slideToggle ();
});
// Mobile menu
function openVerticalHeader (){
$ ( 'html' ). scrollTop ( 0 );
$ ( '.verticalHeaderGradient' ). fadeIn ( 200 );
$ ( 'header.vertical-header' ). addClass ( 'in' );
$ ( 'body' ). css ({ 'position' : 'fixed' , 'left' : 0 , 'right' : 0 , 'top' : 0 });
}
function closeVerticalHeader (){
$ ( '.verticalHeaderGradient' ). fadeOut ( 200 );
$ ( 'header.vertical-header' ). removeClass ( 'in' );
$ ( 'body' ). css ({ 'position' : 'initial' , 'left' : 'auto' , 'right' : 'auto' , 'top' : 'auto' });
}
$ ( '.verticalHeaderBtn' ). click ( function () {
openVerticalHeader ();
})
$ ( '.verticalHeaderGradient, .verticalHeaderCloseBtn' ). click ( function () {
closeVerticalHeader ();
})
/* ==================== Dynamic secondary side nav ("Jump to" menu) =================== */
var navContainer = $ ( '#secondaryNav' );
function createHashNav () {
var navContainer = $ ( '#secondaryNav' );
var navHTML = '' ;
var count = 0 ;
$ ( '.cw-content > h2:not(.no-scroll), .cw-content > h3:not(.no-scroll)' ). each ( function ( index ) {
if ( $ ( this ). is ( "h2" )) {
navHTML += '<li><a class="scroll" href="#' + $ ( this ). attr ( 'id' ) + '">' + $ ( this ). text () + '</a></li>' ;
} else {
navHTML += '<li class="inner"><a class="scroll" href="#' + $ ( this ). attr ( 'id' ) + '">' + $ ( this ). text () + '</a></li>' ;
}
count ++ ;
})
if ( count > 1 ) {
navContainer . html ( '<div class="title lead">Jump to</div><ul>' + navHTML + '</ul>' );
} else {
navContainer . html ( '' );
}
}
if ( navContainer . length > 0 ) {
createHashNav ();
}
// Smooth scroll
$ ( 'a.scroll' ). click ( function () {
if ( location . pathname . replace ( /^ \/ / , '' ) == this . pathname . replace ( /^ \/ / , '' ) && location . hostname == this . hostname ) {
var target = $ ( this . hash );
target = target . length ? target : $ ( '[name=' + this . hash . slice ( 1 ) + ']' );
if ( target . length ) {
var stateObj = {
hash : this . hash ,
};
history . pushState ( stateObj , '' , location . pathname + this . hash );
$ ( 'html,body' ). animate ({
scrollTop : target . offset (). top
}, 500 );
return false ;
}
}
});
// On scroll find the first h1 or h2 in the viewport to set as active
$ ( window ). scroll ( function () {
var scrollTop = $ ( window ). scrollTop ();
var windowHeight = $ ( window ). height ();
var first = false ;
$ ( "h3, h2, h1" ). each ( function () {
var offset = $ ( this ). offset ();
if ( scrollTop <= offset . top && ( $ ( this ). height () + offset . top ) < ( scrollTop + windowHeight )) {
$ ( 'a.scroll[href="#' + $ ( this ). attr ( 'id' ) + '"]' ). parent (). siblings (). find ( 'a' ). removeClass ( 'active' );
$ ( 'a.scroll[href="#' + $ ( this ). attr ( 'id' ) + '"]' ). parent (). siblings (). find ( 'a' ). blur ();
$ ( 'a.scroll[href="#' + $ ( this ). attr ( 'id' ) + '"]' ). addClass ( 'active' );
first = true ;
}
if ( first == true ) {
return false ;
}
});
});
/* ==================== Enable tooltips =================== */
$ ( '[data-toggle="tooltip"]' ). tooltip ();
// Dark styled
$ ( '.dark-tooltip' ). tooltip ({
'template' : '<div class="tooltip dark" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>'
});
/* ==================== Datepicker - https://bootstrap-datepicker.readthedocs.io/en/stable/ =================== */
//----- Enable single date picker
$ ( '.datePicker' ). datepicker ({
format : 'mm/dd/yyyy' ,
startDate : '-3d' ,
todayHighlight : true ,
daysOfWeekDisabled : '0,6'
});
// Single date picker trigger
$ ( '.datePickerTrigger' ). click ( function () {
$ ( this ). closest ( '.input-group' ). find ( '.datePicker' ). datepicker ( 'show' );
})
//----- Enable date range
$ ( '.dateRange' ). datepicker ({
inputs : $ ( '.dateRangeInput' )
});
// Date range trigger
$ ( '.dateRangeTrigger' ). click ( function () {
$ ( this ). closest ( '.input-group' ). find ( '.dateRangeInput' ). datepicker ( 'show' );
})
/* ==================== Accordions =================== */
$ ( '.accordion .heading' ). click ( function () {
// Toggle the icon
$ ( this ). find ( 'i' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
})
$ ( '.collapse' ). on ( 'hidden.bs.collapse' , function () {
// Toggle the icon
$ ( this ). find ( 'i.fa-chevron-up' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
// Disable the expand all link
var id = $ ( this ). closest ( '.accordion' ). attr ( 'id' );
$ ( '.expandAll[data-target="#' + id + '"]' ). removeClass ( 'disabled' );
// If all items are hidden then disable the collapse link
if ( $ ( this ). closest ( '.accordion' ). find ( '.collapse.show' ). length == 0 ) {
$ ( '.collapseAll[data-target="#' + id + '"]' ). addClass ( 'disabled' );
}
})
$ ( '.collapse' ). on ( 'shown.bs.collapse' , function () {
// Toggle the icon
$ ( this ). find ( 'i.fa-chevron-down' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
// Disable the collapse all link
var id = $ ( this ). closest ( '.accordion' ). attr ( 'id' );
$ ( '.collapseAll[data-target="#' + id + '"]' ). removeClass ( 'disabled' );
// If all items are shown then disable the expand link
if ( $ ( this ). closest ( '.accordion' ). find ( '.collapse:not(.show)' ). length == 0 ) {
$ ( '.expandAll[data-target="#' + id + '"]' ). addClass ( 'disabled' );
}
})
$ ( '.expandAll' ). click ( function () {
// Disable the expand all link
var id = $ ( this ). attr ( 'data-target' );
$ ( this ). addClass ( 'disabled' );
// Enable the collapse all link
$ ( '.collapseAll[data-target="' + id + '"]' ). removeClass ( 'disabled' );
// Show all items
$ ( id + ' .collapse' ). collapse ( 'show' );
// Toggle the icons
$ ( id ). find ( 'i.fa-chevron-down' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
})
$ ( '.collapseAll' ). click ( function () {
// Disable the collapse all link
var id = $ ( this ). attr ( 'data-target' );
$ ( this ). addClass ( 'disabled' );
// Enable the expand all link
$ ( '.expandAll[data-target="' + id + '"]' ). removeClass ( 'disabled' );
// Hide all items
$ ( id + ' .collapse' ). collapse ( 'hide' );
// Toggle the icons
$ ( id ). find ( 'i.fa-chevron-up' ). toggleClass ( 'fa-chevron-down fa-chevron-up' );
})
})