Dashboard of sticky notes

Hi,
I need to create a dashboard containing a illusion of sticky notes. Number of notes will be variable and will contain at mix of text, dates and status. The status value will set the background color of the note.
It is important that all notes fit into the dashboard.

There will be no data input, just visualisation.

Any good idea on how to do this?

O

Hi @olab,

You could display an empty drawing with the node-red-contrib-ui-svg node. Then you add (on the "Event" tabsheet) e.g. a double-click event handler:

  1. Somebody double clicks the drawing (either on an empty space or on an existing sticky note).
  2. An output message will be sent.
  3. You could show a popup (I assume) with a ui template node to show a dialog where you can enter the text of the sticky note.
  4. You inject an input message into the SVG node, with the properties of the sticky note (text, location, dimensions).

Of course you would have to calculate the dimensions yourself. So perhaps other solutions based on DIV-elements with a bunch of CSS are much easier. But that is not my cup of coffee ...

Bart

You might also find some ideas on codepen, jsfiddle, ...
For example here.

2 Likes

Sorry I forgot. There will be no user input or interact. Data input will be from a database

O

1 Like

Then I don't think svg is a good idea, because you would have to calculate all the sizes yourself. Plain html will be easier (table or whatever grid structure) I assume.

Thank you for your suggestion @BartButenaers, this is working great!

[
    {
        "id": "e5e49821949645c6",
        "type": "ui_template",
        "z": "42053d03a67b39a9",
        "group": "52aeaff2.e16798",
        "name": "",
        "order": 1,
        "width": "0",
        "height": "0",
        "format": "<!DOCTYPE html>\n<html>\n<head>\n<style>\nbody {\n  background-color:#EAF2E3;\n}\n\n\n/* BOARD */\n#board {\n\tpadding: 100px 30px 30px;\n\tmargin-top: 40px;\n\toverflow-y: visible;\n\t@extend .noflick;\n}\n\n/* NOTE */\n.text p {\n  font-family: Comic Sans, helvetica, arial, sans-serif;\n}\n\n.note-green {\n\tfloat: left;\n\tdisplay: block;\n\tposition: relative;\n\tpadding: 1em;\n\twidth: 150px;\n\tmin-height: 100px;\n\tmargin: 0 30px 30px 0;\n\tbackground: linear-gradient(top, rgba(0,0,0,.05), rgba(0,0,0,.25));\n\tbackground-color: green;\n\tbox-shadow: 5px 5px 10px -2px rgba(33,33,33,.3);\n\ttransform: rotate(10deg);\n\ttransform: skew(-1deg,1deg);\n\ttransition: transform .15s;\n\tz-index: 1;\n\n}\n\n.note-red {\n\tfloat: left;\n\tdisplay: block;\n\tposition: relative;\n\tpadding: 1em;\n\twidth: 150px;\n\tmin-height: 100px;\n\tmargin: 0 30px 30px 0;\n\tbackground: linear-gradient(top, rgba(0,0,0,.05), rgba(0,0,0,.25));\n\tbackground-color: red;\n\tbox-shadow: 5px 5px 10px -2px rgba(33,33,33,.3);\n\ttransform: rotate(10deg);\n\ttransform: skew(-1deg,1deg);\n\ttransition: transform .15s;\n\tz-index: 1;\n\n}\n\n\n\ttextarea {\n\t\tbackground-color: transparent;\n\t\tborder: none;\n\t\tresize: vertical;\n\t\tfont-family: \"Gloria Hallelujah\", cursive;\n\t\twidth: 100%;\n    height: 100%;\n\t\tpadding: 5px;\n    font-size: 12pt;\n}\n</style>\n</head>\n<body>\n\n<div id=\"board\">\n   <div ng-bind-html=\"msg.payload\"></div>\n    \n  </div>\n\n\n</body>\n</html>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1100,
        "y": 260,
        "wires": [
            [
                "e21dd71615597f54"
            ]
        ]
    },
    {
        "id": "ebfaf3dc493aa612",
        "type": "inject",
        "z": "42053d03a67b39a9",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": true,
        "onceDelay": 0.1,
        "topic": "",
        "payloadType": "date",
        "x": 390,
        "y": 260,
        "wires": [
            [
                "f9b45143e979e593",
                "32e3bb5484c7ce49"
            ]
        ]
    },
    {
        "id": "f9b45143e979e593",
        "type": "function",
        "z": "42053d03a67b39a9",
        "name": "",
        "func": "const note= []\n\nnote[0] = {heading:\"Task 1\", info:\"Task performed by Donald\", status:true};\nnote[1] = {heading:\"Task 2\", info:\"Task performed by George\", status:false};\nnote[2] = {heading:\"Task 3\", info:\"Task performed by Thomas\", status:true};\nnote[3] = {heading:\"Task 4\", info:\"Task performed by james\", status:true};\nnote[4] = {heading:\"Task 5\", info:\"Task performed by John\", status:true};\nnote[5] = {heading:\"Task 6\", info:\"Task performed by Andrew\", status:false};\nnote[6] = {heading:\"Task 7\", info:\"Task performed by Martin\", status:true};\nnote[7] = {heading:\"Task 8\", info:\"Task performed by William\", status:true};\nnote[8] = {heading:\"Task 9\", info:\"Task performed by John\", status:false};\n\nmsg.payload = note\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 600,
        "y": 260,
        "wires": [
            [
                "95cebc5d25ab64f1"
            ]
        ]
    },
    {
        "id": "95cebc5d25ab64f1",
        "type": "function",
        "z": "42053d03a67b39a9",
        "name": "",
        "func": "var myhtml = ''\nvar type\n\n\nfor (var i = 0; i < msg.payload.length; i++) {\n \nif (msg.payload[i].status == true) \n{\n  type = \"note-red\";\n}\nelse\n{\n type = \"note-green\";\n}\nmyhtml = myhtml + '<div class=\\\"'+ type +'\\\"><div class=\\\"text\\\"><b>'+ msg.payload[i].heading +'</b><br>'+ msg.payload[i].info +'</div></div>'\n    \n    \n    \n    \n}\n\n\nmsg.payload = myhtml\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 840,
        "y": 260,
        "wires": [
            [
                "e5e49821949645c6"
            ]
        ]
    },
    {
        "id": "e21dd71615597f54",
        "type": "debug",
        "z": "42053d03a67b39a9",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1370,
        "y": 260,
        "wires": []
    },
    {
        "id": "471a87a9ef3f8cc4",
        "type": "ui_template",
        "z": "42053d03a67b39a9",
        "group": "356410a9ed90f742",
        "name": "",
        "order": 1,
        "width": "0",
        "height": "0",
        "format": "<!DOCTYPE html>\n<html>\n<head>\n<style>\nbody {\n  background-color:#EAF2E3;\n}\n\n\n/* BOARD */\n#board {\n\tpadding: 100px 30px 30px;\n\tmargin-top: 40px;\n\toverflow-y: visible;\n\t@extend .noflick;\n}\n\n/* NOTE */\n.text p {\n  font-family: Comic Sans, helvetica, arial, sans-serif;\n}\n\n.note-green {\n\tfloat: left;\n\tdisplay: block;\n\tposition: relative;\n\tpadding: 1em;\n\twidth: 150px;\n\tmin-height: 100px;\n\tmargin: 0 30px 30px 0;\n\tbackground: linear-gradient(top, rgba(0,0,0,.05), rgba(0,0,0,.25));\n\tbackground-color: green;\n\tbox-shadow: 5px 5px 10px -2px rgba(33,33,33,.3);\n\ttransform: rotate(10deg);\n\ttransform: skew(-1deg,1deg);\n\ttransition: transform .15s;\n\tz-index: 1;\n\n}\n\n.note-red {\n\tfloat: left;\n\tdisplay: block;\n\tposition: relative;\n\tpadding: 1em;\n\twidth: 150px;\n\tmin-height: 100px;\n\tmargin: 0 30px 30px 0;\n\tbackground: linear-gradient(top, rgba(0,0,0,.05), rgba(0,0,0,.25));\n\tbackground-color: red;\n\tbox-shadow: 5px 5px 10px -2px rgba(33,33,33,.3);\n\ttransform: rotate(10deg);\n\ttransform: skew(-1deg,1deg);\n\ttransition: transform .15s;\n\tz-index: 1;\n\n}\n\n\n\ttextarea {\n\t\tbackground-color: transparent;\n\t\tborder: none;\n\t\tresize: vertical;\n\t\tfont-family: \"Gloria Hallelujah\", cursive;\n\t\twidth: 100%;\n    height: 100%;\n\t\tpadding: 5px;\n    font-size: 12pt;\n}\n</style>\n</head>\n<body>\n\n<div id=\"board\">\n   <div ng-bind-html=\"msg.payload\"></div>\n    \n  </div>\n\n\n</body>\n</html>",
        "storeOutMessages": true,
        "fwdInMessages": true,
        "resendOnRefresh": true,
        "templateScope": "local",
        "className": "",
        "x": 1080,
        "y": 380,
        "wires": [
            [
                "5968937066f43255"
            ]
        ]
    },
    {
        "id": "32e3bb5484c7ce49",
        "type": "function",
        "z": "42053d03a67b39a9",
        "name": "",
        "func": "const note= []\n\nnote[0] = {heading:\"Task 1\", info:\"Task performed by Donald\", status:true};\nnote[1] = {heading:\"Task 2\", info:\"Task performed by George\", status:false};\nnote[2] = {heading:\"Task 3\", info:\"Task performed by Thomas\", status:true};\nnote[3] = {heading:\"Task 4\", info:\"Task performed by james\", status:true};\nnote[4] = {heading:\"Task 5\", info:\"Task performed by John\", status:true};\nnote[5] = {heading:\"Task 6\", info:\"Task performed by Andrew\", status:false};\nnote[6] = {heading:\"Task 7\", info:\"Task performed by Martin\", status:true};\nnote[7] = {heading:\"Task 8\", info:\"Task performed by William\", status:true};\nnote[8] = {heading:\"Task 9\", info:\"Task performed by John\", status:false};\n\nmsg.payload = note\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 580,
        "y": 380,
        "wires": [
            [
                "5d0e594f540c0292"
            ]
        ]
    },
    {
        "id": "5d0e594f540c0292",
        "type": "function",
        "z": "42053d03a67b39a9",
        "name": "",
        "func": "var myhtml = ''\nvar type\n\n\nfor (var i = 0; i < msg.payload.length; i++) {\n \nif (msg.payload[i].status == true) \n{\n  type = \"note-red\";\n}\nelse\n{\n type = \"note-green\";\n}\nmyhtml = myhtml + '<div class=\\\"'+ type +'\\\"><div class=\\\"text\\\"><b>'+ msg.payload[i].heading +'</b><br>'+ msg.payload[i].info +'</div></div>'\n    \n    \n    \n    \n}\n\n\nmsg.payload = myhtml\nreturn msg;",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 820,
        "y": 380,
        "wires": [
            [
                "471a87a9ef3f8cc4"
            ]
        ]
    },
    {
        "id": "5968937066f43255",
        "type": "debug",
        "z": "42053d03a67b39a9",
        "name": "",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "false",
        "statusVal": "",
        "statusType": "auto",
        "x": 1350,
        "y": 380,
        "wires": []
    },
    {
        "id": "52aeaff2.e16798",
        "type": "ui_group",
        "name": "Daily tasks",
        "tab": "ca621891.e2b488",
        "order": 1,
        "disp": true,
        "width": "25",
        "collapse": false,
        "className": ""
    },
    {
        "id": "356410a9ed90f742",
        "type": "ui_group",
        "name": "Weekly tasks",
        "tab": "ca621891.e2b488",
        "order": 2,
        "disp": true,
        "width": "25",
        "collapse": false,
        "className": ""
    },
    {
        "id": "ca621891.e2b488",
        "type": "ui_tab",
        "name": "Home",
        "icon": "dashboard"
    }
]
3 Likes

Nice to hear that it works. And thanks for sharing the solution, which might help other users in the future!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.