UNPKG

node-red-contrib-uibuilder

Version:

Easily create data-driven web UI's for Node-RED. Single- & Multi-page. Multiple UI's. Work with existing web development workflows or mix and match with no-code/low-code features.

530 lines (529 loc) 23.1 kB
[ { "id": "4609ab6ec2568455", "type": "group", "z": "7e598dbf2e556452", "name": "Example content-heavy standard layout (blog-style)", "style": { "fill": "#e3f3d3", "fill-opacity": "0.31", "label": true, "color": "#000000" }, "nodes": [ "abd74b7c71705183", "1e31ada9e399ea1b", "37c5ea9212d472d6", "e4bb79221cd4d494", "d87282975afb0ff0", "e68ff082f08f4e09", "9dce05a892338fb0", "fd4bef967d319a77", "33596b16c79744cf" ], "x": 57, "y": 39, "w": 1004, "h": 380 }, { "id": "abd74b7c71705183", "type": "inject", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "", "props": [], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 145, "y": 100, "wires": [ [ "1e31ada9e399ea1b" ] ], "l": false }, { "id": "1e31ada9e399ea1b", "type": "uibuilder", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "", "topic": "", "url": "layout-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-grid/?windowId=_blank", "x": 310, "y": 100, "wires": [ [ "37c5ea9212d472d6" ], [ "e4bb79221cd4d494" ] ] }, { "id": "37c5ea9212d472d6", "type": "debug", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "debug 448", "active": true, "tosidebar": true, "console": false, "tostatus": true, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "counter", "x": 505, "y": 80, "wires": [], "l": false }, { "id": "e4bb79221cd4d494", "type": "debug", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "debug 449", "active": false, "tosidebar": true, "console": false, "tostatus": true, "complete": "true", "targetType": "full", "statusVal": "", "statusType": "counter", "x": 445, "y": 120, "wires": [], "l": false }, { "id": "d87282975afb0ff0", "type": "comment", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "Design", "info": "A fairly common blog-style or content heavy\nlayout.\n\n```\n+-------------------------------------------+\n| Title (h1) |\n| Sub-title (div |\n| Nav1 Nav2 Nav2 (menu) |\n+-------------------------------------------+\n+ Sidebar + Main (for articles) |\n| (aside) | |\n| | +-----------------------------+ |\n| | | Article title (h2) | |\n| | +-----------------------------+ |\n| | | Article body | |\n| | +-----------------------------+ |\n| | +-----------------------------+ |\n| | | Article title (h2) | |\n| | +-----------------------------+ |\n| | | Article body | |\n| | +-----------------------------+ |\n| | |\n| +---------------------------------+\n| | Footer |\n+---------+---------------------------------+\n```\n\nUses a CSS Grid with named grid template areas.\nThis makes it simple to adjust.\n\nThe areas for the layout above are:\n\n```css\ngrid-template-areas: \n \"header header\"\n \"sidebar main\"\n \"sidebar footer\";\n```\n\nTo make the footer full width, use:\n\n```css\ngrid-template-areas: \n \"header header\"\n \"sidebar main\"\n \"footer footer\";\n```\n\nTo move the sidebar to the right, use:\n\n```css\ngrid-template-areas: \n \"header header\"\n \"main sidebar\"\n \"footer sidebar\";\n```\n\nThe example has a breakpoint for narrow\nscreens (set at 512px) where it switches to\na single column with the sidebar below the \nmain area.", "x": 750, "y": 80, "wires": [] }, { "id": "e68ff082f08f4e09", "type": "group", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "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": [ "84807a7720ef4d0f", "0cfd3ddb0693fad1", "ae59ccb45c3e20ac", "a58da542c04e47b9", "d0f6781d12dddb92", "49b428fbb525f866" ], "x": 85, "y": 169, "w": 672, "h": 122 }, { "id": "84807a7720ef4d0f", "type": "template", "z": "7e598dbf2e556452", "g": "e68ff082f08f4e09", "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>Grid Layout - Node-RED uibuilder</title>\n <meta name=\"description\" content=\"Node-RED uibuilder - Grid 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\">Grid Layout Example</h1>\n <div role=\"doc-subtitle\">Using the uibuilder IIFE library.</div>\n <nav class=\"nav-main\">\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 </header>\n\n <main id=\"more\"><!-- '#more' is used as a parent for dynamic HTML content in examples -->\n <article>\n <h2>Example blog-style layout</h2>\n <p>\n A grid of 2 columns and 3 rows. Right column and middle row are larger than the others.\n </p>\n </article>\n\n <article>\n <h2>Article 2</h2>\n <p>\n We use a well structured HTML 5 tag structure to define the layout.\n </p>\n </article>\n </main>\n\n <aside class=\"sidebar\">\n Sidebar wider still\n </aside>\n\n <footer>\n The footer\n <div>2nd footer</div>\n </footer>\n </div>\n\n</body></html>", "output": "str", "x": 461, "y": 210, "wires": [ [ "a58da542c04e47b9" ] ] }, { "id": "0cfd3ddb0693fad1", "type": "inject", "z": "7e598dbf2e556452", "g": "e68ff082f08f4e09", "name": "", "props": [ { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "setup all FE files", "x": 146, "y": 210, "wires": [ [ "ae59ccb45c3e20ac", "d0f6781d12dddb92" ] ], "l": false }, { "id": "ae59ccb45c3e20ac", "type": "change", "z": "7e598dbf2e556452", "g": "e68ff082f08f4e09", "name": "index.html", "rules": [ { "t": "set", "p": "fname", "pt": "msg", "to": "index.html", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 301, "y": 210, "wires": [ [ "84807a7720ef4d0f" ] ] }, { "id": "a58da542c04e47b9", "type": "uib-save", "z": "7e598dbf2e556452", "g": "e68ff082f08f4e09", "url": "layout-grid", "uibId": "1e31ada9e399ea1b", "folder": "src", "fname": "", "createFolder": false, "reload": true, "usePageName": false, "encoding": "utf8", "mode": 438, "name": "", "topic": "", "x": 661, "y": 210, "wires": [] }, { "id": "d0f6781d12dddb92", "type": "change", "z": "7e598dbf2e556452", "g": "e68ff082f08f4e09", "name": "index.css", "rules": [ { "t": "set", "p": "fname", "pt": "msg", "to": "index.css", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 291, "y": 250, "wires": [ [ "49b428fbb525f866" ] ] }, { "id": "49b428fbb525f866", "type": "template", "z": "7e598dbf2e556452", "g": "e68ff082f08f4e09", "name": "index.css", "field": "payload", "fieldType": "msg", "format": "css", "syntax": "mustache", "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 --container-max-width: 1000px;\n --container-grid-col-gap: 1rem;\n --container-grid-row-gap: 0.5rem;\n --main-width: repeat(12, 1fr);\n /* 1fr; */\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-grid-row-gap) var(--container-grid-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-columns: var(--sidebar-min-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/* Assign the main areas to the grid */\nmain {\n /* Where you put your content */\n grid-area: main;\n border: 1px dashed silver;\n /* these just for easier understanding */\n}\n\n/* Set a child div to have same format as an article */\nmain > div {\n /* max-width: var(--max-width); */\n border: 1px solid var(--text3);\n border-radius: var(--border-radius);\n padding: var(--border-pad);\n margin: 1rem var(--border-margin);\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 border: 1px dashed gold;\n}\n\nfooter {\n /* at the bottom, (c), dates, etc */\n grid-area: footer;\n border: 1px dashed green;\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 border: 1px dashed violet;\n}\n\n/* Simple horizontal navigation main menu (in the header) */\n.nav-main {\n background-color: var(--surface3);\n}\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\n/* Add space between menu items */\n.nav-main li {\n margin-right: 1rem;\n}\n\n/* Remove margin on the last item */\n.nav-main li:last-child {\n margin-right: 0;\n}\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\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\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\n\n/* The rest is not needed if using \n UIBUILDER v7 since that has an updated\n uib-brand.css that includes this */\n/* This lets us use an article like a card display */\narticle {\n max-width: var(--max-width);\n border: 1px solid var(--text3);\n border-radius: var(--border-radius);\n padding: var(--border-pad);\n margin: 1rem var(--border-margin);\n background-color: var(--surface3);\n}\narticle>h1::before {\n font-size: 50%;\n color: hsl(var(--failure-hue) 100% 50%);\n content: \"⛔ Do not use H1 headings in articles. \"\n}\narticle>h2,\narticle>h3,\narticle>h4 {\n margin-block-start: 0;\n border-bottom: 1px solid var(--text3);\n padding-block-end: var(--border-pad);\n}", "output": "str", "x": 471, "y": 250, "wires": [ [ "a58da542c04e47b9" ] ] }, { "id": "9dce05a892338fb0", "type": "group", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "Add dynamic data - 2 added widgets, 1 markdown and 1 list", "style": { "label": true, "fill": "#ffffbf", "fill-opacity": "0.22", "color": "#000000" }, "nodes": [ "4afed1a987617465", "9d5eedc93c184d9d", "e443a7981ad81665", "102ec190f356b60f", "42b94d2393565e2f", "0f6958e3d7f65b61", "20927207b979703a" ], "x": 83, "y": 311, "w": 952, "h": 82 }, { "id": "4afed1a987617465", "type": "uib-element", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "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": 449, "y": 352, "wires": [ [ "0f6958e3d7f65b61" ] ] }, { "id": "9d5eedc93c184d9d", "type": "link out", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "name": "to uib input", "mode": "link", "links": [ "fd4bef967d319a77" ], "x": 994, "y": 352, "wires": [] }, { "id": "e443a7981ad81665", "type": "inject", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "name": "", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "$formatInteger($random() * 100, \"#00\")", "payloadType": "jsonata", "x": 144, "y": 352, "wires": [ [ "102ec190f356b60f" ] ], "l": false }, { "id": "102ec190f356b60f", "type": "template", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "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": 269, "y": 352, "wires": [ [ "4afed1a987617465" ] ] }, { "id": "42b94d2393565e2f", "type": "uib-element", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "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": 749, "y": 352, "wires": [ [ "20927207b979703a" ] ] }, { "id": "0f6958e3d7f65b61", "type": "change", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "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": 629, "y": 352, "wires": [ [ "42b94d2393565e2f" ] ] }, { "id": "20927207b979703a", "type": "uib-update", "z": "7e598dbf2e556452", "g": "9dce05a892338fb0", "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": 879, "y": 352, "wires": [ [ "9d5eedc93c184d9d" ] ] }, { "id": "fd4bef967d319a77", "type": "link in", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "uib input", "links": [ "9d5eedc93c184d9d" ], "x": 185, "y": 140, "wires": [ [ "1e31ada9e399ea1b" ] ] }, { "id": "33596b16c79744cf", "type": "comment", "z": "7e598dbf2e556452", "g": "4609ab6ec2568455", "name": "Version: 2024-09-01", "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": 930, "y": 80, "wires": [] } ]