Skip to content
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
78 changes: 78 additions & 0 deletions src/components/BlogCard.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
import type { Post } from '../lib/interfaces'
import { filePath, getPostLink } from '../lib/blog-helpers'
import PostDate from './PostDate.astro'
import PostTags from './PostTags.astro'
import PostExcerpt from './PostExcerpt.astro'

export interface Props {
post: Post
}

const { post } = Astro.props

let image = ''
if (post.FeaturedImage && post.FeaturedImage.Url) {
if (import.meta.env.DEV) {
image = post.FeaturedImage.Url
} else {
image = filePath(new URL(post.FeaturedImage.Url))
}
}

const postLink = getPostLink(post.Slug)
---

<article class="bg-white rounded-xl shadow-md overflow-hidden hover:shadow-xl hover:scale-[1.02] transition-all duration-300">
<a href={postLink} class="block">
<div class="md:flex">
<!-- アイキャッチ画像 -->
<div class="md:w-48 lg:w-64 flex-shrink-0">
<div class="h-48 md:h-full overflow-hidden">
{image ? (
<img
src={image}
alt={post.Title}
class="w-full h-full object-cover"
/>
) : (
<div class="bg-gradient-to-br from-blue-500 to-purple-600 h-full flex items-center justify-center">
<span class="text-white text-4xl">
{post.Icon && post.Icon.Type === 'emoji' && 'Emoji' in post.Icon
? post.Icon.Emoji
: '📝'}
</span>
</div>
)}
</div>
</div>

<!-- コンテンツ -->
<div class="p-5 flex flex-col justify-between flex-grow">
<div>
<div class="text-sm text-gray-500 mb-2">
<PostDate post={post} />
</div>
<h2 class="text-xl font-semibold mb-2 text-gray-800 line-clamp-2 group-hover:text-blue-600 transition-colors">
{post.Title}
</h2>
<div class="mb-3">
<PostTags post={post} enableLink={false} />
</div>
<div class="text-gray-600 text-sm line-clamp-2">
<PostExcerpt post={post} />
</div>
</div>
</div>
</div>
</a>
</article>

<style>
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>
37 changes: 29 additions & 8 deletions src/components/Headline.astro
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
export interface Props {
title: string;
href?: string;
showMascots?: boolean;
}
const { title, href } = Astro.props;
const { title, href, showMascots = false } = Astro.props;
---

<div
Expand All @@ -14,15 +15,35 @@ const { title, href } = Astro.props;
<div class="items-center flex flex-wrap">
<div class="w-full lg:w-12/12 px-4 ml-auto mr-auto text-center max-w-7xl">
<div class="">
{
href ? (
<a href={href}>
<div class="flex items-center justify-center gap-4">
{showMascots && (
<a href="/mascots" class="hidden md:block hover:scale-110 transition-transform">
<img
src="/images/mascots/suu-face.png"
alt="スーちゃん"
class="w-12 h-12 lg:w-16 lg:h-16 object-contain drop-shadow-md"
/>
</a>
)}
{
href ? (
<a href={href} class="hover:text-blue-600 transition-colors">
<h1 class="text-gray-900 font-semibold text-5xl hover:text-blue-600">{title}</h1>
</a>
) : (
<h1 class="text-gray-900 font-semibold text-5xl">{title}</h1>
)
}
{showMascots && (
<a href="/mascots" class="hidden md:block hover:scale-110 transition-transform">
<img
src="/images/mascots/toge-face.png"
alt="トゲくん"
class="w-12 h-12 lg:w-16 lg:h-16 object-contain drop-shadow-md"
/>
</a>
) : (
<h1 class="text-gray-900 font-semibold text-5xl">{title}</h1>
)
}
)}
</div>
<slot />
</div>
</div>
Expand Down
11 changes: 10 additions & 1 deletion src/pages/posts/[slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import PostBody from '../../components/PostBody.astro'
import PostRelativeLink from '../../components/PostRelativeLink.astro'
import BlogPostsLink from '../../components/BlogPostsLink.astro'
import BlogTagsLink from '../../components/BlogTagsLink.astro'
import MascotPeek from '../../components/MascotPeek.astro'
import styles from '../../styles/blog.module.css'
import Layout from '../../layouts/Layout.astro'
import Headline from '../../components/Headline.astro'
Expand Down Expand Up @@ -105,7 +106,7 @@ if (post.FeaturedImage && post.FeaturedImage.Url) {
url={new URL(`blog/${slug}`, Astro.site)}
ogImage={ogImage}
>
<Headline title="Blog">
<Headline title="Blog" href="/posts" showMascots={true}>
<p class="mt-4 text-lg text-black">
CloudNative Days実行委員会によるブログ
</p>
Expand Down Expand Up @@ -144,4 +145,12 @@ if (post.FeaturedImage && post.FeaturedImage.Url) {
</aside>
</div>
</div>

<!-- マスコットのひょっこり -->
<a href="/mascots">
<MascotPeek character="suu" position="left" />
</a>
<a href="/mascots">
<MascotPeek character="toge" position="right" />
</a>
</Layout>
67 changes: 25 additions & 42 deletions src/pages/posts/index.astro
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
---
import BlogCard from '../../components/BlogCard.astro'
import BlogPostsLink from '../../components/BlogPostsLink.astro'
import BlogTagsLink from '../../components/BlogTagsLink.astro'
import Headline from '../../components/Headline.astro'
import MascotPeek from '../../components/MascotPeek.astro'
import NoContents from '../../components/NoContents.astro'
import Pagination from '../../components/Pagination.astro'
import PostDate from '../../components/PostDate.astro'
import PostExcerpt from '../../components/PostExcerpt.astro'
import PostTags from '../../components/PostTags.astro'
import PostTitle from '../../components/PostTitle.astro'
import ReadMoreLink from '../../components/ReadMoreLink.astro'
import Layout from '../../layouts/Layout.astro'
import {
getPosts,
Expand All @@ -17,7 +14,6 @@ import {
getNumberOfPages,
} from '../../lib/notion/client'
import { NUMBER_OF_POSTS_PER_PAGE } from '../../server-constants'
import styles from '../../styles/blog.module.css'

const [posts, rankedPosts, tags, numberOfPages] = await Promise.all([
getPosts(NUMBER_OF_POSTS_PER_PAGE),
Expand All @@ -27,61 +23,48 @@ const [posts, rankedPosts, tags, numberOfPages] = await Promise.all([
])
---

<Layout
<Layout
title="CloudNative Days Blog"
description="CloudNative Days実行委員会によるブログ"
ogImage=""
>
<Headline title="Blog">
<Headline title="Blog" showMascots={true}>
<p class="mt-4 text-lg text-black">
CloudNative Days実行委員会によるブログ
</p>
</Headline>
<div class="px-8 flex flex-wrap gap-5 max-w-7xl md:justify-center md:mx-auto">
<main class="md:w-8/12 w-12/12 bg-white/60 backdrop-blur-sm rounded-xl p-6">
<div class="px-4 md:px-8 flex flex-col lg:flex-row gap-6 max-w-7xl mx-auto">
<main class="flex-1">
{
posts.length === 0 ? (
<NoContents contents={posts} />
) : (
posts.map((post) => (
<div class="py-6">
<div class={styles.post}>
<div class="mb-3">
<PostDate post={post} />
<PostTitle post={post} enableLink={true} />
<div class="mb-2 border-b-2 border-gray-200" />
<PostTags post={post} enableLink={true} />
</div>
<PostExcerpt post={post} />
<ReadMoreLink post={post} />
</div>
</div>
))
<div class="space-y-6">
{posts.map((post) => (
<BlogCard post={post} />
))}
</div>
)
}

<footer class="flex justify-center items-center mt-5">
<footer class="flex justify-center items-center mt-8 mb-8">
<Pagination currentPage={1} numberOfPages={numberOfPages} tag="" />
</footer>
</main>

<aside class="md:mt-0 md:ml-4 md:flex-auto w-12/12 bg-white/60 backdrop-blur-sm rounded-xl p-6 h-fit">
<BlogPostsLink heading="Recommended" posts={rankedPosts} />
<BlogTagsLink heading="Categories" tags={tags} />
<aside class="lg:w-80 flex-shrink-0">
<div class="bg-white/80 backdrop-blur-sm rounded-xl p-6 sticky top-24">
<BlogPostsLink heading="Recommended" posts={rankedPosts} />
<BlogTagsLink heading="Categories" tags={tags} />
</div>
</aside>
</div>
</Layout>

<style>
/* カードデザインの統一のためのスタイルを追加 */
:global(.blog-posts-link ul li a) {
border-radius: 0.375rem;
transition: all 0.3s ease;
}

:global(.blog-posts-link ul li a:hover) {
background-color: #f3f4f6;
transform: translateY(-2px);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
}
</style>
<!-- マスコットのひょっこり -->
<a href="/mascots">
<MascotPeek character="suu" position="left" />
</a>
<a href="/mascots">
<MascotPeek character="toge" position="right" />
</a>
</Layout>
42 changes: 15 additions & 27 deletions src/pages/posts/page/[page].astro
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,10 @@ import {
} from '../../../lib/notion/client'
import Layout from '../../../layouts/Layout.astro'
import NoContents from '../../../components/NoContents.astro'
import PostDate from '../../../components/PostDate.astro'
import PostTags from '../../../components/PostTags.astro'
import PostTitle from '../../../components/PostTitle.astro'
import PostExcerpt from '../../../components/PostExcerpt.astro'
import ReadMoreLink from '../../../components/ReadMoreLink.astro'
import Pagination from '../../../components/Pagination.astro'
import BlogPostsLink from '../../../components/BlogPostsLink.astro'
import BlogTagsLink from '../../../components/BlogTagsLink.astro'
import styles from '../../../styles/blog.module.css'
import BlogCard from '../../../components/BlogCard.astro'
import Headline from '../../../components/Headline.astro'

export async function getStaticPaths() {
Expand Down Expand Up @@ -43,35 +38,26 @@ const [posts, rankedPosts, tags, numberOfPages] = await Promise.all([
description="CloudNative Days実行委員会によるブログ"
ogImage=""
>
<Headline title="Blog">
<Headline title="Blog" showMascots={true}>
<p class="mt-4 text-lg text-black">
CloudNative Days実行委員会によるブログ (Page {page}/{numberOfPages})
</p>
</Headline>
<div class="px-8 flex flex-wrap gap-5 max-w-8xl md:justify-center md:mx-auto">
<main class="w-full lg:w-10/12 bg-white/60 backdrop-blur-sm rounded-xl p-6">
<div class="px-4 md:px-8 flex flex-col lg:flex-row gap-6 max-w-7xl mx-auto">
<main class="flex-1">
{
posts.length === 0 ? (
<NoContents contents={posts} />
) : (
posts.map((post) => (
<div class="py-6">
<div class={styles.post}>
<div class="mb-3">
<PostDate post={post} />
<PostTitle post={post} enableLink={true} />
<div class="mb-2 border-b-2 border-gray-200" />
<PostTags post={post} enableLink={true} />
</div>
<PostExcerpt post={post} />
<ReadMoreLink post={post} />
</div>
</div>
))
<div class="space-y-6">
{posts.map((post) => (
<BlogCard post={post} />
))}
</div>
)
}

<footer class="flex justify-center items-center mt-5">
<footer class="flex justify-center items-center mt-8 mb-8">
<Pagination
currentPage={parseInt(page, 10)}
numberOfPages={numberOfPages}
Expand All @@ -80,9 +66,11 @@ const [posts, rankedPosts, tags, numberOfPages] = await Promise.all([
</footer>
</main>

<aside class="md:mt-0 md:ml-4 md:flex-auto w-12/12 bg-white/60 backdrop-blur-sm rounded-xl p-6 h-fit">
<BlogPostsLink heading="Recommended" posts={rankedPosts} />
<BlogTagsLink heading="Categories" tags={tags} />
<aside class="lg:w-80 flex-shrink-0">
<div class="bg-white/80 backdrop-blur-sm rounded-xl p-6 sticky top-24">
<BlogPostsLink heading="Recommended" posts={rankedPosts} />
<BlogTagsLink heading="Categories" tags={tags} />
</div>
</aside>
</div>
</Layout>
Loading