Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vcci-news-frontend
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Văn Hoàng
vcci-news-frontend
Commits
dd2db2a3
Commit
dd2db2a3
authored
Oct 23, 2026
by
Phạm Quang Bảo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add: failback thumbnail with image in content
parent
0a6eab64
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
26 additions
and
27 deletions
+26
-27
next.config.ts
next.config.ts
+3
-23
data.ts
src/app/(main)/[...slug]/templates/data.ts
+18
-1
index.tsx
src/app/(main)/[...slug]/templates/news-page/index.tsx
+2
-1
news-listing.tsx
src/app/(main)/news/news-listing.tsx
+3
-2
No files found.
next.config.ts
View file @
dd2db2a3
...
@@ -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/**"
,
},
},
],
],
},
},
...
...
src/app/(main)/[...slug]/templates/data.ts
View file @
dd2db2a3
...
@@ -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
src/app/(main)/[...slug]/templates/news-page/index.tsx
View file @
dd2db2a3
...
@@ -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
}
...
...
src/app/(main)/news/news-listing.tsx
View file @
dd2db2a3
...
@@ -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
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment