From 03e1de1d141d13249f455a26d72522e8b43b3f56 Mon Sep 17 00:00:00 2001 From: Amruth Pillai Date: Sun, 5 Jul 2020 13:34:04 +0530 Subject: [PATCH] implement reorder/moving of sections between blocks --- gatsby-browser.js | 5 +- package-lock.json | 54 ++++++++++++ package.json | 1 + src/components/builder/center/Artboard.js | 19 +++- src/components/builder/right/RightSidebar.js | 4 +- src/components/builder/sections/Layout.js | 63 +++++++++++++ .../builder/sections/Layout.module.css | 11 +++ src/contexts/TemplateContext.js | 88 +++++++++++++++++++ 8 files changed, 240 insertions(+), 5 deletions(-) create mode 100644 src/components/builder/sections/Layout.js create mode 100644 src/components/builder/sections/Layout.module.css create mode 100644 src/contexts/TemplateContext.js diff --git a/gatsby-browser.js b/gatsby-browser.js index bffbf171..3facfca8 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -6,6 +6,7 @@ import React from "react"; import { DashboardProvider } from "./src/contexts/DashboardContext"; import { ModalProvider } from "./src/contexts/ModalContext"; import { ResumeProvider } from "./src/contexts/ResumeContext"; +import { TemplateProvider } from "./src/contexts/TemplateContext"; import { ThemeProvider } from "./src/contexts/ThemeContext"; import { UserProvider } from "./src/contexts/UserContext"; import "./src/styles/colors.css"; @@ -27,7 +28,9 @@ export const wrapRootElement = ({ element }) => ( - {element} + + {element} + diff --git a/package-lock.json b/package-lock.json index d5ea2926..51b730dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5382,6 +5382,14 @@ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==" }, + "css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "requires": { + "tiny-invariant": "^1.0.6" + } + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -12257,6 +12265,11 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoize-one": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", + "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -14889,6 +14902,11 @@ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" }, + "raf-schd": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz", + "integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -14962,6 +14980,20 @@ "prop-types": "^15.6.2" } }, + "react-beautiful-dnd": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz", + "integrity": "sha512-87It8sN0ineoC3nBW0SbQuTFXM6bUqM62uJGY4BtTf0yzPl8/3+bHMWkgIe0Z6m8e+gJgjWxefGRVfpE3VcdEg==", + "requires": { + "@babel/runtime": "^7.8.4", + "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-dev-utils": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-4.2.3.tgz", @@ -15299,6 +15331,18 @@ } } }, + "react-redux": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz", + "integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==", + "requires": { + "@babel/runtime": "^7.5.5", + "hoist-non-react-statics": "^3.3.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.9.0" + } + }, "react-refresh": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.7.2.tgz", @@ -17847,6 +17891,11 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, "tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -18648,6 +18697,11 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-memo-one": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz", + "integrity": "sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ==" + }, "utif": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz", diff --git a/package.json b/package.json index ed811e3f..56978e6c 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "lodash": "^4.17.15", "moment": "^2.27.0", "react": "^16.12.0", + "react-beautiful-dnd": "^13.0.0", "react-dom": "^16.12.0", "react-firebase-hooks": "^2.2.0", "react-helmet": "^6.1.0", diff --git a/src/components/builder/center/Artboard.js b/src/components/builder/center/Artboard.js index 2b95974a..de0ebee2 100644 --- a/src/components/builder/center/Artboard.js +++ b/src/components/builder/center/Artboard.js @@ -1,8 +1,23 @@ -import React from "react"; +import React, { useContext } from "react"; +import TemplateContext from "../../../contexts/TemplateContext"; import styles from "./Artboard.module.css"; const Artboard = () => { - return
; + const { blocks } = useContext(TemplateContext); + + return ( +
+
+ {blocks.map((block, ind) => ( +
+ {block.map((x) => ( +
{x.name}
+ ))} +
+ ))} +
+
+ ); }; export default Artboard; diff --git a/src/components/builder/right/RightSidebar.js b/src/components/builder/right/RightSidebar.js index 1790bed5..6365629d 100644 --- a/src/components/builder/right/RightSidebar.js +++ b/src/components/builder/right/RightSidebar.js @@ -1,5 +1,5 @@ import React from "react"; -import Profile from "../sections/Profile"; +import Layout from "../sections/Layout"; import RightNavbar from "./RightNavbar"; import styles from "./RightSidebar.module.css"; @@ -7,7 +7,7 @@ const RightSidebar = () => { return (
- +
diff --git a/src/components/builder/sections/Layout.js b/src/components/builder/sections/Layout.js new file mode 100644 index 00000000..86522975 --- /dev/null +++ b/src/components/builder/sections/Layout.js @@ -0,0 +1,63 @@ +import cx from "classnames"; +import React, { useContext } from "react"; +import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd"; +import TemplateContext from "../../../contexts/TemplateContext"; +import Heading from "../../shared/Heading"; +import styles from "./Layout.module.css"; + +const Layout = () => { + const { blocks, onDragEnd } = useContext(TemplateContext); + + return ( +
+ Layout + +

+ This template supports {blocks.length} blocks. You can re-order or move + sections by dragging/dropping the section names across lists. +

+ +
+ + {blocks.map((el, ind) => ( + + {(provided, snapshot) => ( +
+
+ {el.map((item, index) => ( + + {(provided) => ( +
+ {item.name} +
+ )} +
+ ))} +
+ {provided.placeholder} +
+ )} +
+ ))} +
+
+
+ ); +}; + +export default Layout; diff --git a/src/components/builder/sections/Layout.module.css b/src/components/builder/sections/Layout.module.css new file mode 100644 index 00000000..b7bf2f87 --- /dev/null +++ b/src/components/builder/sections/Layout.module.css @@ -0,0 +1,11 @@ +.droppable { + @apply px-4 py-6 bg-gray-100 col-span-1 rounded; +} + +.droppable.dragging-over { + @apply bg-gray-200; +} + +.draggable { + @apply px-4 py-2 font-medium rounded bg-gray-300; +} diff --git a/src/contexts/TemplateContext.js b/src/contexts/TemplateContext.js new file mode 100644 index 00000000..addcff56 --- /dev/null +++ b/src/contexts/TemplateContext.js @@ -0,0 +1,88 @@ +import React, { createContext, useState } from "react"; + +const defaultState = { + selected: "Pikachu", + setSelected: () => {}, + blocks: [ + [ + { id: "1", name: "Profile" }, + { id: "2", name: "Work" }, + ], + [ + { id: "3", name: "Education" }, + { id: "4", name: "Skills" }, + { id: "5", name: "Hobbies" }, + ], + ], + setBlocks: () => {}, +}; + +const TemplateContext = createContext(defaultState); + +const TemplateProvider = ({ children }) => { + const [selected, setSelected] = useState(defaultState.selected); + const [blocks, setBlocks] = useState(defaultState.blocks); + + const reorder = (list, startIndex, endIndex) => { + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + + return result; + }; + + const move = (source, destination, droppableSource, droppableDestination) => { + const sourceClone = Array.from(source); + const destClone = Array.from(destination); + const [removed] = sourceClone.splice(droppableSource.index, 1); + + destClone.splice(droppableDestination.index, 0, removed); + + const result = {}; + result[droppableSource.droppableId] = sourceClone; + result[droppableDestination.droppableId] = destClone; + + return result; + }; + + const onDragEnd = (result) => { + const { source, destination } = result; + + if (!destination) { + return; + } + const sInd = +source.droppableId; + const dInd = +destination.droppableId; + + if (sInd === dInd) { + const items = reorder(blocks[sInd], source.index, destination.index); + const newState = [...blocks]; + newState[sInd] = items; + setBlocks(newState); + } else { + const result = move(blocks[sInd], blocks[dInd], source, destination); + const newState = [...blocks]; + newState[sInd] = result[sInd]; + newState[dInd] = result[dInd]; + setBlocks(newState); + } + }; + + return ( + + {children} + + ); +}; + +export default TemplateContext; + +export { TemplateProvider };