Skip to content
Open
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
55 changes: 55 additions & 0 deletions components/Blog/Card/index.jsx

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split this into a few different files to make things clearer, such as:

  • Blog/PostCard
  • Blog/Cover (the post image)
  • Blog/Byline (the author info)

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import styles from './index.module.css';

const formatDate = dateString => {
if (!dateString) return '';
const date = new Date(dateString);
return date.toLocaleDateString('en-GB', {
day: 'numeric',
month: 'short',
year: 'numeric',
});
};

export default function BlogCard({
slug,
title,
date,
description,
contributors = [],
}) {
return (
<div className={styles.card}>
<div className={styles.decoration}></div>

<a href={`/blogs/${slug}`} className={styles.mainLink}></a>

<div className={styles.content}>
<h5 className={styles.title}>{title || 'Untitled Post'}</h5>
<p className={styles.description}>{description}</p>
</div>

<div className={styles.footer}>
<div className={styles.avatars}>
{contributors.map(user => (
<a
key={user}
href={`https://github.com/${user}`}
target="_blank"
className={styles.avatarLink}
title={user}
>
<img
src={`https://github.com/${user}.png?size=64`}
alt={user}
className={styles.avatar}
/>
</a>
))}
</div>

<span className={styles.dot}>•</span>
<span className={styles.date}>{formatDate(date)}</span>
</div>
</div>
);
}
125 changes: 125 additions & 0 deletions components/Blog/Card/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
@reference "../../../styles/index.css";

.card {
@apply relative
flex
flex-col
h-full
rounded-xl
border
border-neutral-200
bg-white
p-6
overflow-hidden
transition-colors
duration-150
hover:border-blue-300
hover:bg-blue-50/40
dark:border-neutral-800
dark:bg-neutral-900
dark:hover:border-blue-400/60
dark:hover:bg-blue-950/40;
}

.decoration {
@apply absolute
-right-8
-top-8
size-32
bg-blue-500
opacity-0
transition-all
duration-500
translate-x-4
-translate-y-4;

clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
}

.card:hover .decoration {
@apply opacity-5
dark:opacity-10
translate-x-0
translate-y-0
rotate-12;
}

.mainLink {
@apply absolute
inset-0
z-0
focus:outline-none;
}

.content {
@apply flex
flex-col
gap-3
pb-5
pointer-events-none;
}

.title {
@apply m-0
text-xl
font-bold
leading-tight
text-neutral-900
dark:text-white;
}

.description {
@apply m-0
line-clamp-3
text-base
leading-relaxed
text-neutral-600
dark:text-neutral-400;
}

.footer {
@apply mt-auto
flex
items-center
border-t
border-neutral-100
pt-3
dark:border-neutral-800/80;
}

.avatars {
@apply flex
items-center
-space-x-2;
}

.avatarLink {
@apply relative
z-10
transition-transform
hover:-translate-y-1;
}

.avatar {
@apply size-8
rounded-full
border-2
border-white
bg-neutral-100
dark:border-neutral-900
dark:bg-neutral-800;
}

.dot {
@apply mx-3
text-neutral-300
dark:text-neutral-600;
}

.date {
@apply tabular-nums
text-sm
font-medium
text-neutral-500
dark:text-neutral-400;
}
2 changes: 2 additions & 0 deletions components/Layout.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import DefaultLayout from '@node-core/doc-kit/src/generators/web/ui/components/Layout/index.jsx';
import HomeLayout from '../layouts/Home/index.jsx';
import SponsorsLayout from '../layouts/Sponsors/index.jsx';
import BlogLayout from '../layouts/Blog/index.jsx';
import '../styles/index.css';

const LAYOUTS = {
home: HomeLayout,
sponsors: SponsorsLayout,
blogs: BlogLayout,
};

export default function Layout(props) {
Expand Down
40 changes: 40 additions & 0 deletions layouts/Blog/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import PartialArticle from '../PartialArticle/index.jsx';
import BlogCard from '../../components/Blog/Card/index.jsx';
import blogsData from '../../generated/blogs.json';
import styles from './index.module.css';

/**
* Blogs page layout. Lists all Webpack blog posts in a grid,
* wrapped inside the PartialArticle shell to preserve the Sidebar and Navbar.
*
* @param {{ metadata: object }} props
*/
export default function BlogLayout({ metadata }) {
return (
<PartialArticle metadata={metadata}>
<section className={styles.blogSection}>
<div className={styles.container}>
<header className={styles.header}>
<h1 className={styles.mainTitle}>Webpack Blog</h1>
<p className={styles.subtitle}>
Latest news, updates, and deep dives from the Webpack team and
community.
</p>
</header>
<main className={styles.grid}>
{blogsData.map(post => (
<BlogCard
key={post.slug}
slug={post.slug}
title={post.title}
date={post.date}
description={post.description}
contributors={post.contributors}
/>
))}
</main>
</div>
</section>
</PartialArticle>
);
}
47 changes: 47 additions & 0 deletions layouts/Blog/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@reference "../../styles/index.css";

.blogSection {
@apply bg-white
py-16
lg:py-20
dark:bg-neutral-950;
}

.container {
@apply mx-auto
max-w-7xl
px-6;
}

.header {
@apply mb-12
border-b
border-neutral-200
pb-8
text-center
dark:border-neutral-800;
}

.mainTitle {
@apply mb-3
text-3xl
font-bold
text-neutral-900
lg:text-4xl
dark:text-white;
}

.subtitle {
@apply mx-auto
max-w-2xl
text-lg
text-neutral-600
dark:text-neutral-400;
}

.grid {
@apply grid
gap-6
sm:grid-cols-2
lg:grid-cols-3;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"build:prepare": "node scripts/prepare/index.mjs",
"build:data": "npm-run-all build:data:*",
"build:data:sponsors": "node scripts/data/sponsors.mjs",
"build:data:blog": "node scripts/data/blogs.mjs",
"build:md": "npm-run-all build:md:*",
"build:md:api": "node scripts/markdown/api.mjs",
"build:md:readmes": "node scripts/markdown/readmes.mjs",
Expand Down
Loading