Improve image focus by centering on people and faces

Update AI prompts for more accurate focal point detection and adjust image rendering in various components (MediumCard, SideCard, SingleImageCarousel) to utilize these focal points, enhancing visual composition.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 517dfa7b-26ac-463d-a6e1-a58c6df97188
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: 4e108b3d-fbcd-43ec-8d2f-0a6ed15b2c47
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/f209e72a-0939-48fa-84fc-57854de71967/517dfa7b-26ac-463d-a6e1-a58c6df97188/drGbo1a
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
sebastjanartic
2026-02-28 21:16:53 +00:00
parent 3c23a20652
commit 4046bafaab
3 changed files with 49 additions and 57 deletions
+28 -15
View File
@@ -137,14 +137,22 @@ function GalleryHeroCard({ images }: { images: GalleryImage[] }) {
);
}
function MediumCard({ article }: { article: Article }) {
function getObjectPosition(coverImage: string | null, focalPoints?: Record<string, { x: number; y: number }>): string {
if (!coverImage || !focalPoints) return "center 20%";
const fp = focalPoints[coverImage];
if (!fp) return "center 20%";
return `${fp.x}% ${fp.y}%`;
}
function MediumCard({ article, focalPoints }: { article: Article; focalPoints?: Record<string, { x: number; y: number }> }) {
const isVideo = article.category === "Video";
const objPos = getObjectPosition(article.coverImage, focalPoints);
return (
<Link href={`/article/${article.slug}`}>
<div className="relative group cursor-pointer rounded-lg overflow-hidden h-full bg-card border border-card-border flex flex-col" data-testid={`card-medium-${article.id}`}>
<div className="relative flex-shrink-0">
<div className="overflow-hidden">
<img src={thumbUrl(article.coverImage)} alt={article.title} className="w-full aspect-video object-cover transition-transform duration-500 group-hover:scale-105" style={{ objectPosition: "center 20%" }} loading="lazy" />
<img src={thumbUrl(article.coverImage)} alt={article.title} className="w-full aspect-video object-cover transition-transform duration-500 group-hover:scale-105" style={{ objectPosition: objPos }} loading="lazy" />
</div>
{isVideo && (
<div className="absolute inset-0 flex items-center justify-center">
@@ -171,14 +179,15 @@ function MediumCard({ article }: { article: Article }) {
);
}
function SideCard({ article }: { article: Article }) {
function SideCard({ article, focalPoints }: { article: Article; focalPoints?: Record<string, { x: number; y: number }> }) {
const isVideo = article.category === "Video";
const objPos = getObjectPosition(article.coverImage, focalPoints);
return (
<Link href={`/article/${article.slug}`}>
<div className="relative group cursor-pointer rounded-lg overflow-hidden bg-card border border-card-border h-full flex flex-col" data-testid={`card-side-${article.id}`}>
<div className="relative flex-shrink-0 flex-1 min-h-0">
<div className="overflow-hidden h-full">
<img src={thumbUrl(article.coverImage)} alt={article.title} className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" style={{ objectPosition: "center 20%" }} loading="lazy" />
<img src={thumbUrl(article.coverImage)} alt={article.title} className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-105" style={{ objectPosition: objPos }} loading="lazy" />
</div>
{isVideo && (
<div className="absolute inset-0 flex items-center justify-center">
@@ -289,7 +298,7 @@ function FeaturedCarousel({ articles, popular, galleryImages, focalPoints }: { a
</div>
<div className="lg:col-span-3 grid grid-cols-1 gap-3 grid-rows-2 lg:h-[420px]">
{side.map((a) => (
<SideCard key={a.id} article={a} />
<SideCard key={a.id} article={a} focalPoints={focalPoints} />
))}
</div>
<div className="lg:col-span-2 lg:h-[420px]">
@@ -360,26 +369,30 @@ export default function Home() {
<FeaturedCarousel articles={articles} popular={popular} galleryImages={galleryImages} focalPoints={focalPoints} />
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="columns-1 sm:columns-2 lg:columns-4 gap-4 space-y-4 [column-fill:_balance]">
{row2Left.map((a) => (
<MediumCard key={a.id} article={a} />
<div key={a.id} className="break-inside-avoid">
<MediumCard article={a} focalPoints={focalPoints} />
</div>
))}
<div className="aspect-[4/5] sm:aspect-auto">
<div className="break-inside-avoid">
<PhotoGalleryWidget />
</div>
<div className="aspect-[4/5] sm:aspect-auto">
<div className="break-inside-avoid">
<RecipeWidget />
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
<div className="aspect-[4/5] sm:aspect-auto">
<div className="columns-1 sm:columns-2 lg:columns-4 gap-4 space-y-4 [column-fill:_balance]">
<div className="break-inside-avoid">
<HoroscopeWidget />
</div>
{row3Middle.map((a) => (
<MediumCard key={a.id} article={a} />
<div key={a.id} className="break-inside-avoid">
<MediumCard article={a} focalPoints={focalPoints} />
</div>
))}
<div className="aspect-[4/5] sm:aspect-auto">
<div className="break-inside-avoid">
<NewsWidget />
</div>
</div>
@@ -387,7 +400,7 @@ export default function Home() {
{row4Articles.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{row4Articles.map((a) => (
<MediumCard key={a.id} article={a} />
<MediumCard key={a.id} article={a} focalPoints={focalPoints} />
))}
<NativeAdCard />
</div>
@@ -396,7 +409,7 @@ export default function Home() {
{row5Articles.length > 0 && (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{row5Articles.map((a) => (
<MediumCard key={a.id} article={a} />
<MediumCard key={a.id} article={a} focalPoints={focalPoints} />
))}
<NativeAdCard />
</div>