diff --git a/README.md b/README.md index f4d602c..9a8f825 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ Code House comes up with a whole bunch of amazing features to provide you the be - 📬 **Newsletter** (once a week) - 💻 **Fully Responsive** - 🔤 **Reply to a comment** +- 📩 **Create Collections with Bookmarks** +- 📱 **Drag and Drop to arrange collections** Code House is the next revolutionary app to hunt the best cheat sheets for all types ✨️ @@ -148,6 +150,7 @@ After your PR got merged, you'll be automatically appared on [contributors page] - [Material UI](http://material-ui.com/): for components - [Animate.css](https://animate.style/): for smooth Animations - [AOS](https://michalsnik.github.io/aos/): for scroll animations +- [React Beautiful DND](https://react-beautiful-dnd.netlify.app/): For Drag and Drop support on Collections Page - [Vercel](http://vercel.com/): for hosting ## 🌈 What's next @@ -161,7 +164,6 @@ Here are some idea that is coming really soon 👀 - Markdown support for feature requests - Twitter and Facebook Auth, **In Progress ⏳️** - Perform Operations with API -- Create Collection when bookmarking cheatsheets - Featuring Cheatsheets on day basis - Generate Cover Image for missing ones - Settings page diff --git a/components/core/InfoBar.js b/components/core/InfoBar.js index e15d34f..2e49423 100644 --- a/components/core/InfoBar.js +++ b/components/core/InfoBar.js @@ -46,22 +46,31 @@ const InfoBar = ({ const [text, setText] = useState(""); // destructuring currentPost[0] - const { id, cheatsheet_name, website_url, upvotes, comments } = + let { id, cheatsheet_name, website_url, upvotes, comments } = currentPost.length > 0 && currentPost[0]; // fetching bookmarked cheatsheets and check if already bookmarked or not const fetchBookmarkedCheatsheets = () => { - if (bookmarks.some((cheatsheet) => cheatsheet.id === id)) { - setIsBookMarked(true); - } else { - setIsBookMarked(false); + let bookmarked = false; + for(let bookmark of bookmarks) { + if(bookmark.id === id){ + bookmarked = true; + } } + setIsBookMarked(bookmarked); }; // use effect to handle it useEffect(() => { - fetchBookmarkedCheatsheets(); - }, [bookmarks]); + if(currentPost.length > 0) { + id = currentPost[0].id; + cheatsheet_name = currentPost[0].cheatsheet_name; + website_url = currentPost[0].website_url; + upvotes = currentPost[0].upvotes; + comments = currentPost[0].comments; + } + return fetchBookmarkedCheatsheets(); + }, [bookmarks, currentPost]); useEffect(() => { // normal state @@ -251,8 +260,6 @@ const InfoBar = ({ } }; - console.log(comments); - return (
{loading ? ( diff --git a/components/index.js b/components/index.js index 24cad3b..fcd308b 100644 --- a/components/index.js +++ b/components/index.js @@ -30,3 +30,7 @@ export { default as FeatureComponent } from "./utils/FeatureComponent"; export { default as BmcButton } from "./utils/BmcButton"; export { default as TwitterBtn } from "./utils/TwitterBtn"; export { default as Loader } from "./utils/Loader"; +export { default as Dnd } from "./utils/Dnd"; +export { default as BookmarksItem} from "./utils/Bookmarks"; +export { default as BookmarksDialog } from "./utils/BookmarksDialog"; +export { default as Collection } from "./utils/Collection"; diff --git a/components/utils/BookMarkItem.js b/components/utils/BookMarkItem.js index c918aa2..8a1fa52 100644 --- a/components/utils/BookMarkItem.js +++ b/components/utils/BookMarkItem.js @@ -14,7 +14,9 @@ import { Btn } from ".."; // axios for data fetching import axios from "axios"; -const BookMarkItem = ({ data, bookmarks, fetchBookmarks }) => { +const BookMarkItem = ({ data, bookmarks, fetchBookmarks, animated, interactive }) => { + if(animated === undefined || animated === null) animated = true; + if(interactive === undefined || interactive === null) interactive = true; const [meta, setMetadata] = useState([]); const [loading, setLoading] = useState(false); @@ -118,9 +120,9 @@ const BookMarkItem = ({ data, bookmarks, fetchBookmarks }) => { return (
{loading ? (
@@ -164,7 +166,7 @@ const BookMarkItem = ({ data, bookmarks, fetchBookmarks }) => { > {url.hostname && url.hostname} - +

{cheatsheet_name.length > 50 ? cheatsheet_name.slice(0, 50) + "..." diff --git a/components/utils/Bookmarks.js b/components/utils/Bookmarks.js new file mode 100644 index 0000000..bd94b95 --- /dev/null +++ b/components/utils/Bookmarks.js @@ -0,0 +1,65 @@ +import React, { useEffect, useState } from "react"; + +import {Droppable, Draggable} from "react-beautiful-dnd"; + +import BookMarkItem from "./BookMarkItem"; + +import {FiPlus, FiTrash2} from "react-icons/fi"; +import {MdApps} from "react-icons/md"; + +export default function BookmarksItem({collectionId, bookmarkData, bookmarkIDs, entities, setEntities, bookmarks, fetchBookmarks}) { + const deleteBookmark = (index) => { + let collections = entities.collections; + let bookmarks = entities.bookmarks; + delete bookmarks[collections[collectionId].bookmarkIDs[index]]; + + collections[collectionId].bookmarkIDs.splice(index, 1); + + console.log(collections, bookmarks); + setEntities({ ...entities, collections, bookmarks }) + } + + return ( + + { + provided => ( +
+ { + bookmarkIDs ? ( + bookmarkIDs.map((bookmarkID, index) => { + const contentIndex = parseInt(bookmarkID.replace("bookmark-", "")) - 1, + content = bookmarkData[contentIndex].content; + return + { + provided => ( +
+
+
+
+ +
+ deleteBookmark(index)} /> +
+ +
+
+ ) + } +
+ })) : ("") + } +
+ ) + } +
+ ) +} diff --git a/components/utils/BookmarksDialog.js b/components/utils/BookmarksDialog.js new file mode 100644 index 0000000..caa03df --- /dev/null +++ b/components/utils/BookmarksDialog.js @@ -0,0 +1,51 @@ +import React, {useEffect, useState } from "react"; + +import {Backdrop} from "@material-ui/core"; +import BookMarkItem from './BookMarkItem'; +import {FiX} from 'react-icons/fi'; + +export default function BookmarksDialog({entities, setEntities, bookmarks, fetchBookmarks, showBookmarks, setShowBookmarks}) { + const addToCollection = (data) => { + const newBookmarkID = `bookmark-${Object.keys(entities.bookmarks).length + 1}`; + let bookmarks = entities.bookmarks; + const newBookmark = { + id: newBookmarkID, + content: data + } + bookmarks.push(newBookmark); + + let collections = entities.collections; + if(!collections[showBookmarks].bookmarkIDs) collections[showBookmarks].bookmarkIDs = []; + + let bookmarkIDs = collections[showBookmarks].bookmarkIDs; + bookmarkIDs.push(newBookmarkID); + + setEntities({ ...entities, bookmarks, collections }); + setShowBookmarks(null); + } + + return ( + setShowBookmarks(false)}> +
e.stopPropagation()}> +
+

All Bookmarks

+ setShowBookmarks(false)} /> +
+
+ {bookmarks.map((cheatsheet, key) => ( +
addToCollection(cheatsheet)}> + +
+ ))} +
+
+
+ ) +} diff --git a/components/utils/Collection.js b/components/utils/Collection.js new file mode 100644 index 0000000..96ee959 --- /dev/null +++ b/components/utils/Collection.js @@ -0,0 +1,60 @@ +import React, {useEffect, useState, useRef} from "react"; + +import {Draggable} from "react-beautiful-dnd"; + +import BookmarksItem from "./Bookmarks"; + +import {FiPlus, FiTrash2} from "react-icons/fi"; +import {MdApps} from "react-icons/md"; + +export default function Collection({entities, setEntities, collectionId, index, showBookmarks, setShowBookmarks, bookmarks, fetchBookmarks}) { + const [collectionTitle, setCollectionTitle] = useState(entities.collections[collectionId].title), + collectionTitleRef = useRef(); + + const deleteCollection = () => { + let collections = entities.collections; + delete collections[collectionId]; + + let collectionOrder = entities.collectionOrder; + collectionOrder.splice(collectionOrder.indexOf(collectionId), 1); + + setEntities({ ...entities, collections, collectionOrder }); + } + + useEffect(() => { + let collections = entities.collections; + collections[collectionId].title = collectionTitle; + + setEntities({...entities, collections}); + }, [collectionTitle]); + + return ( + <> + { + entities?.collections[collectionId]?.id && + { + provided => ( +
+
+
+
+ +
+ setCollectionTitle(e.target.value)} className="text-2xl w-full font-bold text-[#fff] bg-transparent cursor-text" /> +
+ + {setShowBookmarks(collectionId)}}/> +
+
+
+ +
+
+
+ ) + } +
+ } + + ) +} diff --git a/components/utils/Dnd.js b/components/utils/Dnd.js new file mode 100644 index 0000000..886a22a --- /dev/null +++ b/components/utils/Dnd.js @@ -0,0 +1,128 @@ +import React, {useEffect, useState } from "react"; +import { DragDropContext, Droppable } from "react-beautiful-dnd"; +import Collection from "./Collection"; + +import { FiPlus } from "react-icons/fi"; + +function updateLocalStorage(data) { + if(window.localStorage !== null) { + window.localStorage.setItem("codehouse-collections", null); + window.localStorage.setItem("codehouse-collections", JSON.stringify(data)); + } +} + +function getLocalStorage() { + // window.localStorage.setItem("codehouse-collections", null); + + let data = {}; + if(window.localStorage !== null) { + if(JSON.parse(window?.localStorage?.getItem("codehouse-collections"))) + data = JSON.parse(window.localStorage.getItem("codehouse-collections")); + else { + data = { + bookmarks: [], + collectionOrder: [], + collections: {}, + }; + updateLocalStorage(data); + } + } + return data; +} + +function Dnd({bookmarks, fetchBookmarks, entities, setEntities, showBookmarks, setShowBookmarks}) { + const [collectionName, setCollectionName] = useState(""); + + const addNewCollection = (e) => { + if(collectionName.trim()) { + const newCollectionID = `collection-${Object.keys(entities.collections).length + 1}`; + let collections = entities.collections; + const emptyCollection = { + id: newCollectionID, + title: collectionName, + bookmarkIDs: [] + } + collections[newCollectionID] = emptyCollection; + + let collectionOrder = entities.collectionOrder; + collectionOrder.push(newCollectionID); + + setEntities({...entities, collections, collectionOrder}); + setCollectionName(""); + } + } + const onDragStart = (e) => {} + const onDragEnd = (e) => { + try { + if (e.type === "collections") { + let listsArr = entities.collectionOrder; + let sourceIndex = e.source.index; + let targetIndex = e.destination.index; + + let temp = listsArr[sourceIndex]; + listsArr.splice(sourceIndex, 1); + listsArr.splice(targetIndex, 0, temp); + + setEntities({ ...entities, collectionOrder: listsArr }) + } + else if (e.type === "bookmark") { + let listsContent = entities.collections; + + let sourceList = e.source.droppableId, + targetList = e.destination.droppableId, + sourceIndex = e.source.index, + targetIndex = e.destination.index; + + let temp = listsContent[sourceList].bookmarkIDs[sourceIndex]; + listsContent[sourceList].bookmarkIDs.splice(sourceIndex, 1); + + if (!listsContent[targetList].bookmarkIDs) + listsContent[targetList].bookmarkIDs = []; + listsContent[targetList].bookmarkIDs.splice(targetIndex, 0, temp); + + setEntities({ ...entities, collections: listsContent }) + } + } catch (err) { + //Catching errors when the elements are dragged but not moved + //Do Nothing... + } + } + + useEffect(() => { + setEntities(getLocalStorage()); + }, []); + + useEffect(() => { + if(entities) + updateLocalStorage(entities); + }, [entities]); + + return( +
+ + + { + provided => ( +
+
+ {if(e.keyCode === 13) addNewCollection();}} value={collectionName} onChange={(e) => setCollectionName(e.target.value)} /> +
+ +
+
+ { + entities?.collectionOrder && entities.collectionOrder.map((collectionId, index) => ( + + )) + } + {provided.placeholder} +
+ ) + } +
+
+
+ ) +} + +export default Dnd; diff --git a/components/utils/Header.js b/components/utils/Header.js index ed80729..e0f10f1 100644 --- a/components/utils/Header.js +++ b/components/utils/Header.js @@ -83,6 +83,11 @@ const Header = ({ setOpen, user, setUser }) => { On Review
+ + + Collections + + Bookmarks @@ -214,6 +219,13 @@ const Header = ({ setOpen, user, setUser }) => {

+ + +

+ Collections +

+
+

diff --git a/package-lock.json b/package-lock.json index ef7d43f..b4584ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "parallax-js": "^3.1.0", "psl": "^1.8.0", "react": "^17.0.2", + "react-beautiful-dnd": "^13.1.0", "react-content-loader": "^6.0.3", "react-device-detect": "^1.17.0", "react-dom": "^17.0.2", @@ -2801,6 +2802,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/http-assert": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.1.tgz", @@ -2894,6 +2904,17 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-redux": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", + "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", @@ -4216,6 +4237,14 @@ "node": ">=8" } }, + "node_modules/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==", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/css-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -5999,6 +6028,11 @@ "node": ">= 0.6" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -7108,6 +7142,11 @@ "performance-now": "^2.1.0" } }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -7170,6 +7209,24 @@ "node": ">=0.10.0" } }, + "node_modules/react-beautiful-dnd": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", + "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==", + "dependencies": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0", + "react-dom": "^16.8.5 || ^17.0.0" + } + }, "node_modules/react-content-loader": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-6.0.3.tgz", @@ -7233,6 +7290,30 @@ "@emotion/core": "^10.0.22" } }, + "node_modules/react-redux": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz", + "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "@types/react-redux": "^7.1.16", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, "node_modules/react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -7297,6 +7378,14 @@ "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true }, + "node_modules/redux": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", + "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -8127,6 +8216,11 @@ "node": ">=0.6.0" } }, + "node_modules/tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, "node_modules/tiny-warning": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", @@ -8344,6 +8438,14 @@ "node": ">=0.4.x" } }, + "node_modules/use-memo-one": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", + "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, "node_modules/use-subscription": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz", @@ -11114,6 +11216,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/http-assert": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/@types/http-assert/-/http-assert-1.5.1.tgz", @@ -11214,6 +11325,17 @@ } } }, + "@types/react-redux": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", + "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, "@types/react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", @@ -12377,6 +12499,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-select": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", @@ -13861,6 +13991,11 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -14791,6 +14926,11 @@ "performance-now": "^2.1.0" } }, + "raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -14843,6 +14983,20 @@ "object-assign": "^4.1.1" } }, + "react-beautiful-dnd": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", + "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==", + "requires": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + } + }, "react-content-loader": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-6.0.3.tgz", @@ -14900,6 +15054,19 @@ "@emotion/core": "^10.0.22" } }, + "react-redux": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz", + "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==", + "requires": { + "@babel/runtime": "^7.12.1", + "@types/react-redux": "^7.1.16", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + } + }, "react-refresh": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", @@ -14957,6 +15124,14 @@ } } }, + "redux": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", + "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -15646,6 +15821,11 @@ "setimmediate": "^1.0.4" } }, + "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", @@ -15818,6 +15998,12 @@ } } }, + "use-memo-one": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", + "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", + "requires": {} + }, "use-subscription": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz", diff --git a/package.json b/package.json index 502a83e..65be5b2 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "parallax-js": "^3.1.0", "psl": "^1.8.0", "react": "^17.0.2", + "react-beautiful-dnd": "^13.1.0", "react-content-loader": "^6.0.3", "react-device-detect": "^1.17.0", "react-dom": "^17.0.2", diff --git a/pages/bookmarks.js b/pages/bookmarks.js index 5ee748b..726baf1 100644 --- a/pages/bookmarks.js +++ b/pages/bookmarks.js @@ -24,12 +24,14 @@ const bookmarksPage = (props) => { />
{bookmarks.map((cheatsheet, key) => ( - +
+ +
))}
diff --git a/pages/collections.js b/pages/collections.js new file mode 100644 index 0000000..8965e44 --- /dev/null +++ b/pages/collections.js @@ -0,0 +1,43 @@ +import React, {useEffect, useState } from "react"; +import dynamic from "next/dynamic"; + +//components +import { RightBar, InfoBar, Header, SvgBanner } from "../components"; + +import Head from "next/head"; +import { useRouter } from "next/router"; + +const Dnd = dynamic(import("../components/utils/Dnd")); +const BookmarksDialog = dynamic(import("../components/utils/BookmarksDialog")); + +function Collections(props) { + const { bookmarks, user, fetchBookmarks, darkMode } = props, + [winReady, setWinReady] = useState(false), + [showBookmarks, setShowBookmarks] = useState(null), + [entities, setEntities] = useState(null); + + useEffect(() => { + return setWinReady(true); + },[]); + + return( +
+ {winReady && } + + + {`Collections (${entities ? entities.collectionOrder.length : 0})`} - Code House + + +
+ + {winReady && } +
+ ) +} + +export default Collections; diff --git a/pages/post/[id].js b/pages/post/[id].js index c36ea10..3c0ac8d 100644 --- a/pages/post/[id].js +++ b/pages/post/[id].js @@ -44,7 +44,7 @@ const Cheatsheet = (props) => {
- {currentPost[0] && currentPost[0].cheatsheet_name}- Code House + {currentPost[0] && currentPost[0].cheatsheet_name} - Code House
diff --git a/pages/user/[name].js b/pages/user/[name].js new file mode 100644 index 0000000..9901031 --- /dev/null +++ b/pages/user/[name].js @@ -0,0 +1,24 @@ +import React, {useEffect, useState} from 'react'; + +//components +import { RightBar, InfoBar, Header } from "../../components"; + +import Head from "next/head"; +import { useRouter } from "next/router"; + +export default function User(props) { + const router = useRouter(); // router + const { name } = router.query; + + console.log(name); + return ( +
+ + + {name} - Code House + + +
+
+ ) +} diff --git a/styles/App.css b/styles/App.css index 80388fd..6f99b69 100644 --- a/styles/App.css +++ b/styles/App.css @@ -8,6 +8,10 @@ @import url(./animations.css); @import url(./components.css); +@tailwind base; +@tailwind components; +@tailwind utilities; + /* Root */ * { font-family: "Epilogue", sans-serif; diff --git a/tailwind.config.js b/tailwind.config.js index c04f18e..24a8ae3 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,4 +1,5 @@ module.exports = { + important: true, mode: "jit", purge: ["./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"], darkMode: "class", // or 'media' or 'class'