UIBUILDER: Example web page layout #2 (Dashboard Style)

As hinted at in UIBUILDER: Example web page layout (typical blog style), here is the 2nd example page layout.

The flow below contains everything needed to fully reproduce this layout along with some design documentation and hints on adjusting it to taste.

Cards 7 & 8 have been dynamically inserted from Node-RED by the use of UIBUILDER's no-code uib-element node. A no-code uib-update node also illustrates how to make further adjustments - in this case, adding a style attribute to change the width of the card.

While I have only put a heading and some text in the cards - which you may think of as "widgets" in Dashboard terminology - you could, of course, put anything such as user inputs, charts, gauges, etc.

Example flow

[{"id":"f3af73c0bc66eba4","type":"group","z":"7e598dbf2e556452","name":"Example Dashboard-style layout","style":{"fill":"#bfdbef","fill-opacity":"0.31","label":true,"color":"#000000"},"nodes":["aace4caa6a7f9504","c491db3c048c152f","1dfd6d4773866c25","dca484848d810b89","eb4e4f88d0796b52","558cd04e3f31a17a","09b283477b67586e","63c60624c5178d4f"],"x":58,"y":599,"w":1004,"h":368},{"id":"aace4caa6a7f9504","type":"inject","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"","props":[],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":145,"y":660,"wires":[["c491db3c048c152f"]],"l":false},{"id":"c491db3c048c152f","type":"uibuilder","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"","topic":"","url":"layout-dash-grid","okToGo":true,"fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"reload":true,"sourceFolder":"src","deployedVersion":"7.0.0","showMsgUib":false,"title":"","descr":"","editurl":"vscode://file/src/uibRoot/layout-dash-grid/?windowId=_blank","x":330,"y":660,"wires":[["1dfd6d4773866c25"],["dca484848d810b89"]]},{"id":"1dfd6d4773866c25","type":"debug","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"debug 452","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":525,"y":640,"wires":[],"l":false},{"id":"dca484848d810b89","type":"debug","z":"7e598dbf2e556452","d":true,"g":"f3af73c0bc66eba4","name":"debug 453","active":false,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"","statusType":"counter","x":465,"y":680,"wires":[],"l":false},{"id":"eb4e4f88d0796b52","type":"comment","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"Design","info":"This layout is designed to roughly replicate\nthe Node-RED Dashboard grid layout.\n\nIt keeps the outer layout from the content/blog\nstyle (header, footer, left-sidebar, main).\n\nBut the sidebar now has the navigation menu\ninstead of the header.\n\nThe main content area is now a sub-grid. It has\nthe `id` of `more` which means that you can\neasily add new content using uibuilder's \nno-code nodes.\n\nEach `<article>` or `<div>` tag in the main \ncontent sub-grid can be considered the \nequivalent of a \"widget\" in Node-RED Dashboard \nterms. It can contain whatever you want it to.\nIt has a slightly different background colour\nand a rounded border.\n\nIn the example all of the layout can be\ncontrolled from the CSS variables in `:root`.\n\nThe sub-grid has 12 columns by default, you\ncan change that to whatever is useful to you.\n\nThe articles have a default width of 3. You can\neasily override a single article by adding:\n`--article-width: 6` or however many columns\nyou want it to take up.\n\nBy default, specific grid rows are undefined\n(set to `auto`) so articles take up whatever\nheight they need. If you want to define the\nrows, you can easily do so by changing\n`--main-rows` to `repeat(12, 1fr)` or some\nother number. You have lots of control over the\ncolumn/row layout but it can get a bit complex\nso you are advised to keep it simple, at least\nto start with.\n\n-----------------\n\n## NOTES\n\nIt is very likely that much of the\ndefined CSS in this example will be incorporated\ninto UIBUILDER's `uib-brand.css` in the \nfuture.\n\nThe Markdown-IT library has been included in\n`index.html`, loaded from a public Internet\nCDN. Install & use the library locally using \nUIBUILDER's library manager if you prefer.\nOr remove completely if you don't need to use\nMarkdown dynamic content.","x":690,"y":660,"wires":[]},{"id":"558cd04e3f31a17a","type":"group","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"Setup - run this first to set up the page and style - only needs to run once","style":{"fill":"#ffffff","fill-opacity":"0.31","label":true,"color":"#000000"},"nodes":["91bd4a5399fd8450","7d99df5c50fe8352","d6b8ff40eb6cee22","6017acfb3acc8300","162206ae3cbdc006","e79304a2973c2f53"],"x":94,"y":719,"w":782,"h":122},{"id":"91bd4a5399fd8450","type":"template","z":"7e598dbf2e556452","g":"558cd04e3f31a17a","name":"index.html","field":"payload","fieldType":"msg","format":"html","syntax":"mustache","template":"<!doctype html>\n<html lang=\"en\"><head>\n\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"icon\" href=\"../uibuilder/images/node-blue.ico\">\n\n    <title>Dashboard Layout - Node-RED uibuilder</title>\n    <meta name=\"description\" content=\"Node-RED uibuilder - Dashboard Layout\">\n\n    <!-- Your own CSS (defaults to loading uibuilders css)-->\n    <link type=\"text/css\" rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n\n    <!-- #region Supporting Scripts. These MUST be in the right order. Note no leading / -->\n    <script defer src=\"https://cdn.jsdelivr.net/npm/markdown-it/dist/markdown-it.min.js\"></script>\n    <script defer src=\"../uibuilder/uibuilder.iife.min.js\"></script>\n    <!-- <script defer src=\"./index.js\">/* <= OPTIONAL: Put your custom code in that */</script> -->\n    <!-- #endregion -->\n\n</head><body>\n\n    <div class=\"container\">\n        <header class=\"header\">\n            <h1 class=\"with-subtitle\">Dashboard Layout Example</h1>\n            <div role=\"doc-subtitle\">Using the uibuilder IIFE library.</div>\n        </header>\n\n        <main id=\"more\"><!-- '#more' is used as a parent for dynamic HTML content in examples -->\n            <article>\n                <h2>Card 1</h2>\n                <p>\n                    The main content area contains a series of cards (AKA widgets).\n                </p>\n            </article>\n\n            <article>\n                <h2>Card 2</h2>\n                <p>\n                    We use a well structured HTML 5 tag structure and CSS to define the layout.\n                </p>\n            </article>\n\n            <article>\n                <h2>Card 3</h2>\n                <p>\n                    This could contain anything of course.\n                </p>\n            </article>\n\n            <article>\n                <h2>Card 4</h2>\n                <p>\n                    This could contain anything of course.\n                </p>\n            </article>\n\n            <article style=\"--article-width: 7;\">\n                <h2>Card 5</h2>\n                <p>\n                    This has an overridden width, see the HTML. Sets the number of grid columns used, there are 12 total in the default example but you can change this to anything in the CSS file.\n                </p>\n            </article>\n\n            <article style=\"--article-width: 5;\">\n                <h2>Card 6</h2>\n                <p>\n                    Also changed width. The <code>--article-width</code> CSS variable is all that needs to be set.\n                </p>\n            </article>\n        </main>\n\n        <aside class=\"sidebar\">\n            <nav class=\"nav-side\">\n                <ul>\n                    <li><a href=\"#nav1\">Nav 1</a></li>\n                    <li><a href=\"#nav2\">Nav 2</a></li>\n                    <li><a href=\"#nav3\">Nav 3</a></li>\n                </ul>\n            </nav>\n        </aside>\n\n        <footer>\n            The footer\n            <div>2nd footer</div>\n        </footer>\n    </div>\n\n</body></html>\n","output":"str","x":550,"y":760,"wires":[["6017acfb3acc8300"]]},{"id":"7d99df5c50fe8352","type":"inject","z":"7e598dbf2e556452","g":"558cd04e3f31a17a","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"setup all FE files","x":155,"y":760,"wires":[["d6b8ff40eb6cee22","162206ae3cbdc006"]],"l":false},{"id":"d6b8ff40eb6cee22","type":"change","z":"7e598dbf2e556452","g":"558cd04e3f31a17a","name":"index.html","rules":[{"t":"set","p":"fname","pt":"msg","to":"index.html","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":760,"wires":[["91bd4a5399fd8450"]]},{"id":"6017acfb3acc8300","type":"uib-save","z":"7e598dbf2e556452","g":"558cd04e3f31a17a","url":"layout-dash-grid","uibId":"c491db3c048c152f","folder":"src","fname":"","createFolder":false,"reload":true,"usePageName":false,"encoding":"utf8","mode":438,"name":"","topic":"","x":770,"y":760,"wires":[]},{"id":"162206ae3cbdc006","type":"change","z":"7e598dbf2e556452","g":"558cd04e3f31a17a","name":"index.css","rules":[{"t":"set","p":"fname","pt":"msg","to":"index.css","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":300,"y":800,"wires":[["e79304a2973c2f53"]]},{"id":"e79304a2973c2f53","type":"template","z":"7e598dbf2e556452","g":"558cd04e3f31a17a","name":"index.css","field":"payload","fieldType":"msg","format":"css","syntax":"plain","template":"/* Load defaults from `<userDir>/node_modules/node-red-contrib-uibuilder/front-end/uib-brand.min.css`\n * This version auto-adjusts for light/dark browser settings.\n */\n@import url(\"../uibuilder/uib-brand.min.css\");\n\n/* CSS variables to make it easier to control */\n:root {\n    /* The layout container */\n    --container-max-width: 1000px;\n    --container-col-gap: 1rem;\n    --container-row-gap: 1rem;\n\n    /* The main content container */\n    --main-cols: repeat(12, 1fr);\n    --main-rows: auto; /* auto OR repeat(12, 1fr); ... */\n    --main-col-gap: var(--container-col-gap);\n    --main-row-gap: var(--container-row-gap);\n    \n    /* The articles */\n    --article-width: 3; /* number of columns or auto */\n    --article-height: auto; /* auto or number of rows */\n\n    /* The Sidebar container */\n    --sidebar-max-width: 1fr;\n    --sidebar-min-width: 0.1fr;\n}\n\n/* The outer container div */\n.container {\n    width: 100%;\n    max-width: var(--container-max-width);\n    margin: 0 auto;\n    /* Center the container horizontally */\n    display: grid;\n    gap: var(--container-row-gap) var(--container-col-gap);\n\n    /* 2 cols x 3 rows layout. Middle row & right column are larger. Left col is constrained min/max */\n    grid-template-columns: minmax(var(--sidebar-min-width), var(--sidebar-max-width)) var(--main-width);\n    grid-template-rows: 0fr 1fr 0fr;\n    grid-template-areas: \n        \"header header\"\n        \"sidebar main\"\n        \"sidebar footer\";\n    justify-items: stretch;\n}\n\n/* The main content container */\nmain {\n    /* Where you put your content */\n    grid-area: main;\n    \n    display: grid;\n    gap: var(--main-row-gap) var(--main-col-gap);\n    grid-template-columns: var(--main-cols, 12); /* fallback to 12 cols */\n    grid-template-rows: var(--main-rows, auto); /* fallback to auto */\n}\n\n/* Any article within the main container */\nmain > article, main > div {\n    /* Width of an article in number of columns */\n    grid-column: span var(--article-width);\n    /* Height of an article in number of rows */\n    grid-row: span var(--article-height);\n    margin: 0;\n}\n/* Set a child div to have same format as an article */\nmain > div {\n    border: 1px solid var(--text3);\n    border-radius: var(--border-radius);\n    padding: var(--border-pad);\n    margin: 0;\n    background-color: var(--surface3);\n}\nmain > div > h2, main > div > h3, main > div > h4 {\n    margin-block-start: 0;\n    border-bottom: 1px solid var(--text3);\n    padding-block-end: var(--border-pad);\n}\n\nheader {\n    /* Headings, nav, etc */\n    grid-area: header;\n}\n\nfooter {\n    /* at the bottom, (c), dates, etc */\n    grid-area: footer;\n    margin-top: 0;\n}\n\n/* We might want other sidebars so be more explicit for this */\naside.sidebar {\n    /* stuff to one side of the main content */\n    grid-area: sidebar;\n}\n\n/*#region Simple horizontal navigation main menu (in the header) */\n.nav-main {\n    background-color: var(--surface3);\n}\n.nav-main ul {\n    /* Remove bullet points */\n    list-style-type: none;\n    /* Remove default padding */\n    padding: 0;\n    /* Remove default margin */\n    margin: 0;\n    /* Use Flexbox to align items horizontally */\n    display: flex;\n}\n/* Add space between menu items */\n.nav-main li {\n    margin-right: 1rem;\n}\n/* Remove margin on the last item */\n.nav-main li:last-child {\n    margin-right: 0;\n}\n.nav-main a {\n    /* Remove underline from links */\n    text-decoration: none;\n    /* Add padding for better click area */\n    padding: var(--border-pad);\n    /* Ensure the entire area is clickable */\n    display: block;\n}\n/* Highlight on hover */\n.nav-main a:hover {\n    background-color: var(--surface5);\n    /* Optional: Add rounded corners */\n    border-radius: var(--border-radius);\n}\n/*#endregion */\n\n/*#region simple vertical navigation menu */\n.nav-side {\n    background-color: var(--surface3);\n}\n.nav-side ul {\n    /* Remove bullet points */\n    list-style-type: none;\n    /* Remove default padding */\n    padding: 0;\n    /* Remove default margin */\n    margin: 0;\n}\n.nav-side a {\n    /* Remove underline from links */\n    text-decoration: none;\n    /* Add padding for better click area */\n    padding: 0.5rem 1rem;\n    /* Ensure the entire area is clickable */\n    display: block;\n}\n/* Highlight on hover */\n.nav-side a:hover {\n    background-color: var(--surface5);\n}\n/*#endregion */\n\n/* Adapt for narrow screens */\n@media only screen and (max-width: 512px) {\n    /* Very simple adaption example, a single column, 4 rows */\n    .container {\n        gap: 0.5rem;\n\n        /* 1 cols x 4 rows layout. 2nd row is larger */\n        grid-template-columns: 1fr;\n        grid-template-rows: 0.1fr 1fr 0.1fr 0.1fr;\n        grid-template-areas:\n            \"header\"\n            \"main\"\n            \"sidebar\"\n            \"footer\";\n    }\n}\n","output":"str","x":560,"y":800,"wires":[["6017acfb3acc8300"]]},{"id":"09b283477b67586e","type":"link in","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"uib input","links":["a200ce9460e26c07"],"x":185,"y":680,"wires":[["c491db3c048c152f"]]},{"id":"63c60624c5178d4f","type":"group","z":"7e598dbf2e556452","g":"f3af73c0bc66eba4","name":"Add dynamic data - 2 added widgets, 1 markdown and 1 list","style":{"label":true,"fill":"#ffffbf","fill-opacity":"0.22","color":"#000000"},"nodes":["7dc04e1820bfa998","a200ce9460e26c07","ad9aa1454c010926","478c86bc95d76da9","dab3745a1b327ad3","6cff3768c26f6361","2e1e04d89c148272"],"x":84,"y":859,"w":952,"h":82},{"id":"7dc04e1820bfa998","type":"uib-element","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"Markdown article","topic":"","elementtype":"markdown","parent":"#more","parentSource":"","parentSourceType":"str","elementid":"md1","elementId":"","elementIdSourceType":"str","heading":"","headingSourceType":"str","headingLevel":"h2","data":"payload","dataSourceType":"msg","position":"last","positionSourceType":"str","passthrough":false,"confData":{},"x":450,"y":900,"wires":[["6cff3768c26f6361"]]},{"id":"a200ce9460e26c07","type":"link out","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"to uib input","mode":"link","links":["09b283477b67586e"],"x":995,"y":900,"wires":[]},{"id":"ad9aa1454c010926","type":"inject","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"$formatInteger($random() * 100, \"#00\")","payloadType":"jsonata","x":145,"y":900,"wires":[["478c86bc95d76da9"]],"l":false},{"id":"478c86bc95d76da9","type":"template","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"Markdown","field":"payload","fieldType":"msg","format":"markdown","syntax":"mustache","template":"## Markdown Card\n\nDynamically added from a Node-RED/UIBUILDER no-code node.\n\nRandom number: {{payload}}","output":"str","x":270,"y":900,"wires":[["7dc04e1820bfa998"]]},{"id":"dab3745a1b327ad3","type":"uib-element","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"List","topic":"","elementtype":"ul","parent":"#more","parentSource":"#more","parentSourceType":"str","elementid":"ul1","elementIdSourceType":"str","heading":"A List","headingSourceType":"str","headingLevel":"h2","data":"payload","dataSourceType":"msg","position":"last","positionSourceType":"str","passthrough":false,"confData":{},"x":750,"y":900,"wires":[["2e1e04d89c148272"]]},{"id":"6cff3768c26f6361","type":"change","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"List","rules":[{"t":"set","p":"payload","pt":"msg","to":"[\"I was dynamically\",\"inserted by a\",\"Node-RED/UIBUILDER\",\"no-code flow\"]","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":630,"y":900,"wires":[["dab3745a1b327ad3"]]},{"id":"2e1e04d89c148272","type":"uib-update","z":"7e598dbf2e556452","g":"63c60624c5178d4f","name":"List width","topic":"","mode":"update","modeSourceType":"update","cssSelector":"#ul1","cssSelectorType":"str","slotSourceProp":"","slotSourcePropType":"msg","attribsSource":"{\"style\":\"--article-width: 6;\"}","attribsSourceType":"json","slotPropMarkdown":false,"x":880,"y":900,"wires":[["a200ce9460e26c07"]]}]

This example will be part of UIBUILDER v7.

2 Likes

I have always been intrigued with UIB.

If truth be told - I dislike the out of box limitations/themes (massive text for example) that D1 and D2 provides - I REALLY dislike Grid layouts - I think they are awful things, (at least for me) you can't create sharp looking interfaces - everything is just too big.

One day I will crack UIB - just need to expose myself to Vue somewhat before I do.

I don't use any dashboards (of any kind) currently in Node RED - but for UI / Application design, UIB keeps appearing to me

Why? Honestly, unless you are building something really complex, I'd personally say that all of the front-end frameworks are now real overkill. Seriously, next time you want to build a new UI, give me a shout and I'll show you how easy it is with just native HTML and some CSS (and maybe the occasional tiny bit of JavaScript) - with UIBUILDER and Node-RED doing the heavy lifting of course! :sunglasses:

You should have a play with the example, it is complete so if you have uibuilder installed, just import the flow and run the setup flow. Then have a quick play because you will quickly see how easy it is to change the white-space and tighten things as much (or little) as you like.

Grids really do have a place and they can be really helpful for packing in a large amount of data while still keeping things comprehensible. But if you don't need to do that, you probably won't "get" them and that is absolutely fine.

I keep getting people say how complex it is to use UIBUILDER vs Dashboard but I don't really get that. They are different approaches, sure, but I would now never go back to either of the Dashboards since I can copy a simple HTML layout and some pre-written CSS and I'm good to go. Even better, I don't have to run up multiple instances of Node-RED to get another UI, I just add another uibuilder node.

2 Likes

I actuality don't use D1 or D2 - because of the limitation (that I see) with Grid Layouts.

My previous Life (before infrastructure lead) was Lead Application Developer, and I may be to used to freehand layouts (win forms - cough cough) :nerd_face:

This is why I am intrigued with UIB - it doesn't enforce the Grid thing.
I am happier designing my own HTML/CSS then being limited by restricted grids - hence my interest with UIB.

Then you will have no problem with it. Just do yourself a favour and ignore VueJS. :slight_smile:

But do remember that HTML isn't really designed for free-form layouts. It can do them for sure, but it is hard work. HTML excels at layout flows - hierarchies - more document style than free-form.

Life is much easier if you can live with that and simply accept the natural flow of an HTML hierarchical layout. You can still do massively clever layouts while staying withing that hierarchy thankfully but it is a rather different way of thinking than totally free-form layouts.

Kanban boards are an interesting example. They look complex but really all they are is a set of nested lists. You could easily re-envision a kanban board as a mind-map for example, or simple lists. There is a hierarchy that is easy to envisage. And that makes them good candidates for web UI's.

I really want to be able to find the time to build a Node-RED driven Kanban board feature with UIBUILDER. I just need to master some drag/drop stuff - urm, and find the time! The grid layout in this example is actually quite a long way towards the required layout for a kanban. And that's the power of web UI's, they tend to naturally evolve if you start with simple.

I'm just writing a moveElement function for the uibuilder client library and that will be really useful for this.

1 Like

What's wrong with my import?

This is UIBUILDER 6.8.2

Nothing! :slight_smile: The layout is correct but you are missing some CSS that has been included in the v7 default css that isn't in v6.

My bad, I'd added it to the previous layout example but failed to include it when posting this one.

Please add the following to the end of your index.css:


/* The rest is not needed if using 
   UIBUILDER v7 since that has an updated
   uib-brand.css that includes this */
/* This lets us use an article like a card display */
article {
    max-width: var(--max-width);
    border: 1px solid var(--text3);
    border-radius: var(--border-radius);
    padding: var(--border-pad);
    margin: 1rem var(--border-margin);
    background-color: var(--surface3);
}
article>h1::before {
    font-size: 50%;
    color: hsl(var(--failure-hue) 100% 50%);
    content: "⛔ Do not use H1 headings in articles. "
}
article>h2,
article>h3,
article>h4 {
    margin-block-start: 0;
    border-bottom: 1px solid var(--text3);
    padding-block-end: var(--border-pad);
}
1 Like

Already added to the backlog as a priority for a follow-up to v7.0 are two new ideas that will make this kind of layout even more powerful.

  • A collapsible list widget so that you can dump a nested array and get a proper collapsible nested list. Great for more complex navigation menus.

  • Drag/Drop: With a "draggable-container" class to constrain where you can drag/drop and draggable class that will make an element draggable within the container. This will let you dynamically re-order the cards in the UI. On drop, a control message will be returned to Node-RED so that you can trigger a full HTML capture & save if you want to make the change permanent for future loads (for everyone). I will also try to work out how to have a localised option for saving as well.

It works

1 Like

Of course! :grinning:

And thanks for illustrating that UIBUILDER's default CSS is light/dark aware.

What I love about UIBUILDER is the freedom it gives you.
Added some box shadow...

1 Like

Nice! I tend to forget about shadows because I generally work in dark mode and shadows are notoriously hard to do in that mode.

The uib-brand.css should actually have some shadows pre-defined. Looks like I left them off the article definition. Something else to add to the backlog. :slight_smile:

Or actually, I should probably just add a .shadow class, that would be more flexible.

1 Like

Yes, but I understand you can't add ALL. Every user has his own preference, so shadowing, borders, widget color, should be left to user experience.
The grid you made is very nice and easy to use.

Maybe you should work a little bit on the responsiveness.

The articles should display one per line...

(I remember how much I worked in order to have an acceptable masonry grid! It was exhausting.)

Nah! As you've already pointed out, some things need to be left to the user! After all, nobody can predict what layout you actually want or what devices you need to support.

I already include a responsive section for the master layout so it shouldn't be too hard to work out what you want for the sub-grid. You can simply set --article-width: 12; I think in the @media section. That should make each article take up the whole width of the container.

I'll make a note though and will probably improve it later. Right now I'm desperately trying to get v7 out the door.

Actually, that will only work where the width hasn't been overridden. Instead add this to the @media section:

    main {
        display: block;
    }
    main > article, main > div {
        margin-top: 0.5em;
    }

Yes, thanks! But I didn't want you to be distracted from your main target (v.7)!

Haha, well I managed to get the release out anyway! So no harm done. :grinning: