Skip to content

Commit 4d8fed4

Browse files
authored
Merge branch 'main' into testimonial
2 parents 945e18a + 4d6345f commit 4d8fed4

8 files changed

Lines changed: 369 additions & 169 deletions

File tree

README.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
<div style="text-align: center">
1+
<div align="center">
22
<a href="https://www.recodehive.com">
33
<img src="static/icons/Logo-512X512.png" alt="recode hive logo" width="150" />
44
</a>
55
</div>
66

7-
<h1 style="text-align: center">recode hive</h1>
7+
<h1 align="center">recode hive</h1>
88

9-
<div style="text-align: center">
9+
<div align="center">
1010

1111
[![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors)
1212
[![Stars Badge](https://img.shields.io/github/stars/recodehive/recode-website)](https://github.com/recodehive/recode-website/stargazers)
@@ -16,11 +16,11 @@
1616
[![Contributors](https://img.shields.io/github/contributors/recodehive/recode-website?color=2b9348)](https://github.com/recodehive/recode-website/graphs/contributors)
1717
[![License Badge](https://img.shields.io/github/license/recodehive/recode-website?color=2b9348)](https://github.com/recodehive/recode-website/LICENSE)
1818

19-
<h2 style="text-align: center">Collaboration 1st , code 2nd.</h2>
19+
<h2 align="center">Collaboration 1st , code 2nd.</h2>
2020

21-
**Your all-in-one resource for learning Git, GitHub, Python through comprehensive tutorials and hands-on projects.**
21+
**Your all-in-one resource for learning Git, GitHub and, Python through comprehensive tutorials and hands-on projects.**
2222

23-
[Website](https://recodehive.com/)[Documentation](https://recodehive.com/docs)[Contributing](community/contributing-guidelines.md)[Discord](https://discord.gg/dh3TA8U55Q)
23+
[Website](https://recodehive.com/)[Documentation](https://recodehive.com/docs)[Contributing](community/contributing-guidelines.md)[Discord](https://discord.gg/Yxv9RA3r)
2424

2525
</div>
2626

@@ -199,7 +199,7 @@ git push origin feature/your-feature-name
199199
<p>How to Contribute to this Repo | How to Setup - Watch Video</p>
200200
</a>
201201
<a href="https://www.loom.com/share/c8d8d5f0c2534a1f86fc510dcef52ee0">
202-
<img style="max-width:700px;" src="https://cdn.loom.com/sessions/thumbnails/c8d8d5f0c2534a1f86fc510dcef52ee0-30cac2eeec09a266-full-play.gif" alt="How to Contribute video thumbnail">
202+
<img style="max-width:700px;" src="https://cdn.loom.com/sessions/thumbnails/c8d8d5f0c2534a1f86fc510dcef52ee0-30cac2eeec09a266-full-play.gif">
203203
</a>
204204
</div>
205205

@@ -216,7 +216,7 @@ For detailed guidelines, please refer to our [Contributing Guidelines](community
216216

217217
Join our community and connect with fellow learners:
218218

219-
[![Discord](https://img.shields.io/badge/Discord-5865F2.svg?style=for-the-badge&logo=Discord&logoColor=white)](https://discord.gg/dh3TA8U55Q)
219+
[![Discord](https://img.shields.io/badge/Discord-5865F2.svg?style=for-the-badge&logo=Discord&logoColor=white)](https://discord.gg/Yxv9RA3r)
220220
[![LinkedIn](https://img.shields.io/badge/Follow%20on-LinkedIn-blue?style=for-the-badge&logo=linkedin)](https://www.linkedin.com/in/sanjay-k-v/)
221221

222222
## 📊 Project Statistics
@@ -235,7 +235,7 @@ Join our community and connect with fellow learners:
235235
We appreciate all contributions to recode hive! Thank you to everyone who has helped make this project better.
236236

237237
<a href="https://github.com/RecodeHive/recode-website/graphs/contributors">
238-
<img src="https://contrib.rocks/image?repo=RecodeHive/recode-website" alt="Contributors image" />
238+
<img src="https://contrib.rocks/image?repo=RecodeHive/recode-website" />
239239
</a>
240240

241241
## ⚖️ License
@@ -247,18 +247,20 @@ This project is licensed under the [MIT License](LICENSE). See the LICENSE file
247247
Stay up to date with the latest from recode hive:
248248

249249
- **Website:** [recodehive.com](https://recodehive.com/)
250-
- **LinkedIn:** [LinkedIn](https://www.linkedin.com/in/sanjay-k-v/)
251-
- **Twitter:** [X](https://x.com/sanjay_kv_)
250+
- **Instagram:** [@nomad_brains](https://www.instagram.com/nomad_brains/)
251+
- **LinkedIn:** [Sanjay K V](https://www.linkedin.com/in/sanjay-k-v/)
252+
- **Twitter:** [@sanjay*kv*](https://x.com/sanjay_kv_)
252253
- **YouTube:** [@RecodeHive](https://www.youtube.com/@RecodeHive)
253254
- **Newsletter:** [Subscribe](https://recodehive.substack.com/)
254255

255256
---
256257

257-
<div style="text-align: center">
258+
<div align="center">
259+
258260
**Happy open-source contributions—here's to your career success! 🎉**
259261

260-
<p style="text-align: center">
261-
<img src="https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif" width="600" alt="recode hive showcase">
262+
<p align="center">
263+
<img src="https://user-images.githubusercontent.com/74038190/212284100-561aa473-3905-4a80-b561-0d28506553ee.gif" width="600">
262264
</p>
263265

264266
Made with ❤️ by the recode hive community
Lines changed: 136 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"use client";
22
import React from "react";
33
import Link from "@docusaurus/Link";
4-
import { getAuthorProfiles, getAuthorTooltip } from "../../utils/authors";
4+
import { getAuthorProfiles } from "../../utils/authors";
55

66
interface BlogCardProps {
77
type: string;
@@ -11,140 +11,172 @@ interface BlogCardProps {
1111
imageUrl: string;
1212
id: string;
1313
authors?: string[];
14+
tags?: string[];
15+
category?: string;
16+
}
17+
18+
const TAG_COLORS = [
19+
{ dot: "#f59e0b", border: "#fde68a", bg: "#fffbeb", text: "#92400e" },
20+
{ dot: "#6366f1", border: "#c7d2fe", bg: "#eef2ff", text: "#3730a3" },
21+
{ dot: "#ec4899", border: "#fbcfe8", bg: "#fdf2f8", text: "#9d174d" },
22+
{ dot: "#10b981", border: "#a7f3d0", bg: "#ecfdf5", text: "#065f46" },
23+
{ dot: "#3b82f6", border: "#bfdbfe", bg: "#eff6ff", text: "#1e40af" },
24+
{ dot: "#8b5cf6", border: "#ddd6fe", bg: "#f5f3ff", text: "#5b21b6" },
25+
{ dot: "#f97316", border: "#fed7aa", bg: "#fff7ed", text: "#9a3412" },
26+
{ dot: "#14b8a6", border: "#99f6e4", bg: "#f0fdfa", text: "#134e4a" },
27+
];
28+
29+
function tagColor(label: string) {
30+
let hash = 0;
31+
for (let i = 0; i < label.length; i++)
32+
hash = label.charCodeAt(i) + ((hash << 5) - hash);
33+
return TAG_COLORS[Math.abs(hash) % TAG_COLORS.length];
34+
}
35+
36+
function formatDate(dateStr?: string) {
37+
if (!dateStr) return "";
38+
const d = new Date(dateStr);
39+
if (isNaN(d.getTime())) return dateStr;
40+
return d.toLocaleDateString("en-US", {
41+
month: "short",
42+
day: "2-digit",
43+
year: "numeric",
44+
});
1445
}
1546

1647
const BlogCard = ({
1748
type,
49+
date,
1850
title,
19-
content,
2051
imageUrl,
2152
id,
2253
authors,
54+
tags,
55+
category,
2356
}: BlogCardProps) => {
2457
const authorProfiles = getAuthorProfiles(authors || []);
2558

2659
if (!id || !type) {
2760
return <div>data not fetched properly, imageId and entryId not found</div>;
2861
}
2962

30-
// Get category from title for demo purposes
31-
const getCategory = (title) => {
32-
if (
33-
title.toLowerCase().includes("design") ||
34-
title.toLowerCase().includes("ux")
35-
)
36-
return "Design";
37-
if (
38-
title.toLowerCase().includes("ai") ||
39-
title.toLowerCase().includes("deepmind")
40-
)
41-
return "AI & Tech";
42-
if (
43-
title.toLowerCase().includes("github") ||
44-
title.toLowerCase().includes("git")
45-
)
46-
return "Development";
47-
return "Resources";
48-
};
63+
// Tags: use tags array first, then category, skip generic "blog"
64+
const rawTags = Array.isArray(tags) && tags.length > 0
65+
? tags
66+
: category
67+
? [category]
68+
: [];
4969

50-
const category = getCategory(title);
70+
const tagList = rawTags.filter(
71+
(t) => t && t.toLowerCase() !== "blog" && t.toLowerCase() !== "post"
72+
);
5173

5274
return (
53-
<div className="relative h-full overflow-hidden transition-all duration-300">
54-
<div className="article-card h-full">
55-
{/* Category Badge */}
56-
<div className="card-category">{category}</div>
57-
58-
{/* Card Image */}
59-
<div className="card-image">
60-
<img src={imageUrl} alt={title} />
61-
</div>
75+
<div className="article-card">
76+
{/* Image */}
77+
<div className="card-image">
78+
<img src={imageUrl} alt={title} loading="lazy" />
79+
</div>
6280

63-
{/* Card Content */}
64-
<div className="card-content">
65-
<h3 className="card-title">
66-
<Link to={`/blog/${id}`} className="card-title-link">
67-
{title}
68-
</Link>
69-
</h3>
70-
<p className="card-description">{content}</p>
81+
{/* Content */}
82+
<div className="card-content">
83+
{/* Title */}
84+
<h3 className="card-title">
85+
<Link to={`/blog/${id}`} className="card-title-link">
86+
{title}
87+
</Link>
88+
</h3>
7189

72-
{/* Card Meta */}
73-
<div className="card-meta">
74-
<div className="card-author">
75-
{/* Stacked Author Avatars */}
76-
{authorProfiles.length > 0 &&
77-
(() => {
78-
const max = 3;
79-
const visible = authorProfiles.slice(0, max);
80-
const extra = Math.max(0, authorProfiles.length - max);
81-
return (
82-
<div className="author-stack" aria-hidden>
83-
{visible.map((a, i) => (
84-
<div
85-
key={a.id}
86-
className="author-stack-item"
87-
style={{ zIndex: max - i }}
88-
>
89-
{a.imageUrl ? (
90-
<img
91-
src={a.imageUrl}
92-
alt={a.name}
93-
className="author-stack-avatar"
94-
onError={(e) => {
95-
const target = e.currentTarget;
96-
target.style.display = "none";
97-
const fallback =
98-
target.nextElementSibling as HTMLElement | null;
99-
if (fallback) fallback.style.display = "flex";
100-
}}
101-
/>
102-
) : (
103-
<span className="author-stack-fallback">
104-
{a.name.charAt(0).toUpperCase()}
105-
</span>
106-
)}
107-
</div>
108-
))}
109-
{extra > 0 && (
110-
<div className="author-stack-more">+{extra}</div>
111-
)}
112-
</div>
113-
);
114-
})()}
90+
{/* Tag pills */}
91+
{tagList.length > 0 && (
92+
<div className="card-tags">
93+
{tagList.slice(0, 5).map((tag) => {
94+
const c = tagColor(tag);
95+
return (
96+
<span
97+
key={tag}
98+
className="card-tag"
99+
style={{
100+
"--tag-dot": c.dot,
101+
"--tag-border": c.border,
102+
"--tag-bg": c.bg,
103+
"--tag-text": c.text,
104+
} as React.CSSProperties}
105+
>
106+
<span className="card-tag-dot" />
107+
{tag}
108+
</span>
109+
);
110+
})}
111+
</div>
112+
)}
115113

116-
{/* Author Names */}
117-
<div className="author-name-group">
118-
{authorProfiles.map((author, authorIndex) => (
119-
<span key={author.id} className="author-item">
120-
{authorIndex > 0 && (
121-
<span className="author-separator">,</span>
122-
)}
123-
<Link
124-
href={author.githubUrl}
125-
className="author-name author-link"
126-
target="_blank"
127-
rel="noopener noreferrer"
128-
data-author-tooltip={getAuthorTooltip(author.id)}
129-
aria-label={`Open ${author.name} on GitHub`}
114+
{/* Footer: avatars + author names/date + Read → */}
115+
<div className="card-footer">
116+
<div className="card-author-row">
117+
{/* Avatar stack — shows all authors overlapped */}
118+
{authorProfiles.length > 0 && (
119+
<div className="card-avatar-stack">
120+
{authorProfiles.map((author, i) => (
121+
<div
122+
key={author.id || i}
123+
className="card-avatar"
124+
style={{ zIndex: authorProfiles.length - i }}
125+
>
126+
{author.imageUrl ? (
127+
<img
128+
src={author.imageUrl}
129+
alt={author.name}
130+
className="card-avatar-img"
131+
onError={(e) => {
132+
const t = e.currentTarget;
133+
t.style.display = "none";
134+
const fb = t.nextElementSibling as HTMLElement | null;
135+
if (fb) fb.style.display = "flex";
136+
}}
137+
/>
138+
) : null}
139+
<span
140+
className="card-avatar-fallback"
141+
style={{ display: author.imageUrl ? "none" : "flex" }}
130142
>
131-
{author.name}
132-
</Link>
133-
</span>
143+
{author.name.charAt(0).toUpperCase()}
144+
</span>
145+
</div>
134146
))}
135147
</div>
148+
)}
149+
150+
<div className="card-author-info">
151+
{/* All author names inline, separated by commas */}
152+
{authorProfiles.length > 0 && (
153+
<div className="card-author-names">
154+
{authorProfiles.map((author, i) => (
155+
<React.Fragment key={author.id || i}>
156+
{i > 0 && <span className="card-author-sep">, </span>}
157+
<Link
158+
href={author.githubUrl}
159+
className="card-author-handle"
160+
target="_blank"
161+
rel="noopener noreferrer"
162+
>
163+
@{author.id || author.name.toLowerCase().replace(/\s+/g, "")}
164+
</Link>
165+
</React.Fragment>
166+
))}
167+
</div>
168+
)}
169+
{date && <span className="card-date">{formatDate(date)}</span>}
136170
</div>
137-
<span className="card-read-time">5 min read</span>
138171
</div>
139172

140-
{/* Read More Button */}
141-
<Link to={`/blog/${id}`} className="card-read-more">
142-
Read Article →
173+
<Link to={`/blog/${id}`} className="card-read-link">
174+
Read →
143175
</Link>
144176
</div>
145177
</div>
146178
</div>
147179
);
148180
};
149181

150-
export default BlogCard;
182+
export default BlogCard;

0 commit comments

Comments
 (0)