Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

styles(blog): UI improvements #468

Merged
merged 14 commits into from
Dec 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 11 additions & 21 deletions src/components/Blog/Authors/index.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,20 @@
import { Avatar, AvatarGroup, Typography } from '@mui/material'
import css from '../styles.module.css'
import { Avatar, AvatarGroup } from '@mui/material'
import type { Entry } from 'contentful'
import type { TypeAuthorSkeleton } from '@/contentful/types'
import { isAsset } from '@/lib/typeGuards'
import { formatAuthorsList } from '@/components/Blog/utils/formatAuthorsList'

export type AuthorsProps = Entry<TypeAuthorSkeleton, undefined, string>[]

const Authors = ({ authors }: { authors: AuthorsProps }) => {
return (
<div className={css.authors}>
<AvatarGroup className={css.avatarGroup} max={3}>
{authors.map((author) => {
const { name, picture } = author.fields
const Authors = ({ authors }: { authors: AuthorsProps }) => (
<AvatarGroup max={3}>
{authors.map((author) => {
const { name, picture } = author.fields

return isAsset(picture) && picture.fields.file?.url ? (
<Avatar key={name} src={picture.fields.file.url} alt={picture.fields.title} />
) : undefined
})}
</AvatarGroup>

<Typography variant="caption" color="text.primary">
{formatAuthorsList(authors)}
</Typography>
</div>
)
}
return isAsset(picture) && picture.fields.file?.url ? (
<Avatar key={name} src={picture.fields.file.url} alt={picture.fields.title} />
) : undefined
})}
</AvatarGroup>
)

export default Authors
29 changes: 12 additions & 17 deletions src/components/Blog/BreadcrumbsNav/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import type { ReactNode } from 'react'
import type { UrlObject } from 'url'
import { Breadcrumbs, Typography } from '@mui/material'
import Link from 'next/link'
import css from './styles.module.css'
import { type UrlObject } from 'url'
import CategoryIcon from '@/public/images/Blog/category-icon.svg'
import { type ReactNode } from 'react'
import { AppRoutes } from '@/config/routes'
import AngleIcon from '@/public/images/angle-icon.svg'
import css from './styles.module.css'

const TYPOGRAPHY_VARIANT = 'caption'
const TYPOGRAPHY_COLOR = 'text.primary'
const TYPOGRAPHY_VARIANT = 'body2'

type BreadcrumbsType = {
category: string
Expand All @@ -16,7 +15,7 @@ type BreadcrumbsType = {

const createBreadcrumb = (key: string, text: ReactNode, linkProps: string | UrlObject) => (
<Link key={key} href={linkProps}>
<Typography variant={TYPOGRAPHY_VARIANT} color={TYPOGRAPHY_COLOR}>
<Typography variant={TYPOGRAPHY_VARIANT} color="primary.light">
{text}
</Typography>
</Link>
Expand All @@ -25,21 +24,17 @@ const createBreadcrumb = (key: string, text: ReactNode, linkProps: string | UrlO
const BreadcrumbsNav = ({ category, title }: BreadcrumbsType) => {
const breadcrumbs = [
createBreadcrumb('1', 'Blog', { pathname: AppRoutes.blog.index }),
createBreadcrumb(
'2',
<div className={css.category}>
<CategoryIcon />
{category}
</div>,
{ pathname: AppRoutes.blog.index, query: { category } },
),
<Typography key="3" variant={TYPOGRAPHY_VARIANT} color={TYPOGRAPHY_COLOR}>
createBreadcrumb('2', category, {
pathname: AppRoutes.blog.index,
query: { category },
}),
<Typography key="3" variant={TYPOGRAPHY_VARIANT} className={css.title}>
{title}
</Typography>,
]

return (
<Breadcrumbs separator=">" className={css.breadcrumbs}>
<Breadcrumbs separator={<AngleIcon />} className={css.breadcrumbs}>
{breadcrumbs}
</Breadcrumbs>
)
Expand Down
27 changes: 15 additions & 12 deletions src/components/Blog/BreadcrumbsNav/styles.module.css
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
.breadcrumbs,
.breadcrumbs li {
display: flex;
align-items: center;
}

.breadcrumbs a {
color: var(--mui-palette-text-primary);
margin-bottom: 24px;
transition-duration: var(--transition-duration);
}

.breadcrumbs a:hover {
color: var(--mui-palette-primary-light);
text-decoration: underline;
}

.breadcrumbs :global .MuiBreadcrumbs-separator {
margin: 0 4px;
width: 8px;
height: 8px;
}

.breadcrumbs :global .MuiTypography-root {
line-height: inherit;
}

.category {
display: flex;
gap: 4px;
align-items: center;
.title {
width: 290px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: var(--mui-palette-primary-light);
}
15 changes: 4 additions & 11 deletions src/components/Blog/Card/index.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import Image from 'next/image'
import Link from 'next/link'
import { Box, Typography } from '@mui/material'
import css from './styles.module.css'
import { calculateReadingTimeInMin } from '@/components/Blog/utils/calculateReadingTime'
import Tags from '@/components/Blog/Tags'
import CategoryIcon from '@/public/images/Blog/category-icon.svg'
import { isAsset } from '@/lib/typeGuards'
import type { BlogPostEntry } from '@/config/types'
import Meta from '@/components/Blog/Meta'
import { AppRoutes } from '@/config/routes'
import css from './styles.module.css'

const Card = (props: BlogPostEntry) => {
const { slug, title, content, coverImage, tags, category } = props.fields
const { slug, title, coverImage, tags } = props.fields

return (
<div className={css.postCard}>
Expand All @@ -27,13 +26,7 @@ const Card = (props: BlogPostEntry) => {
) : undefined}

<div className={css.cardBody}>
<div className={css.meta}>
<CategoryIcon />
<Typography variant="caption" color="text.primary">
{category}
</Typography>
<Typography variant="caption">{calculateReadingTimeInMin(content)}</Typography>
</div>
<Meta post={props} />

<div className={css.title}>
<Typography variant="h5">{title}</Typography>
Expand Down
33 changes: 23 additions & 10 deletions src/components/Blog/Card/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,26 @@
display: flex;
flex-direction: column;
border-radius: 8px;
border: 1px solid var(--mui-palette-border-main);
overflow: hidden;
outline: 1px solid var(--mui-palette-border-main);
transition-duration: var(--transition-duration);
}

.postCard:hover {
border: 1px solid var(--mui-palette-primary-main);
.postCard::before {
content: '';
position: absolute;
border-radius: 11px;
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
z-index: -1;
background: linear-gradient(to bottom left, #12ff80, #5fddff);
opacity: 0;
}

.postCard:hover::before {
opacity: 1;
box-shadow: 10px 10px 25px 0 rgba(18, 255, 128, 0.2);
}

.link {
Expand All @@ -27,25 +40,25 @@
object-position: center left;
border-bottom: 1px solid var(--mui-palette-border-main);
transition-duration: var(--transition-duration);
border-top-left-radius: 8px;
border-top-right-radius: 8px;
}

.cardBody {
padding: 24px 16px;
display: flex;
flex-direction: column;
flex-grow: 1;
}

.meta {
display: flex;
gap: 8px;
align-items: center;
background-color: var(--mui-palette-background-default);
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}

.title {
margin-top: 16px;
overflow: hidden;
display: -webkit-box;
line-clamp: 3;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
40 changes: 24 additions & 16 deletions src/components/Blog/ContentsTable/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useMemo } from 'react'
import { scrollToElement } from '@/lib/scrollSmooth'
import { Typography } from '@mui/material'
import Link from 'next/link'
import css from '../styles.module.css'
import css from './styles.module.css'

const ContentsTable = ({ content }: { content: ContentfulDocument }) => {
const handleContentTableClick = (e: React.MouseEvent<HTMLAnchorElement>, target: string) => {
Expand All @@ -25,22 +25,30 @@ const ContentsTable = ({ content }: { content: ContentfulDocument }) => {
[content],
)

if (!headings.length) return null

return (
<ul className={css.contentsTable}>
{headings.map((heading) => {
const headingKey = kebabCase(heading.id)

return (
<li key={headingKey}>
<Typography>
<Link onClick={(e) => handleContentTableClick(e, headingKey)} href={`#${headingKey}`}>
{heading.text}
</Link>
</Typography>
</li>
)
})}
</ul>
<div className={css.contentsTable}>
<Typography variant="caption" color="text.primary">
Table of contents
</Typography>

<ol>
{headings.map((heading) => {
const headingKey = kebabCase(heading.id)

return (
<li key={headingKey}>
<Typography>
<Link onClick={(e) => handleContentTableClick(e, headingKey)} href={`#${headingKey}`}>
{heading.text}
</Link>
</Typography>
</li>
)
})}
</ol>
</div>
)
}

Expand Down
30 changes: 30 additions & 0 deletions src/components/Blog/ContentsTable/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.contentsTable {
margin: 0;
border: 1px solid var(--mui-palette-border-light);
border-radius: 8px;
padding: 24px;
margin-bottom: 24px;
}

.contentsTable ol {
list-style-type: none;
padding-left: 0px;
}

.contentsTable li {
counter-increment: step-counter;
display: flex;
align-items: flex-start;
gap: 8px;
}

.contentsTable li::before {
content: counter(step-counter) ' ';
white-space: pre;
color: var(--mui-palette-primary-light);
}

.contentsTable a:hover {
text-decoration: underline;
color: var(--mui-palette-primary-main);
}
20 changes: 3 additions & 17 deletions src/components/Blog/FeaturedPost/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ import Image from 'next/image'
import Tags from '@/components/Blog/Tags'
import { Box, Grid, Link, Typography } from '@mui/material'
import css from './styles.module.css'
import { formatBlogDate } from '@/components/Blog/utils/formatBlogDate'
import { calculateReadingTimeInMin } from '@/components/Blog/utils/calculateReadingTime'
import type { BlogPostEntry } from '@/config/types'
import { isAsset } from '@/lib/typeGuards'
import CategoryIcon from '@/public/images/Blog/category-icon.svg'
import { AppRoutes } from '@/config/routes'
import { containsTag, PRESS_RELEASE_TAG } from '@/lib/containsTag'
import Meta from '@/components/Blog/Meta'

const FeaturedPost = ({ post }: { post: BlogPostEntry }) => {
const { slug, coverImage, category, date, title, excerpt, tags, content } = post.fields
const { slug, coverImage, title, excerpt, tags } = post.fields

const isPressRelease = containsTag(tags, PRESS_RELEASE_TAG)

Expand All @@ -38,19 +36,7 @@ const FeaturedPost = ({ post }: { post: BlogPostEntry }) => {
</Grid>

<Grid item lg={5} className={css.body}>
<div className={css.meta}>
<div className={css.metaStart}>
<CategoryIcon />

<Typography variant="caption" color="text.primary">
{category}
</Typography>

<Typography variant="caption">{calculateReadingTimeInMin(content)}</Typography>
</div>

<Typography variant="caption">{formatBlogDate(date)}</Typography>
</div>
<Meta post={post} />

<Typography variant="h3" className={css.title}>
<Link href={`${AppRoutes.blog.index}/${slug}`}>{title}</Link>
Expand Down
14 changes: 0 additions & 14 deletions src/components/Blog/FeaturedPost/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,6 @@
gap: 16px;
}

.meta {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}

.metaStart {
display: flex;
flex-wrap: nowrap;
align-items: center;
gap: 8px;
}

.title,
.excerpt {
overflow: hidden;
Expand Down
Loading
Loading