diff --git a/gatsby-browser.js b/gatsby-browser.js
index aee72655..bffbf171 100644
--- a/gatsby-browser.js
+++ b/gatsby-browser.js
@@ -3,6 +3,7 @@ import "firebase/analytics";
import "firebase/auth";
import "firebase/firestore";
import React from "react";
+import { DashboardProvider } from "./src/contexts/DashboardContext";
import { ModalProvider } from "./src/contexts/ModalContext";
import { ResumeProvider } from "./src/contexts/ResumeContext";
import { ThemeProvider } from "./src/contexts/ThemeContext";
@@ -25,7 +26,9 @@ export const wrapRootElement = ({ element }) => (
- {element}
+
+ {element}
+
diff --git a/src/components/builder/center/Artboard.js b/src/components/builder/center/Artboard.js
new file mode 100644
index 00000000..2b95974a
--- /dev/null
+++ b/src/components/builder/center/Artboard.js
@@ -0,0 +1,8 @@
+import React from "react";
+import styles from "./Artboard.module.css";
+
+const Artboard = () => {
+ return
;
+};
+
+export default Artboard;
diff --git a/src/components/builder/center/Artboard.module.css b/src/components/builder/center/Artboard.module.css
new file mode 100644
index 00000000..30fbacee
--- /dev/null
+++ b/src/components/builder/center/Artboard.module.css
@@ -0,0 +1,6 @@
+.container {
+ width: 400px;
+ height: 600px;
+ box-shadow: var(--shadow);
+ @apply bg-white;
+}
diff --git a/src/components/builder/left/LeftNavbar.js b/src/components/builder/left/LeftNavbar.js
index 610f4f79..d578d7a8 100644
--- a/src/components/builder/left/LeftNavbar.js
+++ b/src/components/builder/left/LeftNavbar.js
@@ -1,5 +1,6 @@
import { Link } from "gatsby";
import React from "react";
+import { MdPerson } from "react-icons/md";
import Avatar from "../../shared/Avatar";
import Logo from "../../shared/Logo";
import styles from "./LeftNavbar.module.css";
@@ -11,9 +12,16 @@ const LeftNavbar = () => {
-
+
-
+
+
+
+
+
diff --git a/src/components/builder/left/LeftNavbar.module.css b/src/components/builder/left/LeftNavbar.module.css
index 76be3678..7c6bb9e9 100644
--- a/src/components/builder/left/LeftNavbar.module.css
+++ b/src/components/builder/left/LeftNavbar.module.css
@@ -2,5 +2,5 @@
width: 75px;
z-index: 20;
box-shadow: var(--left-shadow);
- @apply p-4 h-screen flex flex-col items-center;
+ @apply px-4 py-6 h-screen flex flex-col items-center;
}
diff --git a/src/components/builder/left/LeftSidebar.js b/src/components/builder/left/LeftSidebar.js
index b66d4dc4..b6ce284b 100644
--- a/src/components/builder/left/LeftSidebar.js
+++ b/src/components/builder/left/LeftSidebar.js
@@ -1,5 +1,5 @@
import React from "react";
-import Input from "../../shared/Input";
+import Profile from "../sections/Profile";
import LeftNavbar from "./LeftNavbar";
import styles from "./LeftSidebar.module.css";
@@ -9,13 +9,7 @@ const LeftSidebar = () => {
);
diff --git a/src/components/builder/left/LeftSidebar.module.css b/src/components/builder/left/LeftSidebar.module.css
index 12374d54..3e6abd80 100644
--- a/src/components/builder/left/LeftSidebar.module.css
+++ b/src/components/builder/left/LeftSidebar.module.css
@@ -3,10 +3,3 @@
box-shadow: var(--left-shadow);
@apply w-full h-screen p-8;
}
-
-.circle {
- width: 60px;
- height: 60px;
- flex: 0 0 60px;
- @apply bg-gray-300 rounded-full;
-}
diff --git a/src/components/builder/right/RightNavbar.js b/src/components/builder/right/RightNavbar.js
new file mode 100644
index 00000000..f483f551
--- /dev/null
+++ b/src/components/builder/right/RightNavbar.js
@@ -0,0 +1,18 @@
+import React from "react";
+import { MdPerson } from "react-icons/md";
+import styles from "./RightNavbar.module.css";
+
+const RightNavbar = () => {
+ return (
+
+ );
+};
+
+export default RightNavbar;
diff --git a/src/components/builder/right/RightNavbar.module.css b/src/components/builder/right/RightNavbar.module.css
new file mode 100644
index 00000000..b5f24230
--- /dev/null
+++ b/src/components/builder/right/RightNavbar.module.css
@@ -0,0 +1,6 @@
+.container {
+ width: 75px;
+ z-index: 20;
+ box-shadow: var(--right-shadow);
+ @apply px-4 py-6 h-screen flex flex-col items-center;
+}
diff --git a/src/components/builder/right/RightSidebar.js b/src/components/builder/right/RightSidebar.js
new file mode 100644
index 00000000..1790bed5
--- /dev/null
+++ b/src/components/builder/right/RightSidebar.js
@@ -0,0 +1,18 @@
+import React from "react";
+import Profile from "../sections/Profile";
+import RightNavbar from "./RightNavbar";
+import styles from "./RightSidebar.module.css";
+
+const RightSidebar = () => {
+ return (
+
+ );
+};
+
+export default RightSidebar;
diff --git a/src/components/builder/right/RightSidebar.module.css b/src/components/builder/right/RightSidebar.module.css
new file mode 100644
index 00000000..9465ae61
--- /dev/null
+++ b/src/components/builder/right/RightSidebar.module.css
@@ -0,0 +1,5 @@
+.container {
+ z-index: 10;
+ box-shadow: var(--right-shadow);
+ @apply w-full h-screen p-8;
+}
diff --git a/src/components/builder/sections/Profile.js b/src/components/builder/sections/Profile.js
new file mode 100644
index 00000000..e4326376
--- /dev/null
+++ b/src/components/builder/sections/Profile.js
@@ -0,0 +1,27 @@
+import React from "react";
+import { MdFileUpload } from "react-icons/md";
+import Heading from "../../shared/Heading";
+import Input from "../../shared/Input";
+import styles from "./Profile.module.css";
+
+const Profile = () => {
+ return (
+
+ );
+};
+
+export default Profile;
diff --git a/src/components/builder/sections/Profile.module.css b/src/components/builder/sections/Profile.module.css
new file mode 100644
index 00000000..c9346816
--- /dev/null
+++ b/src/components/builder/sections/Profile.module.css
@@ -0,0 +1,6 @@
+.circle {
+ width: 60px;
+ height: 60px;
+ flex: 0 0 60px;
+ @apply flex items-center justify-center bg-secondary rounded-full;
+}
diff --git a/src/components/dashboard/CreateResume.module.css b/src/components/dashboard/CreateResume.module.css
index a783e025..59104ed0 100644
--- a/src/components/dashboard/CreateResume.module.css
+++ b/src/components/dashboard/CreateResume.module.css
@@ -12,7 +12,7 @@
.resume > .page {
max-width: 184px;
height: 260px;
- @apply rounded absolute w-full bg-white;
+ @apply rounded absolute w-full bg-inverse;
@apply transition-opacity duration-200 ease-in-out;
@apply cursor-pointer absolute text-gray-500 flex justify-center items-center;
}
diff --git a/src/components/dashboard/ResumePreview.js b/src/components/dashboard/ResumePreview.js
index c65baf83..cbdc1516 100644
--- a/src/components/dashboard/ResumePreview.js
+++ b/src/components/dashboard/ResumePreview.js
@@ -4,14 +4,14 @@ import moment from "moment";
import React, { useContext, useState } from "react";
import { MdMoreHoriz, MdOpenInNew } from "react-icons/md";
import { toast } from "react-toastify";
+import DashboardContext from "../../contexts/DashboardContext";
import ModalContext from "../../contexts/ModalContext";
-import ResumeContext from "../../contexts/ResumeContext";
import styles from "./ResumePreview.module.css";
const ResumePreview = ({ resume }) => {
const [anchorEl, setAnchorEl] = useState(null);
const { createResumeModal } = useContext(ModalContext);
- const { deleteResume } = useContext(ResumeContext);
+ const { deleteResume } = useContext(DashboardContext);
const handleOpen = () => navigate(`/app/builder/${resume.id}`);
diff --git a/src/components/shared/Heading.js b/src/components/shared/Heading.js
new file mode 100644
index 00000000..d9bba1ea
--- /dev/null
+++ b/src/components/shared/Heading.js
@@ -0,0 +1,7 @@
+import React from "react";
+
+const Heading = ({ children }) => {
+ return {children}
;
+};
+
+export default Heading;
diff --git a/src/components/shared/Input.js b/src/components/shared/Input.js
index e34af5a0..b89c5141 100644
--- a/src/components/shared/Input.js
+++ b/src/components/shared/Input.js
@@ -1,11 +1,14 @@
import cx from "classnames";
-import React from "react";
+import { get } from "lodash";
+import React, { useContext } from "react";
import { v4 as uuidv4 } from "uuid";
+import ResumeContext from "../../contexts/ResumeContext";
import styles from "./Input.module.css";
const Input = ({
- label,
name,
+ path,
+ label,
value,
error,
onChange,
@@ -14,6 +17,20 @@ const Input = ({
type = "text",
}) => {
const uuid = uuidv4();
+ const { state, dispatch } = useContext(ResumeContext);
+
+ const inputProps = (path) => ({
+ value: get(state, path),
+ onChange: (e) => {
+ dispatch({
+ type: "on_input",
+ payload: {
+ path,
+ value: e.target.value,
+ },
+ });
+ },
+ });
return (
@@ -26,8 +43,9 @@ const Input = ({
value={value}
onChange={onChange}
placeholder={placeholder}
+ {...(path && inputProps(path))}
/>
-
{error}
+
{error}
);
diff --git a/src/components/shared/Input.module.css b/src/components/shared/Input.module.css
index cb62014f..e0f65f55 100644
--- a/src/components/shared/Input.module.css
+++ b/src/components/shared/Input.module.css
@@ -7,13 +7,21 @@
}
.container > label > span {
- @apply mb-1 text-gray-600 font-medium text-sm uppercase;
+ @apply mb-1 text-secondary-dark font-medium text-xs uppercase;
}
.container > label > input {
- @apply py-4 px-4 rounded bg-gray-200 border border-gray-200;
+ @apply py-3 px-4 rounded bg-secondary text-primary border border-secondary;
+}
+
+.container > label > input::placeholder {
+ @apply text-primary opacity-50;
}
.container > label > input:focus {
- @apply outline-none border-gray-400;
+ @apply outline-none border-secondary-dark;
+}
+
+.container > label > p {
+ @apply mt-1 text-red-600 text-xs;
}
diff --git a/src/contexts/DashboardContext.js b/src/contexts/DashboardContext.js
new file mode 100644
index 00000000..57e8f8cd
--- /dev/null
+++ b/src/contexts/DashboardContext.js
@@ -0,0 +1,81 @@
+import firebase from "gatsby-plugin-firebase";
+import React, { createContext, useContext, useEffect, useState } from "react";
+import { v4 as uuidv4 } from "uuid";
+import { transformCollectionSnapshot } from "../utils";
+import UserContext from "./UserContext";
+
+const defaultState = {
+ resumes: [],
+ createResume: async () => {},
+ deleteResume: async () => {},
+};
+
+const DashboardContext = createContext(defaultState);
+
+const DashboardProvider = ({ children }) => {
+ const [resumes, setResumes] = useState([null]);
+ const [collectionRef, setCollectionRef] = useState(null);
+ const { user } = useContext(UserContext);
+
+ useEffect(() => {
+ if (user) {
+ setCollectionRef(`users/${user.uid}/resumes`);
+ }
+ }, [user]);
+
+ useEffect(() => {
+ if (collectionRef) {
+ firebase
+ .firestore()
+ .collection(collectionRef)
+ .onSnapshot((snapshot) =>
+ transformCollectionSnapshot(snapshot, setResumes)
+ );
+ }
+ }, [collectionRef]);
+
+ const createResume = async ({ name }) => {
+ const id = uuidv4();
+ const createdAt = firebase.firestore.FieldValue.serverTimestamp();
+ await firebase.firestore().collection(collectionRef).doc(id).set({
+ id,
+ name,
+ createdAt,
+ updatedAt: createdAt,
+ });
+ };
+
+ const updateResume = async (resume) => {
+ const { id, name } = resume;
+
+ if (resumes.find((x) => x.id === id) === resume) return;
+
+ await firebase.firestore().collection(collectionRef).doc(id).update({
+ id,
+ name,
+ updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
+ });
+ };
+
+ const deleteResume = async (resume) => {
+ const { id } = resume;
+ await firebase.firestore().collection(collectionRef).doc(id).delete();
+ };
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default DashboardContext;
+
+export { DashboardProvider };
diff --git a/src/contexts/ResumeContext.js b/src/contexts/ResumeContext.js
index fd818fa2..e3523986 100644
--- a/src/contexts/ResumeContext.js
+++ b/src/contexts/ResumeContext.js
@@ -1,76 +1,28 @@
-import firebase from "gatsby-plugin-firebase";
-import React, { createContext, useContext, useEffect, useState } from "react";
-import { v4 as uuidv4 } from "uuid";
-import { transformCollectionSnapshot } from "../utils";
-import UserContext from "./UserContext";
+import { set } from "lodash";
+import React, { createContext, useReducer } from "react";
-const defaultState = {
- resumes: [],
- createResume: async () => {},
- deleteResume: async () => {},
+const initialState = {
+ profile: {
+ photograph: "",
+ firstName: "",
+ lastName: "",
+ },
};
-const ResumeContext = createContext(defaultState);
+const ResumeContext = createContext(initialState);
const ResumeProvider = ({ children }) => {
- const [resumes, setResumes] = useState([null]);
- const [collectionRef, setCollectionRef] = useState(null);
- const { user } = useContext(UserContext);
-
- useEffect(() => {
- if (user) {
- setCollectionRef(`users/${user.uid}/resumes`);
+ const [state, dispatch] = useReducer((state, { type, payload }) => {
+ switch (type) {
+ case "on_input":
+ return set({ ...state }, payload.path, payload.value);
+ default:
+ throw new Error();
}
- }, [user]);
-
- useEffect(() => {
- if (collectionRef) {
- firebase
- .firestore()
- .collection(collectionRef)
- .onSnapshot((snapshot) =>
- transformCollectionSnapshot(snapshot, setResumes)
- );
- }
- }, [collectionRef]);
-
- const createResume = async ({ name }) => {
- const id = uuidv4();
- const createdAt = firebase.firestore.FieldValue.serverTimestamp();
- await firebase.firestore().collection(collectionRef).doc(id).set({
- id,
- name,
- createdAt,
- updatedAt: createdAt,
- });
- };
-
- const updateResume = async (resume) => {
- const { id, name } = resume;
-
- if (resumes.find((x) => x.id === id) === resume) return;
-
- await firebase.firestore().collection(collectionRef).doc(id).update({
- id,
- name,
- updatedAt: firebase.firestore.FieldValue.serverTimestamp(),
- });
- };
-
- const deleteResume = async (resume) => {
- const { id } = resume;
- await firebase.firestore().collection(collectionRef).doc(id).delete();
- };
+ }, initialState);
return (
-
+
{children}
);
diff --git a/src/contexts/ThemeContext.js b/src/contexts/ThemeContext.js
index 6acd83d6..15efeb72 100644
--- a/src/contexts/ThemeContext.js
+++ b/src/contexts/ThemeContext.js
@@ -1,4 +1,4 @@
-import React, { useState, useEffect, createContext } from "react";
+import React, { createContext, useEffect, useState } from "react";
const COLOR_CONFIG = {
light: {
@@ -6,12 +6,16 @@ const COLOR_CONFIG = {
"--color-primary-dark": "#333",
"--color-inverse": "#fff",
"--color-inverse-dark": "#f5f5f5",
+ "--color-secondary": "#edf2f7",
+ "--color-secondary-dark": "#718096",
},
dark: {
"--color-primary": "#f5f5f5",
- "--color-primary-dark": "#eee",
+ "--color-primary-dark": "#eeeeee",
"--color-inverse": "#212121",
"--color-inverse-dark": "#181818",
+ "--color-secondary": "#444",
+ "--color-secondary-dark": "#888",
},
};
diff --git a/src/modals/CreateResumeModal.js b/src/modals/CreateResumeModal.js
index 085869d3..92d60d02 100644
--- a/src/modals/CreateResumeModal.js
+++ b/src/modals/CreateResumeModal.js
@@ -3,8 +3,8 @@ import React, { useContext, useEffect, useRef, useState } from "react";
import * as Yup from "yup";
import Button from "../components/shared/Button";
import Input from "../components/shared/Input";
+import DashboardContext from "../contexts/DashboardContext";
import ModalContext from "../contexts/ModalContext";
-import ResumeContext from "../contexts/ResumeContext";
import { getModalText } from "../utils";
import BaseModal from "./BaseModal";
@@ -18,7 +18,7 @@ const CreateResumeModal = ({ data }) => {
const modalRef = useRef(null);
const [isEditMode, setEditMode] = useState(false);
const { createResumeModal } = useContext(ModalContext);
- const { createResume, updateResume } = useContext(ResumeContext);
+ const { createResume, updateResume } = useContext(DashboardContext);
const formik = useFormik({
initialValues: {
diff --git a/src/pages/app/builder.js b/src/pages/app/builder.js
index 535f7e68..2bd4a355 100644
--- a/src/pages/app/builder.js
+++ b/src/pages/app/builder.js
@@ -1,16 +1,22 @@
import React from "react";
+import Artboard from "../../components/builder/center/Artboard";
import LeftSidebar from "../../components/builder/left/LeftSidebar";
+import RightSidebar from "../../components/builder/right/RightSidebar";
import Wrapper from "../../components/shared/Wrapper";
const Builder = ({ id }) => {
return (
-
+
);
diff --git a/src/pages/app/dashboard.js b/src/pages/app/dashboard.js
index 3cbe90c3..480e9b0e 100644
--- a/src/pages/app/dashboard.js
+++ b/src/pages/app/dashboard.js
@@ -1,12 +1,12 @@
import React, { useContext } from "react";
-import Wrapper from "../../components/shared/Wrapper";
import CreateResume from "../../components/dashboard/CreateResume";
import ResumePreview from "../../components/dashboard/ResumePreview";
import TopNavbar from "../../components/dashboard/TopNavbar";
-import ResumeContext from "../../contexts/ResumeContext";
+import Wrapper from "../../components/shared/Wrapper";
+import DashboardContext from "../../contexts/DashboardContext";
const Dashboard = () => {
- const { resumes } = useContext(ResumeContext);
+ const { resumes } = useContext(DashboardContext);
return (
diff --git a/src/styles/colors.css b/src/styles/colors.css
index 38af36e8..c6a86344 100644
--- a/src/styles/colors.css
+++ b/src/styles/colors.css
@@ -3,4 +3,6 @@
--color-primary-dark: #333;
--color-inverse: #fff;
--color-inverse-dark: #f5f5f5;
+ --color-secondary: #edf2f7;
+ --color-secondary-dark: #718096;
}
diff --git a/src/styles/global.css b/src/styles/global.css
index ce6e0b48..4ee1e7ff 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -24,5 +24,9 @@ a:hover {
}
hr {
- @apply w-full h-1;
+ @apply w-full border-secondary h-1;
+}
+
+section {
+ @apply grid grid-cols-1 gap-8;
}
diff --git a/src/styles/shadows.css b/src/styles/shadows.css
index db471320..772084b4 100644
--- a/src/styles/shadows.css
+++ b/src/styles/shadows.css
@@ -1,6 +1,7 @@
:root {
- --shadow: 0 0 8px 0 rgba(0, 0, 0, 0.04);
- --shadow-strong: 0 0 8px 0 rgba(0, 0, 0, 0.08);
- --left-shadow: 8px 0 8px -4px rgba(0, 0, 0, 0.04);
- --bottom-shadow: 0 8px 8px -4px rgba(0, 0, 0, 0.04);
+ --shadow: 0 0 6px 0 rgba(0, 0, 0, 0.05);
+ --shadow-strong: 0 0 6px 0 rgba(0, 0, 0, 0.1);
+ --left-shadow: 6px 0 6px -6px rgba(0, 0, 0, 0.05);
+ --right-shadow: -6px 0 6px -6px rgba(0, 0, 0, 0.05);
+ --bottom-shadow: 0 6px 6px -6px rgba(0, 0, 0, 0.05);
}
diff --git a/tailwind.config.js b/tailwind.config.js
index 394d98c6..811e7a0d 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -10,6 +10,8 @@ module.exports = {
"primary-dark": "var(--color-primary-dark)",
inverse: "var(--color-inverse)",
"inverse-dark": "var(--color-inverse-dark)",
+ secondary: "var(--color-secondary)",
+ "secondary-dark": "var(--color-secondary-dark)",
},
},
},