Progress towards sidebar layout
authorNick Downing <nick@ndcode.org>
Tue, 1 Feb 2022 04:16:22 +0000 (15:16 +1100)
committerNick Downing <nick@ndcode.org>
Sat, 12 Feb 2022 01:53:36 +0000 (12:53 +1100)
_lib/breadcrumbs.jst
_lib/navbar.jst
blog/20220131/index.html.jst
css/bootstrap/_custom.scss

index 754a211..d822672 100644 (file)
@@ -7,7 +7,7 @@ return async (env, _out) => {
   let component_titles = env.component_titles
 
   // present component_titles as breadcrumbs, except last one as text
-  h2.mt-3 {
+  h2.page-header.grid-gutter-background.py-2 {
     for (let i = 0; i < component_names.length; ++i) {
       a.h4(
         href=
index 76c0269..e45f329 100644 (file)
@@ -100,15 +100,11 @@ return async (env, head, body, scripts) => {
   // component_titles[i] corresponds to component_names[i - 1], i >= 1
   env.component_names = component_names
   env.component_titles = component_titles
-  console.log('cn', component_names)
-  console.log('ct', component_titles)
 
   // note: menu_titles.length === menu_names.length + 1
   // menu_titles[0] corresponds to /, is 'Home' or similar
-  // menu_titles[i] corresponds to menu_names[i - 1], i >= 1a
+  // menu_titles[i] corresponds to menu_names[i - 1], i >= 1
   // (navbar has Home appearing at same level as its immediate children)
-  console.log('mn', menu_names)
-  console.log('mt', menu_titles)
 
   await page(
     env,
@@ -132,23 +128,24 @@ return async (env, head, body, scripts) => {
       let dir = index === -1 ? '' : env.parsed_url.pathname.slice(1, index)
 
       div.scrollbar-fix {
-        div.container {
-          div.row.align-items-center.py-3 {
-            div.col-sm-8 {
-              b.h1 {
-                div.mr-3(style="display: inline-block; vertical-align: -40px; width: 128px; height: 128px;") {
+        div.container-fluid {
+          div.row {
+            div.'col-md-2'.bg-gray-200 {
+              div.'mt-1'.mb-4 {
+                div(style="width: 128px; height: 128px;") {
                   _out.push(avatar_maker)
                 }
-                'nick.downing.id'
+                b.h1 {
+                  `${site_title}`
+                }
               }
-            }
-            div.'col-sm-4' {
-              div.'mb-1'.text-right {
+
+              div.mb-2 {
                 span#navbar-signed-in-status {
                   if (signed_in_as !== undefined)
-                    'Signed in.' //`Signed in as ${signed_in_as}.`
+                    'Signed in.'
                   else
-                    'Browsing as guest.'
+                    'Signed out.'
                 }
                 ' '
                 if (signed_in_as !== undefined)
@@ -167,7 +164,7 @@ return async (env, head, body, scripts) => {
                   a#navbar-sign-out(href="#" hidden) {'Sign out'}
               }
 
-              form(action="/search/index.html") {
+              form.mb-4(action="/search/index.html") {
                 div.input-group {
                   input.form-control(name="query" type="text" placeholder="Search" aria-describedby="search-button") {}
                   div.input-group-append {
@@ -179,120 +176,101 @@ return async (env, head, body, scripts) => {
                   }
                 }
               }
-            }
 
-            //div.'col-sm-1'.vbottom {
-            //  // a nested div is used to avoid hover colour on the padding
-            //  div.nav-li-a(style="text-align: center;") {
-            //    a(href="/online_store/view_cart/index.html") {
-            //      div.cart-icon {
-            //        _out.push(icon_cart_small)
-            //      }
-            //      div.cart-number {
-            //        div.cart-circle {
-            //          `${(env.cart.items || []).length}`
-            //        }
-            //      }
-            //    }
-            //  }
-            //}
-          }
-        }
-      }
-      nav.navbar.navbar-expand-lg.navbar-dark.bg-primary.scrollbar-fix {
-        div.container {
-          //a.navbar-brand(href="#") {'Navbar'}
-          //' '
-          button.navbar-toggler(type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation") {
-            span.navbar-toggler-icon {}
-          }
-          div.collapse.navbar-collapse#navbarSupportedContent {
-            ul.navbar-nav.mr-auto {
-              // the active entry in the navbar bar is based on which top-level
-              // page we are under, even if we are not directly on that page
-              // but one of its children, this may be unexpected as the active
-              // entry does not highlight on hover, but you can still click it;
-              // we determine here the path to the corresponding top-level page
-              let component_prefix = component_names.slice(0, 1)
-
-              for (let i = 0; i < menu_titles.length; ++i) {
-                // construct path to the top-level page about to be described
-                let menu_prefix =
-                  i == 0 ? [] : [menu_names[i - 1]]
-                let menu_prefix_path =
-                  menu_prefix.map(name => '/' + name).join('') + '/index.html'
-
-                if (arrays_equal(menu_prefix, component_prefix))
-                  li.nav-item.active {
-                    a.nav-link(href=menu_prefix_path) {
-                      `${menu_titles[i]}`
-                      span.sr-only {' (current)'}
+              //nav.navbar.navbar-expand-lg.navbar-dark.bg-primary.scrollbar-fix {
+                //a.navbar-brand(href="#") {'Navbar'}
+                //' '
+                //button.navbar-toggler(type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation") {
+                //  span.navbar-toggler-icon {}
+                //}
+                //div.collapse.navbar-collapse#navbarSupportedContent {
+                  ul.nav.flex-column { //ul.navbar-nav.mr-auto {
+                    // the active entry in the navbar bar is based on which top-level
+                    // page we are under, even if we are not directly on that page
+                    // but one of its children, this may be unexpected as the active
+                    // entry does not highlight on hover, but you can still click it;
+                    // we determine here the path to the corresponding top-level page
+                    let component_prefix = component_names.slice(0, 1)
+      
+                    for (let i = 0; i < menu_titles.length; ++i) {
+                      // construct path to the top-level page about to be described
+                      let menu_prefix =
+                        i == 0 ? [] : [menu_names[i - 1]]
+                      let menu_prefix_path =
+                        menu_prefix.map(name => '/' + name).join('') + '/index.html'
+      
+                      if (arrays_equal(menu_prefix, component_prefix))
+                        li.nav-item.active {
+                          a.nav-link(href=menu_prefix_path) {
+                            `${menu_titles[i]}`
+                            span.sr-only {' (current)'}
+                          }
+                        }
+                      else
+                        li.nav-item {
+                          a.nav-link(href=menu_prefix_path) {
+                            `${menu_titles[i]}`
+                          }
+                        }
                     }
-                  }
-                else
-                  li.nav-item {
-                    a.nav-link(href=menu_prefix_path) {
-                      `${menu_titles[i]}`
+                    //li.nav-item.dropdown {
+                    //  a.nav-link.dropdown-toggle#navbarDropdown(href="#" role="button" data-toggle="dropdown" aria-expanded="false") {
+                    //    'Dropdown'
+                    //  }
+                    //  div.dropdown-menu(aria-labelledby="navbarDropdown") {
+                    //    a.dropdown-item(href="#") {
+                    //      'Action'
+                    //    }
+                    //    ' '
+                    //    a.dropdown-item(href="#") {
+                    //      'Another action'
+                    //    }
+                    //    div.dropdown-divider {}
+                    //    a.dropdown-item(href="#") {
+                    //      'Something else here'
+                    //    }
+                    //  }
+                    //}
+                    //li.nav-item {
+                    //  a.nav-link.disabled {
+                    //    'Disabled'
+                    //  }
+                    //}
+                  //}
+                  //ul.navbar-nav.ml-auto {
+                    li.nav-item.mt-4 {
+                      a.nav-link#navbar-give-feedback(href="#") {'Give feedback'}
                     }
                   }
-              }
-              //li.nav-item.dropdown {
-              //  a.nav-link.dropdown-toggle#navbarDropdown(href="#" role="button" data-toggle="dropdown" aria-expanded="false") {
-              //    'Dropdown'
-              //  }
-              //  div.dropdown-menu(aria-labelledby="navbarDropdown") {
-              //    a.dropdown-item(href="#") {
-              //      'Action'
-              //    }
-              //    ' '
-              //    a.dropdown-item(href="#") {
-              //      'Another action'
-              //    }
-              //    div.dropdown-divider {}
-              //    a.dropdown-item(href="#") {
-              //      'Something else here'
-              //    }
-              //  }
-              //}
-              //li.nav-item {
-              //  a.nav-link.disabled {
-              //    'Disabled'
-              //  }
+                //}
               //}
             }
-            ul.navbar-nav.ml-auto {
-              li.nav-item {
-                a.nav-link#navbar-give-feedback(href="#") {'Give feedback'}
+
+            div.col-md-9 {
+              await body(_out)
+
+              footer.page-footer.grid-gutter-background.py-5 {
+                a(rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/") {
+                  img(alt="Creative Commons License" style="border-width:0;" src="/images/by-sa_3.0_88x31.png") {}
+                }
+                p {
+                  'This website is '
+                  a(href="https://git.ndcode.org/public/nick_site.git") {
+                    'open source'
+                  }
+                  ' and licensed under a '
+                  a(rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/") {
+                    'Creative Commons Attribution-ShareAlike 3.0 Unported License'
+                  }
+                  '.'
+                }
+      
+                p.mb-0 {`Copyright © ${new XDate(env.now).getUTCFullYear()} ${copyright}.`}
               }
             }
           }
         }
       }
-      div.scrollbar-fix {
-        div.container {
-          await body(_out)
-        }
-      }
-      footer.scrollbar-fix {
-        div.container {
-          a(rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/") {
-            img(alt="Creative Commons License" style="border-width:0;" src="/images/by-sa_3.0_88x31.png") {}
-          }
-          p {
-            'This website is '
-            a(href="https://git.ndcode.org/public/nick_site.git") {
-              'open source'
-            }
-            ' and licensed under a '
-            a(rel="license" href="http://creativecommons.org/licenses/by-sa/3.0/") {
-              'Creative Commons Attribution-ShareAlike 3.0 Unported License'
-            }
-            '.'
-          }
-
-          p {`Copyright © ${new XDate(env.now).getUTCFullYear()} ${copyright}.`}
-        }
-      }
 
       // hidden part
       div.modal#navbar-sign-in-modal(tabindex="-1") {
@@ -598,7 +576,7 @@ return async (env, head, body, scripts) => {
                   // not show status/dialog, as it causes an annoying flicker
                   return
 
-                id_navbar_signed_in_status.textContent = 'Signed in.' //`Signed in as ${email}.`
+                id_navbar_signed_in_status.textContent = 'Signed in.'
                 id_navbar_sign_in.hidden = true
                 id_navbar_sign_up.hidden = true
                 id_navbar_sign_out.hidden = false
@@ -635,7 +613,7 @@ return async (env, head, body, scripts) => {
                   // not show status/dialog, as it causes an annoying flicker
                   return
 
-                id_navbar_signed_in_status.textContent = 'Browsing as guest.'
+                id_navbar_signed_in_status.textContent = 'Signed out.'
                 id_navbar_sign_in.hidden = false
                 id_navbar_sign_up.hidden = false
                 id_navbar_sign_out.hidden = true
index edb52af..2350b90 100644 (file)
@@ -1,7 +1,7 @@
 return async env => {
   let blog_post = await _require('/_lib/blog_post.jst')
   let fa_cloud_upload_alt = await env.site.get_min_svg('/_svg/fa_cloud-upload-alt.svg')
-  let fa_server = await env.site.get_min_svg('/blog/20220128/fa_server.svg')
+  let fa_server = await env.site.get_min_svg('/blog/20220131/fa_server.svg')
   let icon_cross = await env.site.get_min_svg('/_svg/icon_cross.svg')
   let icon_tick = await env.site.get_min_svg('/_svg/icon_tick.svg')
 
index 53b4834..fac6403 100644 (file)
@@ -5,11 +5,31 @@ $footer-link-hover-color: darken($footer-link-color, 10%);
 
 // apply this to a div inside the body tag
 // prevents page shifting to left/right as scrollbar appears/disappears
-// it works by calculating the width of the scrollbar and then adding
-// the corresponding amount of padding to left to keep things centered
-// see https://stackoverflow.com/questions/45524214/how-do-i-stop-my-web-content-from-shifting-left-when-the-vertical-scrollbar-appe
+// uses negative margin to force content to be drawn under the scrollbar
+// (this is useful for modals since scrollbar disappears during a modal)
+// note: intended to be used with div.container which adds padding for
+// media sizes sm and above, don't do it for xs to avoid losing content
 .scrollbar-fix {
-  padding-left: calc(100vw - 100%);
+  @include media-breakpoint-up(sm) {
+    margin-right: calc(100% - 100vw);
+  }
+}
+
+// place a container div around entire page, and then use this
+// to make the background on navbar or footer appear full-width
+.extend-background {
+  margin-left: calc(-.5 * (100vw - 100%));
+  margin-right: calc(-.5 * (100vw - 100%));
+  padding-left: calc(.5 * (100vw - 100%));
+  padding-right: calc(.5 * (100vw - 100%));
+}
+
+// use within a grid column to extend the background to left/right
+.grid-gutter-background {
+  margin-left: -.5 * $grid-gutter-width;
+  margin-right: -.5 * $grid-gutter-width;
+  padding-left: .5 * $grid-gutter-width;
+  padding-right: .5 * $grid-gutter-width;
 }
 
 // needed for svg icons inside buttons, card headers, etc
@@ -57,9 +77,11 @@ $icon-sizes: (
   margin-bottom: .5em;
 }
 
-footer, .footer {
-  padding-top: 35px;
-  padding-bottom: 25px;
+.page-header {
+  background-color: theme-color-level("primary", $alert-bg-level);
+}
+
+.page-footer {
   background-color: $gray-400;
   a {
     color: $footer-link-color;