refactor: move all text-related classes to Typography component (#198)
This commit is contained in:
parent
20e1423bf5
commit
aa373785de
12 changed files with 69 additions and 73 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
import Description from '@/components/description.astro';
|
import Description from '@/components/description.astro';
|
||||||
|
import { variantToClassName } from './typography.astro';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
content: string;
|
content: string;
|
||||||
|
|
@ -7,9 +8,6 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { content, class: className } = Astro.props;
|
const { content, class: className } = Astro.props;
|
||||||
|
|
||||||
const baseClass =
|
|
||||||
/* tw */ 'text-sm leading-relaxed font-normal text-gray-500 sm:text-base sm:leading-relaxed dark:text-gray-300';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Description content={content} classList={[baseClass, className]} />
|
<Description content={content} classList={[variantToClassName.paragraph, className]} />
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,21 @@
|
||||||
---
|
---
|
||||||
import type { DownloadButton } from '@/types/shared';
|
import type { DownloadButton } from '@/types/shared';
|
||||||
|
import Typography from './typography.astro';
|
||||||
|
|
||||||
export interface Props extends DownloadButton {}
|
export interface Props extends DownloadButton {}
|
||||||
|
|
||||||
const { url, downloadedFileName, label } = Astro.props;
|
const { url, downloadedFileName, label } = Astro.props;
|
||||||
|
|
||||||
const classes = /* tw */ {
|
const classes = /* tw */ {
|
||||||
main: 'inline-flex items-center px-4 h-10 text-base font-medium rounded-md shadow-sm text-white bg-primary-600 select-none cursor-pointer',
|
main: 'inline-flex items-center px-4 h-10 rounded-md shadow-sm bg-primary-600 select-none cursor-pointer',
|
||||||
hover: 'hover:bg-primary-700',
|
hover: 'hover:bg-primary-700',
|
||||||
active: 'active:translate-y-px',
|
active: 'active:translate-y-px',
|
||||||
focus: 'focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500',
|
focus: 'focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const className = Object.values(classes).join(' ');
|
||||||
---
|
---
|
||||||
|
|
||||||
<a href={url} class:list={[classes.main, classes.hover, classes.active, classes.focus]} download={downloadedFileName}>
|
<Typography variant="button" as="a" href={url} class={className} download={downloadedFileName}>
|
||||||
{label}
|
{label}
|
||||||
</a>
|
</Typography>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
import type { LabelledValue } from '@/types/shared';
|
import type { LabelledValue } from '@/types/shared';
|
||||||
|
import Typography from './typography.astro';
|
||||||
|
|
||||||
export interface Props extends LabelledValue {}
|
export interface Props extends LabelledValue {}
|
||||||
|
|
||||||
|
|
@ -8,15 +9,15 @@ const { label, value, url } = Astro.props;
|
||||||
const parsedValue = Array.isArray(value) ? value.join(', ') : value;
|
const parsedValue = Array.isArray(value) ? value.join(', ') : value;
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="text-base">
|
<div>
|
||||||
<span class="font-medium text-gray-700 dark:text-gray-300">{label}:</span>
|
<Typography variant="label">{label}:</Typography>
|
||||||
{
|
{
|
||||||
url ? (
|
url ? (
|
||||||
<a href={url} target="_blank" class="font-normal text-gray-500 underline dark:text-gray-400">
|
<Typography as="a" href={url} target="_blank" class="underline">
|
||||||
{parsedValue}
|
{parsedValue}
|
||||||
</a>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<span class="font-normal text-gray-500 dark:text-gray-400">{parsedValue}</span>
|
<Typography variant="value">{parsedValue}</Typography>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,27 @@
|
||||||
---
|
---
|
||||||
import type { Tag } from '@/types/shared';
|
import type { Tag } from '@/types/shared';
|
||||||
import Icon from './icon.astro';
|
import Icon from './icon.astro';
|
||||||
|
import Typography from './typography.astro';
|
||||||
|
|
||||||
export interface Props extends Tag {}
|
export interface Props extends Tag {}
|
||||||
|
|
||||||
const { name, description, icon, iconColor, url } = Astro.props;
|
const { name, description, icon, iconColor, url } = Astro.props;
|
||||||
|
|
||||||
const className =
|
const className = /* tw */ 'flex h-6 w-fit items-center gap-x-1.5 rounded bg-gray-100 px-2.5 dark:bg-gray-700';
|
||||||
/* tw */ 'flex h-6 w-fit items-center gap-x-1.5 rounded bg-gray-100 px-2.5 text-sm font-medium tracking-wide text-gray-700 dark:bg-gray-700 dark:text-gray-100';
|
const customProps = url
|
||||||
|
? ({
|
||||||
|
href: url,
|
||||||
|
as: 'a',
|
||||||
|
target: '_blank',
|
||||||
|
rel: 'noopener noreferrer',
|
||||||
|
class: `${className} hover:bg-gray-200 dark:hover:bg-gray-600`,
|
||||||
|
} as const)
|
||||||
|
: {
|
||||||
|
class: className,
|
||||||
|
};
|
||||||
---
|
---
|
||||||
|
|
||||||
{
|
<Typography variant="tag" data-tooltip={description} {...customProps}>
|
||||||
url ? (
|
{icon && <Icon name={icon} color={iconColor} size={16} />}
|
||||||
<a
|
{name}
|
||||||
class:list={[className, 'hover:bg-gray-200 dark:hover:bg-gray-600']}
|
</Typography>
|
||||||
data-tooltip={description}
|
|
||||||
href={url}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
{icon && <Icon name={icon} color={iconColor} size={16} />}
|
|
||||||
{name}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<div class={className} data-tooltip={description}>
|
|
||||||
{icon && <Icon name={icon} color={iconColor} size={16} />}
|
|
||||||
{name}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
import type { TagsList } from '@/types/shared';
|
import type { TagsList } from '@/types/shared';
|
||||||
import Tag from './tag.astro';
|
import Tag from './tag.astro';
|
||||||
|
import Typography from './typography.astro';
|
||||||
|
|
||||||
export interface Props extends Omit<TagsList, 'title'> {
|
export interface Props extends Omit<TagsList, 'title'> {
|
||||||
title?: TagsList['title'];
|
title?: TagsList['title'];
|
||||||
|
|
@ -12,7 +13,7 @@ const { tags, title } = Astro.props;
|
||||||
{
|
{
|
||||||
title ? (
|
title ? (
|
||||||
<div class="flex flex-col gap-1.5">
|
<div class="flex flex-col gap-1.5">
|
||||||
<div class="font-medium text-gray-700 dark:text-gray-300">{title}:</div>
|
<Typography variant="label">{title}:</Typography>
|
||||||
<div class="flex flex-wrap gap-3">
|
<div class="flex flex-wrap gap-3">
|
||||||
{tags.map((tag) => (
|
{tags.map((tag) => (
|
||||||
<Tag {...tag} />
|
<Tag {...tag} />
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,6 @@ export interface Props {
|
||||||
const { dates } = Astro.props;
|
const { dates } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<Typography variant="item-subtitle">
|
<Typography variant="item-subtitle-secondary">
|
||||||
{formatDateRange(dates)}
|
{formatDateRange(dates)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,5 @@
|
||||||
---
|
---
|
||||||
type TypographyVariant =
|
type TypographyVariant = keyof typeof variantToElement;
|
||||||
| 'main-title'
|
|
||||||
| 'main-subtitle'
|
|
||||||
| 'section-title'
|
|
||||||
| 'section-subtitle'
|
|
||||||
| 'item-title'
|
|
||||||
| 'item-title-suffix'
|
|
||||||
| 'item-subtitle'
|
|
||||||
| 'tile-title'
|
|
||||||
| 'tile-subtitle'
|
|
||||||
| 'paragraph';
|
|
||||||
|
|
||||||
const variantToElement = {
|
const variantToElement = {
|
||||||
'main-title': 'h1',
|
'main-title': 'h1',
|
||||||
|
|
@ -17,33 +7,50 @@ const variantToElement = {
|
||||||
'section-title': 'h2',
|
'section-title': 'h2',
|
||||||
'section-subtitle': 'h3',
|
'section-subtitle': 'h3',
|
||||||
'item-title': 'h3',
|
'item-title': 'h3',
|
||||||
'item-title-suffix': 'span',
|
'item-subtitle-primary': 'p',
|
||||||
'item-subtitle': 'p',
|
'item-subtitle-secondary': 'p',
|
||||||
'tile-title': 'h4',
|
'tile-title': 'h4',
|
||||||
'tile-subtitle': 'p',
|
'tile-subtitle': 'p',
|
||||||
paragraph: 'p',
|
paragraph: 'p',
|
||||||
|
label: 'span',
|
||||||
|
value: 'span',
|
||||||
|
skill: 'span',
|
||||||
|
tag: 'div',
|
||||||
|
button: 'div',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const variantToClassName /* tw */ = {
|
export const variantToClassName: Record<TypographyVariant, string> /* tw */ = {
|
||||||
'main-title': 'text-3xl sm:text-4xl font-extrabold text-gray-900 dark:text-gray-100',
|
'main-title': 'text-3xl sm:text-4xl font-extrabold text-gray-900 dark:text-gray-100',
|
||||||
'main-subtitle': 'text-base sm:text-lg font-medium text-gray-700 dark:text-gray-100',
|
'main-subtitle': 'text-base sm:text-lg font-medium text-gray-700 dark:text-gray-100',
|
||||||
'section-title': 'text-3xl font-extrabold text-gray-900 dark:text-gray-100',
|
'section-title': 'text-3xl font-extrabold text-gray-900 dark:text-gray-100',
|
||||||
'section-subtitle': 'text-lg font-extrabold text-gray-900 dark:text-gray-100',
|
'section-subtitle': 'text-lg font-extrabold text-gray-900 dark:text-gray-100',
|
||||||
'item-title': 'text-xl font-extrabold text-gray-900 dark:text-gray-100',
|
'item-title': 'text-xl font-extrabold text-gray-900 dark:text-gray-100',
|
||||||
'item-title-suffix': 'text-xl font-medium text-gray-700 dark:text-gray-100',
|
'item-subtitle-primary': 'text-base font-semibold leading-snug text-gray-900 dark:text-gray-100',
|
||||||
'item-subtitle': 'text-sm font-medium text-gray-700 dark:text-gray-100',
|
'item-subtitle-secondary': 'text-sm font-medium text-gray-700 dark:text-gray-100',
|
||||||
'tile-title': 'text-sm font-medium text-gray-700 dark:text-gray-200',
|
'tile-title': 'text-sm font-medium text-gray-700 dark:text-gray-200',
|
||||||
'tile-subtitle': 'text-sm font-normal text-gray-500 dark:text-gray-300',
|
'tile-subtitle': 'text-sm font-normal text-gray-500 dark:text-gray-300',
|
||||||
paragraph: 'text-sm leading-relaxed font-normal text-gray-500 sm:text-base sm:leading-relaxed dark:text-gray-300',
|
paragraph: 'text-sm leading-relaxed font-normal text-gray-500 sm:text-base sm:leading-relaxed dark:text-gray-300',
|
||||||
|
label: 'text-base font-medium text-gray-700 dark:text-gray-300',
|
||||||
|
value: 'text-base font-normal text-gray-500 dark:text-gray-400',
|
||||||
|
skill: 'text-sm font-medium text-gray-700 dark:text-gray-300',
|
||||||
|
tag: 'text-sm font-medium tracking-wide text-gray-700 dark:text-gray-100',
|
||||||
|
button: 'text-base font-medium text-white',
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Props extends Omit<astroHTML.JSX.HTMLAttributes, 'slot'> {
|
interface LinkProps {
|
||||||
variant?: TypographyVariant;
|
href?: string;
|
||||||
component?: keyof JSX.IntrinsicElements;
|
target?: string;
|
||||||
|
rel?: string;
|
||||||
|
download?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { variant = 'paragraph', component, ...props } = Astro.props;
|
export interface Props extends Omit<astroHTML.JSX.HTMLAttributes, 'slot'>, LinkProps {
|
||||||
const Element = component ?? variantToElement[variant];
|
as?: keyof JSX.IntrinsicElements;
|
||||||
|
variant?: TypographyVariant;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { variant = 'paragraph', as, class: className, ...props } = Astro.props;
|
||||||
|
const Element = as ?? variantToElement[variant];
|
||||||
---
|
---
|
||||||
|
|
||||||
<Element {...props} class:list={[variantToClassName[variant], props.class]}><slot /></Element>
|
<Element {...props} class:list={[variantToClassName[variant], className]}><slot /></Element>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ const { title, institution, dates, description, links, image } = Astro.props;
|
||||||
<Thumbnail src={image} alt={`${institution} logo`} size="large" />
|
<Thumbnail src={image} alt={`${institution} logo`} size="large" />
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<Typography variant="item-title">{title}</Typography>
|
<Typography variant="item-title">{title}</Typography>
|
||||||
<div class="mb-0.5 text-base font-semibold leading-snug text-gray-900 dark:text-gray-100">{institution}</div>
|
<Typography variant="item-subtitle-primary" class="mb-0.5">{institution}</Typography>
|
||||||
<Timestamp dates={dates} />
|
<Timestamp dates={dates} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const { role, company, dates, description, links, tagsList, image } = Astro.prop
|
||||||
<Thumbnail src={image} alt={`${company} logo`} size="large" />
|
<Thumbnail src={image} alt={`${company} logo`} size="large" />
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<Typography variant="item-title">{role}</Typography>
|
<Typography variant="item-title">{role}</Typography>
|
||||||
<div class="mb-0.5 text-base font-semibold leading-snug text-gray-900 dark:text-gray-100">{company}</div>
|
<Typography variant="item-subtitle-primary" class="mb-0.5">{company}</Typography>
|
||||||
<Timestamp dates={dates} />
|
<Timestamp dates={dates} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import Photo from '@/components/photo.astro';
|
||||||
import SectionCard from '@/web/components/section-card.astro';
|
import SectionCard from '@/web/components/section-card.astro';
|
||||||
import TagsList from '@/web/components/tags-list.astro';
|
import TagsList from '@/web/components/tags-list.astro';
|
||||||
import Typography from '@/web/components/typography.astro';
|
import Typography from '@/web/components/typography.astro';
|
||||||
|
import LabelledValue from '@/web/components/labelled-value.astro';
|
||||||
|
|
||||||
export interface Props extends MainSection {}
|
export interface Props extends MainSection {}
|
||||||
|
|
||||||
|
|
@ -43,16 +44,7 @@ const { action, config, description, details, fullName, image, links, role, tags
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-6">
|
<div class="flex flex-col gap-6">
|
||||||
<div class="inline-grid xl:grid-cols-[auto_auto]">
|
<div class="inline-grid xl:grid-cols-[auto_auto]">
|
||||||
{
|
{details.map((detail) => <LabelledValue {...detail} />)}
|
||||||
details.map(({ label: detailLabel, value }) => (
|
|
||||||
<div class="w-fit">
|
|
||||||
<Typography variant="paragraph">
|
|
||||||
<span class="text-gray-700 dark:text-gray-300">{detailLabel}: </span>
|
|
||||||
<span class="break-all dark:text-gray-400">{value}</span>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<Description content={description} />
|
<Description content={description} />
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,7 @@ const IconWrapper = url ? 'a' : 'div';
|
||||||
<div class="flex h-5 items-center justify-between">
|
<div class="flex h-5 items-center justify-between">
|
||||||
<IconWrapper class="flex gap-2 h-5" {...url && { href: url, target: '_blank', rel: 'noopener noreferrer' }}>
|
<IconWrapper class="flex gap-2 h-5" {...url && { href: url, target: '_blank', rel: 'noopener noreferrer' }}>
|
||||||
{icon && <Icon name={icon} color={iconColor} size={20} />}
|
{icon && <Icon name={icon} color={iconColor} size={20} />}
|
||||||
<Typography variant="tile-subtitle">
|
<Typography variant="skill">{name}</Typography>
|
||||||
<span class="text-gray-700 dark:text-gray-300">{name}</span>
|
|
||||||
</Typography>
|
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
{
|
{
|
||||||
description && (
|
description && (
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const { author, content, image, links, relation } = Astro.props;
|
||||||
<Thumbnail src={image} alt={author} size="small" />
|
<Thumbnail src={image} alt={author} size="small" />
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="item-title">{author}</Typography>
|
<Typography variant="item-title">{author}</Typography>
|
||||||
<Typography variant="item-subtitle">{relation}</Typography>
|
<Typography variant="item-subtitle-secondary">{relation}</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue