Commit dd2db2a3 authored by Phạm Quang Bảo's avatar Phạm Quang Bảo

add: failback thumbnail with image in content

parent 0a6eab64
...@@ -5,33 +5,13 @@ const nextConfig: NextConfig = { ...@@ -5,33 +5,13 @@ const nextConfig: NextConfig = {
remotePatterns: [ remotePatterns: [
{ {
protocol: "http", protocol: "http",
hostname: "localhost", hostname: "**",
port: "3001",
pathname: "/uploads/**",
},
{
protocol: "https",
hostname: "vcci-hcm.org.vn",
port: "",
pathname: "/**", pathname: "/**",
}, },
{ {
protocol: "https", protocol: "https",
hostname: "vccihcm.vn", hostname: "**",
port: "", pathname: "/**",
pathname: "/images/**",
},
{
protocol: "https",
hostname: "img.youtube.com",
port: "",
pathname: "/vi/**",
},
{
protocol: "https",
hostname: "news.vccihcm.vn",
port: "",
pathname: "/uploads/**",
}, },
], ],
}, },
......
...@@ -407,6 +407,12 @@ export function resolveDynamicPostImage(thumbnail?: DynamicPostThumbnail) { ...@@ -407,6 +407,12 @@ export function resolveDynamicPostImage(thumbnail?: DynamicPostThumbnail) {
return Links.resolveImageUrl(value); return Links.resolveImageUrl(value);
} }
const extractFirstImageFromHtml = (html?: string | null): string | null => {
if (!html) return null;
const match = html.match(/<img[^>]+src=["']([^"']+)["']/i);
return match?.[1]?.trim() || null;
};
export function getDynamicPostSeoImage(post: DynamicPostItem | null): string { export function getDynamicPostSeoImage(post: DynamicPostItem | null): string {
if (!post) return "/thumbnail.png"; if (!post) return "/thumbnail.png";
...@@ -415,7 +421,18 @@ export function getDynamicPostSeoImage(post: DynamicPostItem | null): string { ...@@ -415,7 +421,18 @@ export function getDynamicPostSeoImage(post: DynamicPostItem | null): string {
if (resolved && resolved !== "/thumbnail.png") return resolved; if (resolved && resolved !== "/thumbnail.png") return resolved;
} }
// 1. First image embedded in the raw HTML content.
const contentImage = extractFirstImageFromHtml(post.content);
if (contentImage) return Links.resolveImageUrl(contentImage);
// 2. First image embedded in any section's HTML content.
const sections = post.content_structure?.post_content ?? []; const sections = post.content_structure?.post_content ?? [];
for (const section of sections) {
const sectionImage = extractFirstImageFromHtml(section.content);
if (sectionImage) return Links.resolveImageUrl(sectionImage);
}
// 3. First structured section image.
for (const section of sections) { for (const section of sections) {
for (const item of section.images) { for (const item of section.images) {
const url = item.image?.url; const url = item.image?.url;
...@@ -540,4 +557,4 @@ export function isDynamicPostVisible(post: DynamicPostItem) { ...@@ -540,4 +557,4 @@ export function isDynamicPostVisible(post: DynamicPostItem) {
return true; return true;
} }
export { buildPostFilters, normalizePath }; export { buildPostFilters, normalizePath };
\ No newline at end of file
...@@ -18,6 +18,7 @@ import { ...@@ -18,6 +18,7 @@ import {
findDisplayCategoryForPost, findDisplayCategoryForPost,
getDynamicPostExcerpt, getDynamicPostExcerpt,
resolveDynamicPostImage, resolveDynamicPostImage,
getDynamicPostSeoImage,
} from "../data"; } from "../data";
import type { DynamicCategoryRouteItem } from "../types"; import type { DynamicCategoryRouteItem } from "../types";
import type { DynamicPostItem } from "@/api/vcci-news/types/post"; import type { DynamicPostItem } from "@/api/vcci-news/types/post";
...@@ -159,7 +160,7 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) { ...@@ -159,7 +160,7 @@ export default function NewsPage({ category, allCategories }: NewsPageProps) {
> >
<div className="relative overflow-hidden rounded-md bg-[#edf1f5] aspect-[25/15] sm:aspect-[5/3]"> <div className="relative overflow-hidden rounded-md bg-[#edf1f5] aspect-[25/15] sm:aspect-[5/3]">
<Image <Image
src={resolveDynamicPostImage(item.thumbnail)} src={getDynamicPostSeoImage(item)}
alt={item.title} alt={item.title}
width={520} width={520}
height={360} height={360}
......
...@@ -14,6 +14,7 @@ import { Button } from "@/components/ui/button"; ...@@ -14,6 +14,7 @@ import { Button } from "@/components/ui/button";
import { import {
buildDynamicPostHref, buildDynamicPostHref,
resolveDynamicPostImage, resolveDynamicPostImage,
getDynamicPostSeoImage,
stripHtml, stripHtml,
} from "../[...slug]/templates/data"; } from "../[...slug]/templates/data";
...@@ -147,7 +148,7 @@ export default function NewsListing() { ...@@ -147,7 +148,7 @@ export default function NewsListing() {
> >
<div className="relative aspect-[25/15] overflow-hidden rounded-md bg-[#edf1f5] sm:aspect-[5/3]"> <div className="relative aspect-[25/15] overflow-hidden rounded-md bg-[#edf1f5] sm:aspect-[5/3]">
<Image <Image
src={resolveDynamicPostImage(item.thumbnail)} src={getDynamicPostSeoImage(item)}
alt={item.title} alt={item.title}
width={520} width={520}
height={360} height={360}
...@@ -265,4 +266,4 @@ export default function NewsListing() { ...@@ -265,4 +266,4 @@ export default function NewsListing() {
</div> </div>
</div> </div>
); );
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment