mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-17 18:21:28 +10:00
feat: adding a toggle switch for left panel items
This commit is contained in:
@ -4,6 +4,7 @@ import { Draggable } from 'react-beautiful-dnd';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
|
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
|
||||||
import { MdMoreVert } from 'react-icons/md';
|
import { MdMoreVert } from 'react-icons/md';
|
||||||
|
import Switch from '@material-ui/core/Switch';
|
||||||
import { useDispatch } from '../../../contexts/ResumeContext';
|
import { useDispatch } from '../../../contexts/ResumeContext';
|
||||||
import styles from './ListItem.module.css';
|
import styles from './ListItem.module.css';
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ const ListItem = ({
|
|||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
|
|
||||||
const handleClick = (event) => setAnchorEl(event.currentTarget);
|
const handleClick = (event) => setAnchorEl(event.currentTarget);
|
||||||
|
const toggleSwitchState = 'isVisible' in data ? data.isVisible : true;
|
||||||
|
|
||||||
const handleClose = () => setAnchorEl(null);
|
const handleClose = () => setAnchorEl(null);
|
||||||
|
|
||||||
@ -69,6 +71,16 @@ const ListItem = ({
|
|||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggleUse = () => {
|
||||||
|
dispatch({
|
||||||
|
type: 'on_toggle_use_item',
|
||||||
|
payload: {
|
||||||
|
path,
|
||||||
|
value: data,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Draggable draggableId={data.id} index={index}>
|
<Draggable draggableId={data.id} index={index}>
|
||||||
{(dragProvided) => (
|
{(dragProvided) => (
|
||||||
@ -94,6 +106,15 @@ const ListItem = ({
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className={styles.toggleButton}>
|
||||||
|
<Switch
|
||||||
|
checked={toggleSwitchState}
|
||||||
|
onChange={handleToggleUse}
|
||||||
|
color="primary"
|
||||||
|
name="toggleSwitch"
|
||||||
|
className="toggle-button"
|
||||||
|
inputProps={{ 'aria-label': 'primary checkbox' }}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className={styles.menu}>
|
<div className={styles.menu}>
|
||||||
<MdMoreVert
|
<MdMoreVert
|
||||||
@ -127,6 +148,7 @@ const ListItem = ({
|
|||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</Draggable>
|
</Draggable>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -15,3 +15,7 @@
|
|||||||
@apply opacity-100;
|
@apply opacity-100;
|
||||||
@apply transition-opacity duration-200 ease-in-out;
|
@apply transition-opacity duration-200 ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toggle-button {
|
||||||
|
@apply flex items-center justify-center
|
||||||
|
}
|
||||||
@ -68,6 +68,18 @@ const ResumeProvider = ({ children }) => {
|
|||||||
debouncedUpdateResume(newState);
|
debouncedUpdateResume(newState);
|
||||||
return newState;
|
return newState;
|
||||||
|
|
||||||
|
case 'on_toggle_use_item':
|
||||||
|
items = get(state, payload.path);
|
||||||
|
index = findIndex(items, ['id', payload.value.id]);
|
||||||
|
if ('isVisible' in items[index]) {
|
||||||
|
items[index].isVisible = !items[index].isVisible;
|
||||||
|
} else {
|
||||||
|
items[index].isVisible = false;
|
||||||
|
}
|
||||||
|
newState = setWith(clone(state), payload.path, items, clone);
|
||||||
|
debouncedUpdateResume(newState);
|
||||||
|
return newState;
|
||||||
|
|
||||||
case 'on_move_item_up':
|
case 'on_move_item_up':
|
||||||
items = get(state, payload.path);
|
items = get(state, payload.path);
|
||||||
index = findIndex(items, ['id', payload.value.id]);
|
index = findIndex(items, ['id', payload.value.id]);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { formatDate, safetyCheck } from '../../../utils';
|
import { formatDate, safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const AwardItem = ({ item, language }) => (
|
const AwardItem = ({ item, language }) => (
|
||||||
<div>
|
<div>
|
||||||
@ -29,9 +29,16 @@ const AwardsA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.awards.heading}</Heading>
|
<Heading>{data.awards.heading}</Heading>
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{data.awards.items.map((x) => (
|
{data.awards.items.map(
|
||||||
<AwardItem key={x.id} item={x} language={data.metadata.language} />
|
(x) =>
|
||||||
))}
|
isItemVisible(x) && (
|
||||||
|
<AwardItem
|
||||||
|
key={x.id}
|
||||||
|
item={x}
|
||||||
|
language={data.metadata.language}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { formatDate, safetyCheck } from '../../../utils';
|
import { formatDate, safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const CertificationItem = ({ item, language }) => (
|
const CertificationItem = ({ item, language }) => (
|
||||||
<div>
|
<div>
|
||||||
@ -29,13 +29,16 @@ const CertificationsA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.certifications.heading}</Heading>
|
<Heading>{data.certifications.heading}</Heading>
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{data.certifications.items.map((x) => (
|
{data.certifications.items.map(
|
||||||
|
(x) =>
|
||||||
|
isItemVisible(x) && (
|
||||||
<CertificationItem
|
<CertificationItem
|
||||||
key={x.id}
|
key={x.id}
|
||||||
item={x}
|
item={x}
|
||||||
language={data.metadata.language}
|
language={data.metadata.language}
|
||||||
/>
|
/>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React, { memo, useContext } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { formatDateRange, safetyCheck } from '../../../utils';
|
import { formatDateRange, safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const EducationItem = ({ item, language }) => {
|
const EducationItem = ({ item, language }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -50,13 +50,16 @@ const EducationA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.education.heading}</Heading>
|
<Heading>{data.education.heading}</Heading>
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{data.education.items.map((x) => (
|
{data.education.items.map(
|
||||||
|
(x) =>
|
||||||
|
isItemVisible(x) && (
|
||||||
<EducationItem
|
<EducationItem
|
||||||
key={x.id}
|
key={x.id}
|
||||||
item={x}
|
item={x}
|
||||||
language={data.metadata.language}
|
language={data.metadata.language}
|
||||||
/>
|
/>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const HobbyA = (x) => (
|
const HobbyA = (x) => (
|
||||||
<div key={x.id}>
|
<div key={x.id}>
|
||||||
@ -14,7 +14,9 @@ const HobbiesA = () => {
|
|||||||
return safetyCheck(data.hobbies) ? (
|
return safetyCheck(data.hobbies) ? (
|
||||||
<div>
|
<div>
|
||||||
<Heading>{data.hobbies.heading}</Heading>
|
<Heading>{data.hobbies.heading}</Heading>
|
||||||
<div className="grid gap-2">{data.hobbies.items.map(HobbyA)}</div>
|
<div className="grid gap-2">
|
||||||
|
{data.hobbies.items.map((x) => isItemVisible(x) && HobbyA(x))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const LanguageItem = (x) => (
|
const LanguageItem = (x) => (
|
||||||
<div key={x.id} className="flex flex-col">
|
<div key={x.id} className="flex flex-col">
|
||||||
@ -16,7 +16,7 @@ const LanguagesA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.languages.heading}</Heading>
|
<Heading>{data.languages.heading}</Heading>
|
||||||
<div className="grid grid-cols-2 gap-2">
|
<div className="grid grid-cols-2 gap-2">
|
||||||
{data.languages.items.map(LanguageItem)}
|
{data.languages.items.map((x) => isItemVisible(x) && LanguageItem(x))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const LanguageItem = (x) => (
|
const LanguageItem = (x) => (
|
||||||
<div key={x.id} className="flex flex-col">
|
<div key={x.id} className="flex flex-col">
|
||||||
@ -15,7 +15,9 @@ const LanguagesB = () => {
|
|||||||
return safetyCheck(data.languages) ? (
|
return safetyCheck(data.languages) ? (
|
||||||
<div>
|
<div>
|
||||||
<Heading>{data.languages.heading}</Heading>
|
<Heading>{data.languages.heading}</Heading>
|
||||||
<div className="grid gap-2">{data.languages.items.map(LanguageItem)}</div>
|
<div className="grid gap-2">
|
||||||
|
{data.languages.items.map((x) => isItemVisible(x) && LanguageItem(x))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import React, { memo, useContext } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { formatDateRange, safetyCheck } from '../../../utils';
|
import { formatDateRange, isItemVisible, safetyCheck } from '../../../utils';
|
||||||
|
|
||||||
const ProjectItem = ({ item, language }) => {
|
const ProjectItem = ({ item, language }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -49,9 +49,16 @@ const ProjectsA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.projects.heading}</Heading>
|
<Heading>{data.projects.heading}</Heading>
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{data.projects.items.map((x) => (
|
{data.projects.items.map(
|
||||||
<ProjectItem key={x.id} item={x} language={data.metadata.language} />
|
(x) =>
|
||||||
))}
|
isItemVisible(x) && (
|
||||||
|
<ProjectItem
|
||||||
|
key={x.id}
|
||||||
|
item={x}
|
||||||
|
language={data.metadata.language}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { isItemVisible, safetyCheck } from '../../../utils';
|
||||||
|
|
||||||
const ReferenceItem = (x) => (
|
const ReferenceItem = (x) => (
|
||||||
<div key={x.id} className="flex flex-col">
|
<div key={x.id} className="flex flex-col">
|
||||||
@ -22,7 +22,7 @@ const ReferencesA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.references.heading}</Heading>
|
<Heading>{data.references.heading}</Heading>
|
||||||
<div className="grid grid-cols-3 gap-4">
|
<div className="grid grid-cols-3 gap-4">
|
||||||
{data.references.items.map(ReferenceItem)}
|
{data.references.items.map((x) => isItemVisible(x) && ReferenceItem(x))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { isItemVisible, safetyCheck } from '../../../utils';
|
||||||
|
|
||||||
const ReferenceItem = (x) => (
|
const ReferenceItem = (x) => (
|
||||||
<div key={x.id} className="flex flex-col">
|
<div key={x.id} className="flex flex-col">
|
||||||
@ -22,7 +22,7 @@ const ReferencesB = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.references.heading}</Heading>
|
<Heading>{data.references.heading}</Heading>
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{data.references.items.map(ReferenceItem)}
|
{data.references.items.map((x) => isItemVisible(x) && ReferenceItem(x))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const SkillItem = (x) => (
|
const SkillItem = (x) => (
|
||||||
<div key={x.id} className="flex flex-col">
|
<div key={x.id} className="flex flex-col">
|
||||||
@ -16,7 +16,7 @@ const SkillsA = () => {
|
|||||||
<div>
|
<div>
|
||||||
<Heading>{data.skills.heading}</Heading>
|
<Heading>{data.skills.heading}</Heading>
|
||||||
<div className="grid grid-cols-2 gap-y-2 gap-x-4">
|
<div className="grid grid-cols-2 gap-y-2 gap-x-4">
|
||||||
{data.skills.items.map(SkillItem)}
|
{data.skills.items.map((x) => isItemVisible(x) && SkillItem(x))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { memo, useContext } from 'react';
|
import React, { memo, useContext } from 'react';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { safetyCheck } from '../../../utils';
|
import { safetyCheck, isItemVisible } from '../../../utils';
|
||||||
|
|
||||||
const SkillItem = (x) => (
|
const SkillItem = (x) => (
|
||||||
<li key={x.id} className="text-sm py-1">
|
<li key={x.id} className="text-sm py-1">
|
||||||
@ -14,7 +14,7 @@ const SkillsA = () => {
|
|||||||
return safetyCheck(data.skills) ? (
|
return safetyCheck(data.skills) ? (
|
||||||
<div>
|
<div>
|
||||||
<Heading>{data.skills.heading}</Heading>
|
<Heading>{data.skills.heading}</Heading>
|
||||||
<ul>{data.skills.items.map(SkillItem)}</ul>
|
<ul>{data.skills.items.map((x) => isItemVisible(x) && SkillItem(x))}</ul>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,7 +2,12 @@ import React, { memo, useContext } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import ReactMarkdown from 'react-markdown';
|
import ReactMarkdown from 'react-markdown';
|
||||||
import PageContext from '../../../contexts/PageContext';
|
import PageContext from '../../../contexts/PageContext';
|
||||||
import { formatDateRange, safetyCheck } from '../../../utils';
|
import {
|
||||||
|
formatDateRange,
|
||||||
|
safetyCheck,
|
||||||
|
isItemVisible,
|
||||||
|
genericFilter,
|
||||||
|
} from '../../../utils';
|
||||||
|
|
||||||
const WorkItem = ({ item, language }) => {
|
const WorkItem = ({ item, language }) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@ -40,14 +45,16 @@ const WorkItem = ({ item, language }) => {
|
|||||||
|
|
||||||
const WorkA = () => {
|
const WorkA = () => {
|
||||||
const { data, heading: Heading } = useContext(PageContext);
|
const { data, heading: Heading } = useContext(PageContext);
|
||||||
|
|
||||||
return safetyCheck(data.work) ? (
|
return safetyCheck(data.work) ? (
|
||||||
<div>
|
<div>
|
||||||
<Heading>{data.work.heading}</Heading>
|
<Heading>{data.work.heading}</Heading>
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
{data.work.items.map((x) => (
|
{data.work.items.map(
|
||||||
|
(x) =>
|
||||||
|
isItemVisible(x) && (
|
||||||
<WorkItem key={x.id} item={x} language={data.metadata.language} />
|
<WorkItem key={x.id} item={x} language={data.metadata.language} />
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { get, isEmpty } from 'lodash';
|
import { get, isEmpty, clone } from 'lodash';
|
||||||
|
|
||||||
export const getModalText = (isEditMode, type, t) =>
|
export const getModalText = (isEditMode, type, t) =>
|
||||||
isEditMode
|
isEditMode
|
||||||
@ -9,6 +9,18 @@ export const getModalText = (isEditMode, type, t) =>
|
|||||||
export const safetyCheck = (section, path = 'items') =>
|
export const safetyCheck = (section, path = 'items') =>
|
||||||
!!(section && section.visible === true && !isEmpty(section[path]));
|
!!(section && section.visible === true && !isEmpty(section[path]));
|
||||||
|
|
||||||
|
export const isItemVisible = (section) =>
|
||||||
|
section && section.isVisible !== false;
|
||||||
|
|
||||||
|
// Thought about creating a generic function to filter out non-visible items
|
||||||
|
export const genericFilter = (key, data) => {
|
||||||
|
const clonedData = clone(data);
|
||||||
|
clonedData[`${key}`].items = clonedData[`${key}`].items.filter((x) =>
|
||||||
|
isItemVisible(x),
|
||||||
|
);
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
export const handleKeyUp = (event, action) => {
|
export const handleKeyUp = (event, action) => {
|
||||||
(event.which === 13 || event.which === 32) && action();
|
(event.which === 13 || event.which === 32) && action();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user