mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-10 04:22:27 +10:00
- refactor sections
- combine resume and metadata contexts
This commit is contained in:
@ -1,11 +1,11 @@
|
|||||||
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core';
|
import { createMuiTheme, MuiThemeProvider } from '@material-ui/core';
|
||||||
|
import 'animate.css';
|
||||||
import 'firebase/analytics';
|
import 'firebase/analytics';
|
||||||
import 'firebase/auth';
|
import 'firebase/auth';
|
||||||
import 'firebase/database';
|
import 'firebase/database';
|
||||||
import 'firebase/storage';
|
import 'firebase/storage';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { DatabaseProvider } from './src/contexts/DatabaseContext';
|
import { DatabaseProvider } from './src/contexts/DatabaseContext';
|
||||||
import { MetadataProvider } from './src/contexts/MetadataContext';
|
|
||||||
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 { StorageProvider } from './src/contexts/StorageContext';
|
import { StorageProvider } from './src/contexts/StorageContext';
|
||||||
@ -32,9 +32,7 @@ export const wrapRootElement = ({ element }) => (
|
|||||||
<UserProvider>
|
<UserProvider>
|
||||||
<DatabaseProvider>
|
<DatabaseProvider>
|
||||||
<ResumeProvider>
|
<ResumeProvider>
|
||||||
<MetadataProvider>
|
<StorageProvider>{element}</StorageProvider>
|
||||||
<StorageProvider>{element}</StorageProvider>
|
|
||||||
</MetadataProvider>
|
|
||||||
</ResumeProvider>
|
</ResumeProvider>
|
||||||
</DatabaseProvider>
|
</DatabaseProvider>
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
|
|||||||
89
package-lock.json
generated
89
package-lock.json
generated
@ -2700,6 +2700,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
|
||||||
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
|
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
|
||||||
},
|
},
|
||||||
|
"animate.css": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/animate.css/-/animate.css-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-0aVcfWDeU9ykV6vjn1P67ZSs01jxoUQZCGaYbkk0SIIelIG8kUdLrIkua1+VabHfTtsSivDRMMn0ILPvZum2gw=="
|
||||||
|
},
|
||||||
"ansi-align": {
|
"ansi-align": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
|
||||||
@ -8225,9 +8230,9 @@
|
|||||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
|
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
|
||||||
},
|
},
|
||||||
"gatsby": {
|
"gatsby": {
|
||||||
"version": "2.24.0",
|
"version": "2.24.1",
|
||||||
"resolved": "https://registry.npmjs.org/gatsby/-/gatsby-2.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/gatsby/-/gatsby-2.24.1.tgz",
|
||||||
"integrity": "sha512-l/9ueKdnHNB3+nbzZRaj2mYWJMAay7PwMN+M0VfdIgA2K6d/lz3xI8W5BRNmNJyuk8itykB64r7NFNxsnTChRw==",
|
"integrity": "sha512-aqFfx+Vj3kBhS17tgL1LrkMzip2Xctd3lCj+pogCGV9GCkg6wOqW2uOEqWeoiCNq09sPuwv3GNB8sbEFoQ/2DA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/code-frame": "^7.10.3",
|
"@babel/code-frame": "^7.10.3",
|
||||||
"@babel/core": "^7.10.3",
|
"@babel/core": "^7.10.3",
|
||||||
@ -8543,11 +8548,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
||||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
|
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
|
||||||
},
|
},
|
||||||
"is-plain-obj": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
|
||||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
|
|
||||||
},
|
|
||||||
"lru-cache": {
|
"lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
@ -8556,49 +8556,11 @@
|
|||||||
"yallist": "^3.0.2"
|
"yallist": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mini-css-extract-plugin": {
|
|
||||||
"version": "0.8.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.2.tgz",
|
|
||||||
"integrity": "sha512-a3Y4of27Wz+mqK3qrcd3VhYz6cU0iW5x3Sgvqzbj+XmlrSizmvu8QQMl5oMYJjgHOC4iyt+w7l4umP+dQeW3bw==",
|
|
||||||
"requires": {
|
|
||||||
"loader-utils": "^1.1.0",
|
|
||||||
"normalize-url": "1.9.1",
|
|
||||||
"schema-utils": "^1.0.0",
|
|
||||||
"webpack-sources": "^1.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "2.6.0",
|
"version": "2.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||||
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
|
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
|
||||||
},
|
},
|
||||||
"normalize-url": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
|
||||||
"integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
|
|
||||||
"requires": {
|
|
||||||
"object-assign": "^4.0.1",
|
|
||||||
"prepend-http": "^1.0.0",
|
|
||||||
"query-string": "^4.1.0",
|
|
||||||
"sort-keys": "^1.0.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"query-string": {
|
|
||||||
"version": "4.3.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
|
||||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
|
||||||
"requires": {
|
|
||||||
"object-assign": "^4.1.0",
|
|
||||||
"strict-uri-encode": "^1.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"prepend-http": {
|
|
||||||
"version": "1.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
|
||||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
|
|
||||||
},
|
|
||||||
"regexpp": {
|
"regexpp": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
|
||||||
@ -8612,29 +8574,11 @@
|
|||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema-utils": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
|
|
||||||
"requires": {
|
|
||||||
"ajv": "^6.1.0",
|
|
||||||
"ajv-errors": "^1.0.0",
|
|
||||||
"ajv-keywords": "^3.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "5.7.1",
|
"version": "5.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||||
},
|
},
|
||||||
"sort-keys": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
|
||||||
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
|
|
||||||
"requires": {
|
|
||||||
"is-plain-obj": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.7.3",
|
"version": "0.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||||
@ -12667,10 +12611,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mini-css-extract-plugin": {
|
"mini-css-extract-plugin": {
|
||||||
"version": "0.9.0",
|
"version": "0.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.2.tgz",
|
||||||
"integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==",
|
"integrity": "sha512-a3Y4of27Wz+mqK3qrcd3VhYz6cU0iW5x3Sgvqzbj+XmlrSizmvu8QQMl5oMYJjgHOC4iyt+w7l4umP+dQeW3bw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"loader-utils": "^1.1.0",
|
"loader-utils": "^1.1.0",
|
||||||
"normalize-url": "1.9.1",
|
"normalize-url": "1.9.1",
|
||||||
@ -12681,14 +12624,12 @@
|
|||||||
"is-plain-obj": {
|
"is-plain-obj": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
||||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
|
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"normalize-url": {
|
"normalize-url": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
|
||||||
"integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
|
"integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"object-assign": "^4.0.1",
|
"object-assign": "^4.0.1",
|
||||||
"prepend-http": "^1.0.0",
|
"prepend-http": "^1.0.0",
|
||||||
@ -12699,14 +12640,12 @@
|
|||||||
"prepend-http": {
|
"prepend-http": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
|
||||||
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
|
"integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"query-string": {
|
"query-string": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"object-assign": "^4.1.0",
|
"object-assign": "^4.1.0",
|
||||||
"strict-uri-encode": "^1.0.0"
|
"strict-uri-encode": "^1.0.0"
|
||||||
@ -12716,7 +12655,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
|
||||||
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
|
"integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ajv": "^6.1.0",
|
"ajv": "^6.1.0",
|
||||||
"ajv-errors": "^1.0.0",
|
"ajv-errors": "^1.0.0",
|
||||||
@ -12727,7 +12665,6 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
||||||
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
|
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-plain-obj": "^1.0.0"
|
"is-plain-obj": "^1.0.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,12 +18,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material-ui/core": "^4.11.0",
|
"@material-ui/core": "^4.11.0",
|
||||||
"@reach/router": "^1.3.4",
|
"@reach/router": "^1.3.4",
|
||||||
|
"animate.css": "^4.1.0",
|
||||||
"array-move": "^2.2.2",
|
"array-move": "^2.2.2",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"firebase": "^7.15.5",
|
"firebase": "^7.15.5",
|
||||||
"formik": "^2.1.4",
|
"formik": "^2.1.4",
|
||||||
"gatsby": "^2.24.0",
|
"gatsby": "^2.24.1",
|
||||||
"gatsby-image": "^2.4.13",
|
"gatsby-image": "^2.4.13",
|
||||||
"gatsby-plugin-create-client-paths": "^2.3.10",
|
"gatsby-plugin-create-client-paths": "^2.3.10",
|
||||||
"gatsby-plugin-firebase": "^0.2.0-beta.4",
|
"gatsby-plugin-firebase": "^0.2.0-beta.4",
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import { useSelector as useMetadataSelector } from '../../../contexts/MetadataContext';
|
import { useSelector } from '../../../contexts/ResumeContext';
|
||||||
import { useSelector as useResumeSelector } from '../../../contexts/ResumeContext';
|
|
||||||
import Onyx from '../../../templates/Onyx';
|
import Onyx from '../../../templates/Onyx';
|
||||||
import styles from './Artboard.module.css';
|
import styles from './Artboard.module.css';
|
||||||
|
|
||||||
const Artboard = () => {
|
const Artboard = () => {
|
||||||
const { template, layout, colors } = useMetadataSelector((store) => store);
|
const state = useSelector();
|
||||||
const state = useResumeSelector((store) => store);
|
const { id, name, metadata } = state;
|
||||||
const { id, name } = state;
|
const { template } = metadata;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -18,9 +17,7 @@ const Artboard = () => {
|
|||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<div id="artboard" className={styles.container}>
|
<div id="artboard" className={styles.container}>
|
||||||
{template === 'Onyx' && (
|
{template === 'onyx' && <Onyx data={state} />}
|
||||||
<Onyx data={state} layout={layout} colors={colors} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -14,7 +14,7 @@ const LeftNavbar = () => (
|
|||||||
|
|
||||||
<hr className="my-6" />
|
<hr className="my-6" />
|
||||||
|
|
||||||
<div className="grid grid-cols-1 gap-5 text-secondary-dark">
|
<div className="grid grid-cols-1 gap-4 text-secondary-dark">
|
||||||
{sections.map((x) => (
|
{sections.map((x) => (
|
||||||
<SectionIcon
|
<SectionIcon
|
||||||
key={x.id}
|
key={x.id}
|
||||||
|
|||||||
@ -1,17 +1,17 @@
|
|||||||
import React, { Fragment, memo } from 'react';
|
import React, { Fragment, memo } from 'react';
|
||||||
import { Element } from 'react-scroll';
|
import { Element } from 'react-scroll';
|
||||||
import sections from '../../../data/leftSections';
|
import sections from '../../../data/leftSections';
|
||||||
import Awards from '../sections/Awards';
|
import Awards from './sections/Awards';
|
||||||
import Certifications from '../sections/Certifications';
|
import Certifications from './sections/Certifications';
|
||||||
import Education from '../sections/Education';
|
import Education from './sections/Education';
|
||||||
import Hobbies from '../sections/Hobbies';
|
import Hobbies from './sections/Hobbies';
|
||||||
import Languages from '../sections/Languages';
|
import Languages from './sections/Languages';
|
||||||
import Objective from '../sections/Objective';
|
import Objective from './sections/Objective';
|
||||||
import Profile from '../sections/Profile';
|
import Profile from './sections/Profile';
|
||||||
import References from '../sections/References';
|
import References from './sections/References';
|
||||||
import Skills from '../sections/Skills';
|
import Skills from './sections/Skills';
|
||||||
import Social from '../sections/Social';
|
import Social from './sections/Social';
|
||||||
import Work from '../sections/Work';
|
import Work from './sections/Work';
|
||||||
import LeftNavbar from './LeftNavbar';
|
import LeftNavbar from './LeftNavbar';
|
||||||
import styles from './LeftSidebar.module.css';
|
import styles from './LeftSidebar.module.css';
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Awards = ({ id, name, event }) => {
|
const Awards = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Certifications = ({ id, name, event }) => {
|
const Certifications = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Education = ({ id, name, event }) => {
|
const Education = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Hobbies = ({ id, name, event }) => {
|
const Hobbies = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Languages = ({ id, name, event }) => {
|
const Languages = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import Input from '../../shared/Input';
|
import Input from '../../../shared/Input';
|
||||||
|
|
||||||
const Objective = () => {
|
const Objective = () => {
|
||||||
return (
|
return (
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import Input from '../../shared/Input';
|
import Input from '../../../shared/Input';
|
||||||
import PhotoUpload from '../../shared/PhotoUpload';
|
import PhotoUpload from '../../../shared/PhotoUpload';
|
||||||
|
|
||||||
const Profile = () => {
|
const Profile = () => {
|
||||||
return (
|
return (
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const References = ({ id, name, event }) => {
|
const References = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Skills = ({ id, name, event }) => {
|
const Skills = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Social = ({ id, name, event }) => {
|
const Social = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import List from '../lists/List';
|
import List from '../../lists/List';
|
||||||
|
|
||||||
const Work = ({ id, name, event }) => {
|
const Work = ({ id, name, event }) => {
|
||||||
const path = `${id}.items`;
|
const path = `${id}.items`;
|
||||||
@ -20,7 +20,7 @@ const List = ({
|
|||||||
hasDate,
|
hasDate,
|
||||||
event,
|
event,
|
||||||
}) => {
|
}) => {
|
||||||
const items = useSelector((state) => get(state, path, []));
|
const items = useSelector(path, []);
|
||||||
const { emitter } = useContext(ModalContext);
|
const { emitter } = useContext(ModalContext);
|
||||||
|
|
||||||
const handleAdd = () => emitter.emit(event);
|
const handleAdd = () => emitter.emit(event);
|
||||||
|
|||||||
@ -82,7 +82,7 @@ const ListItem = ({
|
|||||||
size="18px"
|
size="18px"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
className="cursor-pointer"
|
className="cursor-context-menu"
|
||||||
/>
|
/>
|
||||||
<Menu
|
<Menu
|
||||||
keepMounted
|
keepMounted
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import SyncIndicator from './SyncIndicator';
|
|||||||
const RightNavbar = () => {
|
const RightNavbar = () => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className="grid grid-cols-1 gap-6 text-secondary-dark">
|
<div className="grid grid-cols-1 gap-4 text-secondary-dark">
|
||||||
{sections.map((x) => (
|
{sections.map((x) => (
|
||||||
<SectionIcon
|
<SectionIcon
|
||||||
key={x.id}
|
key={x.id}
|
||||||
|
|||||||
@ -1,12 +1,15 @@
|
|||||||
import React, { Fragment, memo } from 'react';
|
import React, { Fragment, memo } from 'react';
|
||||||
import { Element } from 'react-scroll';
|
import { Element } from 'react-scroll';
|
||||||
import sections from '../../../data/rightSections';
|
import sections from '../../../data/rightSections';
|
||||||
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';
|
||||||
|
import Layout from './sections/Layout';
|
||||||
|
import Templates from './sections/Templates';
|
||||||
|
|
||||||
const getComponent = (id) => {
|
const getComponent = (id) => {
|
||||||
switch (id) {
|
switch (id) {
|
||||||
|
case 'templates':
|
||||||
|
return Templates;
|
||||||
case 'layout':
|
case 'layout':
|
||||||
return Layout;
|
return Layout;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
@apply w-full h-screen overflow-scroll p-8;
|
@apply w-full h-screen overflow-scroll p-8;
|
||||||
@apply grid gap-6;
|
@apply grid gap-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container::-webkit-scrollbar {
|
.container::-webkit-scrollbar {
|
||||||
|
|||||||
47
src/components/builder/right/sections/Colors.js
Normal file
47
src/components/builder/right/sections/Colors.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import React, { memo } from 'react';
|
||||||
|
import { useDispatch } from '../../../../contexts/ResumeContext';
|
||||||
|
import Heading from '../../../shared/Heading';
|
||||||
|
import Input from '../../../shared/Input';
|
||||||
|
|
||||||
|
const Colors = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const handleClick = (value) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'on_input',
|
||||||
|
payload: {
|
||||||
|
path: 'metadata.colors.primary',
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<Heading>Colors</Heading>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
name="primary"
|
||||||
|
label="Primary Color"
|
||||||
|
placeholder="#FF4081"
|
||||||
|
path="metadata.colors.primary"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
name="text"
|
||||||
|
label="Text Color"
|
||||||
|
placeholder="#444444"
|
||||||
|
path="metadata.colors.text"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Input
|
||||||
|
name="background"
|
||||||
|
label="Background Color"
|
||||||
|
placeholder="#FFFFFF"
|
||||||
|
path="metadata.colors.background"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(Colors);
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||||
import { useDispatch, useSelector } from '../../../contexts/MetadataContext';
|
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||||
import { move, reorder } from '../../../utils';
|
import { move, reorder } from '../../../../utils';
|
||||||
import Heading from '../../shared/Heading';
|
import Heading from '../../../shared/Heading';
|
||||||
import styles from './Layout.module.css';
|
import styles from './Layout.module.css';
|
||||||
|
|
||||||
const Layout = () => {
|
const Layout = () => {
|
||||||
const blocks = useSelector((state) => state.layout);
|
const blocks = useSelector('metadata.layout');
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const onDragEnd = (result) => {
|
const onDragEnd = (result) => {
|
||||||
@ -22,13 +22,25 @@ const Layout = () => {
|
|||||||
const items = reorder(blocks[sInd], source.index, destination.index);
|
const items = reorder(blocks[sInd], source.index, destination.index);
|
||||||
const newState = [...blocks];
|
const newState = [...blocks];
|
||||||
newState[sInd] = items;
|
newState[sInd] = items;
|
||||||
dispatch({ type: 'set_layout', payload: newState });
|
dispatch({
|
||||||
|
type: 'on_input',
|
||||||
|
payload: {
|
||||||
|
path: 'metadata.layout',
|
||||||
|
value: newState,
|
||||||
|
},
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const newResult = move(blocks[sInd], blocks[dInd], source, destination);
|
const newResult = move(blocks[sInd], blocks[dInd], source, destination);
|
||||||
const newState = [...blocks];
|
const newState = [...blocks];
|
||||||
newState[sInd] = newResult[sInd];
|
newState[sInd] = newResult[sInd];
|
||||||
newState[dInd] = newResult[dInd];
|
newState[dInd] = newResult[dInd];
|
||||||
dispatch({ type: 'set_layout', payload: newState });
|
dispatch({
|
||||||
|
type: 'on_input',
|
||||||
|
payload: {
|
||||||
|
path: 'layout',
|
||||||
|
value: newState,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -58,8 +70,8 @@ const Layout = () => {
|
|||||||
{el.map((item, index) => (
|
{el.map((item, index) => (
|
||||||
<Draggable
|
<Draggable
|
||||||
key={item.id}
|
key={item.id}
|
||||||
draggableId={item.id}
|
|
||||||
index={index}
|
index={index}
|
||||||
|
draggableId={item.id}
|
||||||
>
|
>
|
||||||
{(dragProvided) => (
|
{(dragProvided) => (
|
||||||
<div
|
<div
|
||||||
48
src/components/builder/right/sections/Templates.js
Normal file
48
src/components/builder/right/sections/Templates.js
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import cx from 'classnames';
|
||||||
|
import React, { memo } from 'react';
|
||||||
|
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||||
|
import templates from '../../../../data/templates';
|
||||||
|
import { handleKeyUp } from '../../../../utils';
|
||||||
|
import Heading from '../../../shared/Heading';
|
||||||
|
import styles from './Templates.module.css';
|
||||||
|
|
||||||
|
const Templates = () => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const template = useSelector('metadata.template');
|
||||||
|
|
||||||
|
const handleClick = (value) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'on_input',
|
||||||
|
payload: {
|
||||||
|
path: 'metadata.template',
|
||||||
|
value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<Heading>Templates</Heading>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-2 gap-8">
|
||||||
|
{templates.map((x) => (
|
||||||
|
<div
|
||||||
|
key={x.id}
|
||||||
|
tabIndex="0"
|
||||||
|
role="button"
|
||||||
|
onKeyUp={(e) => handleKeyUp(e, () => handleClick(x.id))}
|
||||||
|
onClick={() => handleClick(x.id)}
|
||||||
|
className={cx(styles.template, {
|
||||||
|
[styles.selected]: template === x.id,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<img loading="lazy" height="240px" src={x.preview} alt={x.name} />
|
||||||
|
<span>{x.name}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default memo(Templates);
|
||||||
26
src/components/builder/right/sections/Templates.module.css
Normal file
26
src/components/builder/right/sections/Templates.module.css
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
.template {
|
||||||
|
@apply w-full rounded flex flex-col items-center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template:focus {
|
||||||
|
@apply outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template img {
|
||||||
|
height: 240px;
|
||||||
|
@apply w-full object-cover border-2 border-transparent rounded;
|
||||||
|
@apply transition-opacity duration-200 ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template.selected img {
|
||||||
|
@apply border-2 border-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template:hover img {
|
||||||
|
@apply cursor-pointer opacity-75;
|
||||||
|
@apply transition-opacity duration-200 ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.template span {
|
||||||
|
@apply mt-1 text-center text-sm font-semibold;
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { get, isFunction } from 'lodash';
|
import { isFunction } from 'lodash';
|
||||||
import React, { memo, useEffect, useState } from 'react';
|
import React, { memo, useEffect, useState } from 'react';
|
||||||
import { FaAngleDown } from 'react-icons/fa';
|
import { FaAngleDown } from 'react-icons/fa';
|
||||||
import { MdClose } from 'react-icons/md';
|
import { MdClose } from 'react-icons/md';
|
||||||
@ -26,14 +26,14 @@ const Input = ({
|
|||||||
type = 'text',
|
type = 'text',
|
||||||
}) => {
|
}) => {
|
||||||
const [uuid, setUuid] = useState(null);
|
const [uuid, setUuid] = useState(null);
|
||||||
const stateValue = useSelector((state) => get(state, path));
|
const stateValue = useSelector(path, '');
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setUuid(uuidv4());
|
setUuid(uuidv4());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
value = isFunction(onChange) ? value : stateValue;
|
value = path ? stateValue : value;
|
||||||
onChange = isFunction(onChange)
|
onChange = isFunction(onChange)
|
||||||
? onChange
|
? onChange
|
||||||
: (e) => {
|
: (e) => {
|
||||||
|
|||||||
@ -14,10 +14,16 @@
|
|||||||
@apply text-primary opacity-50;
|
@apply text-primary opacity-50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container label input:hover,
|
||||||
|
.container label textarea:hover,
|
||||||
|
.container label select:hover {
|
||||||
|
@apply outline-none border-secondary-dark;
|
||||||
|
}
|
||||||
|
|
||||||
.container label input:focus,
|
.container label input:focus,
|
||||||
.container label textarea:focus,
|
.container label textarea:focus,
|
||||||
.container label select:focus {
|
.container label select:focus {
|
||||||
@apply outline-none border-gray-500;
|
@apply outline-none border-primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container label > p {
|
.container label > p {
|
||||||
|
|||||||
@ -3,4 +3,14 @@
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
flex: 0 0 60px;
|
flex: 0 0 60px;
|
||||||
@apply flex items-center justify-center cursor-pointer bg-secondary text-secondary-dark rounded-full;
|
@apply flex items-center justify-center cursor-pointer bg-secondary text-secondary-dark rounded-full;
|
||||||
|
@apply transition-opacity duration-200 ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle:focus {
|
||||||
|
@apply outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle:hover {
|
||||||
|
@apply opacity-75;
|
||||||
|
@apply transition-opacity duration-200 ease-in-out;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,9 @@ const SectionIcon = ({ section, containerId, tooltipPlacement }) => {
|
|||||||
duration={500}
|
duration={500}
|
||||||
containerId={containerId}
|
containerId={containerId}
|
||||||
activeClass="text-primary"
|
activeClass="text-primary"
|
||||||
className="py-2 cursor-pointer focus:outline-none focus:text-primary hover:text-primary"
|
className="py-2 cursor-pointer focus:outline-none focus:text-primary hover:text-primary animate__animated animate__fadeIn"
|
||||||
>
|
>
|
||||||
<Icon size="16px" />
|
<Icon size="18px" />
|
||||||
</Link>
|
</Link>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
import { clone, setWith } from 'lodash';
|
|
||||||
import React, {
|
|
||||||
createContext,
|
|
||||||
memo,
|
|
||||||
useCallback,
|
|
||||||
useContext,
|
|
||||||
useReducer,
|
|
||||||
} from 'react';
|
|
||||||
import leftSections from '../data/leftSections';
|
|
||||||
import DatabaseContext from './DatabaseContext';
|
|
||||||
import { useSelector as useResumeSelector } from './ResumeContext';
|
|
||||||
|
|
||||||
const initialState = {
|
|
||||||
template: 'Onyx',
|
|
||||||
font: 'Montserrat',
|
|
||||||
layout: [leftSections.map(({ id, name }) => ({ id, name }))],
|
|
||||||
colors: {
|
|
||||||
textColor: '#444444',
|
|
||||||
primaryColor: '#5875DB',
|
|
||||||
backgroundColor: '#FFFFFF',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const MetadataContext = createContext({});
|
|
||||||
|
|
||||||
const MetadataProvider = ({ children }) => {
|
|
||||||
const id = useResumeSelector((state) => state.id);
|
|
||||||
const { debouncedUpdateMetadata } = useContext(DatabaseContext);
|
|
||||||
|
|
||||||
const memoizedReducer = useCallback(
|
|
||||||
(state, { type, payload }) => {
|
|
||||||
let newState;
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'set_layout':
|
|
||||||
newState = setWith(clone(state), 'layout', payload, clone);
|
|
||||||
debouncedUpdateMetadata(id, newState);
|
|
||||||
return newState;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[id, debouncedUpdateMetadata],
|
|
||||||
);
|
|
||||||
|
|
||||||
const [state, dispatch] = useReducer(memoizedReducer, initialState);
|
|
||||||
|
|
||||||
const selectValue = (callback) => callback(state);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<MetadataContext.Provider value={{ selectValue, dispatch }}>
|
|
||||||
{children}
|
|
||||||
</MetadataContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useSelector = (callback) => {
|
|
||||||
const { selectValue } = useContext(MetadataContext);
|
|
||||||
return selectValue(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
const useDispatch = () => {
|
|
||||||
const { dispatch } = useContext(MetadataContext);
|
|
||||||
return dispatch;
|
|
||||||
};
|
|
||||||
|
|
||||||
const memoizedProvider = memo(MetadataProvider);
|
|
||||||
|
|
||||||
export { memoizedProvider as MetadataProvider, useSelector, useDispatch };
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import arrayMove from 'array-move';
|
import arrayMove from 'array-move';
|
||||||
import { clone, findIndex, get, setWith } from 'lodash';
|
import { clone, findIndex, get, isUndefined, setWith } from 'lodash';
|
||||||
import React, {
|
import React, {
|
||||||
createContext,
|
createContext,
|
||||||
memo,
|
memo,
|
||||||
@ -7,9 +7,22 @@ import React, {
|
|||||||
useContext,
|
useContext,
|
||||||
useReducer,
|
useReducer,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
import leftSections from '../data/leftSections';
|
||||||
import DatabaseContext from './DatabaseContext';
|
import DatabaseContext from './DatabaseContext';
|
||||||
|
|
||||||
const initialState = {};
|
const initialState = {
|
||||||
|
name: '',
|
||||||
|
metadata: {
|
||||||
|
template: 'onyx',
|
||||||
|
font: 'Montserrat',
|
||||||
|
layout: [leftSections.map(({ id, name }) => ({ id, name }))],
|
||||||
|
colors: {
|
||||||
|
text: '#444444',
|
||||||
|
primary: '#5875DB',
|
||||||
|
background: '#FFFFFF',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const ResumeContext = createContext({});
|
const ResumeContext = createContext({});
|
||||||
|
|
||||||
@ -89,18 +102,22 @@ const ResumeProvider = ({ children }) => {
|
|||||||
|
|
||||||
const [state, dispatch] = useReducer(memoizedReducer, initialState);
|
const [state, dispatch] = useReducer(memoizedReducer, initialState);
|
||||||
|
|
||||||
const selectValue = (callback) => callback(state);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResumeContext.Provider value={{ selectValue, dispatch }}>
|
<ResumeContext.Provider value={{ state, dispatch }}>
|
||||||
{children}
|
{children}
|
||||||
</ResumeContext.Provider>
|
</ResumeContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useSelector = (callback) => {
|
const useSelector = (path, fallback) => {
|
||||||
const { selectValue } = useContext(ResumeContext);
|
const { state } = useContext(ResumeContext);
|
||||||
return selectValue(callback);
|
let value = get(state, path);
|
||||||
|
|
||||||
|
if (isUndefined(value)) {
|
||||||
|
value = isUndefined(fallback) ? state : fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useDispatch = () => {
|
const useDispatch = () => {
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const StorageProvider = ({ children }) => {
|
|||||||
|
|
||||||
const { user } = useContext(UserContext);
|
const { user } = useContext(UserContext);
|
||||||
|
|
||||||
const id = useSelector((state) => state.id);
|
const id = useSelector('id');
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const uploadPhotograph = async (file) => {
|
const uploadPhotograph = async (file) => {
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
import { MdDashboard } from 'react-icons/md';
|
import { MdDashboard, MdStyle } from 'react-icons/md';
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
|
{
|
||||||
|
id: 'templates',
|
||||||
|
name: 'Templates',
|
||||||
|
icon: MdStyle,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'layout',
|
id: 'layout',
|
||||||
name: 'Layout',
|
name: 'Layout',
|
||||||
|
|||||||
14
src/data/templates.js
Normal file
14
src/data/templates.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const templates = [
|
||||||
|
{
|
||||||
|
id: 'onyx',
|
||||||
|
name: 'Onyx',
|
||||||
|
preview: 'https://source.unsplash.com/random/300x500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'pikachu',
|
||||||
|
name: 'Pikachu',
|
||||||
|
preview: 'https://source.unsplash.com/random/301x501',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default templates;
|
||||||
@ -6,9 +6,20 @@ import ModalEvents from '../constants/ModalEvents';
|
|||||||
import DatabaseContext from '../contexts/DatabaseContext';
|
import DatabaseContext from '../contexts/DatabaseContext';
|
||||||
import { getFieldProps } from '../utils';
|
import { getFieldProps } from '../utils';
|
||||||
import DataModal from './DataModal';
|
import DataModal from './DataModal';
|
||||||
|
import leftSections from '../data/leftSections';
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
name: '',
|
name: '',
|
||||||
|
metadata: {
|
||||||
|
template: 'onyx',
|
||||||
|
font: 'Montserrat',
|
||||||
|
layout: [leftSections.map(({ id, name }) => ({ id, name }))],
|
||||||
|
colors: {
|
||||||
|
text: '#444444',
|
||||||
|
primary: '#5875DB',
|
||||||
|
background: '#FFFFFF',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const schema = Yup.object().shape({
|
const schema = Yup.object().shape({
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import firebase from 'gatsby-plugin-firebase';
|
import firebase from 'gatsby-plugin-firebase';
|
||||||
import React, { memo, useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import CreateResume from '../../components/dashboard/CreateResume';
|
import CreateResume from '../../components/dashboard/CreateResume';
|
||||||
import ResumePreview from '../../components/dashboard/ResumePreview';
|
import ResumePreview from '../../components/dashboard/ResumePreview';
|
||||||
@ -27,6 +27,15 @@ const Dashboard = ({ user }) => {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
firebase
|
||||||
|
.database()
|
||||||
|
.ref(ref)
|
||||||
|
.on('child_removed', (snapshot) => {
|
||||||
|
if (snapshot.val()) {
|
||||||
|
setResumes(resumes.filter((x) => x.id === snapshot.val().id));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
firebase.database().ref(ref).off();
|
firebase.database().ref(ref).off();
|
||||||
};
|
};
|
||||||
@ -58,4 +67,4 @@ const Dashboard = ({ user }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default memo(Dashboard);
|
export default Dashboard;
|
||||||
|
|||||||
@ -2,13 +2,16 @@ import React, { memo } from 'react';
|
|||||||
import { FaGlobeAmericas, FaPhone } from 'react-icons/fa';
|
import { FaGlobeAmericas, FaPhone } from 'react-icons/fa';
|
||||||
import { MdEmail } from 'react-icons/md';
|
import { MdEmail } from 'react-icons/md';
|
||||||
|
|
||||||
const Onyx = ({ data, layout, colors }) => {
|
const Onyx = ({ data }) => {
|
||||||
|
const { profile, metadata } = data;
|
||||||
|
const { colors, layout } = metadata;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="p-8 grid grid-cols-10 gap-4 items-center"
|
className="p-8 grid grid-cols-10 gap-4 items-center"
|
||||||
style={{
|
style={{
|
||||||
color: colors.textColor,
|
color: colors.text,
|
||||||
backgroundColor: colors.backgroundColor,
|
backgroundColor: colors.background,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
@ -17,11 +20,8 @@ const Onyx = ({ data, layout, colors }) => {
|
|||||||
alt="Photograph"
|
alt="Photograph"
|
||||||
/>
|
/>
|
||||||
<div className="col-span-5">
|
<div className="col-span-5">
|
||||||
<h2
|
<h2 className="text-4xl font-bold" style={{ color: colors.primary }}>
|
||||||
className="text-4xl font-bold"
|
{profile.firstName} {profile.lastName}
|
||||||
style={{ color: colors.primaryColor }}
|
|
||||||
>
|
|
||||||
{data.profile.firstName} {data.profile.lastName}
|
|
||||||
</h2>
|
</h2>
|
||||||
<span className="font-medium">Customer Sales Representative</span>
|
<span className="font-medium">Customer Sales Representative</span>
|
||||||
|
|
||||||
@ -33,17 +33,17 @@ const Onyx = ({ data, layout, colors }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col-span-3 grid gap-4">
|
<div className="col-span-3 grid gap-4">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<FaPhone size="14" style={{ color: colors.primaryColor }} />
|
<FaPhone size="14" style={{ color: colors.primary }} />
|
||||||
<span className="ml-4 text-sm font-medium">+1 661-808-4188</span>
|
<span className="ml-4 text-sm font-medium">+1 661-808-4188</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<FaGlobeAmericas size="14" style={{ color: colors.primaryColor }} />
|
<FaGlobeAmericas size="14" style={{ color: colors.primary }} />
|
||||||
<span className="ml-4 text-sm font-medium">nancyontheweb.com</span>
|
<span className="ml-4 text-sm font-medium">nancyontheweb.com</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<MdEmail size="14" style={{ color: colors.primaryColor }} />
|
<MdEmail size="14" style={{ color: colors.primary }} />
|
||||||
<span className="ml-4 text-sm font-medium">
|
<span className="ml-4 text-sm font-medium">
|
||||||
nancyjack43@gmail.com
|
nancyjack43@gmail.com
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -5,6 +5,9 @@ module.exports = {
|
|||||||
center: true,
|
center: true,
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
|
cursor: {
|
||||||
|
'context-menu': 'context-menu',
|
||||||
|
},
|
||||||
colors: {
|
colors: {
|
||||||
primary: 'var(--color-primary)',
|
primary: 'var(--color-primary)',
|
||||||
'primary-dark': 'var(--color-primary-dark)',
|
'primary-dark': 'var(--color-primary-dark)',
|
||||||
|
|||||||
Reference in New Issue
Block a user