Consolidate component folders
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
|
||||
const ContentContainer = ({ post, width = "200px", variant = "vertical" }) => {
|
||||
// Get the corresponding icon based on the same logic as background images
|
||||
const getIconImage = (slug, variant) => {
|
||||
const verticalIcons = [
|
||||
"/assets/Content_Thumbnail/Icon_1.svg",
|
||||
"/assets/Content_Thumbnail/Icon_2.svg",
|
||||
"/assets/Content_Thumbnail/Icon_3.svg",
|
||||
];
|
||||
|
||||
const horizontalIcons = [
|
||||
"/assets/Content_Thumbnail/Icon_1.svg",
|
||||
"/assets/Content_Thumbnail/Icon_2.svg",
|
||||
"/assets/Content_Thumbnail/Icon_3.svg",
|
||||
];
|
||||
|
||||
const icons = variant === "vertical" ? verticalIcons : horizontalIcons;
|
||||
|
||||
if (!slug) return icons[0];
|
||||
|
||||
// Use the same hash logic as background images to ensure matching
|
||||
const hash = slug.split("").reduce((a, b) => {
|
||||
a = (a << 5) - a + b.charCodeAt(0);
|
||||
return a & a;
|
||||
}, 0);
|
||||
|
||||
return icons[Math.abs(hash) % icons.length];
|
||||
};
|
||||
|
||||
const iconImage = getIconImage(post.slug, variant);
|
||||
|
||||
return (
|
||||
<div className="relative z-20 h-full flex flex-col gap-3" style={{ width }}>
|
||||
{/* Content Container - 8px gap between icon and text */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{/* Icon */}
|
||||
<div className="w-6 h-6 flex items-center justify-center">
|
||||
<img
|
||||
src={iconImage}
|
||||
alt={`Icon for ${post.frontmatter.title}`}
|
||||
className="w-6 h-6 object-contain"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Text Container */}
|
||||
<div className="space-y-2">
|
||||
{/* Title */}
|
||||
<h3
|
||||
className="text-lg font-medium group-hover:text-blue-200 transition-colors"
|
||||
style={{
|
||||
fontFamily: "Bricolage Grotesque",
|
||||
fontWeight: 500,
|
||||
fontSize: "18px",
|
||||
lineHeight: "120%",
|
||||
color: "var(--color-content-inverse-brand-royal)",
|
||||
}}
|
||||
>
|
||||
{post.frontmatter.title}
|
||||
</h3>
|
||||
|
||||
{/* Description */}
|
||||
<p
|
||||
className="max-w-md"
|
||||
style={{
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 400,
|
||||
fontSize: "12px",
|
||||
lineHeight: "16px",
|
||||
color: "var(--color-content-inverse-brand-royal)",
|
||||
}}
|
||||
>
|
||||
{post.frontmatter.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Metadata Container - horizontal with 8px gap */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* Author Name */}
|
||||
<span
|
||||
style={{
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 400,
|
||||
fontSize: "10px",
|
||||
lineHeight: "14px",
|
||||
color: "var(--color-content-inverse-brand-royal)",
|
||||
}}
|
||||
>
|
||||
{post.frontmatter.author}
|
||||
</span>
|
||||
|
||||
{/* Date */}
|
||||
<span
|
||||
style={{
|
||||
fontFamily: "Inter",
|
||||
fontWeight: 400,
|
||||
fontSize: "10px",
|
||||
lineHeight: "14px",
|
||||
color: "var(--color-content-inverse-brand-royal)",
|
||||
}}
|
||||
>
|
||||
{new Date(post.frontmatter.date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentContainer;
|
||||
@@ -0,0 +1,114 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
import Link from "next/link";
|
||||
import ContentContainer from "./ContentContainer";
|
||||
|
||||
/**
|
||||
* ContentThumbnailTemplate component for displaying blog post previews
|
||||
* Simplified version to debug infinite loop
|
||||
*/
|
||||
const ContentThumbnailTemplate = ({
|
||||
post,
|
||||
variant = "vertical",
|
||||
className = "",
|
||||
showReadingTime = true,
|
||||
}) => {
|
||||
// Post-specific background selection - different SVG for each post
|
||||
const getBackgroundImage = (slug, variant) => {
|
||||
const verticalImages = [
|
||||
"/assets/Content_Thumbnail/Vertical_1.svg",
|
||||
"/assets/Content_Thumbnail/Vertical_2.svg",
|
||||
"/assets/Content_Thumbnail/Vertical_3.svg",
|
||||
];
|
||||
|
||||
const horizontalImages = [
|
||||
"/assets/Content_Thumbnail/Horizontal_1.svg",
|
||||
"/assets/Content_Thumbnail/Horizontal_2.svg",
|
||||
"/assets/Content_Thumbnail/Horizontal_3.svg",
|
||||
];
|
||||
|
||||
const images = variant === "vertical" ? verticalImages : horizontalImages;
|
||||
|
||||
if (!slug) return images[0];
|
||||
|
||||
// Use the slug to deterministically select an image
|
||||
const hash = slug.split("").reduce((a, b) => {
|
||||
a = (a << 5) - a + b.charCodeAt(0);
|
||||
return a & a;
|
||||
}, 0);
|
||||
|
||||
return images[Math.abs(hash) % images.length];
|
||||
};
|
||||
|
||||
const backgroundImage = getBackgroundImage(post.slug, variant);
|
||||
|
||||
if (variant === "vertical") {
|
||||
return (
|
||||
<Link
|
||||
href={`/blog/${post.slug}`}
|
||||
className={`block group transition-transform duration-300 hover:scale-105 ${className}`}
|
||||
>
|
||||
<div
|
||||
className="relative w-[260px] h-[390px] overflow-hidden rounded-lg shadow-lg"
|
||||
style={{
|
||||
paddingTop: "18px",
|
||||
paddingLeft: "18px",
|
||||
paddingRight: "42px",
|
||||
paddingBottom: "212px",
|
||||
}}
|
||||
>
|
||||
{/* Background SVG - sized to fit the 260x390 container exactly */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<img
|
||||
src={backgroundImage}
|
||||
alt={`Background for ${post.frontmatter.title}`}
|
||||
className="w-[260px] h-[390px] object-cover"
|
||||
style={{ width: "260px", height: "390px" }}
|
||||
/>
|
||||
{/* Gradient overlay for better text readability */}
|
||||
<div className="absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-black/60 z-10" />
|
||||
</div>
|
||||
|
||||
{/* Content Section - positioned within the padding constraints */}
|
||||
<ContentContainer post={post} width="200px" variant="vertical" />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
// Horizontal variant
|
||||
return (
|
||||
<Link
|
||||
href={`/blog/${post.slug}`}
|
||||
className={`block group transition-transform duration-300 hover:scale-105 ${className}`}
|
||||
>
|
||||
<div
|
||||
className="relative w-[320px] h-[225.5px] overflow-hidden rounded-lg shadow-lg"
|
||||
style={{
|
||||
paddingTop: "13.75px",
|
||||
paddingRight: "76px",
|
||||
paddingBottom: "73.75px",
|
||||
paddingLeft: "14px",
|
||||
}}
|
||||
>
|
||||
{/* Background SVG - sized to fit the 320x225.5 container exactly */}
|
||||
<div className="absolute inset-0 z-0">
|
||||
<img
|
||||
src={backgroundImage}
|
||||
alt={`Background for ${post.frontmatter.title}`}
|
||||
className="w-[320px] h-[225.5px] object-cover"
|
||||
style={{ width: "320px", height: "225.5px" }}
|
||||
/>
|
||||
{/* Gradient overlay */}
|
||||
<div className="absolute inset-0 bg-gradient-to-r from-transparent via-transparent to-black/70 z-10" />
|
||||
</div>
|
||||
|
||||
{/* Content - positioned within the padding constraints */}
|
||||
<ContentContainer post={post} width="230px" variant="horizontal" />
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContentThumbnailTemplate;
|
||||
@@ -0,0 +1,37 @@
|
||||
"use client";
|
||||
|
||||
import React from "react";
|
||||
|
||||
/**
|
||||
* Simple image placeholder component for testing
|
||||
* Generates colored backgrounds with text overlays
|
||||
*/
|
||||
const ImagePlaceholder = ({
|
||||
width = 260,
|
||||
height = 390,
|
||||
text = "Blog Image",
|
||||
color = "blue",
|
||||
className = "",
|
||||
}) => {
|
||||
const colors = {
|
||||
blue: "bg-blue-500",
|
||||
green: "bg-green-500",
|
||||
purple: "bg-purple-500",
|
||||
red: "bg-red-500",
|
||||
orange: "bg-orange-500",
|
||||
teal: "bg-teal-500",
|
||||
};
|
||||
|
||||
const bgColor = colors[color] || colors.blue;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${bgColor} flex items-center justify-center text-white font-bold text-lg ${className}`}
|
||||
style={{ width: `${width}px`, height: `${height}px` }}
|
||||
>
|
||||
{text}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImagePlaceholder;
|
||||
Reference in New Issue
Block a user