From a017cafd712d5f76f558dbce567b3910a9594a6a Mon Sep 17 00:00:00 2001 From: Peter van Hardenberg Date: Mon, 18 Nov 2019 15:38:36 -0800 Subject: [PATCH 1/5] demo code imported from beautiful-dnd for play --- package.json | 1 + src/renderer/components/Root.tsx | 1 + .../components/content-types/ListContent.css | 0 .../components/content-types/ListContent.tsx | 149 ++++++++++++++++++ yarn.lock | 101 +++++++++++- 5 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 src/renderer/components/content-types/ListContent.css create mode 100644 src/renderer/components/content-types/ListContent.tsx diff --git a/package.json b/package.json index 6398888f..d3143058 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "quill": "^1.3.6", "quill-delta": "^3.6.2", "react": "16.8.6", + "react-beautiful-dnd": "^12.1.1", "react-color": "^2.17.3", "react-dom": ">=16.8.6", "react-measure": "^2.3.0", diff --git a/src/renderer/components/Root.tsx b/src/renderer/components/Root.tsx index 476ce5c3..d0a61409 100644 --- a/src/renderer/components/Root.tsx +++ b/src/renderer/components/Root.tsx @@ -17,6 +17,7 @@ import './content-types/board' import './content-types/contact' import './content-types/files' import './content-types/storage-peer' +import './content-types/ListContent' // other single-context components import './content-types/TextContent' diff --git a/src/renderer/components/content-types/ListContent.css b/src/renderer/components/content-types/ListContent.css new file mode 100644 index 00000000..e69de29b diff --git a/src/renderer/components/content-types/ListContent.tsx b/src/renderer/components/content-types/ListContent.tsx new file mode 100644 index 00000000..0aaadf28 --- /dev/null +++ b/src/renderer/components/content-types/ListContent.tsx @@ -0,0 +1,149 @@ +import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd' + +import React, { useState, useCallback } from 'react' + +import * as ContentTypes from '../../ContentTypes' +import Content, { ContentProps } from '../Content' +import { createDocumentLink, HypermergeUrl, PushpinUrl } from '../../ShareLink' +import { useDocument } from '../../Hooks' +import './ListContent.css' +import { string } from 'prop-types' + +export type CardId = string & { cardId: true } + +export interface ListDocCard { + id: CardId + url: PushpinUrl +} + +export interface ListDoc { + title: string + backgroundColor: string + cards: ListDocCard[] + hypermergeUrl: HypermergeUrl // added by workspace + authorIds: HypermergeUrl[] +} + +ListContent.minWidth = 9 +ListContent.minHeight = 6 +ListContent.defaultWidth = 16 +ListContent.defaultHeight = 18 +ListContent.maxWidth = 24 +ListContent.maxHeight = 36 + +/* demo helpers */ + +// fake data generator +const getItems = (count): ListItem[] => + Array.from({ length: count }, (v, k) => k).map((k) => ({ + id: `item-${k}`, + content: `item ${k}`, + })) + +interface ListItem { + id: string + content: string +} + +// a little function to help us with reordering the result +const reorder = (list: ListItem[], startIndex, endIndex): ListItem[] => { + const result = Array.from(list) + const [removed] = result.splice(startIndex, 1) + result.splice(endIndex, 0, removed) + + return result +} + +const grid = 8 + +const getItemStyle = (draggableStyle, isDragging) => ({ + // some basic styles to make the items look a bit nicer + userSelect: 'none', + padding: grid * 2, + margin: `0 0 ${grid}px 0`, + + // change background colour if dragging + background: isDragging ? 'lightgreen' : 'grey', + + // styles we need to apply on draggables + ...draggableStyle, +}) + +const getListStyle = (isDraggingOver) => ({ + background: isDraggingOver ? 'lightblue' : 'lightgrey', + padding: grid, + width: 250, +}) + +/* demo helpers end */ + +export default function ListContent(props: ContentProps) { + const [items, setItems] = useState(getItems(10)) + const [doc, changeDoc] = useDocument(props.hypermergeUrl) + + const onDragEnd = useCallback( + (result) => { + // dropped outside the list + if (!result.destination) { + return + } + + setItems(reorder(items, result.source.index, result.destination.index)) + }, + [items] + ) + + if (!doc) { + return null + } + + return ( + + + {(provided, snapshot) => ( +
+ {items.map((item, index) => ( + + {(provided, snapshot) => ( +
+
+ {item.content} +
+ {provided.placeholder} +
+ )} +
+ ))} + {provided.placeholder} +
+ )} +
+
+ ) +} + +function create(unusedAttrs, handle) { + handle.change((doc) => { + doc.cards = {} + }) +} + +ContentTypes.register({ + type: 'list', + name: 'List', + icon: 'list', + contexts: { + workspace: ListContent, + board: ListContent, + }, + create, +}) diff --git a/yarn.lock b/yarn.lock index 5a346ef8..7f91cdc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36,6 +36,14 @@ core-js "^2.6.5" regenerator-runtime "^0.13.2" +"@babel/runtime-corejs2@^7.6.3": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.7.2.tgz#5a8c4e2f8688ce58adc9eb1d8320b6e7341f96ce" + integrity sha512-GfVnHchOBvIMsweQ13l4jd9lT4brkevnavnVOej5g2y7PpTRY+R4pcQlCjWMZoUla5rMLFzaS/Ll2s59cB1TqQ== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.2" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.2.0": version "7.4.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.5.tgz#582bb531f5f9dc67d2fcb682979894f75e253f12" @@ -43,6 +51,13 @@ dependencies: regenerator-runtime "^0.13.2" +"@babel/runtime@^7.5.5": + version "7.7.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.2.tgz#111a78002a5c25fc8e3361bedc9529c696b85a6a" + integrity sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw== + dependencies: + regenerator-runtime "^0.13.2" + "@develar/schema-utils@~2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.1.0.tgz#eceb1695bfbed6f6bb84666d5d3abe5e1fd54e17" @@ -2348,6 +2363,13 @@ crypto-random-string@^1.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= +css-box-model@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.0.tgz#3a26377b4162b3200d2ede4b064ec5b6a75186d0" + integrity sha512-lri0br+jSNV0kkkiGEp9y9y3Njq2PmpqbeGWRFQJuZteZzY9iC9GZhQ8Y4WpPwM/2YocjHePxy14igJY7YKzkA== + dependencies: + tiny-invariant "^1.0.6" + css-loader@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.0.0.tgz#bdd48a4921eefedf1f0a55266585944d4e5efc63" @@ -4332,6 +4354,13 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#101685d3aff3b23ea213163f6e8e12f4f111e19f" + integrity sha512-wbg3bpgA/ZqWrZuMOeJi8+SKMhr7X9TesL/rXMjTzh0p0JUBo3II8DHboYbuIXWRlttrUFxwcu/5kygrCw8fJw== + dependencies: + react-is "^16.7.0" + homedir-polyfill@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" @@ -4746,6 +4775,13 @@ interpret@1.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" @@ -5504,7 +5540,7 @@ loglevel@^1.6.3: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -5636,6 +5672,11 @@ memoize-one@^4.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.1.0.tgz#a2387c58c03fff27ca390c31b764a79addf3f906" integrity sha512-2GApq0yI/b22J2j9rhbrAlsHb0Qcz+7yWxeLG8h+95sl1XPUgeLimQSOdur4Vw7cUhrBHwaUZxWFZueojqNRzA== +memoize-one@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" + integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== + memoize-weak@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/memoize-weak/-/memoize-weak-1.0.2.tgz#d0015a4c7c6cff2263dbbb49db1dc206ebb94916" @@ -7258,6 +7299,11 @@ quill@^1.3.6: parchment "^1.1.4" quill-delta "^3.6.2" +raf-schd@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.2.tgz#bd44c708188f2e84c810bf55fcea9231bcaed8a0" + integrity sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ== + raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -7347,6 +7393,19 @@ re-resizable@4.11.0: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-4.11.0.tgz#d5df10bda445c4ec0945751a223bf195afb61890" integrity sha512-dye+7rERqNf/6mDT1iwps+4Gf42420xuZgygF33uX178DxffqcyeuHbBuJ382FIcB5iP6mMZOhfW7kI0uXwb/Q== +react-beautiful-dnd@^12.1.1: + version "12.1.1" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-12.1.1.tgz#810f9b9d94f667b15b253793e853d016a0f3f07c" + integrity sha512-w/mpIXMEXowc53PCEnMoFyAEYFgxMfygMK5msLo5ifJ2/CiSACLov9A79EomnPF7zno3N207QGXsraBxAJnyrw== + dependencies: + "@babel/runtime-corejs2" "^7.6.3" + css-box-model "^1.2.0" + memoize-one "^5.1.1" + raf-schd "^4.0.2" + react-redux "^7.1.1" + redux "^4.0.4" + use-memo-one "^1.1.1" + react-color@^2.17.3: version "2.17.3" resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.17.3.tgz#b8556d744f95193468c7061d2aa19180118d4a48" @@ -7377,6 +7436,11 @@ react-draggable@3.1.1: classnames "^2.2.5" prop-types "^15.6.0" +react-is@^16.7.0, react-is@^16.9.0: + version "16.12.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" + integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== + react-is@^16.8.1, react-is@^16.8.6: version "16.8.6" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" @@ -7404,6 +7468,18 @@ react-pdf@^4.1.0: pdfjs-dist "2.1.266" prop-types "^15.6.2" +react-redux@^7.1.1: + version "7.1.3" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.3.tgz#717a3d7bbe3a1b2d535c94885ce04cdc5a33fc79" + integrity sha512-uI1wca+ECG9RoVkWQFF4jDMqmaw0/qnvaSvOoL/GA4dNxf6LoV8sUAcNDvE5NWKs4hFpn0t6wswNQnY3f7HT3w== + dependencies: + "@babel/runtime" "^7.5.5" + hoist-non-react-statics "^3.3.0" + invariant "^2.2.4" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^16.9.0" + react-rnd@^9.1.2: version "9.1.2" resolved "https://registry.yarnpkg.com/react-rnd/-/react-rnd-9.1.2.tgz#3b3be3294a4866d7bdd702ec4743fb19a906c4d8" @@ -7559,6 +7635,14 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +redux@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.4.tgz#4ee1aeb164b63d6a1bcc57ae4aa0b6e6fa7a3796" + integrity sha512-vKv4WdiJxOWKxK0yRoaK3Y4pxxB0ilzVx6dszU2W8wLxlb2yikRph4iV/ymtdJ6ZxpBLFbyrxklnT5yBbQSl3Q== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + reflect.ownkeys@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz#749aceec7f3fdf8b63f927a04809e90c5c0b3460" @@ -8606,6 +8690,11 @@ svgpng@^4.0.1: execcli "^5.0.6" sharp "^0.22.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + table@^5.2.3: version "5.4.1" resolved "https://registry.yarnpkg.com/table/-/table-5.4.1.tgz#0691ae2ebe8259858efb63e550b6d5f9300171e8" @@ -8766,6 +8855,11 @@ timm@^1.6.1: resolved "https://registry.yarnpkg.com/timm/-/timm-1.6.1.tgz#5f8aafc932248c76caf2c6af60542a32d3c30701" integrity sha512-hqDTYi/bWuDxL2i6T3v6nrvkAQ/1Bc060GSkVEQZp02zTSTB4CHSKsOkliequCftQaNRcjRqUZmpGWs5FfhrNg== +tiny-invariant@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73" + integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA== + tinycolor2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" @@ -9132,6 +9226,11 @@ use-immer@^0.3.3: resolved "https://registry.yarnpkg.com/use-immer/-/use-immer-0.3.3.tgz#870479127f6050a62c321cf2cb6182e154a1786a" integrity sha512-BYRzcmbdY3wEBz0BZ1NHL15TzAAYmWJq/qj53xhmtgQ2w1/lNI3dxW6j33H0bR1Ycc4NYal0pwPj+107sgC4DQ== +use-memo-one@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.1.tgz#39e6f08fe27e422a7d7b234b5f9056af313bd22c" + integrity sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" From fa30f04ceed2ca4a3a3a5ea3c52716f06e4034e4 Mon Sep 17 00:00:00 2001 From: Peter van Hardenberg Date: Mon, 18 Nov 2019 15:55:45 -0800 Subject: [PATCH 2/5] persist some cards --- .../components/content-types/ListContent.tsx | 59 +++++++++---------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/src/renderer/components/content-types/ListContent.tsx b/src/renderer/components/content-types/ListContent.tsx index 0aaadf28..ef747cdc 100644 --- a/src/renderer/components/content-types/ListContent.tsx +++ b/src/renderer/components/content-types/ListContent.tsx @@ -1,13 +1,12 @@ +import React, { useCallback, useImperativeHandle } from 'react' import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd' - -import React, { useState, useCallback } from 'react' +import uuid from 'uuid' import * as ContentTypes from '../../ContentTypes' import Content, { ContentProps } from '../Content' -import { createDocumentLink, HypermergeUrl, PushpinUrl } from '../../ShareLink' +import { HypermergeUrl, PushpinUrl } from '../../ShareLink' import { useDocument } from '../../Hooks' import './ListContent.css' -import { string } from 'prop-types' export type CardId = string & { cardId: true } @@ -33,27 +32,6 @@ ListContent.maxHeight = 36 /* demo helpers */ -// fake data generator -const getItems = (count): ListItem[] => - Array.from({ length: count }, (v, k) => k).map((k) => ({ - id: `item-${k}`, - content: `item ${k}`, - })) - -interface ListItem { - id: string - content: string -} - -// a little function to help us with reordering the result -const reorder = (list: ListItem[], startIndex, endIndex): ListItem[] => { - const result = Array.from(list) - const [removed] = result.splice(startIndex, 1) - result.splice(endIndex, 0, removed) - - return result -} - const grid = 8 const getItemStyle = (draggableStyle, isDragging) => ({ @@ -78,19 +56,36 @@ const getListStyle = (isDraggingOver) => ({ /* demo helpers end */ export default function ListContent(props: ContentProps) { - const [items, setItems] = useState(getItems(10)) + useImperativeHandle(props.contentRef, () => ({ + onContent: (url: PushpinUrl) => onContent(url), + })) const [doc, changeDoc] = useDocument(props.hypermergeUrl) + const onContent = useCallback( + (url: PushpinUrl) => { + changeDoc((doc) => { + const id = uuid() as CardId + doc.cards.unshift({ id, url }) + }) + return true + }, + [doc] + ) + const onDragEnd = useCallback( (result) => { // dropped outside the list if (!result.destination) { return } - - setItems(reorder(items, result.source.index, result.destination.index)) + changeDoc((doc) => { + const from = result.source.index + const to = result.destination.index + const [removed] = doc.cards.splice(from, 1) + doc.cards.splice(to, 0, removed) + }) }, - [items] + [doc] ) if (!doc) { @@ -106,7 +101,7 @@ export default function ListContent(props: ContentProps) { style={getListStyle(snapshot.isDraggingOver)} {...provided.droppableProps} > - {items.map((item, index) => ( + {doc.cards.map((item, index) => ( {(provided, snapshot) => (
@@ -116,7 +111,7 @@ export default function ListContent(props: ContentProps) { {...provided.draggableProps} style={getItemStyle(provided.draggableProps.style, snapshot.isDragging)} > - {item.content} +
{provided.placeholder} @@ -133,7 +128,7 @@ export default function ListContent(props: ContentProps) { function create(unusedAttrs, handle) { handle.change((doc) => { - doc.cards = {} + doc.cards = [] }) } From 08432ded18371e20af581281d3891c950043cdd4 Mon Sep 17 00:00:00 2001 From: Peter van Hardenberg Date: Mon, 18 Nov 2019 16:35:01 -0800 Subject: [PATCH 3/5] paste support --- .../components/content-types/ListContent.tsx | 41 ++++++++++++++++--- .../components/content-types/board/Board.tsx | 2 + 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/renderer/components/content-types/ListContent.tsx b/src/renderer/components/content-types/ListContent.tsx index ef747cdc..bc2a86b0 100644 --- a/src/renderer/components/content-types/ListContent.tsx +++ b/src/renderer/components/content-types/ListContent.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useImperativeHandle } from 'react' +import React, { useCallback, useImperativeHandle, useEffect } from 'react' import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd' import uuid from 'uuid' @@ -6,6 +6,8 @@ import * as ContentTypes from '../../ContentTypes' import Content, { ContentProps } from '../Content' import { HypermergeUrl, PushpinUrl } from '../../ShareLink' import { useDocument } from '../../Hooks' +import * as ImportData from '../../ImportData' + import './ListContent.css' export type CardId = string & { cardId: true } @@ -32,7 +34,7 @@ ListContent.maxHeight = 36 /* demo helpers */ -const grid = 8 +const grid = 10 const getItemStyle = (draggableStyle, isDragging) => ({ // some basic styles to make the items look a bit nicer @@ -41,7 +43,7 @@ const getItemStyle = (draggableStyle, isDragging) => ({ margin: `0 0 ${grid}px 0`, // change background colour if dragging - background: isDragging ? 'lightgreen' : 'grey', + background: isDragging && 'lightgreen', // styles we need to apply on draggables ...draggableStyle, @@ -50,7 +52,8 @@ const getItemStyle = (draggableStyle, isDragging) => ({ const getListStyle = (isDraggingOver) => ({ background: isDraggingOver ? 'lightblue' : 'lightgrey', padding: grid, - width: 250, + position: 'relative', + width: '100%', }) /* demo helpers end */ @@ -72,6 +75,34 @@ export default function ListContent(props: ContentProps) { [doc] ) + const onPaste = useCallback( + (e: ClipboardEvent) => { + console.log('onPaste', e) + e.preventDefault() + e.stopPropagation() + + if (!e.clipboardData) { + return + } + + ImportData.importDataTransfer(e.clipboardData, (url, importCount) => { + console.log('imported', url) + changeDoc((doc) => { + const id = uuid() as CardId + doc.cards.unshift({ id, url }) + }) + }) + }, + [doc] + ) + + useEffect(() => { + document.addEventListener('paste', onPaste) + return () => { + document.removeEventListener('paste', onPaste) + } + }, [onPaste]) + const onDragEnd = useCallback( (result) => { // dropped outside the list @@ -111,7 +142,7 @@ export default function ListContent(props: ContentProps) { {...provided.draggableProps} style={getItemStyle(provided.draggableProps.style, snapshot.isDragging)} > - + {provided.placeholder} diff --git a/src/renderer/components/content-types/board/Board.tsx b/src/renderer/components/content-types/board/Board.tsx index 3860dd84..d86e456c 100644 --- a/src/renderer/components/content-types/board/Board.tsx +++ b/src/renderer/components/content-types/board/Board.tsx @@ -12,6 +12,7 @@ import { ContextMenuTrigger } from 'react-contextmenu' import * as ContentTypes from '../../../ContentTypes' import * as ImportData from '../../../ImportData' +import * as UriList from '../../../UriList' import { PushpinUrl } from '../../../ShareLink' import { ContentProps } from '../../Content' import { BoardDoc, BoardDocCard, CardId } from '.' @@ -271,6 +272,7 @@ const Board: FunctionComponent = (props: ContentProps) => { .map((c) => cards[c]) .map((c) => ({ ...c, x: c.x - offset.x, y: c.y - offset.y })) e.clipboardData.setData(MIMETYPE_BOARD_CARD_DATA, JSON.stringify(boardCards)) + e.clipboardData.setData(UriList.MIME_TYPE, UriList.stringify(boardCards.map((c) => c.url))) }, [cards, selection] ) From f615c13f88c5da38eb20e42a46961a6b0f106e72 Mon Sep 17 00:00:00 2001 From: Peter van Hardenberg Date: Mon, 18 Nov 2019 16:42:25 -0800 Subject: [PATCH 4/5] little bit of css --- src/renderer/components/content-types/ListContent.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/content-types/ListContent.tsx b/src/renderer/components/content-types/ListContent.tsx index bc2a86b0..dbb0c458 100644 --- a/src/renderer/components/content-types/ListContent.tsx +++ b/src/renderer/components/content-types/ListContent.tsx @@ -50,10 +50,11 @@ const getItemStyle = (draggableStyle, isDragging) => ({ }) const getListStyle = (isDraggingOver) => ({ - background: isDraggingOver ? 'lightblue' : 'lightgrey', + background: isDraggingOver ? 'lightblue' : 'white', padding: grid, position: 'relative', width: '100%', + overflowY: 'auto', }) /* demo helpers end */ @@ -128,6 +129,7 @@ export default function ListContent(props: ContentProps) { {(provided, snapshot) => (
Date: Mon, 18 Nov 2019 16:47:50 -0800 Subject: [PATCH 5/5] drag between lists doesn't work yet --- src/renderer/components/content-types/ListContent.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/renderer/components/content-types/ListContent.tsx b/src/renderer/components/content-types/ListContent.tsx index dbb0c458..79e101ea 100644 --- a/src/renderer/components/content-types/ListContent.tsx +++ b/src/renderer/components/content-types/ListContent.tsx @@ -124,9 +124,11 @@ export default function ListContent(props: ContentProps) { return null } + // TODO: droppableId must be unique, but if you have two instances of the + // same list on a board this will probably fail in creative ways return ( - + {(provided, snapshot) => (