@@ -8,6 +8,14 @@ interface Props {
88
99const { currentSlug, posts } = Astro .props ;
1010
11+ // Default fallback image
12+ const defaultImage = " /images/png/defguard.png" ;
13+
14+ // Get image for a post
15+ const getPostImage = (post : CollectionEntry <" blog" >) => {
16+ return post .data .image || defaultImage ;
17+ };
18+
1119// Format date function
1220const formatDate = (date : Date ) => {
1321 return new Date (date ).toLocaleDateString (" en-US" , {
@@ -17,6 +25,12 @@ const formatDate = (date: Date) => {
1725 });
1826};
1927
28+ // Truncate description
29+ const truncateDescription = (text : string , maxLength : number = 100 ) => {
30+ if (text .length <= maxLength ) return text ;
31+ return text .slice (0 , maxLength ).trim () + " ..." ;
32+ };
33+
2034// Filter out current post and get 3 random posts
2135const otherPosts = posts .filter ((post ) => post .slug !== currentSlug );
2236const selectedPosts = otherPosts .sort (() => Math .random () - 0.5 ).slice (0 , 3 );
@@ -29,23 +43,27 @@ const selectedPosts = otherPosts.sort(() => Math.random() - 0.5).slice(0, 3);
2943 {
3044 selectedPosts .map ((post ) => (
3145 <article class = " post-card" >
32- <h3 class = " post-title" >
33- <a href = { ` /blog/${post .slug } ` } >{ post .data .title } </a >
34- </h3 >
35- <div class = " post-meta" >
36- <time datetime = { post .data .publishDate .toISOString ()} >
37- { formatDate (post .data .publishDate )}
38- </time >
39- { post .data .author && <span class = " post-author" >by { post .data .author } </span >}
40- </div >
41- { post .data .companyName && (
42- <p >
43- <span class = " case-study-label" >Case Study</span >
44- </p >
45- )}
46- <p class = " post-description" >{ post .data .description } </p >
47- <a href = { ` /blog/${post .slug } ` } class = " read-more" >
48- Read more →
46+ <a href = { ` /blog/${post .slug } ` } class = " post-card-link" >
47+ <div class = " post-image-wrapper" >
48+ <img
49+ src = { getPostImage (post )}
50+ alt = { post .data .title }
51+ loading = " lazy"
52+ class = " post-image"
53+ />
54+ { post .data .companyName && (
55+ <span class = " card-badge-case-study" >Case Study</span >
56+ )}
57+ </div >
58+ <div class = " post-content" >
59+ <h3 class = " post-title" >{ post .data .title } </h3 >
60+ <p class = " post-description" >{ truncateDescription (post .data .description )} </p >
61+ <div class = " post-meta" >
62+ <time datetime = { post .data .publishDate .toISOString ()} >
63+ { formatDate (post .data .publishDate )}
64+ </time >
65+ </div >
66+ </div >
4967 </a >
5068 </article >
5169 ))
@@ -67,109 +85,123 @@ const selectedPosts = otherPosts.sort(() => Math.random() - 0.5).slice(0, 3);
6785
6886 .section-title {
6987 margin: 0 0 2rem;
70- font-size: calc(1rem * var(--font-scale-factor));
71- font-weight: 400 ;
88+ font-size: calc(1. 1rem * var(--font-scale-factor));
89+ font-weight: 500 ;
7290 color: var(--text-body-primary);
7391 text-align: left;
74- padding-left: 20px;
7592 }
7693
7794 .posts-grid {
7895 display: grid;
79- grid-template-columns: repeat(1, 1fr) ;
80- gap: 25px ;
96+ grid-template-columns: 1fr;
97+ gap: 24px ;
8198
8299 @media (min-width: 640px) {
83100 grid-template-columns: repeat(2, 1fr);
84- gap: 30px ;
101+ gap: 28px ;
85102 }
86103
87104 @media (min-width: 1024px) {
88105 grid-template-columns: repeat(3, 1fr);
89- gap: 40px ;
106+ gap: 32px ;
90107 }
91108 }
92109
93110 .post-card {
94- display: block;
95- text-decoration: none;
96- color: inherit;
97- padding: 20px;
98- background-color: #f9f9f9;
99- border-width: 0 0 2px 0;
100- border-style: solid;
101- border-color: #f5f5f5;
102- transition:
103- transform 0.2s ease,
104- box-shadow 0.2s ease,
105- border-color 0.2s ease;
106- transform: translateY(0);
107- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.03);
111+ background: white;
112+ border-radius: 10px;
113+ overflow: hidden;
114+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
115+ transition: transform 0.25s ease, box-shadow 0.25s ease;
108116
109117 &:hover {
110- transform: translateY(-5px);
111- border-color: var(--primary-button-bg, #0c8ce0);
112- }
118+ transform: translateY(-6px);
119+ box-shadow: 0 12px 32px rgba(0, 0, 0, 0.1);
113120
114- .post-title {
115- margin: 0 0 15px 0;
116- font-size: calc(1.5rem * var(--font-scale-factor));
117- font-weight: 400;
118-
119- a {
120- color: var(--text-body-primary);
121- text-decoration: none;
122- &:hover {
123- color: var(--primary-button-bg, #0c8ce0);
124- }
121+ .post-image {
122+ transform: scale(1.05);
123+ }
124+
125+ .post-title {
126+ color: var(--primary-button-bg, #0c8ce0);
125127 }
126128 }
127129
128- .post-meta {
129- display: flex;
130- flex-wrap: wrap;
131- gap: 0.5rem;
132- color: var(--text-body-secondary);
133- margin-bottom: 8px;
134- font-size: 14px;
135- font-weight: 300;
130+ .post-card-link {
131+ display: block;
132+ text-decoration: none;
133+ color: inherit;
134+ }
136135
137- .post-author {
138- &::before {
139- content: "•";
140- margin-right: 0.5rem;
141- }
142- }
136+ .post-image-wrapper {
137+ position: relative;
138+ overflow: hidden;
139+ background: #f8f8f8;
143140 }
144141
145- .post-description {
146- margin: 1rem 0;
147- line-height: 1.6;
148- font-weight: 300;
149- color: var(--text-body-primary);
150- font-size: calc(1rem * var(--font-scale-factor));
142+ .post-image {
143+ width: 100%;
144+ height: auto;
145+ display: block;
146+ transition: transform 0.4s ease;
151147 }
152148
153- .case-study-label {
154- display: inline-block;
155- color: var(--surface-main-primary);
149+ .card-badge-case-study {
150+ position: absolute;
151+ top: 12px;
152+ left: 12px;
153+ padding: 4px 10px;
154+ background: rgba(255, 255, 255, 0.95);
155+ color: #166534;
156156 font-size: 10px;
157- font-weight: 400;
158- padding: 5px 10px;
159- margin-bottom: 0.5rem;
160- border-radius: 50px;
161- background-color: #f5f5f5;
162- border: 1px solid var(--surface-main-primary);
157+ font-weight: 600;
158+ text-transform: uppercase;
159+ letter-spacing: 0.5px;
160+ border-radius: 4px;
161+ backdrop-filter: blur(4px);
162+ }
163+
164+ .post-content {
165+ padding: 1.25rem;
166+ }
167+
168+ .post-title {
169+ margin: 0 0 0.75rem;
170+ font-size: 1.1rem;
171+ font-weight: 500;
172+ line-height: 1.4;
173+ color: var(--text-body-primary);
174+ transition: color 0.2s ease;
175+
176+ // Clamp to 2 lines
177+ display: -webkit-box;
178+ -webkit-line-clamp: 2;
179+ -webkit-box-orient: vertical;
180+ overflow: hidden;
163181 }
164182
165- .read-more {
166- display: inline-block;
167- color: var(--primary-text-color);
168- font-size: 14px;
183+ .post-description {
184+ margin: 0 0 1rem;
185+ font-size: 0.9rem;
186+ line-height: 1.5;
187+ color: var(--text-body-secondary, #666);
169188 font-weight: 300;
170- text-decoration: none;
171- &:hover {
172- text-decoration: underline;
189+
190+ // Clamp to 2 lines for more stories
191+ display: -webkit-box;
192+ -webkit-line-clamp: 2;
193+ -webkit-box-orient: vertical;
194+ overflow: hidden;
195+ }
196+
197+ .post-meta {
198+ display: flex;
199+ align-items: center;
200+ font-size: 12px;
201+ color: var(--text-body-secondary, #888);
202+
203+ time {
204+ font-weight: 400;
173205 }
174206 }
175207 }
0 commit comments