-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #811 from klejejs/main
A new template - Leafish
- Loading branch information
Showing
7 changed files
with
265 additions
and
0 deletions.
There are no files selected for viewing
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.page {} | ||
|
||
.container { | ||
@apply grid grid-cols-2 gap-8 px-6 py-4; | ||
|
||
.column { | ||
@apply col-span-1 flex flex-col; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { useMemo } from 'react'; | ||
|
||
import { useAppSelector } from '@/store/hooks'; | ||
import { PageProps } from '@/utils/template'; | ||
|
||
import { getSectionById } from '../sectionMap'; | ||
import styles from './Leafish.module.scss'; | ||
import Masthead from './widgets/Masthead'; | ||
import Section from './widgets/Section'; | ||
|
||
const Leafish: React.FC<PageProps> = ({ page }) => { | ||
const isFirstPage = useMemo(() => page === 0, [page]); | ||
|
||
const layout: string[][] = useAppSelector((state) => state.resume.metadata.layout[page]); | ||
|
||
return ( | ||
<div className={styles.page}> | ||
{isFirstPage && <Masthead />} | ||
|
||
<div className={styles.container}> | ||
<div className={styles.column}>{layout[0].map((key) => getSectionById(key, Section))}</div> | ||
<div className={styles.column}>{layout[1].map((key) => getSectionById(key, Section))}</div> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Leafish; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Theme } from '@reactive-resume/schema'; | ||
import get from 'lodash/get'; | ||
|
||
import { useAppSelector } from '@/store/hooks'; | ||
|
||
const Heading: React.FC = ({ children }) => { | ||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {})); | ||
|
||
return ( | ||
<h2 | ||
className="pb-1 mb-2 font-bold uppercase opacity-75" | ||
style={{ borderBottomWidth: '3px', borderColor: theme.primary, color: theme.primary, display: 'inline-block' }} | ||
> | ||
{children} | ||
</h2> | ||
); | ||
}; | ||
|
||
export default Heading; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { Email, Phone, Public, Room } from '@mui/icons-material'; | ||
import { alpha } from '@mui/material'; | ||
import { Theme } from '@reactive-resume/schema'; | ||
import get from 'lodash/get'; | ||
import isEmpty from 'lodash/isEmpty'; | ||
|
||
import { useAppSelector } from '@/store/hooks'; | ||
import DataDisplay from '@/templates/shared/DataDisplay'; | ||
import getProfileIcon from '@/utils/getProfileIcon'; | ||
import { addHttp, formatLocation, getPhotoClassNames } from '@/utils/template'; | ||
|
||
const Masthead: React.FC = () => { | ||
const { name, photo, headline, summary, email, phone, website, location, profiles } = useAppSelector( | ||
(state) => state.resume.basics | ||
); | ||
const theme: Theme = useAppSelector((state) => get(state.resume, 'metadata.theme', {})); | ||
|
||
return ( | ||
<div> | ||
<div | ||
className="flex items-center gap-4 p-6" | ||
id="Masterhead_main" | ||
style={{ backgroundColor: alpha(theme.primary, 0.2) }} | ||
> | ||
<div className="grid flex-1 gap-1"> | ||
<h1 id="Masterhead_name">{name}</h1> | ||
<p style={{ color: theme.primary }} id="Masterhead_headline"> | ||
{headline} | ||
</p> | ||
<p className="opacity-75" id="Masterhead_summary"> | ||
{summary} | ||
</p> | ||
</div> | ||
|
||
{photo.visible && !isEmpty(photo.url) && ( | ||
<img | ||
alt={name} | ||
src={photo.url} | ||
width={photo.filters.size} | ||
height={photo.filters.size} | ||
className={getPhotoClassNames(photo.filters)} | ||
id="Masterhead_photo" | ||
/> | ||
)} | ||
</div> | ||
<div | ||
className="grid gap-y-2 px-8 py-4" | ||
id="Masterhead_data" | ||
style={{ backgroundColor: alpha(theme.primary, 0.4), gridTemplateColumns: `repeat(2, minmax(0, 1fr))` }} | ||
> | ||
<DataDisplay icon={<Email />} link={`mailto:${email}`}> | ||
{email} | ||
</DataDisplay> | ||
|
||
<DataDisplay icon={<Phone />} link={`tel:${phone}`}> | ||
{phone} | ||
</DataDisplay> | ||
|
||
<DataDisplay icon={<Public />} link={addHttp(website)}> | ||
{website} | ||
</DataDisplay> | ||
|
||
<DataDisplay icon={<Room />}>{formatLocation(location)}</DataDisplay> | ||
|
||
{profiles.map(({ id, username, network, url }) => ( | ||
<DataDisplay key={id} icon={getProfileIcon(network)} link={url && addHttp(url)}> | ||
{username} | ||
</DataDisplay> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Masthead; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { Email, Link, Phone } from '@mui/icons-material'; | ||
import { ListItem, Section as SectionType } from '@reactive-resume/schema'; | ||
import get from 'lodash/get'; | ||
import isArray from 'lodash/isArray'; | ||
import isEmpty from 'lodash/isEmpty'; | ||
|
||
import Markdown from '@/components/shared/Markdown'; | ||
import { useAppSelector } from '@/store/hooks'; | ||
import { SectionProps } from '@/templates/sectionMap'; | ||
import DataDisplay from '@/templates/shared/DataDisplay'; | ||
import { formatDateString } from '@/utils/date'; | ||
import { parseListItemPath } from '@/utils/template'; | ||
|
||
import Heading from './Heading'; | ||
|
||
const Section: React.FC<SectionProps> = ({ | ||
path, | ||
titlePath = 'title', | ||
subtitlePath = 'subtitle', | ||
headlinePath = 'headline', | ||
keywordsPath = 'keywords', | ||
}) => { | ||
const section: SectionType = useAppSelector((state) => get(state.resume, path, {})); | ||
const dateFormat: string = useAppSelector((state) => get(state.resume, 'metadata.date.format')); | ||
const primaryColor: string = useAppSelector((state) => get(state.resume, 'metadata.theme.primary')); | ||
|
||
if (!section.visible) return null; | ||
|
||
if (isArray(section.items) && isEmpty(section.items)) return null; | ||
|
||
return ( | ||
<section className="mb-4"> | ||
<Heading>{section.name}</Heading> | ||
|
||
<div | ||
className="grid items-start gap-4" | ||
style={{ gridTemplateColumns: `repeat(${section.columns}, minmax(0, 1fr))` }} | ||
id={`Section_${section.id}`} | ||
> | ||
{section.items.map((item: ListItem) => { | ||
const id = item.id, | ||
title = parseListItemPath(item, titlePath), | ||
subtitle = parseListItemPath(item, subtitlePath), | ||
headline = parseListItemPath(item, headlinePath), | ||
keywords: string[] = get(item, keywordsPath), | ||
url: string = get(item, 'url'), | ||
summary: string = get(item, 'summary'), | ||
level: string = get(item, 'level'), | ||
levelNum: number = get(item, 'levelNum'), | ||
phone: string = get(item, 'phone'), | ||
email: string = get(item, 'email'), | ||
date = formatDateString(get(item, 'date'), dateFormat); | ||
|
||
return ( | ||
<div key={id} id={id} className={`grid gap-1 mb-2 Section_${section.id}_inner`}> | ||
<div> | ||
{title && <div className="font-bold Section_title">{title}</div>} | ||
{subtitle && <div className="Section_subtitle">{subtitle}</div>} | ||
{date && ( | ||
<div className="italic text-xs Section_date" style={{ color: primaryColor }}> | ||
({date}) | ||
</div> | ||
)} | ||
{headline && <div className="opacity-50 Section_headline">{headline}</div>} | ||
</div> | ||
|
||
{(level || levelNum > 0) && ( | ||
<div className="grid gap-1"> | ||
{level && <span className="opacity-75">{level}</span>} | ||
{levelNum > 0 && ( | ||
<div className="flex"> | ||
{Array.from(Array(5).keys()).map((_, index) => ( | ||
<div | ||
key={index} | ||
className="mr-1 h-3 w-3 rounded-full border-2" | ||
style={{ | ||
borderColor: primaryColor, | ||
backgroundColor: levelNum / (10 / 5) > index ? primaryColor : '', | ||
}} | ||
/> | ||
))} | ||
</div> | ||
)} | ||
</div> | ||
)} | ||
|
||
{summary && ( | ||
<div> | ||
<div className="italic text-xs" style={{ color: primaryColor }}> | ||
Overview | ||
</div> | ||
<Markdown className={`marker:text-[${primaryColor}]`}>{summary}</Markdown> | ||
</div> | ||
)} | ||
|
||
{url && ( | ||
<DataDisplay icon={<Link />} link={url} className="text-xs"> | ||
{url} | ||
</DataDisplay> | ||
)} | ||
|
||
{keywords && <div>{keywords.join(', ')}</div>} | ||
|
||
{(phone || email) && ( | ||
<div className="grid gap-1"> | ||
{phone && ( | ||
<DataDisplay icon={<Phone />} link={`tel:${phone}`}> | ||
{phone} | ||
</DataDisplay> | ||
)} | ||
|
||
{email && ( | ||
<DataDisplay icon={<Email />} link={`mailto:${email}`}> | ||
{email} | ||
</DataDisplay> | ||
)} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
})} | ||
</div> | ||
</section> | ||
); | ||
}; | ||
|
||
export default Section; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters