« get me outta code hell

hsmusic-wiki - HSMusic - static wiki software cataloguing collaborative creation
about summary refs log tree commit diff
path: root/src/content/dependencies/generatePageLayout.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/content/dependencies/generatePageLayout.js')
-rw-r--r--src/content/dependencies/generatePageLayout.js128
1 files changed, 113 insertions, 15 deletions
diff --git a/src/content/dependencies/generatePageLayout.js b/src/content/dependencies/generatePageLayout.js
index 98b2d350..1ea5ce24 100644
--- a/src/content/dependencies/generatePageLayout.js
+++ b/src/content/dependencies/generatePageLayout.js
@@ -29,6 +29,47 @@ export default {
     transformMultiline,
     wikiInfo,
   }) {
+    const sidebarSlots = side => ({
+      // Content is a flat HTML array. It'll generate one sidebar section
+      // if specified.
+      [side + 'Content']: {type: 'html'},
+
+      // Multiple is an array of {content: (HTML)} objects. Each of these
+      // will generate one sidebar section.
+      [side + 'Multiple']: {
+        validate: v =>
+          v.arrayOf(
+            v.validateProperties({
+              content: v.isHTML,
+            })),
+      },
+
+      // Sticky mode controls which sidebar section(s), if any, follow the
+      // scroll position, "sticking" to the top of the browser viewport.
+      //
+      // 'last' - last or only sidebar box is sticky
+      // 'column' - entire column, incl. multiple boxes from top, is sticky
+      // 'none' - sidebar not sticky at all, stays at top of page
+      //
+      // Note: This doesn't affect the content of any sidebar section, only
+      // the whole section's containing box (or the sidebar column as a whole).
+      [side + 'StickyMode']: {
+        validate: v => v.is('last', 'column', 'static'),
+      },
+
+      // Collapsing sidebars disappear when the viewport is sufficiently
+      // thin. (This is the default.) Override as false to make the sidebar
+      // stay visible in thinner viewports, where the page layout will be
+      // reflowed so the sidebar is as wide as the screen and appears below
+      // nav, above the main content.
+      [side + 'Collapse']: {type: 'boolean', default: true},
+
+      // Wide sidebars generally take up more horizontal space in the normal
+      // page layout, and should be used if the content of the sidebar has
+      // a greater than typical focus compared to main content.
+      [side + 'Wide']: {type: 'boolean', defualt: false},
+    });
+
     return html.template({
       annotation: 'generatePageLayout',
 
@@ -36,15 +77,8 @@ export default {
         title: {type: 'html'},
         cover: {type: 'html'},
 
-        mainContent: {type: 'html'},
-        footerContent: {type: 'html'},
         socialEmbed: {type: 'html'},
 
-        headingMode: {
-          validate: v => v.is('sticky', 'static'),
-          default: 'static',
-        },
-
         styleRules: {
           validate: v => v.arrayOf(v.isString),
           default: [],
@@ -54,6 +88,24 @@ export default {
           validate: v => v.arrayOf(v.isString),
           default: [],
         },
+
+        // Main
+
+        mainContent: {type: 'html'},
+
+        headingMode: {
+          validate: v => v.is('sticky', 'static'),
+          default: 'static',
+        },
+
+        // Sidebars
+
+        ...sidebarSlots('leftSidebar'),
+        ...sidebarSlots('rightSidebar'),
+
+        // Nav & Footer
+
+        footerContent: {type: 'html'},
       },
 
       content(slots) {
@@ -114,6 +166,52 @@ export default {
               relations.footerLocalizationLinks,
             ]);
 
+        const generateSidebarHTML = (side, id) => {
+          const content = slots[side + 'Content'];
+          const multiple = slots[side + 'Multiple'];
+          const stickyMode = slots[side + 'StickyMode'];
+          const wide = slots[side + 'Wide'];
+          const collapse = slots[side + 'Collapse'];
+
+          let sidebarClasses = [];
+          let sidebarContent = html.blank();
+
+          if (!html.isBlank(content)) {
+            sidebarClasses = ['sidebar'];
+            sidebarContent = content;
+          } else if (multiple) {
+            sidebarClasses = ['sidebar-multiple'];
+            sidebarContent =
+              multiple
+                .filter(Boolean)
+                .map(({content}) =>
+                  html.tag('div',
+                    {
+                      [html.onlyIfContent]: true,
+                      class: 'sidebar',
+                    },
+                    content));
+          }
+
+          return html.tag('div',
+            {
+              [html.onlyIfContent]: true,
+              id,
+              class: [
+                'sidebar-column',
+                wide && 'wide',
+                !collapse && 'no-hide',
+                stickyMode !== 'static' && `sticky-${stickyMode}`,
+                ...sidebarClasses,
+              ],
+            },
+            sidebarContent);
+        }
+
+        const sidebarLeftHTML = generateSidebarHTML('leftSidebar', 'sidebar-left');
+        const sidebarRightHTML = generateSidebarHTML('rightSidebar', 'sidebar-right');
+        const collapseSidebars = slots.leftSidebarCollapse && slots.rightSidebarCollapse;
+
         const layoutHTML = [
           // navHTML,
           // banner.position === 'top' && bannerHTML,
@@ -122,18 +220,18 @@ export default {
             {
               class: [
                 'layout-columns',
-                // !collapseSidebars && 'vertical-when-thin',
-                // (sidebarLeftHTML || sidebarRightHTML) && 'has-one-sidebar',
-                // (sidebarLeftHTML && sidebarRightHTML) && 'has-two-sidebars',
-                // !(sidebarLeftHTML || sidebarRightHTML) && 'has-zero-sidebars',
-                // sidebarLeftHTML && 'has-sidebar-left',
-                // sidebarRightHTML && 'has-sidebar-right',
+                !collapseSidebars && 'vertical-when-thin',
+                (sidebarLeftHTML || sidebarRightHTML) && 'has-one-sidebar',
+                (sidebarLeftHTML && sidebarRightHTML) && 'has-two-sidebars',
+                !(sidebarLeftHTML || sidebarRightHTML) && 'has-zero-sidebars',
+                sidebarLeftHTML && 'has-sidebar-left',
+                sidebarRightHTML && 'has-sidebar-right',
               ],
             },
             [
-              // sidebarLeftHTML,
+              sidebarLeftHTML,
               mainHTML,
-              // sidebarRightHTML,
+              sidebarRightHTML,
             ]),
           // banner.position === 'bottom' && bannerHTML,
           footerHTML,