- implement about section

This commit is contained in:
Amruth Pillai
2020-07-14 22:59:59 +05:30
parent af955bbf55
commit b7c565de79
20 changed files with 441 additions and 112 deletions

View File

@ -13,6 +13,7 @@ import { StorageProvider } from './src/contexts/StorageContext';
import { ThemeProvider } from './src/contexts/ThemeContext'; import { ThemeProvider } from './src/contexts/ThemeContext';
import { UserProvider } from './src/contexts/UserContext'; import { UserProvider } from './src/contexts/UserContext';
import './src/styles/global.css'; import './src/styles/global.css';
import './src/styles/forms.css';
import './src/styles/shadows.css'; import './src/styles/shadows.css';
import './src/styles/tailwind.css'; import './src/styles/tailwind.css';
import './src/styles/toastify.css'; import './src/styles/toastify.css';

14
package-lock.json generated
View File

@ -18567,6 +18567,20 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"typeit": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/typeit/-/typeit-7.0.4.tgz",
"integrity": "sha512-ETiVr3s4XOXUE9W+tVhF3gxGTf5z4tc35YjvWEQhqKsJhXWvpQlt/D/ZvIHkZzHegU3stxagjeG2pfm1/AWsYQ=="
},
"typeit-react": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/typeit-react/-/typeit-react-0.1.3.tgz",
"integrity": "sha512-9HiAghnq8NjLj67dakc9C4eCHyunsCgl7ZSo04w/7YWAjs12bHb/+J3geFfTgBVpbWCL6GPDZ7eWBXNZ3ZweGw==",
"requires": {
"@types/react": "^16.9.19",
"typeit": "^7.0.3"
}
},
"unbzip2-stream": { "unbzip2-stream": {
"version": "1.4.3", "version": "1.4.3",
"resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",

View File

@ -52,6 +52,7 @@
"react-scroll": "^1.8.0", "react-scroll": "^1.8.0",
"react-toastify": "^6.0.8", "react-toastify": "^6.0.8",
"short-unique-id": "^3.0.3", "short-unique-id": "^3.0.3",
"typeit-react": "^0.1.3",
"uuid": "^8.2.0", "uuid": "^8.2.0",
"yup": "^0.29.1" "yup": "^0.29.1"
}, },

View File

@ -1,5 +1,6 @@
import React, { memo } from 'react'; import React, { memo } from 'react';
import { FaCoffee } from 'react-icons/fa'; import { FaCoffee, FaBug } from 'react-icons/fa';
import { MdCode } from 'react-icons/md';
import Button from '../../../shared/Button'; import Button from '../../../shared/Button';
import Heading from '../../../shared/Heading'; import Heading from '../../../shared/Heading';
import styles from './About.module.css'; import styles from './About.module.css';
@ -37,6 +38,75 @@ const About = () => {
</a> </a>
</div> </div>
</div> </div>
<div className={styles.container}>
<h5>Bug? Feature Request?</h5>
<p className="leading-loose">
Something halting your progress from making a resume? Found a pesky
bug that just won&apos;t quit? Talk about it on the GitHub Issues
section, or send me and email using the actions below.
</p>
<div className="mt-4 flex">
<a
href="https://github.com/AmruthPillai/Reactive-Resume/issues/new"
rel="noreferrer"
target="_blank"
>
<Button icon={FaBug}>Raise an Issue</Button>
</a>
</div>
</div>
<div className={styles.container}>
<h5>Source Code</h5>
<p className="leading-loose">
Want to run the project from its source? Are you a developer willing
to contribute to the open-source development of this project? Click
the button below.
</p>
<div className="mt-4 flex">
<a
href="https://github.com/AmruthPillai/Reactive-Resume"
rel="noreferrer"
target="_blank"
>
<Button icon={MdCode}>GitHub Repo</Button>
</a>
</div>
</div>
<div className={styles.container}>
<h5>License Information</h5>
<p className="leading-loose">
The project is governed under the MIT License, which you can read more
about below. Basically, you are allowed to use the project anywhere
provided you give credits to the original author.
</p>
<div className="mt-4 flex">
<a
href="https://github.com/AmruthPillai/Reactive-Resume/blob/master/LICENSE"
rel="noreferrer"
target="_blank"
>
<Button icon={MdCode}>MIT License</Button>
</a>
</div>
</div>
<div className="my-4 text-center opacity-50 text-sm">
<p>
Made with Love by{' '}
<a href="https://amruthpillai.com" rel="noreferrer" target="_blank">
Amruth Pillai
</a>
</p>
</div>
</section> </section>
); );
}; };

View File

@ -1,4 +1,5 @@
import React, { memo, useContext, useState } from 'react'; import React, { memo, useContext, useState } from 'react';
import { FaAngleDown } from 'react-icons/fa';
import UserContext from '../../../../contexts/UserContext'; import UserContext from '../../../../contexts/UserContext';
import Button from '../../../shared/Button'; import Button from '../../../shared/Button';
import Heading from '../../../shared/Heading'; import Heading from '../../../shared/Heading';
@ -6,6 +7,7 @@ import styles from './Settings.module.css';
import Input from '../../../shared/Input'; import Input from '../../../shared/Input';
import ThemeContext from '../../../../contexts/ThemeContext'; import ThemeContext from '../../../../contexts/ThemeContext';
import themeConfig from '../../../../data/themeConfig'; import themeConfig from '../../../../data/themeConfig';
import languageConfig from '../../../../data/languageConfig';
const Settings = () => { const Settings = () => {
const [deleteText, setDeleteText] = useState('Delete Account'); const [deleteText, setDeleteText] = useState('Delete Account');
@ -16,6 +18,10 @@ const Settings = () => {
setTheme(e.target.value); setTheme(e.target.value);
}; };
const handleChangeLanguage = (e) => {
console.log(e.target.value);
};
const handleDeleteAccount = () => { const handleDeleteAccount = () => {
if (deleteText === 'Delete Account') { if (deleteText === 'Delete Account') {
setDeleteText('Are you sure?'); setDeleteText('Are you sure?');
@ -40,6 +46,37 @@ const Settings = () => {
onChange={handleChangeTheme} onChange={handleChangeTheme}
/> />
<label>
<span>Language</span>
<div className="relative grid items-center">
<select onChange={handleChangeLanguage}>
{languageConfig.map((x) => (
<option key={x.key} value={x.key}>
{x.name}
</option>
))}
</select>
<FaAngleDown
size="16px"
className="absolute right-0 opacity-50 hover:opacity-75 mx-4"
/>
</div>
</label>
<p className="text-sm leading-loose">
If you would like to contribute by providing translations to Reactive
Resume in your language,{' '}
<a
href="https://github.com/AmruthPillai/Reactive-Resume/blob/master/TRANSLATING.md"
rel="noreferrer"
target="_blank"
>
please visit this link
</a>
.
</p>
<div className={styles.container}> <div className={styles.container}>
<h5>Danger Zone</h5> <h5>Danger Zone</h5>

View File

@ -1,5 +1,7 @@
import { navigate } from 'gatsby'; import { navigate } from 'gatsby';
import TypeIt from 'typeit-react';
import React, { memo, useContext } from 'react'; import React, { memo, useContext } from 'react';
import { FaGithub } from 'react-icons/fa';
import ModalContext from '../../contexts/ModalContext'; import ModalContext from '../../contexts/ModalContext';
import UserContext from '../../contexts/UserContext'; import UserContext from '../../contexts/UserContext';
import Button from '../shared/Button'; import Button from '../shared/Button';
@ -18,7 +20,21 @@ const Hero = () => {
<Logo className="shadow-lg" size="256px" /> <Logo className="shadow-lg" size="256px" />
<div className="ml-12"> <div className="ml-12">
<h1 className="text-5xl font-bold">Reactive Resume</h1> <h1 className="sr-only">Reactive Resume</h1>
<div className="text-5xl font-bold">
<TypeIt
getBeforeInit={(instance) => {
return instance
.type('Creative Resume')
.pause(500)
.move(-11)
.delete(4)
.pause(250)
.type('Reac')
.move('END');
}}
/>
</div>
<h2 className="mt-1 text-3xl text-primary-500"> <h2 className="mt-1 text-3xl text-primary-500">
A free and open-source resume builder. A free and open-source resume builder.
</h2> </h2>
@ -33,6 +49,16 @@ const Hero = () => {
Login Login
</Button> </Button>
)} )}
<a
href="https://github.com/AmruthPillai/Reactive-Resume"
rel="noreferrer"
target="_blank"
>
<Button outline icon={FaGithub} className="ml-8">
Source Code
</Button>
</a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -18,7 +18,9 @@ const Avatar = ({ className }) => {
handleClose(); handleClose();
}; };
const photoURL = useMemo(() => toUrl(user.email, 'size=128'), [user.email]); const photoURL = useMemo(() => toUrl(user.email || '', 'size=128&d=retro'), [
user.email,
]);
return ( return (
<div> <div>
@ -31,7 +33,7 @@ const Avatar = ({ className }) => {
> >
<img <img
src={photoURL} src={photoURL}
alt={user.displayName} alt={user.displayName || 'Anonymous User'}
className={cx(styles.container, className)} className={cx(styles.container, className)}
/> />
</div> </div>

View File

@ -46,7 +46,7 @@ const Input = ({
}; };
return ( return (
<div className={cx(styles.container, className)}> <div className={className}>
<label htmlFor={uuid}> <label htmlFor={uuid}>
<span> <span>
{label}{' '} {label}{' '}
@ -115,7 +115,9 @@ const Input = ({
onChange={onChange} onChange={onChange}
> >
{options.map((x) => ( {options.map((x) => (
<option key={x}>{x}</option> <option key={x} value={x}>
{x}
</option>
))} ))}
</select> </select>

View File

@ -1,31 +1,3 @@
.container label input,
.container label textarea,
.container label select {
@apply w-full py-3 px-4 rounded text-primary-900 bg-primary-200 border border-transparent appearance-none;
}
.container label input::placeholder,
.container label textarea::placeholder,
.container label select::placeholder {
@apply opacity-50;
}
.container label input:hover,
.container label textarea:hover,
.container label select:hover {
@apply outline-none border-primary-400;
}
.container label input:focus,
.container label textarea:focus,
.container label select:focus {
@apply outline-none border-primary-600;
}
.container label > p {
@apply mt-1 text-red-600 text-xs;
}
.circle { .circle {
left: 14px; left: 14px;
@apply absolute bg-primary-900 rounded-full w-6 h-6; @apply absolute bg-primary-900 rounded-full w-6 h-6;

View File

@ -17,6 +17,7 @@ const defaultState = {
user: defaultUser, user: defaultUser,
logout: async () => {}, logout: async () => {},
loginWithGoogle: async () => {}, loginWithGoogle: async () => {},
loginAnonymously: async () => {},
deleteAccount: async () => {}, deleteAccount: async () => {},
}; };
@ -57,6 +58,14 @@ const UserProvider = ({ children }) => {
} }
}; };
const loginAnonymously = async () => {
try {
return await firebase.auth().signInAnonymously();
} catch (error) {
toast.error(error.message);
}
};
const logout = () => { const logout = () => {
firebase.auth().signOut(); firebase.auth().signOut();
localStorage.removeItem('user'); localStorage.removeItem('user');
@ -87,6 +96,7 @@ const UserProvider = ({ children }) => {
logout, logout,
loading, loading,
loginWithGoogle, loginWithGoogle,
loginAnonymously,
deleteAccount, deleteAccount,
}} }}
> >

View File

@ -17,11 +17,11 @@
"title": "Venturesity Banyan Hack" "title": "Venturesity Banyan Hack"
}, },
{ {
"title": "Smart India Hackathon",
"awarder": "Govt. of India", "awarder": "Govt. of India",
"date": "2017-04-01", "date": "2017-04-01",
"id": "89c0171a-eae9-403e-9f4c-a757fb535c2b",
"summary": "", "summary": "",
"id": "89c0171a-eae9-403e-9f4c-a757fb535c2b" "title": "Smart India Hackathon"
} }
], ],
"visible": true "visible": true
@ -44,11 +44,11 @@
"title": "VCP6-DCV" "title": "VCP6-DCV"
}, },
{ {
"title": "DCUCI 642-999",
"issuer": "Cisco Systems",
"date": "2014-04-01", "date": "2014-04-01",
"id": "11107df6-5f3c-49ae-bcd4-62b8baa181a1",
"issuer": "Cisco Systems",
"summary": "", "summary": "",
"id": "11107df6-5f3c-49ae-bcd4-62b8baa181a1" "title": "DCUCI 642-999"
} }
], ],
"visible": true "visible": true
@ -82,8 +82,8 @@
"hobbies": { "hobbies": {
"heading": "Hobbies", "heading": "Hobbies",
"items": [ "items": [
{ "name": "Poetry", "id": "788dcf5a-78ca-4866-8397-c7a29073d9a1" }, { "id": "788dcf5a-78ca-4866-8397-c7a29073d9a1", "name": "Poetry" },
{ "name": "Travelling", "id": "e3523371-f50c-4348-8c5e-35fe84c0006d" }, { "id": "e3523371-f50c-4348-8c5e-35fe84c0006d", "name": "Travelling" },
{ "id": "92c35e3b-6cd7-4cea-b505-61347ec61b68", "name": "Photography" }, { "id": "92c35e3b-6cd7-4cea-b505-61347ec61b68", "name": "Photography" },
{ {
"id": "d36f2089-93a9-4f30-a425-3dd81c6b89df", "id": "d36f2089-93a9-4f30-a425-3dd81c6b89df",
@ -130,6 +130,31 @@
}, },
"font": "Open Sans", "font": "Open Sans",
"layout": { "layout": {
"castform": [
["awards", "certifications", "languages", "hobbies"],
["objective", "work", "education", "skills", "projects", "references"]
],
"celebi": [
["awards", "certifications", "languages", "hobbies"],
["objective", "work", "education", "skills", "projects", "references"]
],
"gengar": [
["objective", "skills"],
["awards", "certifications", "languages", "references", "hobbies"],
["work", "education", "projects"]
],
"glalie": [
["awards", "certifications", "hobbies"],
[
"objective",
"work",
"education",
"skills",
"projects",
"languages",
"references"
]
],
"onyx": [ "onyx": [
["objective", "work", "education", "projects"], ["objective", "work", "education", "projects"],
["hobbies", "languages", "awards", "certifications"], ["hobbies", "languages", "awards", "certifications"],
@ -138,26 +163,9 @@
"pikachu": [ "pikachu": [
["skills", "languages", "hobbies", "awards", "certifications"], ["skills", "languages", "hobbies", "awards", "certifications"],
["work", "education", "projects", "references"] ["work", "education", "projects", "references"]
],
"gengar": [
["objective", "skills"],
["awards", "certifications", "languages", "references", "hobbies"],
["work", "education", "projects"]
],
"castform": [
["awards", "certifications", "languages", "hobbies"],
["objective", "work", "education", "skills", "projects", "references"]
],
"glalie": [
["awards", "certifications", "hobbies"],
["objective", "work", "education", "skills", "projects", "languages", "references"]
],
"celebi": [
["awards", "certifications", "languages", "hobbies"],
["objective", "work", "education", "skills", "projects", "references"]
] ]
}, },
"template": "pikachu" "template": "castform"
}, },
"objective": { "objective": {
"body": "To obtain a job within my chosen field that will challenge me and allow me to use my education, skills and past experiences in a way that is mutually beneficial to both myself and my employer and allow for future growth and advancement.", "body": "To obtain a job within my chosen field that will challenge me and allow me to use my education, skills and past experiences in a way that is mutually beneficial to both myself and my employer and allow for future growth and advancement.",
@ -222,12 +230,12 @@
"summary": "" "summary": ""
}, },
{ {
"name": "Lorraine Beasley",
"position": "Head of HR, Carson Logistics",
"phone": "+1 661-808-4188",
"email": "l.beasley@carsonlogistics.com", "email": "l.beasley@carsonlogistics.com",
"summary": "", "id": "94e3447b-0a78-4fb7-b14d-591982d35320",
"id": "94e3447b-0a78-4fb7-b14d-591982d35320" "name": "Lorraine Beasley",
"phone": "+1 661-808-4188",
"position": "Head of HR, Carson Logistics",
"summary": ""
} }
], ],
"visible": true "visible": true
@ -256,14 +264,14 @@
"name": "Call Center Management" "name": "Call Center Management"
}, },
{ {
"name": "Teambuilding & Training", "id": "08d6c739-1465-41f7-8825-b8d94faa38d6",
"level": "Novice", "level": "Novice",
"id": "08d6c739-1465-41f7-8825-b8d94faa38d6" "name": "Teambuilding & Training"
}, },
{ {
"name": "Continuous Improvement", "id": "261b8fc3-aeec-4347-88a8-bcacb1a17aa3",
"level": "Fundamental Awareness", "level": "Fundamental Awareness",
"id": "261b8fc3-aeec-4347-88a8-bcacb1a17aa3" "name": "Continuous Improvement"
} }
], ],
"visible": true "visible": true
@ -272,10 +280,10 @@
"heading": "Social", "heading": "Social",
"items": [ "items": [
{ {
"url": "https://pillai.xyz/instagram", "id": "a832b37d-f11d-4a80-8b4d-24796e571b17",
"network": "Instagram", "network": "Instagram",
"username": "AmruthPillai", "url": "https://pillai.xyz/instagram",
"id": "a832b37d-f11d-4a80-8b4d-24796e571b17" "username": "AmruthPillai"
}, },
{ {
"id": "a72107fa-a4a5-407d-9e85-39bdb9c0b11a", "id": "a72107fa-a4a5-407d-9e85-39bdb9c0b11a",
@ -315,12 +323,12 @@
}, },
{ {
"company": "Pizza Hut, Newark, NJ", "company": "Pizza Hut, Newark, NJ",
"position": "Waiter",
"website": "https://pizzahut.com",
"startDate": "2005-08-01",
"endDate": "2009-09-01", "endDate": "2009-09-01",
"id": "dd935088-6fe7-4a4b-8ff5-7417c32d2add",
"position": "Waiter",
"startDate": "2005-08-01",
"summary": "- Worked passionately in customer service in a high volume restaurant.\n- Completed the FAST customer service training class.\n- Maintained a high tip average thanks to consistent customer satisfaction.", "summary": "- Worked passionately in customer service in a high volume restaurant.\n- Completed the FAST customer service training class.\n- Maintained a high tip average thanks to consistent customer satisfaction.",
"id": "dd935088-6fe7-4a4b-8ff5-7417c32d2add" "website": "https://pizzahut.com"
} }
], ],
"visible": true "visible": true

View File

@ -0,0 +1,8 @@
const languageConfig = [
{
key: 'en',
name: 'English',
},
];
export default languageConfig;

View File

@ -7,10 +7,13 @@ import BaseModal from './BaseModal';
const AuthModal = () => { const AuthModal = () => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [isLoading, setLoading] = useState(false); const [isLoadingGoogle, setLoadingGoogle] = useState(false);
const [isLoadingAnonymous, setLoadingAnonymous] = useState(false);
const { emitter, events } = useContext(ModalContext); const { emitter, events } = useContext(ModalContext);
const { user, loginWithGoogle, logout } = useContext(UserContext); const { user, loginWithGoogle, loginAnonymously, logout } = useContext(
UserContext,
);
useEffect(() => { useEffect(() => {
const unbind = emitter.on(events.AUTH_MODAL, () => setOpen(true)); const unbind = emitter.on(events.AUTH_MODAL, () => setOpen(true));
@ -19,9 +22,15 @@ const AuthModal = () => {
}, [emitter, events]); }, [emitter, events]);
const handleSignInWithGoogle = async () => { const handleSignInWithGoogle = async () => {
setLoading(true); setLoadingGoogle(true);
await loginWithGoogle(); await loginWithGoogle();
setLoading(false); setLoadingGoogle(false);
};
const handleSignInAnonymously = async () => {
setLoadingAnonymous(true);
await loginAnonymously();
setLoadingAnonymous(false);
}; };
const handleGotoApp = () => { const handleGotoApp = () => {
@ -30,7 +39,7 @@ const AuthModal = () => {
}; };
const getTitle = () => const getTitle = () =>
user ? `Welcome, ${user.displayName}` : 'Who are you?'; user ? `Welcome, ${user.displayName || 'Agent 47'}` : 'Who are you?';
const getMessage = () => const getMessage = () =>
user user
@ -49,9 +58,18 @@ const AuthModal = () => {
); );
const loggedOutAction = ( const loggedOutAction = (
<Button isLoading={isLoading} onClick={handleSignInWithGoogle}> <div className="flex">
<Button isLoading={isLoadingGoogle} onClick={handleSignInWithGoogle}>
Sign in with Google Sign in with Google
</Button> </Button>
<Button
className="ml-8"
isLoading={isLoadingAnonymous}
onClick={handleSignInAnonymously}
>
Sign in Anonymously
</Button>
</div>
); );
return ( return (

View File

@ -7,12 +7,17 @@ import RightSidebar from '../../components/builder/right/RightSidebar';
import LoadingScreen from '../../components/router/LoadingScreen'; import LoadingScreen from '../../components/router/LoadingScreen';
import DatabaseContext from '../../contexts/DatabaseContext'; import DatabaseContext from '../../contexts/DatabaseContext';
import { useDispatch } from '../../contexts/ResumeContext'; import { useDispatch } from '../../contexts/ResumeContext';
import Button from '../../components/shared/Button';
const Builder = ({ id }) => { const Builder = ({ id }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const { getResume } = useContext(DatabaseContext); const { getResume } = useContext(DatabaseContext);
const handleLoadDemoData = () => {
dispatch({ type: 'load_demo_data' });
};
useEffect(() => { useEffect(() => {
(async () => { (async () => {
const resume = await getResume(id); const resume = await getResume(id);
@ -25,6 +30,21 @@ const Builder = ({ id }) => {
return null; return null;
} }
if (resume.createdAt === resume.updatedAt) {
toast.dark(() => (
<div className="py-2">
<p className="leading-loose">
Not sure where to begin? Try <strong>Loading Demo Data</strong> to
see what Reactive Resume has to offer.
</p>
<Button className="mt-4" onClick={handleLoadDemoData}>
Load Demo Data
</Button>
</div>
));
}
dispatch({ type: 'set_data', payload: resume }); dispatch({ type: 'set_data', payload: resume });
return setLoading(false); return setLoading(false);
})(); })();

89
src/pages/faq.js Normal file
View File

@ -0,0 +1,89 @@
import React from 'react';
import { MdKeyboardArrowLeft } from 'react-icons/md';
import { Link } from '@reach/router';
import Wrapper from '../components/shared/Wrapper';
const FrequentlyAskedQuestions = () => {
return (
<Wrapper>
<div className="md:w-1/2 container px-8 md:px-0 py-16 grid gap-12">
<div className="flex items-center">
<Link to="/">
<MdKeyboardArrowLeft size="32px" />
</Link>
<h1 className="ml-6 text-4xl font-semibold">
Frequently Asked Questions
</h1>
</div>
<div>
<p className="leading-loose">
This is aimed to be the world&apos;s simplest privacy policy. This
document should explain to you why the app collects some
information, what happens when your account is deleted and some
other frequently asked questions answered regarding your privacy.
</p>
<p className="mt-6 leading-loose">
If you have any more questions, please raise an issue regarding the
same on GitHub and I&apos;ll answer as honest and quickly as
possible :)
</p>
</div>
<hr />
<div>
<h4 className="text-xl font-medium mb-4">
What identifiable information is stored about me?
</h4>
<p className="leading-loose">
Your name and your email address is stored along with your user
information, if you signed in with Google, and of course, all the
information you input in your resume is also stored in the database.
</p>
</div>
<hr />
<div>
<h4 className="text-xl font-medium mb-4">
Why are you using a database, why not keep everything local like in
the first version of Reactive Resume?
</h4>
<p className="leading-loose">
Not having a centralized database cause a lot more problems than I
could solve, mainly having a large chunk of the users of the app
having an outdated schema as the app evolved. This was a problem I
could not solve without having at least some control.
</p>
<p className="mt-6 leading-loose">
Also, a lot of users were having trouble printing their resumes on
their browsers, so with the help of Cloud Functions from Firebase,
you can now print your resumes remotely. None of the resumes are
stored, and they are sent to you immediately after generation, which
can be verified by looking through the source code.
</p>
</div>
<hr />
<div>
<h4 className="text-xl font-medium mb-4">
How is this all free? There must be a catch!
</h4>
<p className="leading-loose">
<strong>Absolutely no catch to this freebie.</strong> This project
is just my way of giving back to the community that I&apos;ve
learned so much from. If you&apos;d like to show your appreciation
however, you can follow me on my social media and let me know, or
donate to the app to help pay the cloud bills.
</p>
</div>
</div>
</Wrapper>
);
};
export default FrequentlyAskedQuestions;

View File

@ -1,5 +1,6 @@
import React, { memo } from 'react'; import React, { memo } from 'react';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { Link } from '@reach/router';
import Hero from '../components/landing/Hero'; import Hero from '../components/landing/Hero';
import Wrapper from '../components/shared/Wrapper'; import Wrapper from '../components/shared/Wrapper';
@ -14,6 +15,10 @@ const Home = () => {
<div className="container mt-24"> <div className="container mt-24">
<Hero /> <Hero />
<div className="my-24">
<h4 className="text-xl uppercase font-bold mb-8">Screenshots</h4>
</div>
<div className="pt-8"> <div className="pt-8">
<Feature title="Create a resume thats worthy of who you are."> <Feature title="Create a resume thats worthy of who you are.">
Keep up with the latest trends in resume design without having to Keep up with the latest trends in resume design without having to
@ -51,12 +56,27 @@ const Home = () => {
You must be thinking, if you&apos;re not paying for the product, You must be thinking, if you&apos;re not paying for the product,
then you are the product. Or, at least your data is?{' '} then you are the product. Or, at least your data is?{' '}
<strong>Well, this is the exception</strong>. Your data is your own, <strong>Well, this is the exception</strong>. Your data is your own,
as stated in the ridiculously simple <a href="">Privacy Policy</a>, as stated in the ridiculously simple{' '}
I don&apos;t do anything with the data, it just exists on a database <Link to="/faq">Privacy Policy</Link>, I don&apos;t do anything with
for the convinient features provided by Reactive Resume. the data, it just exists on a database for the convinient features
provided by Reactive Resume.
</Feature> </Feature>
</div> </div>
<div className="my-24">
<h4 className="text-xl uppercase font-bold mb-8">
Links of Interest
</h4>
<div className="grid grid-cols-4 gap-8">
<Link to="/faq">Frequently Asked Questions</Link>
<Link to="/faq">Checkout Source Code</Link>
<Link to="/faq">Upvote on Product Hunt</Link>
<Link to="/faq">Raise an Issue on GitHub</Link>
<Link to="/faq">Donate to Reactive Resume</Link>
<Link to="/faq">Building Great Looking Resumes</Link>
</div>
</div>
<footer className="my-24"> <footer className="my-24">
<p className="text-primary-500 opacity-75"> <p className="text-primary-500 opacity-75">
Licensed under <a href="/">MIT</a> Licensed under <a href="/">MIT</a>

35
src/styles/forms.css Normal file
View File

@ -0,0 +1,35 @@
label {
@apply flex flex-col;
}
label > span:first-child {
@apply mb-1 text-primary-600 font-semibold tracking-wide text-xs uppercase;
}
label > p {
@apply mt-1 text-red-600 text-xs;
}
label input,
label textarea,
label select {
@apply w-full py-3 px-4 rounded text-primary-900 bg-primary-200 border border-transparent appearance-none;
}
label input::placeholder,
label textarea::placeholder,
label select::placeholder {
@apply opacity-50;
}
label input:hover,
label textarea:hover,
label select:hover {
@apply outline-none border-primary-400;
}
label input:focus,
label textarea:focus,
label select:focus {
@apply outline-none border-primary-600;
}

View File

@ -26,14 +26,6 @@ section {
@apply grid grid-cols-1 gap-8; @apply grid grid-cols-1 gap-8;
} }
label {
@apply flex flex-col;
}
label > span:first-child {
@apply mb-1 text-primary-600 font-semibold tracking-wide text-xs uppercase;
}
.MuiTooltip-tooltip { .MuiTooltip-tooltip {
font-size: 10px; font-size: 10px;
} }

View File

@ -22,6 +22,7 @@ const ContactC = () => {
return ( return (
<div className="text-xs grid gap-2"> <div className="text-xs grid gap-2">
{data.profile.address.line1 && (
<div> <div>
<h6 className="capitalize font-semibold">Address</h6> <h6 className="capitalize font-semibold">Address</h6>
<div className="flex flex-col text-xs"> <div className="flex flex-col text-xs">
@ -32,6 +33,7 @@ const ContactC = () => {
</span> </span>
</div> </div>
</div> </div>
)}
<ContactItem <ContactItem
label="phone" label="phone"

View File

@ -40,6 +40,7 @@ const ContactD = () => {
<MdFlare size="20px" /> <MdFlare size="20px" />
</div> </div>
{data.profile.address.line1 && (
<div> <div>
<h6 className="capitalize font-semibold">Address</h6> <h6 className="capitalize font-semibold">Address</h6>
<div className="flex flex-col text-xs"> <div className="flex flex-col text-xs">
@ -50,6 +51,7 @@ const ContactD = () => {
</span> </span>
</div> </div>
</div> </div>
)}
<ContactItem <ContactItem
label="phone" label="phone"