fix styling issues and theme cascades across all templates

This commit is contained in:
Amruth Pillai
2022-11-23 15:20:04 +01:00
parent 9a42d684fb
commit 42d0e14b98
10 changed files with 100 additions and 57 deletions

View File

@ -1,7 +1,6 @@
import clsx from 'clsx'; import clsx from 'clsx';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
type Props = { type Props = {
children?: string; children?: string;
@ -12,7 +11,7 @@ const Markdown: React.FC<Props> = ({ className, children }) => {
if (!children || isEmpty(children)) return null; if (!children || isEmpty(children)) return null;
return ( return (
<ReactMarkdown remarkPlugins={[remarkGfm]} className={clsx('markdown', className)}> <ReactMarkdown remarkPlugins={[]} className={clsx('markdown', className)}>
{children} {children}
</ReactMarkdown> </ReactMarkdown>
); );

View File

@ -35,34 +35,55 @@ export const MastheadSidebar: React.FC = () => {
/> />
)} )}
<div> <div className={clsx({ invert: contrast === 'light' })}>
<h1 className="mb-1">{name}</h1> <h1 className="mb-1">{name}</h1>
<p className="opacity-75">{headline}</p> <p className="opacity-75">{headline}</p>
</div> </div>
<div className={clsx('flex flex-col gap-2.5', css(`svg { color: ${color} }`))}> <div className={clsx('flex flex-col gap-2.5', css(`svg { color: ${color} }`))}>
<DataDisplay icon={<Room />} className="!gap-2 text-xs"> <DataDisplay icon={<Room />} className="!gap-2 text-xs" textClassName={clsx({ invert: contrast === 'light' })}>
{formatLocation(location)} {formatLocation(location)}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Cake />} className="!gap-2 text-xs"> <DataDisplay icon={<Cake />} className="!gap-2 text-xs" textClassName={clsx({ invert: contrast === 'light' })}>
{formatDateString(birthdate, dateFormat)} {formatDateString(birthdate, dateFormat)}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Email />} className="!gap-2 text-xs" link={`mailto:${email}`}> <DataDisplay
icon={<Email />}
className="!gap-2 text-xs"
link={`mailto:${email}`}
textClassName={clsx({ invert: contrast === 'light' })}
>
{email} {email}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Phone />} className="!gap-2 text-xs" link={`tel:${phone}`}> <DataDisplay
icon={<Phone />}
className="!gap-2 text-xs"
link={`tel:${phone}`}
textClassName={clsx({ invert: contrast === 'light' })}
>
{phone} {phone}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Public />} link={website && addHttp(website)} className="!gap-2 text-xs"> <DataDisplay
icon={<Public />}
link={website && addHttp(website)}
className="!gap-2 text-xs"
textClassName={clsx({ invert: contrast === 'light' })}
>
{website} {website}
</DataDisplay> </DataDisplay>
{profiles.map(({ id, username, network, url }) => ( {profiles.map(({ id, username, network, url }) => (
<DataDisplay key={id} icon={getProfileIcon(network)} link={url && addHttp(url)} className="!gap-2 text-xs"> <DataDisplay
key={id}
icon={getProfileIcon(network)}
link={url && addHttp(url)}
className="!gap-2 text-xs"
textClassName={clsx({ invert: contrast === 'light' })}
>
{username} {username}
</DataDisplay> </DataDisplay>
))} ))}

View File

@ -1,5 +1,6 @@
import { Email, Link, Phone } from '@mui/icons-material'; import { Email, Link, Phone } from '@mui/icons-material';
import { ListItem, Section as SectionType } from '@reactive-resume/schema'; import { ListItem, Section as SectionType } from '@reactive-resume/schema';
import clsx from 'clsx';
import get from 'lodash/get'; import get from 'lodash/get';
import isArray from 'lodash/isArray'; import isArray from 'lodash/isArray';
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
@ -23,8 +24,10 @@ const Section: React.FC<SectionProps> = ({
}) => { }) => {
const section: SectionType = useAppSelector((state) => get(state.resume.present, path, {} as SectionType)); const section: SectionType = useAppSelector((state) => get(state.resume.present, path, {} as SectionType));
const dateFormat: string = useAppSelector((state) => get(state.resume.present, 'metadata.date.format')); const dateFormat: string = useAppSelector((state) => get(state.resume.present, 'metadata.date.format'));
const layout: string[][][] = useAppSelector((state) => get(state.resume.present, 'metadata.layout'));
const sectionId = useMemo(() => section.id || path.replace('sections.', ''), [path, section]); const sectionId = useMemo(() => section.id || path.replace('sections.', ''), [path, section]);
const isSidebarSection = useMemo(() => layout.some((row) => row[1].includes(sectionId)), [layout, sectionId]);
if (!section.visible) return null; if (!section.visible) return null;
@ -35,7 +38,7 @@ const Section: React.FC<SectionProps> = ({
<Heading>{section.name}</Heading> <Heading>{section.name}</Heading>
<div <div
className="grid items-start gap-4" className={clsx('grid items-start gap-4', { invert: isSidebarSection })}
style={{ gridTemplateColumns: `repeat(${section.columns}, minmax(0, 1fr))` }} style={{ gridTemplateColumns: `repeat(${section.columns}, minmax(0, 1fr))` }}
> >
{section.items.map((item: ListItem) => { {section.items.map((item: ListItem) => {
@ -76,8 +79,13 @@ const Section: React.FC<SectionProps> = ({
key={index} key={index}
className="mr-2 h-3 w-3 rounded-full border" className="mr-2 h-3 w-3 rounded-full border"
style={{ style={{
borderColor: 'var(--primary-color)', borderColor: isSidebarSection ? 'var(--text-color)' : 'var(--primary-color)',
backgroundColor: levelNum / (10 / 5) > index ? 'var(--primary-color)' : '', backgroundColor:
levelNum / (10 / 5) > index
? isSidebarSection
? 'var(--text-color)'
: 'var(--primary-color)'
: '',
}} }}
/> />
))} ))}
@ -94,7 +102,7 @@ const Section: React.FC<SectionProps> = ({
</DataDisplay> </DataDisplay>
)} )}
{keywords && <div>{keywords.join(', ')}</div>} {keywords && <span>{keywords.join(', ')}</span>}
{(phone || email) && ( {(phone || email) && (
<div className="grid gap-1"> <div className="grid gap-1">

View File

@ -36,34 +36,55 @@ export const MastheadSidebar: React.FC = () => {
/> />
)} )}
<div> <div className={clsx({ invert: contrast === 'light' })}>
<h1 className="mb-1">{name}</h1> <h1 className="mb-1">{name}</h1>
<p className="opacity-75">{headline}</p> <p className="opacity-75">{headline}</p>
</div> </div>
<div className={clsx('flex flex-col gap-2.5', css(`svg { color: ${iconColor} }`))}> <div className={clsx('flex flex-col gap-2.5', css(`svg { color: ${iconColor} }`))}>
<DataDisplay icon={<Room />} className="!gap-2 text-xs"> <DataDisplay icon={<Room />} className="!gap-2 text-xs" textClassName={clsx({ invert: contrast === 'light' })}>
{formatLocation(location)} {formatLocation(location)}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Cake />} className="!gap-2 text-xs"> <DataDisplay icon={<Cake />} className="!gap-2 text-xs" textClassName={clsx({ invert: contrast === 'light' })}>
{formatDateString(birthdate, dateFormat)} {formatDateString(birthdate, dateFormat)}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Email />} className="!gap-2 text-xs" link={`mailto:${email}`}> <DataDisplay
icon={<Email />}
className="!gap-2 text-xs"
link={`mailto:${email}`}
textClassName={clsx({ invert: contrast === 'light' })}
>
{email} {email}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Phone />} className="!gap-2 text-xs" link={`tel:${phone}`}> <DataDisplay
icon={<Phone />}
className="!gap-2 text-xs"
link={`tel:${phone}`}
textClassName={clsx({ invert: contrast === 'light' })}
>
{phone} {phone}
</DataDisplay> </DataDisplay>
<DataDisplay icon={<Public />} link={website && addHttp(website)} className="!gap-2 text-xs"> <DataDisplay
icon={<Public />}
link={website && addHttp(website)}
className="!gap-2 text-xs"
textClassName={clsx({ invert: contrast === 'light' })}
>
{website} {website}
</DataDisplay> </DataDisplay>
{profiles.map(({ id, username, network, url }) => ( {profiles.map(({ id, username, network, url }) => (
<DataDisplay key={id} icon={getProfileIcon(network)} link={url && addHttp(url)} className="!gap-2 text-xs"> <DataDisplay
key={id}
icon={getProfileIcon(network)}
link={url && addHttp(url)}
className="!gap-2 text-xs"
textClassName="invert"
>
{username} {username}
</DataDisplay> </DataDisplay>
))} ))}

View File

@ -21,15 +21,8 @@ const BadgeDisplay: React.FC<Props> = ({ items }) => {
return ( return (
<ul className="mt-1 flex flex-wrap gap-2 text-xs"> <ul className="mt-1 flex flex-wrap gap-2 text-xs">
{items.map((item) => ( {items.map((item) => (
<li <li key={item} className="rounded-sm px-2 py-0.5" style={{ backgroundColor: alpha(theme.primary, 0.75) }}>
key={item} <span style={{ color: contrast === 'dark' ? theme.text : theme.background }}>{item}</span>
className="rounded-sm px-2 py-0.5"
style={{
color: contrast === 'dark' ? theme.text : theme.background,
backgroundColor: alpha(theme.primary, 0.75),
}}
>
{item}
</li> </li>
))} ))}
</ul> </ul>

View File

@ -20,15 +20,8 @@ const BadgeDisplay: React.FC<Props> = ({ items }) => {
return ( return (
<ul className="my-1 flex flex-wrap items-start justify-center gap-1.5"> <ul className="my-1 flex flex-wrap items-start justify-center gap-1.5">
{items.map((item) => ( {items.map((item) => (
<li <li key={item} className="rounded-lg px-2 py-0.5 text-xs" style={{ backgroundColor: theme.primary }}>
key={item} <span style={{ color: contrast === 'dark' ? theme.text : theme.background }}>{item}</span>
className="rounded-lg px-2 py-0.5 text-xs"
style={{
color: contrast === 'dark' ? theme.text : theme.background,
backgroundColor: theme.primary,
}}
>
{item}
</li> </li>
))} ))}
</ul> </ul>

View File

@ -1,5 +1,5 @@
.container { .container {
@apply grid grid-cols-2 gap-4 px-6 py-4; @apply grid grid-cols-2 gap-4 px-6 py-4 items-start;
.main { .main {
@apply grid gap-4; @apply grid gap-4;

View File

@ -1,5 +1,6 @@
import { Cake, Email, Phone, Public, Room } from '@mui/icons-material'; import { Cake, Email, Phone, Public, Room } from '@mui/icons-material';
import { ThemeConfig } from '@reactive-resume/schema'; import { ThemeConfig } from '@reactive-resume/schema';
import clsx from 'clsx';
import get from 'lodash/get'; import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty'; import isEmpty from 'lodash/isEmpty';
import { useMemo } from 'react'; import { useMemo } from 'react';
@ -72,14 +73,14 @@ export const MastheadMain: React.FC = () => {
className="grid gap-2 p-4" className="grid gap-2 p-4"
style={{ color: contrast === 'dark' ? theme.text : theme.background, backgroundColor: theme.primary }} style={{ color: contrast === 'dark' ? theme.text : theme.background, backgroundColor: theme.primary }}
> >
<div> <div className={clsx({ invert: contrast === 'light' })}>
<h1>{name}</h1> <h1>{name}</h1>
<p className="opacity-75">{headline}</p> <p className="opacity-75">{headline}</p>
</div> </div>
<hr className="opacity-25" /> <hr className="opacity-25" />
<Markdown>{summary}</Markdown> <Markdown className={clsx({ invert: contrast === 'light' })}>{summary}</Markdown>
</div> </div>
); );
}; };

View File

@ -5,16 +5,17 @@ type Props = {
icon?: JSX.Element; icon?: JSX.Element;
link?: string; link?: string;
className?: string; className?: string;
textClassName?: string;
}; };
const DataDisplay: React.FC<React.PropsWithChildren<Props>> = ({ icon, link, className, children }) => { const DataDisplay: React.FC<React.PropsWithChildren<Props>> = ({ icon, link, className, textClassName, children }) => {
if (isEmpty(children)) return null; if (isEmpty(children)) return null;
if (!isEmpty(link)) { if (!isEmpty(link)) {
return ( return (
<div className={clsx('inline-flex items-center gap-1', className)}> <div className={clsx('inline-flex items-center gap-1', className)}>
{icon} {icon}
<a href={link} target="_blank" rel="noreferrer"> <a href={link} target="_blank" rel="noreferrer" className={textClassName}>
{children} {children}
</a> </a>
</div> </div>
@ -24,7 +25,7 @@ const DataDisplay: React.FC<React.PropsWithChildren<Props>> = ({ icon, link, cla
return ( return (
<div className={clsx('inline-flex items-center gap-1', className)}> <div className={clsx('inline-flex items-center gap-1', className)}>
{icon} {icon}
<span>{children}</span> <span className={textClassName}>{children}</span>
</div> </div>
); );
}; };

View File

@ -7,7 +7,7 @@ export const generateTypographyStyles = ({ family, size }: Typography): string =
font-size: ${size.body}px !important; font-size: ${size.body}px !important;
font-family: ${family.body} !important; font-family: ${family.body} !important;
svg { font-size: ${size.body}px !important; } p, li, svg { font-size: ${size.body}px !important; line-height: ${size.body * 1.5}px !important; }
h1, h1,
h2, h2,
@ -25,25 +25,31 @@ export const generateTypographyStyles = ({ family, size }: Typography): string =
h4 { font-size: ${size.heading / 2.5}px !important; line-height: ${size.heading / 2.5}px !important; } h4 { font-size: ${size.heading / 2.5}px !important; line-height: ${size.heading / 2.5}px !important; }
h5 { font-size: ${size.heading / 3}px !important; line-height: ${size.heading / 3}px !important; } h5 { font-size: ${size.heading / 3}px !important; line-height: ${size.heading / 3}px !important; }
h6 { font-size: ${size.heading / 3.5}px !important; line-height: ${size.heading / 3.5}px !important; } h6 { font-size: ${size.heading / 3.5}px !important; line-height: ${size.heading / 3.5}px !important; }
.markdown p,
.markdown li {
font-size: ${size.body}px !important;
}
`; `;
export const generateThemeStyles = ({ text, background, primary }: ThemeConfig): string => ` export const generateThemeStyles = ({ text, background, primary }: ThemeConfig): string => `
color: ${text} !important; --text-color: ${text} !important;
background-color: ${background} !important;
--primary-color: ${primary} !important; --primary-color: ${primary} !important;
--background-color: ${background} !important;
svg { color: var(--text-color);
color: var(--primary-color) !important; background-color: var(--background-color);
span,
h1,
h2,
h3,
h4,
h5,
h6,
li,
p,
a {
color: var(--text-color);
} }
.markdown p, svg {
.markdown li { color: var(--primary-color);
color: ${text} !important;
} }
`; `;