mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-13 00:03:27 +10:00
implement reorder/moving of sections between blocks
This commit is contained in:
@ -6,6 +6,7 @@ import React from "react";
|
|||||||
import { DashboardProvider } from "./src/contexts/DashboardContext";
|
import { DashboardProvider } from "./src/contexts/DashboardContext";
|
||||||
import { ModalProvider } from "./src/contexts/ModalContext";
|
import { ModalProvider } from "./src/contexts/ModalContext";
|
||||||
import { ResumeProvider } from "./src/contexts/ResumeContext";
|
import { ResumeProvider } from "./src/contexts/ResumeContext";
|
||||||
|
import { TemplateProvider } from "./src/contexts/TemplateContext";
|
||||||
import { ThemeProvider } from "./src/contexts/ThemeContext";
|
import { ThemeProvider } from "./src/contexts/ThemeContext";
|
||||||
import { UserProvider } from "./src/contexts/UserContext";
|
import { UserProvider } from "./src/contexts/UserContext";
|
||||||
import "./src/styles/colors.css";
|
import "./src/styles/colors.css";
|
||||||
@ -27,7 +28,9 @@ export const wrapRootElement = ({ element }) => (
|
|||||||
<ModalProvider>
|
<ModalProvider>
|
||||||
<UserProvider>
|
<UserProvider>
|
||||||
<DashboardProvider>
|
<DashboardProvider>
|
||||||
<ResumeProvider>{element}</ResumeProvider>
|
<ResumeProvider>
|
||||||
|
<TemplateProvider>{element}</TemplateProvider>
|
||||||
|
</ResumeProvider>
|
||||||
</DashboardProvider>
|
</DashboardProvider>
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
</ModalProvider>
|
</ModalProvider>
|
||||||
|
|||||||
54
package-lock.json
generated
54
package-lock.json
generated
@ -5382,6 +5382,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
||||||
"integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
|
"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": {
|
"css-color-names": {
|
||||||
"version": "0.0.4",
|
"version": "0.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
"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": {
|
"memory-fs": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
|
||||||
"integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA=="
|
"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": {
|
"randombytes": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||||
@ -14962,6 +14980,20 @@
|
|||||||
"prop-types": "^15.6.2"
|
"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": {
|
"react-dev-utils": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-4.2.3.tgz",
|
"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": {
|
"react-refresh": {
|
||||||
"version": "0.7.2",
|
"version": "0.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.7.2.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
|
||||||
"integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
|
"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": {
|
"tiny-warning": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||||
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
|
"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": {
|
"utif": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz",
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"moment": "^2.27.0",
|
"moment": "^2.27.0",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
|
"react-beautiful-dnd": "^13.0.0",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-firebase-hooks": "^2.2.0",
|
"react-firebase-hooks": "^2.2.0",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
|
|||||||
@ -1,8 +1,23 @@
|
|||||||
import React from "react";
|
import React, { useContext } from "react";
|
||||||
|
import TemplateContext from "../../../contexts/TemplateContext";
|
||||||
import styles from "./Artboard.module.css";
|
import styles from "./Artboard.module.css";
|
||||||
|
|
||||||
const Artboard = () => {
|
const Artboard = () => {
|
||||||
return <div className={styles.container}></div>;
|
const { blocks } = useContext(TemplateContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={`grid gap-8 grid-cols-${blocks.length}`}>
|
||||||
|
{blocks.map((block, ind) => (
|
||||||
|
<div key={ind} className="col-span-1">
|
||||||
|
{block.map((x) => (
|
||||||
|
<div key={x.id}>{x.name}</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Artboard;
|
export default Artboard;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Profile from "../sections/Profile";
|
import Layout from "../sections/Layout";
|
||||||
import RightNavbar from "./RightNavbar";
|
import RightNavbar from "./RightNavbar";
|
||||||
import styles from "./RightSidebar.module.css";
|
import styles from "./RightSidebar.module.css";
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ const RightSidebar = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<Profile />
|
<Layout />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RightNavbar />
|
<RightNavbar />
|
||||||
|
|||||||
63
src/components/builder/sections/Layout.js
Normal file
63
src/components/builder/sections/Layout.js
Normal file
@ -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 (
|
||||||
|
<section>
|
||||||
|
<Heading>Layout</Heading>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This template supports {blocks.length} blocks. You can re-order or move
|
||||||
|
sections by dragging/dropping the section names across lists.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className={`grid gap-8 grid-cols-${blocks.length}`}>
|
||||||
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
|
{blocks.map((el, ind) => (
|
||||||
|
<Droppable key={ind} droppableId={`${ind}`}>
|
||||||
|
{(provided, snapshot) => (
|
||||||
|
<div
|
||||||
|
ref={provided.innerRef}
|
||||||
|
className={cx(styles.droppable, {
|
||||||
|
[styles.draggingOver]: snapshot.isDraggingOver,
|
||||||
|
})}
|
||||||
|
{...provided.droppableProps}
|
||||||
|
>
|
||||||
|
<div className="grid gap-3">
|
||||||
|
{el.map((item, index) => (
|
||||||
|
<Draggable
|
||||||
|
key={item.id}
|
||||||
|
draggableId={item.id}
|
||||||
|
index={index}
|
||||||
|
>
|
||||||
|
{(provided) => (
|
||||||
|
<div
|
||||||
|
ref={provided.innerRef}
|
||||||
|
className={styles.draggable}
|
||||||
|
{...provided.draggableProps}
|
||||||
|
{...provided.dragHandleProps}
|
||||||
|
>
|
||||||
|
{item.name}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Draggable>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{provided.placeholder}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Droppable>
|
||||||
|
))}
|
||||||
|
</DragDropContext>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Layout;
|
||||||
11
src/components/builder/sections/Layout.module.css
Normal file
11
src/components/builder/sections/Layout.module.css
Normal file
@ -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;
|
||||||
|
}
|
||||||
88
src/contexts/TemplateContext.js
Normal file
88
src/contexts/TemplateContext.js
Normal file
@ -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 (
|
||||||
|
<TemplateContext.Provider
|
||||||
|
value={{
|
||||||
|
selected,
|
||||||
|
setSelected,
|
||||||
|
blocks,
|
||||||
|
setBlocks,
|
||||||
|
onDragEnd,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</TemplateContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TemplateContext;
|
||||||
|
|
||||||
|
export { TemplateProvider };
|
||||||
Reference in New Issue
Block a user