diff --git a/react-ui/.storybook/data/kanban-artworks.json b/react-ui/.storybook/data/kanban-artworks.json
new file mode 100644
index 0000000..023a489
--- /dev/null
+++ b/react-ui/.storybook/data/kanban-artworks.json
@@ -0,0 +1,101 @@
+{
+ "lanes": [
+ {
+ "id": "Uncategorized",
+ "title": "Uncategorized",
+ "label": "20/70",
+ "style": {"width": 280},
+ "cards": []
+ },
+ {
+ "id": "New",
+ "title": "New",
+ "label": "20/70",
+ "style": {"width": 280},
+ "cards": [
+ {
+ "id": "recD3d7eyJRd23Akp",
+ "title": "-",
+ "program": "StART Support",
+ "description": ""
+ },
+ {
+ "id": "reclWYiF8w8f0mEPw",
+ "title": "-",
+ "program": "StART Support",
+ "description": ""
+ }
+ ]
+ },
+ {
+ "id": "In progress",
+ "title": "In progress",
+ "label": "10/20",
+ "style": {"width": 280},
+ "cards": []
+ },
+ {
+ "id": "Completed",
+ "title": "Completed",
+ "label": "0/0",
+ "style": {"width": 280},
+ "cards": []
+ },
+ {
+ "id": "Documentation in progress",
+ "title": "Documentation in progress",
+ "style": {"width": 280},
+ "label": "2/5",
+ "cards": []
+ },
+ {
+ "id": "Published",
+ "title": "Published",
+ "style": {"width": 280},
+ "cards": [
+ {
+ "id": "recsGkS5DtrZANnVe",
+ "title": "Roshni Wijayasinha - York St & Richmond St W",
+ "media": "https://dl.airtable.com/.attachmentThumbnails/de07363e6a0be848cbcbb2ad92f6281c/5838a65d",
+ "program": "Outside the Box",
+ "description": "This piece aims to use various bright colours, energetic lines and shapes that interact with each other, similar to the vibrant and diverse people, communities and landscapes that shape Toronto. "
+ },
+ {
+ "id": "recIqwQAYh3fDPGOT",
+ "title": "Jeannette Nguyen - York Mills Rd & Fenside Dr",
+ "media": "https://dl.airtable.com/.attachmentThumbnails/aa896b19b0ab351326478f54009a8fa3/ae6aab66",
+ "program": "Outside the Box",
+ "description": "This design pays homage to the sometimes pesky, always adorable furry critters Torontonians share the city with. A fox is on the front of the box, ready to eat; around the side of the box, a rabbit realizes he’s being eyed as the fox’s dinner. On the back of the box a raccoon shares his banana with a skunk depicted on the remaining side of the box."
+ },
+ {
+ "id": "rec2Nb1anOd6iJMui",
+ "title": "Kelly Diamond - Yonge St & Yonge Blvd",
+ "media": "https://dl.airtable.com/.attachmentThumbnails/61529bd5e227cf798e7faf8b58ec6049/7fa98897",
+ "program": "Outside the Box",
+ "description": "This piece highlights an incredibly beautiful relationship between bees and flowers, while also highlighting the relationship of bees today in urban environments to shed some light on the troubling numbers of current bee populations."
+ },
+ {
+ "id": "rec3knQ2cKR2jhnOm",
+ "title": "Julii McMillan - Yonge St & Yonge Blvd",
+ "media": "https://dl.airtable.com/.attachmentThumbnails/906f636c6ace0a7dd9f54be49519ff12/bad51517",
+ "program": "Outside the Box",
+ "description": "A box becomes a mini park, full of people, kids and animals, inspired by real characters seen in the neighborhood!"
+ }
+ ]
+ },
+ {
+ "id": "On hold",
+ "title": "On hold",
+ "style": {"width": 280},
+ "label": "1/1",
+ "cards": []
+ },
+ {
+ "id": "Needs repair",
+ "title": "Needs repair",
+ "style": {"width": 280},
+ "label": "1/1",
+ "cards": []
+ }
+ ]
+}
diff --git a/react-ui/.storybook/data/kanban-generic.json b/react-ui/.storybook/data/kanban-generic.json
new file mode 100644
index 0000000..ca51f47
--- /dev/null
+++ b/react-ui/.storybook/data/kanban-generic.json
@@ -0,0 +1,126 @@
+{
+ "lanes": [
+ {
+ "id": "Uncategorized",
+ "title": "Uncategorized",
+ "label": "20/70",
+ "style": {"width": 280},
+ "cards": []
+ },
+ {
+ "id": "New",
+ "title": "New",
+ "label": "20/70",
+ "style": {"width": 280},
+ "cards": [
+ {
+ "id": "Milk",
+ "title": "Buy milk",
+ "label": "15 mins",
+ "description": "Pick it up at the store"
+ },
+ {
+ "id": "Plan2",
+ "title": "Dispose Garbage",
+ "label": "10 mins",
+ "description": "Sort out recyclable and waste as needed"
+ },
+ {
+ "id": "Plan3",
+ "title": "Write Blog",
+ "label": "30 mins",
+ "description": "Can AI make memes?"
+ },
+ {
+ "id": "Plan4",
+ "title": "Pay Rent",
+ "label": "5 mins",
+ "description": "Transfer to bank account"
+ }
+ ]
+ },
+ {
+ "id": "In progress",
+ "title": "In progress",
+ "label": "10/20",
+ "style": {"width": 280},
+ "cards": [
+ {
+ "id": "Wip1",
+ "title": "Clean House",
+ "label": "30 mins",
+ "description": "Soap wash and polish floor. Polish windows and doors. Scrap all broken glasses"
+ }
+ ]
+ },
+ {
+ "id": "Completed",
+ "title": "Completed",
+ "label": "0/0",
+ "style": {"width": 280},
+ "cards": []
+ },
+ {
+ "id": "Documentation in progress",
+ "title": "Documentation in progress",
+ "style": {"width": 280},
+ "label": "2/5",
+ "cards": [
+ {
+ "id": "Completed1",
+ "title": "Practice Meditation",
+ "label": "15 mins",
+ "description": "Use Headspace app"
+ },
+ {
+ "id": "Completed2",
+ "title": "Maintain Daily Journal",
+ "label": "15 mins",
+ "description": "Use Spreadsheet for now"
+ }
+ ]
+ },
+ {
+ "id": "Published",
+ "title": "Published",
+ "style": {"width": 280},
+ "label": "1/1",
+ "cards": [
+ {
+ "id": "Repeat1",
+ "title": "Morning Jog",
+ "label": "30 mins",
+ "description": "Track using fitbit"
+ }
+ ]
+ },
+ {
+ "id": "On hold",
+ "title": "On hold",
+ "style": {"width": 280},
+ "label": "1/1",
+ "cards": [
+ {
+ "id": "Archived1",
+ "title": "Go Trekking",
+ "label": "300 mins",
+ "description": "Completed 10km on cycle"
+ }
+ ]
+ },
+ {
+ "id": "Needs repair",
+ "title": "Needs repair",
+ "style": {"width": 280},
+ "label": "1/1",
+ "cards": [
+ {
+ "id": "Archived2",
+ "title": "Go Jogging",
+ "label": "300 mins",
+ "description": "Completed 10km on cycle"
+ }
+ ]
+ }
+ ]
+}
diff --git a/react-ui/package-lock.json b/react-ui/package-lock.json
index 819a64c..c1a8ccd 100644
--- a/react-ui/package-lock.json
+++ b/react-ui/package-lock.json
@@ -1514,7 +1514,6 @@
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
- "dev": true,
"requires": {
"@emotion/memoize": "0.7.4"
}
@@ -6661,6 +6660,11 @@
"postcss-value-parser": "^4.1.0"
}
},
+ "autosize": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.2.tgz",
+ "integrity": "sha512-jnSyH2d+qdfPGpWlcuhGiHmqBJ6g3X+8T+iRwFrHPLVcdoGJE/x6Qicm6aDHfTsbgZKxyV8UU/YB2p4cjKDRRA=="
+ },
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
@@ -7067,6 +7071,17 @@
"integrity": "sha512-EMZD1563QUqLhzrqcThk759RhuNVX/ZJdrtGK6drwzgvnR+ARjWyXIHPbu+tUNaMGtPz/gQeAM2M6VUw2UiUeA==",
"dev": true
},
+ "babel-plugin-styled-components": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.11.1.tgz",
+ "integrity": "sha512-YwrInHyKUk1PU3avIRdiLyCpM++18Rs1NgyMXEAQC33rIXs/vro0A+stf4sT0Gf22Got+xRWB8Cm0tw+qkRzBA==",
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.0.0",
+ "@babel/helper-module-imports": "^7.0.0",
+ "babel-plugin-syntax-jsx": "^6.18.0",
+ "lodash": "^4.17.11"
+ }
+ },
"babel-plugin-syntax-jsx": {
"version": "6.18.0",
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
@@ -8057,6 +8072,11 @@
"map-obj": "^1.0.0"
}
},
+ "camelize": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
+ "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
+ },
"can-use-dom": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/can-use-dom/-/can-use-dom-0.1.0.tgz",
@@ -9284,6 +9304,11 @@
"postcss": "^7.0.5"
}
},
+ "css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU="
+ },
"css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@@ -9379,6 +9404,16 @@
"resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
"integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
},
+ "css-to-react-native": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz",
+ "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==",
+ "requires": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"css-tree": {
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
@@ -9633,6 +9668,11 @@
"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
"dev": true
},
+ "deep-diff": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
+ "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ="
+ },
"deep-equal": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
@@ -12766,6 +12806,14 @@
"resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz",
"integrity": "sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg=="
},
+ "immutability-helper": {
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/immutability-helper/-/immutability-helper-2.9.1.tgz",
+ "integrity": "sha512-r/RmRG8xO06s/k+PIaif2r5rGc3j4Yhc01jSBfwPCXDLYZwp/yxralI37Df1mwmuzcCsen/E/ITKcTEvc1PQmQ==",
+ "requires": {
+ "invariant": "^2.2.0"
+ }
+ },
"import-cwd": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
@@ -14326,6 +14374,11 @@
}
}
},
+ "just-curry-it": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/just-curry-it/-/just-curry-it-3.1.0.tgz",
+ "integrity": "sha512-mjzgSOFzlrurlURaHVjnQodyPNvrHrf1TbQP2XU9NSqBtHQPuHZ+Eb6TAJP7ASeJN9h9K0KXoRTs8u6ouHBKvg=="
+ },
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@@ -18322,6 +18375,18 @@
"warning": "^4.0.3"
}
},
+ "react-popopo": {
+ "version": "2.1.9",
+ "resolved": "https://registry.npmjs.org/react-popopo/-/react-popopo-2.1.9.tgz",
+ "integrity": "sha512-zXOpcLSpaLZmBxhdtenJzQPLjY81XknVS/tXH4Kv5BBrnYIUPHvVdGmS7+o9s7DjCzzdK7AdVwtG+FVSO0cZ8g==",
+ "requires": {
+ "classnames": ">= 2.0",
+ "prop-types": "^15.7.2",
+ "react": ">= 16.3",
+ "react-dom": ">= 16.3",
+ "styled-components": ">= 4.0"
+ }
+ },
"react-popper": {
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz",
@@ -18355,6 +18420,27 @@
"react-popper": "^1.3.7"
}
},
+ "react-redux": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.2.tgz",
+ "integrity": "sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==",
+ "requires": {
+ "@babel/runtime": "^7.1.2",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.2.4",
+ "loose-envify": "^1.1.0",
+ "prop-types": "^15.6.1",
+ "react-is": "^16.6.0",
+ "react-lifecycles-compat": "^3.0.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ }
+ }
+ },
"react-router": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz",
@@ -18761,6 +18847,25 @@
"prop-types": "^15.6.2"
}
},
+ "react-trello": {
+ "version": "2.2.8",
+ "resolved": "https://registry.npmjs.org/react-trello/-/react-trello-2.2.8.tgz",
+ "integrity": "sha512-SsEYq6z8n2FE1jP54MP7hKtOuxFTJLL4fm/NvulWKeM6Z8zZnM1FnWeZ8W84iFkAWjd1BXytOaZb0dMz3/H0RQ==",
+ "requires": {
+ "autosize": "^4.0.2",
+ "classnames": "^2.2.6",
+ "immutability-helper": "^2.8.1",
+ "lodash": "^4.17.11",
+ "prop-types": "^15.7.2",
+ "react-popopo": "^2.1.9",
+ "react-redux": "^5.0.7",
+ "redux": "^4.0.0",
+ "redux-actions": "^2.6.1",
+ "redux-logger": "^3.0.6",
+ "trello-smooth-dnd": "1.0.0",
+ "uuid": "^3.3.2"
+ }
+ },
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
@@ -18863,6 +18968,40 @@
"strip-indent": "^3.0.0"
}
},
+ "reduce-reducers": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/reduce-reducers/-/reduce-reducers-0.4.3.tgz",
+ "integrity": "sha512-+CNMnI8QhgVMtAt54uQs3kUxC3Sybpa7Y63HR14uGLgI9/QR5ggHvpxwhGGe3wmx5V91YwqQIblN9k5lspAmGw=="
+ },
+ "redux": {
+ "version": "4.0.5",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
+ "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
+ "requires": {
+ "loose-envify": "^1.4.0",
+ "symbol-observable": "^1.2.0"
+ }
+ },
+ "redux-actions": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/redux-actions/-/redux-actions-2.6.5.tgz",
+ "integrity": "sha512-pFhEcWFTYNk7DhQgxMGnbsB1H2glqhQJRQrtPb96kD3hWiZRzXHwwmFPswg6V2MjraXRXWNmuP9P84tvdLAJmw==",
+ "requires": {
+ "invariant": "^2.2.4",
+ "just-curry-it": "^3.1.0",
+ "loose-envify": "^1.4.0",
+ "reduce-reducers": "^0.4.3",
+ "to-camel-case": "^1.0.0"
+ }
+ },
+ "redux-logger": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
+ "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=",
+ "requires": {
+ "deep-diff": "^0.3.5"
+ }
+ },
"refractor": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/refractor/-/refractor-2.10.1.tgz",
@@ -19827,8 +19966,7 @@
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
- "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
- "dev": true
+ "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"shebang-command": {
"version": "1.2.0",
@@ -20603,6 +20741,23 @@
"inline-style-parser": "0.1.1"
}
},
+ "styled-components": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.2.1.tgz",
+ "integrity": "sha512-sBdgLWrCFTKtmZm/9x7jkIabjFNVzCUeKfoQsM6R3saImkUnjx0QYdLwJHBjY9ifEcmjDamJDVfknWm1yxZPxQ==",
+ "requires": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "@babel/traverse": "^7.4.5",
+ "@emotion/is-prop-valid": "^0.8.8",
+ "@emotion/stylis": "^0.8.4",
+ "@emotion/unitless": "^0.7.4",
+ "babel-plugin-styled-components": ">= 1",
+ "css-to-react-native": "^3.0.0",
+ "hoist-non-react-statics": "^3.0.0",
+ "shallowequal": "^1.1.0",
+ "supports-color": "^5.5.0"
+ }
+ },
"stylehacks": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
@@ -21056,11 +21211,24 @@
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
"integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
},
+ "to-camel-case": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/to-camel-case/-/to-camel-case-1.0.0.tgz",
+ "integrity": "sha1-GlYFSy+daWKYzmamCJcyK29CPkY=",
+ "requires": {
+ "to-space-case": "^1.0.0"
+ }
+ },
"to-fast-properties": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
},
+ "to-no-case": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/to-no-case/-/to-no-case-1.0.2.tgz",
+ "integrity": "sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo="
+ },
"to-object-path": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
@@ -21089,6 +21257,14 @@
"repeat-string": "^1.6.1"
}
},
+ "to-space-case": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/to-space-case/-/to-space-case-1.0.0.tgz",
+ "integrity": "sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc=",
+ "requires": {
+ "to-no-case": "^1.0.0"
+ }
+ },
"toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
@@ -21123,6 +21299,11 @@
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
"dev": true
},
+ "trello-smooth-dnd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/trello-smooth-dnd/-/trello-smooth-dnd-1.0.0.tgz",
+ "integrity": "sha512-KgYEwmxX08Dl4OmioEv24LSnlNp9jNv8lwTQlUMbMm6B+VuwyQuuuoyu4wlsRweiMCCC6sZXpCCGkmAni/vCaQ=="
+ },
"trim": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
diff --git a/react-ui/package.json b/react-ui/package.json
index 1594345..2438f58 100644
--- a/react-ui/package.json
+++ b/react-ui/package.json
@@ -24,6 +24,7 @@
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"react-syntax-highlighter": "^12.2.1",
+ "react-trello": "^2.2.8",
"startto-map": "code-for-canada/start-map#master"
},
"devDependencies": {
diff --git a/react-ui/src/assets/images/placeholder.png b/react-ui/src/assets/images/placeholder.png
new file mode 100644
index 0000000..ace89d1
Binary files /dev/null and b/react-ui/src/assets/images/placeholder.png differ
diff --git a/react-ui/src/components/Kanban/CustomCard.js b/react-ui/src/components/Kanban/CustomCard.js
new file mode 100644
index 0000000..b6d64a4
--- /dev/null
+++ b/react-ui/src/components/Kanban/CustomCard.js
@@ -0,0 +1,89 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+
+import {
+ MovableCardWrapper,
+ CardHeader,
+ CardRightContent,
+ CardTitle,
+ Detail,
+ Footer
+} from 'react-trello/dist/styles/Base'
+import Tag from 'react-trello/dist/components/Card/Tag'
+import DeleteButton from 'react-trello/dist/widgets/DeleteButton'
+
+class CustomCard extends Component {
+ onDelete = e => {
+ this.props.onDelete()
+ e.stopPropagation()
+ }
+
+ render() {
+ const {
+ showDeleteButton,
+ style,
+ tagStyle,
+ onClick,
+ //onDelete,
+ className,
+ id,
+ title,
+ label,
+ description,
+ tags,
+ cardDraggable
+ } = this.props
+
+ return (
+
+
+ {title}
+ {label}
+ {showDeleteButton && }
+
+ {description}
+ {tags && tags.length> 0 && (
+
+ )}
+
+ )
+ }
+}
+
+CustomCard.propTypes = {
+ showDeleteButton: PropTypes.bool,
+ onDelete: PropTypes.func,
+ onClick: PropTypes.func,
+ style: PropTypes.object,
+ tagStyle: PropTypes.object,
+ className: PropTypes.string,
+ id: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+ label: PropTypes.string,
+ description: PropTypes.string,
+ tags: PropTypes.array,
+}
+
+CustomCard.defaultProps = {
+ showDeleteButton: true,
+ onDelete: () => {},
+ onClick: () => {},
+ style: {},
+ tagStyle: {},
+ title: 'no title',
+ description: '',
+ label: '',
+ tags: [],
+ className: ''
+}
+
+export default CustomCard
diff --git a/react-ui/src/components/Kanban/CustomCard.stories.js b/react-ui/src/components/Kanban/CustomCard.stories.js
new file mode 100644
index 0000000..aba43d2
--- /dev/null
+++ b/react-ui/src/components/Kanban/CustomCard.stories.js
@@ -0,0 +1,28 @@
+import React from 'react'
+import CustomCard from './CustomCard'
+
+const artworkData = {
+ id: 'recDiogvIMmmefeKs',
+ media: 'https://dl.airtable.com/.attachmentThumbnails/0ce069864d50a15f7ae81479bb893e10/e7c55186',
+ location: 'Danforth Ave & Amroth Ave',
+ title: 'Emilia Jajus',
+ program: 'Partnership Program',
+ artist: 'Emilia Jajus',
+ partner: 'Seeds of Hope Foundation',
+ year: 2012,
+ description: 'The Bell Box Murals project has transformed utility cabinets into works of art. This piece is an interpretation of a historical photograph of horses and wagons on old Danforth Avenue.',
+ ward: 19,
+ status: ['Published']
+}
+
+export default {
+ component: CustomCard,
+ title: 'Kanban Board/CustomCard'
+}
+
+const Template = args =>
+
+export const Default = Template.bind({})
+Default.args = {
+ ...artworkData
+}
diff --git a/react-ui/src/components/Kanban/Kanban.js b/react-ui/src/components/Kanban/Kanban.js
new file mode 100644
index 0000000..d261efd
--- /dev/null
+++ b/react-ui/src/components/Kanban/Kanban.js
@@ -0,0 +1,78 @@
+import React, { useState } from 'react'
+import PropTypes from 'prop-types'
+import Board from 'react-trello'
+import MaterialCard from './MaterialCard'
+import { Button, Dialog, DialogTitle, DialogActions, DialogContent, DialogContentText } from '@material-ui/core'
+import Slide from '@material-ui/core/Slide'
+import OpenInNewIcon from '@material-ui/icons/OpenInNew'
+
+const DialogTransition = React.forwardRef(function DialogTransition(props, ref) {
+ return
+})
+
+const Kanban = ({ data = {}, onCardClick, onDataChange, onDragEnd, airtableViewUrl }) => {
+ const [ showCard, setShowCard ] = useState(false)
+ const [ activeCard, setActiveCard ] = useState({})
+
+ const handleCardClick = (cardId, metadata, laneId) => {
+ onCardClick(cardId, metadata, laneId)
+ setActiveCard(metadata || {})
+ setShowCard(true)
+ }
+
+ const handleClose = () => {
+ setShowCard(false)
+ }
+
+ return (
+ <>
+
+
+ >
+ )
+}
+
+Kanban.propTypes = {
+ data: PropTypes.object,
+ onCardClick: PropTypes.func,
+ onDataChange: PropTypes.func,
+ onDragEnd: PropTypes.func
+}
+
+export default Kanban
diff --git a/react-ui/src/components/Kanban/Kanban.stories.js b/react-ui/src/components/Kanban/Kanban.stories.js
new file mode 100644
index 0000000..021cb37
--- /dev/null
+++ b/react-ui/src/components/Kanban/Kanban.stories.js
@@ -0,0 +1,30 @@
+import React from 'react'
+import Kanban from './Kanban'
+
+const data = require('./../../../.storybook/data/kanban-artworks.json')
+
+const populateMetadata = data => ({
+ lanes: data.lanes.map(lane => ({
+ ...lane,
+ label: lane.cards.length.toString(),
+ cards: lane.cards.map(card => ({
+ ...card,
+ metadata: card
+ }))
+ }))
+})
+
+const populatedData = populateMetadata(data)
+
+export default {
+ component: Kanban,
+ title: 'Kanban Board/Kanban'
+}
+
+const Template = args =>
+
+export const Default = Template.bind({})
+Default.args = {
+ airtableViewUrl: 'https://airtable.com/tbl5ApSEOzPpe4fwp/viw2swQLeJ9xwU82F',
+ data: populatedData
+}
diff --git a/react-ui/src/components/Kanban/MaterialCard.js b/react-ui/src/components/Kanban/MaterialCard.js
new file mode 100644
index 0000000..991e1aa
--- /dev/null
+++ b/react-ui/src/components/Kanban/MaterialCard.js
@@ -0,0 +1,81 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import {
+ Card,
+ CardActionArea,
+ CardContent,
+ CardMedia,
+ createMuiTheme,
+ makeStyles,
+ Typography
+} from '@material-ui/core'
+import ProgramChip from './ProgramChip'
+import placeholder from 'assets/images/placeholder.png'
+
+// const BASE_ID = 'tbl5ApSEOzPpe4fwp'
+// const TABLE_ID = 'viw2swQLeJ9xwU82F'
+
+const theme = createMuiTheme()
+const useStyles = makeStyles({
+ root: {
+ minWidth: 230,
+ maxWidth: 250,
+ marginBottom: theme.spacing(1)
+ },
+ media: {
+ height: 140
+ }
+})
+
+const MaterialCard = props => {
+ const classes = useStyles()
+
+ const image = props.media ? props.media : placeholder
+
+ return (
+
+
+
+
+
+ {props.title}
+
+
+ {props.description}
+
+
+
+
+
+ )
+}
+
+MaterialCard.propTypes = {
+ foo: PropTypes.string,
+}
+
+export default MaterialCard
diff --git a/react-ui/src/components/Kanban/MaterialCard.stories.js b/react-ui/src/components/Kanban/MaterialCard.stories.js
new file mode 100644
index 0000000..5180d38
--- /dev/null
+++ b/react-ui/src/components/Kanban/MaterialCard.stories.js
@@ -0,0 +1,52 @@
+import React from 'react'
+import MaterialCard from './MaterialCard'
+
+const artworkData = {
+ id: 'recDiogvIMmmefeKs',
+ media: 'https://dl.airtable.com/.attachmentThumbnails/0ce069864d50a15f7ae81479bb893e10/e7c55186',
+ location: 'Danforth Ave & Amroth Ave',
+ title: 'Emilia Jajus',
+ program: 'Partnership Program',
+ artist: 'Emilia Jajus',
+ partner: 'Seeds of Hope Foundation',
+ year: 2012,
+ description: 'The Bell Box Murals project has transformed utility cabinets into works of art. This piece is an interpretation of a historical photograph of horses and wagons on old Danforth Avenue.',
+ ward: 19,
+ status: ['Published']
+}
+
+export default {
+ component: MaterialCard,
+ title: 'Kanban Board/MaterialCard'
+}
+
+const Template = args =>
+
+export const Default = Template.bind({})
+Default.args = {
+ ...artworkData
+}
+
+export const TitleOverflow = Template.bind({})
+TitleOverflow.args = {
+ ...Default.args,
+ title: 'Lorem Ipsum Delore blah blah'
+}
+
+export const MissingImage = Template.bind({})
+MissingImage.args = {
+ ...Default.args,
+ media: null
+}
+
+export const AlternativeProgram = Template.bind({})
+AlternativeProgram.args = {
+ ...Default.args,
+ program: "StART Support"
+}
+
+export const TypoedProgram = Template.bind({})
+TypoedProgram.args = {
+ ...Default.args,
+ program: "StART Supports"
+}
diff --git a/react-ui/src/components/Kanban/ProgramChip.js b/react-ui/src/components/Kanban/ProgramChip.js
new file mode 100644
index 0000000..d558c5f
--- /dev/null
+++ b/react-ui/src/components/Kanban/ProgramChip.js
@@ -0,0 +1,33 @@
+import React from 'react'
+import { Chip } from '@material-ui/core'
+
+const COLOR_PARTNERSHIP = '#004b84'
+const COLOR_OUTSIDE_BOX = '#a41632'
+const COLOR_START_SUPPORT = '#037f2f'
+const COLOR_OTHER = '#cfb51c'
+
+const ProgramChip = props => {
+ const labelColors = {
+ 'partnership program': COLOR_PARTNERSHIP,
+ 'outside the box': COLOR_OUTSIDE_BOX,
+ 'start support': COLOR_START_SUPPORT,
+ 'other': COLOR_OTHER
+ }
+
+ const lookupKey = props.label.toLowerCase()
+
+ const labelStyle = {
+ backgroundColor: labelColors[lookupKey],
+ color: '#ffffff'
+ }
+
+ return (
+
+ )
+}
+
+export default ProgramChip