mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-13 08:13:49 +10:00
- completed design of Onyx template
This commit is contained in:
@ -11,11 +11,10 @@ import { ResumeProvider } from './src/contexts/ResumeContext';
|
||||
import { StorageProvider } from './src/contexts/StorageContext';
|
||||
import { ThemeProvider } from './src/contexts/ThemeContext';
|
||||
import { UserProvider } from './src/contexts/UserContext';
|
||||
import './src/styles/colors.css';
|
||||
import './src/styles/global.css';
|
||||
import './src/styles/shadows.css';
|
||||
import './src/styles/tailwind.css';
|
||||
import './src/styles/toastify.css';
|
||||
import './src/styles/global.css';
|
||||
|
||||
const theme = createMuiTheme({
|
||||
typography: {
|
||||
|
||||
@ -86,6 +86,14 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
'gatsby-plugin-lodash',
|
||||
{
|
||||
resolve: `gatsby-plugin-material-ui`,
|
||||
options: {
|
||||
stylesProvider: {
|
||||
injectFirst: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
'gatsby-plugin-postcss',
|
||||
{
|
||||
resolve: 'gatsby-source-filesystem',
|
||||
|
||||
205
package-lock.json
generated
205
package-lock.json
generated
@ -8715,6 +8715,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"gatsby-plugin-material-ui": {
|
||||
"version": "2.1.9",
|
||||
"resolved": "https://registry.npmjs.org/gatsby-plugin-material-ui/-/gatsby-plugin-material-ui-2.1.9.tgz",
|
||||
"integrity": "sha512-bvfAEOugCyDgVY9ZNadnC+RP20qA/G2mMDnoj25hRf98fcTtP128s1DshoeYZF61w46Mqp6ACB+uZtrG6iWDfQ==",
|
||||
"requires": {
|
||||
"autoprefixer": "^9.6.1",
|
||||
"clean-css": "^4.2.1",
|
||||
"postcss": "^7.0.17"
|
||||
}
|
||||
},
|
||||
"gatsby-plugin-offline": {
|
||||
"version": "3.2.17",
|
||||
"resolved": "https://registry.npmjs.org/gatsby-plugin-offline/-/gatsby-plugin-offline-3.2.17.tgz",
|
||||
@ -10043,6 +10053,53 @@
|
||||
"resolved": "https://registry.npmjs.org/html-tag-names/-/html-tag-names-1.1.5.tgz",
|
||||
"integrity": "sha512-aI5tKwNTBzOZApHIynaAwecLBv8TlZTEy/P4Sj2SzzAhBrGuI8yGZ0UIXVPQzOHGS+to2mjb04iy6VWt/8+d8A=="
|
||||
},
|
||||
"html-to-react": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.4.3.tgz",
|
||||
"integrity": "sha512-txe09A3vxW8yEZGJXJ1is5gGDfBEVACmZDSgwDyH5EsfRdOubBwBCg63ZThZP0xBn0UE4FyvMXZXmohusCxDcg==",
|
||||
"requires": {
|
||||
"domhandler": "^3.0",
|
||||
"htmlparser2": "^4.1.0",
|
||||
"lodash.camelcase": "^4.3.0",
|
||||
"ramda": "^0.27"
|
||||
},
|
||||
"dependencies": {
|
||||
"domelementtype": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
|
||||
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
|
||||
},
|
||||
"domhandler": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
|
||||
"integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.1.0.tgz",
|
||||
"integrity": "sha512-CD9M0Dm1iaHfQ1R/TI+z3/JWp/pgub0j4jIQKH89ARR4ATAV2nbaOQS5XxU9maJP5jHaPdDDQSEHuE2UmpUTKg==",
|
||||
"requires": {
|
||||
"dom-serializer": "^0.2.1",
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
|
||||
"integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
|
||||
"requires": {
|
||||
"domelementtype": "^2.0.1",
|
||||
"domhandler": "^3.0.0",
|
||||
"domutils": "^2.0.0",
|
||||
"entities": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"html-void-elements": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz",
|
||||
@ -12330,6 +12387,21 @@
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"mdast-add-list-metadata": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz",
|
||||
"integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==",
|
||||
"requires": {
|
||||
"unist-util-visit-parents": "1.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"unist-util-visit-parents": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz",
|
||||
"integrity": "sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"mdast-squeeze-paragraphs": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz",
|
||||
@ -15051,6 +15123,11 @@
|
||||
"resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz",
|
||||
"integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ=="
|
||||
},
|
||||
"ramda": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.0.tgz",
|
||||
"integrity": "sha512-pVzZdDpWwWqEVVLshWUHjNwuVP7SfcmPraYuqocJp1yo2U1R7P+5QAfDhdItkuoGqIBnBYrtPp7rEPqDn9HlZA=="
|
||||
},
|
||||
"randombytes": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
@ -15451,6 +15528,129 @@
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-markdown": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-4.3.1.tgz",
|
||||
"integrity": "sha512-HQlWFTbDxTtNY6bjgp3C3uv1h2xcjCSi1zAEzfBW9OwJJvENSYiLXWNXN5hHLsoqai7RnZiiHzcnWdXk2Splzw==",
|
||||
"requires": {
|
||||
"html-to-react": "^1.3.4",
|
||||
"mdast-add-list-metadata": "1.0.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.8.6",
|
||||
"remark-parse": "^5.0.0",
|
||||
"unified": "^6.1.5",
|
||||
"unist-util-visit": "^1.3.0",
|
||||
"xtend": "^4.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"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="
|
||||
},
|
||||
"parse-entities": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.2.2.tgz",
|
||||
"integrity": "sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==",
|
||||
"requires": {
|
||||
"character-entities": "^1.0.0",
|
||||
"character-entities-legacy": "^1.0.0",
|
||||
"character-reference-invalid": "^1.0.0",
|
||||
"is-alphanumerical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0",
|
||||
"is-hexadecimal": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"remark-parse": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-5.0.0.tgz",
|
||||
"integrity": "sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==",
|
||||
"requires": {
|
||||
"collapse-white-space": "^1.0.2",
|
||||
"is-alphabetical": "^1.0.0",
|
||||
"is-decimal": "^1.0.0",
|
||||
"is-whitespace-character": "^1.0.0",
|
||||
"is-word-character": "^1.0.0",
|
||||
"markdown-escapes": "^1.0.0",
|
||||
"parse-entities": "^1.1.0",
|
||||
"repeat-string": "^1.5.4",
|
||||
"state-toggle": "^1.0.0",
|
||||
"trim": "0.0.1",
|
||||
"trim-trailing-lines": "^1.0.0",
|
||||
"unherit": "^1.0.4",
|
||||
"unist-util-remove-position": "^1.0.0",
|
||||
"vfile-location": "^2.0.0",
|
||||
"xtend": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"unified": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/unified/-/unified-6.2.0.tgz",
|
||||
"integrity": "sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==",
|
||||
"requires": {
|
||||
"bail": "^1.0.0",
|
||||
"extend": "^3.0.0",
|
||||
"is-plain-obj": "^1.1.0",
|
||||
"trough": "^1.0.0",
|
||||
"vfile": "^2.0.0",
|
||||
"x-is-string": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"unist-util-remove-position": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz",
|
||||
"integrity": "sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A==",
|
||||
"requires": {
|
||||
"unist-util-visit": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"unist-util-stringify-position": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz",
|
||||
"integrity": "sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ=="
|
||||
},
|
||||
"unist-util-visit": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
|
||||
"integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
|
||||
"requires": {
|
||||
"unist-util-visit-parents": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"unist-util-visit-parents": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
|
||||
"integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
|
||||
"requires": {
|
||||
"unist-util-is": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"vfile": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/vfile/-/vfile-2.3.0.tgz",
|
||||
"integrity": "sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==",
|
||||
"requires": {
|
||||
"is-buffer": "^1.1.4",
|
||||
"replace-ext": "1.0.0",
|
||||
"unist-util-stringify-position": "^1.0.0",
|
||||
"vfile-message": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"vfile-location": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.6.tgz",
|
||||
"integrity": "sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA=="
|
||||
},
|
||||
"vfile-message": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-1.1.1.tgz",
|
||||
"integrity": "sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==",
|
||||
"requires": {
|
||||
"unist-util-stringify-position": "^1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-reconciler": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.25.1.tgz",
|
||||
@ -19866,6 +20066,11 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
||||
},
|
||||
"x-is-string": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
|
||||
"integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI="
|
||||
},
|
||||
"xdg-basedir": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
"gatsby-plugin-firebase": "^0.2.0-beta.4",
|
||||
"gatsby-plugin-lodash": "^3.3.10",
|
||||
"gatsby-plugin-manifest": "^2.4.18",
|
||||
"gatsby-plugin-material-ui": "^2.1.9",
|
||||
"gatsby-plugin-offline": "^3.2.17",
|
||||
"gatsby-plugin-postcss": "^2.3.11",
|
||||
"gatsby-plugin-prefetch-google-fonts": "^1.4.3",
|
||||
@ -46,6 +47,7 @@
|
||||
"react-dom": "^16.13.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-icons": "^3.10.0",
|
||||
"react-markdown": "^4.3.1",
|
||||
"react-scroll": "^1.7.16",
|
||||
"react-toastify": "^6.0.8",
|
||||
"uuid": "^8.2.0",
|
||||
|
||||
@ -7,7 +7,7 @@ const Objective = () => {
|
||||
<section>
|
||||
<Heading>Objective</Heading>
|
||||
|
||||
<Input type="textarea" label="Objective" path="objective" />
|
||||
<Input type="textarea" label="Objective" path="objective.body" />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
@ -38,7 +38,7 @@ const Actions = () => {
|
||||
<div className={styles.container}>
|
||||
<h5>Import Your Resume</h5>
|
||||
|
||||
<p>
|
||||
<p className="leading-loose">
|
||||
You can import your information from various sources like JSON Resume
|
||||
or your LinkedIn to autofill most of the data for your resume.
|
||||
</p>
|
||||
@ -53,7 +53,7 @@ const Actions = () => {
|
||||
<div className={styles.container}>
|
||||
<h5>Export Your Resume</h5>
|
||||
|
||||
<p>
|
||||
<p className="leading-loose">
|
||||
Export your resume as a PDF to share with recruiters or a JSON that
|
||||
you will be able to import back onto this app on another computer.
|
||||
</p>
|
||||
@ -73,7 +73,7 @@ const Actions = () => {
|
||||
<div className={styles.container}>
|
||||
<h5>Share Your Resume</h5>
|
||||
|
||||
<p>
|
||||
<p className="leading-loose">
|
||||
The link below will be accessible publicly if you choose to share it,
|
||||
and viewers would see the latest version of your resume at any time.
|
||||
</p>
|
||||
@ -86,7 +86,7 @@ const Actions = () => {
|
||||
<div className={styles.container}>
|
||||
<h5>Load Demo Data</h5>
|
||||
|
||||
<p>
|
||||
<p className="leading-loose">
|
||||
Unclear on what to do with a fresh blank page? Load some demo data to
|
||||
see how a resume should look and you can start editing from there.
|
||||
</p>
|
||||
@ -99,7 +99,7 @@ const Actions = () => {
|
||||
<div className={styles.container}>
|
||||
<h5>Delete Account</h5>
|
||||
|
||||
<p>
|
||||
<p className="leading-loose">
|
||||
If you would like to delete your account and erase all your resumes,
|
||||
it’s just one button away. Please be weary as this is an irreversible
|
||||
process.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { memo } from 'react';
|
||||
import React from 'react';
|
||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import { useDispatch, useSelector } from '../../../../contexts/ResumeContext';
|
||||
import { move, reorder } from '../../../../utils';
|
||||
@ -37,7 +37,7 @@ const Layout = () => {
|
||||
dispatch({
|
||||
type: 'on_input',
|
||||
payload: {
|
||||
path: 'layout',
|
||||
path: 'metadata.layout',
|
||||
value: newState,
|
||||
},
|
||||
});
|
||||
@ -68,11 +68,7 @@ const Layout = () => {
|
||||
Block {ind + 1}
|
||||
</span>
|
||||
{el.map((item, index) => (
|
||||
<Draggable
|
||||
key={item.id}
|
||||
index={index}
|
||||
draggableId={item.id}
|
||||
>
|
||||
<Draggable key={item} index={index} draggableId={item}>
|
||||
{(dragProvided) => (
|
||||
<div
|
||||
ref={dragProvided.innerRef}
|
||||
@ -80,7 +76,7 @@ const Layout = () => {
|
||||
{...dragProvided.draggableProps}
|
||||
{...dragProvided.dragHandleProps}
|
||||
>
|
||||
{item.name}
|
||||
{item}
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
@ -97,4 +93,4 @@ const Layout = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(Layout);
|
||||
export default Layout;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Menu, MenuItem } from '@material-ui/core';
|
||||
import { navigate } from 'gatsby';
|
||||
import moment from 'moment';
|
||||
import React, { memo, useContext, useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { MdMoreHoriz, MdOpenInNew } from 'react-icons/md';
|
||||
import { toast } from 'react-toastify';
|
||||
import DatabaseContext from '../../contexts/DatabaseContext';
|
||||
@ -78,4 +78,4 @@ const ResumePreview = ({ resume }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ResumePreview);
|
||||
export default ResumePreview;
|
||||
|
||||
@ -8,6 +8,7 @@ import React, {
|
||||
useState,
|
||||
} from 'react';
|
||||
import UserContext from './UserContext';
|
||||
import initialState from '../data/initialState';
|
||||
|
||||
const DEBOUNCE_WAIT_TIME = 4000;
|
||||
|
||||
@ -46,8 +47,7 @@ const DatabaseProvider = ({ children }) => {
|
||||
return snapshot.val();
|
||||
};
|
||||
|
||||
const createResume = (resume) => {
|
||||
const { id } = resume;
|
||||
const createResume = ({ id, name }) => {
|
||||
const createdAt = firebase.database.ServerValue.TIMESTAMP;
|
||||
|
||||
let firstName;
|
||||
@ -61,11 +61,14 @@ const DatabaseProvider = ({ children }) => {
|
||||
.database()
|
||||
.ref(`users/${user.uid}/resumes/${id}`)
|
||||
.set({
|
||||
...initialState,
|
||||
id,
|
||||
name,
|
||||
profile: {
|
||||
...initialState.profile,
|
||||
firstName: firstName || '',
|
||||
lastName: lastName || '',
|
||||
},
|
||||
...resume,
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
});
|
||||
|
||||
7
src/contexts/PageContext.js
Normal file
7
src/contexts/PageContext.js
Normal file
@ -0,0 +1,7 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
const defaultState = {};
|
||||
|
||||
const PageContext = createContext(defaultState);
|
||||
|
||||
export default PageContext;
|
||||
@ -1,5 +1,14 @@
|
||||
import arrayMove from 'array-move';
|
||||
import { clone, findIndex, get, isUndefined, setWith } from 'lodash';
|
||||
import {
|
||||
clone,
|
||||
findIndex,
|
||||
get,
|
||||
isUndefined,
|
||||
setWith,
|
||||
flatten,
|
||||
concat,
|
||||
times,
|
||||
} from 'lodash';
|
||||
import React, {
|
||||
createContext,
|
||||
memo,
|
||||
@ -7,22 +16,8 @@ import React, {
|
||||
useContext,
|
||||
useReducer,
|
||||
} from 'react';
|
||||
import leftSections from '../data/leftSections';
|
||||
import DatabaseContext from './DatabaseContext';
|
||||
|
||||
const initialState = {
|
||||
name: '',
|
||||
metadata: {
|
||||
template: 'onyx',
|
||||
font: 'Montserrat',
|
||||
layout: [leftSections.map(({ id, name }) => ({ id, name }))],
|
||||
colors: {
|
||||
text: '#444444',
|
||||
primary: '#5875DB',
|
||||
background: '#FFFFFF',
|
||||
},
|
||||
},
|
||||
};
|
||||
import initialState from '../data/initialState';
|
||||
|
||||
const ResumeContext = createContext({});
|
||||
|
||||
@ -34,6 +29,8 @@ const ResumeProvider = ({ children }) => {
|
||||
let newState;
|
||||
let index;
|
||||
let items;
|
||||
let diff;
|
||||
let temp;
|
||||
|
||||
switch (type) {
|
||||
case 'on_add_item':
|
||||
@ -85,6 +82,30 @@ const ResumeProvider = ({ children }) => {
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'set_block_count':
|
||||
items = get(state, 'metadata.layout');
|
||||
|
||||
if (items.length === payload) return state;
|
||||
|
||||
if (payload === 1) {
|
||||
items = flatten(items);
|
||||
}
|
||||
|
||||
if (items.length > payload) {
|
||||
diff = items.length - payload;
|
||||
temp = items.splice(Math.max(items.length - diff, 1));
|
||||
items[0] = concat(items[0], flatten(temp));
|
||||
}
|
||||
|
||||
if (items.length < payload) {
|
||||
diff = payload - items.length;
|
||||
times(diff, () => items.push([]));
|
||||
}
|
||||
|
||||
newState = setWith(clone(state), 'metadata.layout', items, clone);
|
||||
debouncedUpdateResume(newState);
|
||||
return newState;
|
||||
|
||||
case 'on_input':
|
||||
newState = setWith(clone(state), payload.path, payload.value, clone);
|
||||
debouncedUpdateResume(newState);
|
||||
@ -132,4 +153,9 @@ const useDispatch = () => {
|
||||
|
||||
const memoizedProvider = memo(ResumeProvider);
|
||||
|
||||
export { memoizedProvider as ResumeProvider, useSelector, useDispatch };
|
||||
export {
|
||||
ResumeContext,
|
||||
memoizedProvider as ResumeProvider,
|
||||
useSelector,
|
||||
useDispatch,
|
||||
};
|
||||
|
||||
@ -62,11 +62,9 @@ const StorageProvider = ({ children }) => {
|
||||
render:
|
||||
'Your photograph was uploaded successfully... and you look great!',
|
||||
progress,
|
||||
autoClose: 5000,
|
||||
autoClose: 2000,
|
||||
hideProgressBar: true,
|
||||
});
|
||||
|
||||
toastId.current = null;
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
86
src/data/initialState.js
Normal file
86
src/data/initialState.js
Normal file
@ -0,0 +1,86 @@
|
||||
import leftSections from './leftSections';
|
||||
|
||||
const initialState = {
|
||||
id: '',
|
||||
profile: {
|
||||
heading: 'Profile',
|
||||
photograph: '',
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
subtitle: '',
|
||||
address: {
|
||||
line1: '',
|
||||
line2: '',
|
||||
city: '',
|
||||
pincode: '',
|
||||
},
|
||||
profile: '',
|
||||
website: '',
|
||||
email: '',
|
||||
},
|
||||
social: {
|
||||
heading: 'Social',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
objective: {
|
||||
heading: 'Objective',
|
||||
visible: true,
|
||||
body: '',
|
||||
},
|
||||
work: {
|
||||
heading: 'Work Experience',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
education: {
|
||||
heading: 'Education',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
awards: {
|
||||
heading: 'Awards',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
certifications: {
|
||||
heading: 'Certifications',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
skills: {
|
||||
heading: 'Skills',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
hobbies: {
|
||||
heading: 'Hobbies',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
languages: {
|
||||
heading: 'Languages',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
references: {
|
||||
heading: 'References',
|
||||
visible: true,
|
||||
items: [],
|
||||
},
|
||||
name: '',
|
||||
metadata: {
|
||||
template: 'onyx',
|
||||
font: 'Montserrat',
|
||||
layout: [leftSections.filter((x) => !x.fixed).map((x) => x.id)],
|
||||
colors: {
|
||||
text: '#444444',
|
||||
primary: '#5875DB',
|
||||
background: '#FFFFFF',
|
||||
},
|
||||
},
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
export default initialState;
|
||||
@ -14,12 +14,14 @@ export default [
|
||||
id: 'profile',
|
||||
name: 'Profile',
|
||||
icon: MdPerson,
|
||||
fixed: true,
|
||||
},
|
||||
{
|
||||
id: 'social',
|
||||
name: 'Social Network',
|
||||
icon: AiOutlineTwitter,
|
||||
event: ModalEvents.SOCIAL_MODAL,
|
||||
fixed: true,
|
||||
},
|
||||
{
|
||||
id: 'objective',
|
||||
|
||||
@ -9,7 +9,7 @@ import DataModal from '../DataModal';
|
||||
const initialValues = {
|
||||
name: '',
|
||||
position: '',
|
||||
contact: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
summary: '',
|
||||
};
|
||||
@ -17,7 +17,7 @@ const initialValues = {
|
||||
const schema = Yup.object().shape({
|
||||
name: Yup.string().required('This is a required field.'),
|
||||
position: Yup.string().required('This is a required field.'),
|
||||
contact: Yup.string(),
|
||||
phone: Yup.string(),
|
||||
email: Yup.string().email('Must be a valid email address.'),
|
||||
summary: Yup.string(),
|
||||
});
|
||||
@ -51,7 +51,7 @@ const ReferenceModal = () => {
|
||||
<Input
|
||||
label="Phone Number"
|
||||
placeholder="+1 (708) 756-6065"
|
||||
{...getFieldProps(formik, schema, 'contact')}
|
||||
{...getFieldProps(formik, schema, 'phone')}
|
||||
/>
|
||||
|
||||
<Input
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import firebase from 'gatsby-plugin-firebase';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import CreateResume from '../../components/dashboard/CreateResume';
|
||||
import ResumePreview from '../../components/dashboard/ResumePreview';
|
||||
@ -67,4 +67,4 @@ const Dashboard = ({ user }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
export default memo(Dashboard);
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
:root {
|
||||
--color-primary-50: #FFFFFF;
|
||||
--color-primary-100: #FAFAFA;
|
||||
--color-primary-200: #F1F0F0;
|
||||
--color-primary-300: #D8D2CD;
|
||||
--color-primary-400: #CDC4BA;
|
||||
--color-primary-500: #ABA59D;
|
||||
--color-primary-600: #8A8680;
|
||||
--color-primary-700: #686663;
|
||||
--color-primary-800: #484745;
|
||||
--color-primary-900: #282727;
|
||||
}
|
||||
@ -6,14 +6,6 @@ body {
|
||||
@apply transition-colors duration-200 ease-in-out;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply leading-loose;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-blue-600 font-medium;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
@apply underline;
|
||||
}
|
||||
@ -22,6 +14,10 @@ hr {
|
||||
@apply w-full border-primary-200 h-1;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-disc list-inside;
|
||||
}
|
||||
|
||||
section {
|
||||
@apply grid grid-cols-1 gap-8;
|
||||
}
|
||||
@ -35,11 +31,11 @@ label > span:first-child {
|
||||
}
|
||||
|
||||
.MuiTooltip-tooltip {
|
||||
font-size: 10px !important;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.MuiMenuItem-root {
|
||||
justify-content: center !important;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.spin {
|
||||
|
||||
@ -1,60 +1,107 @@
|
||||
import React, { memo } from 'react';
|
||||
import { FaGlobeAmericas, FaPhone } from 'react-icons/fa';
|
||||
import { MdEmail } from 'react-icons/md';
|
||||
import React, { memo, useEffect } from 'react';
|
||||
import PageContext from '../contexts/PageContext';
|
||||
import { useDispatch } from '../contexts/ResumeContext';
|
||||
import AwardsA from './blocks/Awards/AwardsA';
|
||||
import CertificationsA from './blocks/Certifications/CertificationsA';
|
||||
import Contact from './blocks/Contact/ContactA';
|
||||
import EducationA from './blocks/Education/EducationA';
|
||||
import Heading from './blocks/Heading/HeadingA';
|
||||
import HobbiesA from './blocks/Hobbies/HobbiesA';
|
||||
import LanguagesA from './blocks/Languages/LanguagesA';
|
||||
import ObjectiveA from './blocks/Objective/ObjectiveA';
|
||||
import ReferencesA from './blocks/References/ReferencesA';
|
||||
import SkillsA from './blocks/Skills/SkillsA';
|
||||
import WorkA from './blocks/Work/WorkA';
|
||||
|
||||
const Blocks = {
|
||||
objective: ObjectiveA,
|
||||
work: WorkA,
|
||||
education: EducationA,
|
||||
awards: AwardsA,
|
||||
certifications: CertificationsA,
|
||||
skills: SkillsA,
|
||||
hobbies: HobbiesA,
|
||||
languages: LanguagesA,
|
||||
references: ReferencesA,
|
||||
};
|
||||
|
||||
const Onyx = ({ data }) => {
|
||||
const { profile, metadata } = data;
|
||||
const { font, colors, layout } = metadata;
|
||||
const dispatch = useDispatch();
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({ type: 'set_block_count', payload: 3 });
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="p-8 grid grid-cols-10 gap-4 items-center"
|
||||
style={{
|
||||
fontFamily: font,
|
||||
color: colors.text,
|
||||
backgroundColor: colors.background,
|
||||
}}
|
||||
>
|
||||
<img
|
||||
className="col-span-2 rounded"
|
||||
src="https://i.imgur.com/Icr472Z.jpg"
|
||||
alt="Photograph"
|
||||
/>
|
||||
<div className="col-span-5">
|
||||
<h2 className="text-4xl font-bold" style={{ color: colors.primary }}>
|
||||
{profile.firstName} {profile.lastName}
|
||||
</h2>
|
||||
<span className="font-medium">Customer Sales Representative</span>
|
||||
<PageContext.Provider value={{ data, heading: Heading }}>
|
||||
<div
|
||||
id="page"
|
||||
className="p-10"
|
||||
style={{
|
||||
fontFamily: data.metadata.font,
|
||||
color: data.metadata.colors.text,
|
||||
backgroundColor: data.metadata.colors.background,
|
||||
}}
|
||||
>
|
||||
<div className="grid grid-cols-4 items-center">
|
||||
<div className="col-span-3 flex items-center">
|
||||
<img
|
||||
className="rounded object-cover mr-4"
|
||||
src={data.profile.photograph}
|
||||
alt="Resume Photograph"
|
||||
style={{ width: '120px', height: '120px' }}
|
||||
/>
|
||||
|
||||
<div className="mt-5 flex flex-col">
|
||||
<span>3879 Gateway Avenue,</span>
|
||||
<span>Bakersfield,</span>
|
||||
<span>California, USA</span>
|
||||
<div>
|
||||
<h1
|
||||
className="font-bold text-4xl"
|
||||
style={{ color: data.metadata.colors.primary }}
|
||||
>
|
||||
{data.profile.firstName} {data.profile.lastName}
|
||||
</h1>
|
||||
<h6 className="font-medium text-sm">{data.profile.subtitle}</h6>
|
||||
|
||||
<div className="flex flex-col mt-4 text-xs">
|
||||
<span>{data.profile.address.line1}</span>
|
||||
<span>{data.profile.address.line2}</span>
|
||||
<span>
|
||||
{data.profile.address.city} {data.profile.address.pincode}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Contact />
|
||||
</div>
|
||||
|
||||
<hr
|
||||
className="my-6 opacity-25"
|
||||
style={{ borderColor: data.metadata.colors.text }}
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 col-gap-8">
|
||||
{data.metadata.layout[0] &&
|
||||
data.metadata.layout[0].map((x) => {
|
||||
const Component = Blocks[x];
|
||||
return Component && <Component key={x} />;
|
||||
})}
|
||||
|
||||
<div className="grid grid-cols-3 col-gap-8">
|
||||
{data.metadata.layout[1] &&
|
||||
data.metadata.layout[1].map((x) => {
|
||||
const Component = Blocks[x];
|
||||
return Component && <Component key={x} />;
|
||||
})}
|
||||
</div>
|
||||
|
||||
{data.metadata.layout[2] &&
|
||||
data.metadata.layout[2].map((x) => {
|
||||
const Component = Blocks[x];
|
||||
return Component && <Component key={x} />;
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-3 grid gap-4">
|
||||
<div className="flex items-center">
|
||||
<FaPhone size="14" style={{ color: colors.primary }} />
|
||||
<span className="ml-4 text-sm font-medium">+1 661-808-4188</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<FaGlobeAmericas size="14" style={{ color: colors.primary }} />
|
||||
<span className="ml-4 text-sm font-medium">nancyontheweb.com</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<MdEmail size="14" style={{ color: colors.primary }} />
|
||||
<span className="ml-4 text-sm font-medium">
|
||||
nancyjack43@gmail.com
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr className="my-2 col-span-10" />
|
||||
|
||||
{JSON.stringify(layout)}
|
||||
</div>
|
||||
</PageContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
33
src/templates/blocks/Awards/AwardsA.js
Normal file
33
src/templates/blocks/Awards/AwardsA.js
Normal file
@ -0,0 +1,33 @@
|
||||
import moment from 'moment';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const AwardItem = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h6 className="font-semibold">{x.title}</h6>
|
||||
<p className="text-xs">{x.awarder}</p>
|
||||
</div>
|
||||
|
||||
<h6 className="text-xs font-medium">
|
||||
{moment(x.date).format('MMMM YYYY')}
|
||||
</h6>
|
||||
</div>
|
||||
<ReactMarkdown className="mt-2 text-sm" source={x.summary} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const AwardsA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.awards.visible && data.awards.items ? (
|
||||
<div>
|
||||
<Heading>{data.awards.heading}</Heading>
|
||||
{data.awards.items.map(AwardItem)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(AwardsA);
|
||||
33
src/templates/blocks/Certifications/CertificationsA.js
Normal file
33
src/templates/blocks/Certifications/CertificationsA.js
Normal file
@ -0,0 +1,33 @@
|
||||
import moment from 'moment';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const CertificationItem = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h6 className="font-semibold">{x.title}</h6>
|
||||
<p className="text-xs">{x.issuer}</p>
|
||||
</div>
|
||||
|
||||
<h6 className="text-xs font-medium">
|
||||
{moment(x.date).format('MMMM YYYY')}
|
||||
</h6>
|
||||
</div>
|
||||
<ReactMarkdown className="mt-2 text-sm" source={x.summary} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const CertificationsA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.certifications.visible && data.certifications.items ? (
|
||||
<div>
|
||||
<Heading>{data.certifications.heading}</Heading>
|
||||
{data.certifications.items.map(CertificationItem)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(CertificationsA);
|
||||
66
src/templates/blocks/Contact/ContactA.js
Normal file
66
src/templates/blocks/Contact/ContactA.js
Normal file
@ -0,0 +1,66 @@
|
||||
import { get } from 'lodash';
|
||||
import React, { memo, useContext } from 'react';
|
||||
import { FaCaretRight } from 'react-icons/fa';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
import Icons from '../Icons';
|
||||
|
||||
const ContactItem = ({ value, icon, link }) => {
|
||||
const { data } = useContext(PageContext);
|
||||
const Icon = get(Icons, icon.toLowerCase(), FaCaretRight);
|
||||
|
||||
return value ? (
|
||||
<div className="flex items-center my-3">
|
||||
<Icon
|
||||
size="14px"
|
||||
className="mr-2"
|
||||
style={{ color: data.metadata.colors.primary }}
|
||||
/>
|
||||
{link ? (
|
||||
<a href={link} target="_blank" rel="noopener noreferrer">
|
||||
<span className="font-medium break-all">{value}</span>
|
||||
</a>
|
||||
) : (
|
||||
<span className="font-medium break-all">{value}</span>
|
||||
)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const ContactA = () => {
|
||||
const { data } = useContext(PageContext);
|
||||
|
||||
return (
|
||||
<div className="col-span-1 text-xs">
|
||||
<ContactItem
|
||||
icon="phone"
|
||||
value={data.profile.phone}
|
||||
link={`tel:${data.profile.phone}`}
|
||||
/>
|
||||
<ContactItem
|
||||
icon="website"
|
||||
value={data.profile.website}
|
||||
link={`http://${data.profile.website}`}
|
||||
/>
|
||||
<ContactItem
|
||||
icon="email"
|
||||
value={data.profile.email}
|
||||
link={`mailto:${data.profile.email}`}
|
||||
/>
|
||||
|
||||
{data.social.visible && data.social.items ? (
|
||||
<div>
|
||||
{data.social.items.map((x) => (
|
||||
<ContactItem
|
||||
key={x.id}
|
||||
value={x.username}
|
||||
icon={x.network}
|
||||
link={x.url}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ContactA);
|
||||
42
src/templates/blocks/Education/EducationA.js
Normal file
42
src/templates/blocks/Education/EducationA.js
Normal file
@ -0,0 +1,42 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
import { formatDateRange } from '../../../utils';
|
||||
|
||||
const EducationItem = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h6 className="font-semibold">{x.institution}</h6>
|
||||
<span className="text-xs">
|
||||
<strong>{x.degree}</strong> {x.field}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col items-end">
|
||||
<span className="text-xs font-medium">
|
||||
({formatDateRange({ startDate: x.startDate, endDate: x.endDate })})
|
||||
</span>
|
||||
<h6 className="text-sm font-medium">{x.gpa}</h6>
|
||||
</div>
|
||||
</div>
|
||||
{x.courses && (
|
||||
<ul className="mt-2 text-sm list-disc list-inside">
|
||||
{x.courses.map((y) => (
|
||||
<li key={y}>{y}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const EducationA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.education.visible && data.education.items ? (
|
||||
<div>
|
||||
<Heading>{data.education.heading}</Heading>
|
||||
{data.education.items.map(EducationItem)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(EducationA);
|
||||
17
src/templates/blocks/Heading/HeadingA.js
Normal file
17
src/templates/blocks/Heading/HeadingA.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React, { useContext, memo } from 'react';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const HeadingA = ({ children }) => {
|
||||
const { data } = useContext(PageContext);
|
||||
|
||||
return (
|
||||
<h6
|
||||
className="text-xs font-bold uppercase mt-4 mb-1"
|
||||
style={{ color: data.metadata.colors.primary }}
|
||||
>
|
||||
{children}
|
||||
</h6>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(HeadingA);
|
||||
21
src/templates/blocks/Hobbies/HobbiesA.js
Normal file
21
src/templates/blocks/Hobbies/HobbiesA.js
Normal file
@ -0,0 +1,21 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const HobbyA = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<h6 className="font-semibold">{x.name}</h6>
|
||||
</div>
|
||||
);
|
||||
|
||||
const HobbiesA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.hobbies.visible && data.hobbies.items ? (
|
||||
<div>
|
||||
<Heading>{data.hobbies.heading}</Heading>
|
||||
{data.hobbies.items.map(HobbyA)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(HobbiesA);
|
||||
24
src/templates/blocks/Icons.js
Normal file
24
src/templates/blocks/Icons.js
Normal file
@ -0,0 +1,24 @@
|
||||
import {
|
||||
FaGlobeAmericas,
|
||||
FaFacebookF,
|
||||
FaTwitter,
|
||||
FaLinkedinIn,
|
||||
FaGithub,
|
||||
FaDribbble,
|
||||
FaInstagram,
|
||||
} from 'react-icons/fa';
|
||||
import { MdPhone, MdEmail } from 'react-icons/md';
|
||||
|
||||
const Icons = {
|
||||
phone: MdPhone,
|
||||
website: FaGlobeAmericas,
|
||||
email: MdEmail,
|
||||
facebook: FaFacebookF,
|
||||
twitter: FaTwitter,
|
||||
linkedin: FaLinkedinIn,
|
||||
github: FaGithub,
|
||||
dribbble: FaDribbble,
|
||||
instagram: FaInstagram,
|
||||
};
|
||||
|
||||
export default Icons;
|
||||
22
src/templates/blocks/Languages/LanguagesA.js
Normal file
22
src/templates/blocks/Languages/LanguagesA.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const LanguageItem = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<h6 className="font-semibold">{x.name}</h6>
|
||||
<p className="text-xs">{x.fluency}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const LanguagesA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.languages.visible && data.languages.items ? (
|
||||
<div>
|
||||
<Heading>{data.languages.heading}</Heading>
|
||||
{data.languages.items.map(LanguageItem)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(LanguagesA);
|
||||
16
src/templates/blocks/Objective/ObjectiveA.js
Normal file
16
src/templates/blocks/Objective/ObjectiveA.js
Normal file
@ -0,0 +1,16 @@
|
||||
import React, { useContext, memo } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const ObjectiveA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Heading>{data.objective.heading}</Heading>
|
||||
<ReactMarkdown className="text-sm" source={data.objective.body} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ObjectiveA);
|
||||
28
src/templates/blocks/References/ReferencesA.js
Normal file
28
src/templates/blocks/References/ReferencesA.js
Normal file
@ -0,0 +1,28 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const ReferenceItem = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<h6 className="font-semibold">{x.name}</h6>
|
||||
<p className="text-xs">{x.position}</p>
|
||||
<p className="text-xs">{x.phone}</p>
|
||||
<p className="text-xs">{x.email}</p>
|
||||
<ReactMarkdown className="mt-2 text-sm" source={x.summary} />
|
||||
</div>
|
||||
);
|
||||
|
||||
const ReferencesA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.references.visible && data.references.items ? (
|
||||
<div>
|
||||
<Heading>{data.references.heading}</Heading>
|
||||
<div className="grid grid-cols-3 col-gap-8">
|
||||
{data.references.items.map(ReferenceItem)}
|
||||
</div>
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(ReferencesA);
|
||||
22
src/templates/blocks/Skills/SkillsA.js
Normal file
22
src/templates/blocks/Skills/SkillsA.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React, { memo, useContext } from 'react';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
|
||||
const SkillItem = (x) => (
|
||||
<div key={x.id} className="mb-2">
|
||||
<h6 className="font-semibold">{x.name}</h6>
|
||||
<p className="text-xs">{x.level}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
const SkillsA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.skills.visible && data.skills.items ? (
|
||||
<div>
|
||||
<Heading>{data.skills.heading}</Heading>
|
||||
{data.skills.items.map(SkillItem)}
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(SkillsA);
|
||||
39
src/templates/blocks/Work/WorkA.js
Normal file
39
src/templates/blocks/Work/WorkA.js
Normal file
@ -0,0 +1,39 @@
|
||||
import React, { useContext, memo } from 'react';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import PageContext from '../../../contexts/PageContext';
|
||||
import { formatDateRange } from '../../../utils';
|
||||
|
||||
const WorkItem = (x) => (
|
||||
<div key={x.id} className="mb-4 last:mb-0">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<h6 className="font-semibold">{x.company}</h6>
|
||||
<span className="text-xs">{x.position}</span>
|
||||
</div>
|
||||
<span className="text-xs font-medium">
|
||||
({formatDateRange({ startDate: x.startDate, endDate: x.endDate })})
|
||||
</span>
|
||||
</div>
|
||||
<ReactMarkdown className="mt-2 text-sm" source={x.summary} />
|
||||
{x.highlights && (
|
||||
<ul className="mt-2 text-sm list-disc list-inside">
|
||||
{x.highlights.map((y) => (
|
||||
<li key={y}>{y}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const WorkA = () => {
|
||||
const { data, heading: Heading } = useContext(PageContext);
|
||||
|
||||
return data.work.visible && data.work.items ? (
|
||||
<div>
|
||||
<Heading>{data.work.heading}</Heading>
|
||||
<div>{data.work.items.map(WorkItem)}</div>
|
||||
</div>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export default memo(WorkA);
|
||||
@ -20,9 +20,9 @@ export const isFileImage = (file) => {
|
||||
return file && acceptedImageTypes.includes(file.type);
|
||||
};
|
||||
|
||||
export const formatDateRange = (x) =>
|
||||
`${moment(x.startDate).format('MMMM Y')} — ${
|
||||
moment(x.endDate).isValid() ? moment(x.endDate).format('MMMM Y') : 'Present'
|
||||
export const formatDateRange = ({ startDate, endDate }) =>
|
||||
`${moment(startDate).format('MMMM Y')} — ${
|
||||
moment(endDate).isValid() ? moment(endDate).format('MMMM Y') : 'Present'
|
||||
}`;
|
||||
|
||||
export const getFieldProps = (formik, schema, name) => ({
|
||||
|
||||
Reference in New Issue
Block a user