Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
VCCI-News
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
Commits
02f1714c
Commit
02f1714c
authored
Aug 10, 2026
by
Lê Bảo Hồng Đức
☄
Browse files
Options
Browse Files
Download
Plain Diff
[tag]0.1-vcci
parents
010e75cf
bc53cf05
Pipeline
#52482
passed with stages
in 4 minutes
Changes
17
Pipelines
1
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
543 additions
and
181 deletions
+543
-181
index.tsx
src/app/(main)/(home)/components/banner/index.tsx
+6
-5
index.tsx
...(main)/(home)/components/business-opportunities/index.tsx
+2
-2
index.tsx
src/app/(main)/(home)/components/events/index.tsx
+25
-12
index.tsx
src/app/(main)/(home)/components/featured-news/index.tsx
+31
-28
index.tsx
src/app/(main)/(home)/components/members/index.tsx
+107
-19
index.tsx
src/app/(main)/(home)/components/news/index.tsx
+207
-39
index.tsx
src/app/(main)/(home)/components/policies-and-laws/index.tsx
+2
-2
index.tsx
src/app/(main)/(home)/components/quick-links/index.tsx
+38
-39
index.tsx
src/app/(main)/(home)/components/video-and-patners/index.tsx
+1
-1
use-home-posts.ts
src/app/(main)/(home)/lib/use-home-posts.ts
+19
-1
page.tsx
src/app/(main)/(home)/page.tsx
+10
-7
MarketProfilePage.tsx
.....slug]/templates/information-pages/MarketProfilePage.tsx
+9
-3
page.tsx
src/app/admin/contact-management/newsletter-emails/page.tsx
+22
-0
page.tsx
src/app/admin/header-config/page.tsx
+24
-0
page.tsx
src/app/admin/media/page.tsx
+23
-5
index.ts
src/links/index.ts
+9
-18
swiper-css.d.ts
src/types/swiper-css.d.ts
+8
-0
No files found.
src/app/(main)/(home)/components/banner/index.tsx
View file @
02f1714c
...
...
@@ -72,7 +72,7 @@ function BannerSlideItem({
if
(
isPending
)
{
return
(
<
Skeleton
className=
"w-full h-[2
00px] sm:h-[300px] md:h-[400px] lg:h-[50
0px]"
/>
<
Skeleton
className=
"w-full h-[2
20px] sm:h-[320px] md:h-[430px] lg:h-[54
0px]"
/>
);
}
...
...
@@ -80,7 +80,7 @@ function BannerSlideItem({
?
src
:
file
?
resolveCmsFileUrl
(
file
.
path
)
:
"/
img-error
.png"
;
:
"/
thumbnail
.png"
;
return
(
<
ImageNext
...
...
@@ -89,7 +89,8 @@ function BannerSlideItem({
width=
{
2560
}
height=
{
720
}
sizes=
"100vw"
className=
"w-full h-[200px] sm:h-[300px] md:h-[400px] lg:h-[500px] object-cover"
fallback=
"/thumbnail.png"
className=
"w-full h-[220px] sm:h-[320px] md:h-[430px] lg:h-[540px] object-cover"
/>
);
}
...
...
@@ -119,7 +120,7 @@ const Banner = () => {
if
(
isPending
&&
!
rows
.
length
)
{
return
(
<
div
className=
"w-full h-[2
00px] sm:h-[300px] md:h-[400px] lg:h-[50
0px] bg-slate-100 flex items-center justify-center"
>
<
div
className=
"w-full h-[2
20px] sm:h-[320px] md:h-[430px] lg:h-[54
0px] bg-slate-100 flex items-center justify-center"
>
<
Skeleton
className=
"w-full h-full"
/>
</
div
>
);
...
...
@@ -127,7 +128,7 @@ const Banner = () => {
if
(
!
rows
||
rows
.
length
===
0
)
{
return
(
<
div
className=
"w-full h-[2
00px] sm:h-[300px] md:h-[400px] lg:h-[50
0px] bg-slate-100 flex items-center justify-center"
>
<
div
className=
"w-full h-[2
20px] sm:h-[320px] md:h-[430px] lg:h-[54
0px] bg-slate-100 flex items-center justify-center"
>
<
Skeleton
className=
"w-full h-full"
/>
</
div
>
);
...
...
src/app/(main)/(home)/components/business-opportunities/index.tsx
View file @
02f1714c
...
...
@@ -43,10 +43,10 @@ function BusinessOpportunities() {
<
span
className=
"mt-1 h-[40px] w-[2px] shrink-0 rounded-full bg-[#f7b500] transition-opacity duration-200 group-hover:opacity-0"
/>
<
div
className=
"hidden min-w-0 group-hover:block"
>
<
h3
className=
"line-clamp-2 text-[1
6px] font-bold leading-[1.45] text-[#264798] md:text-[17
px]"
>
<
h3
className=
"line-clamp-2 text-[1
5px] font-bold leading-[1.45] text-[#264798] md:text-[16
px]"
>
{
item
.
title
}
</
h3
>
<
p
className=
"mt-
2
text-[13px] text-[#9aa8c1]"
>
<
p
className=
"mt-
1.5
text-[13px] text-[#9aa8c1]"
>
{
dayjs
(
item
.
publishedAt
||
item
.
createdAt
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
</
div
>
...
...
src/app/(main)/(home)/components/events/index.tsx
View file @
02f1714c
...
...
@@ -32,13 +32,13 @@ function Events() {
</
Link
>
</
div
>
<
div
className=
"grid items-stretch gap-3
xl
:grid-cols-[minmax(0,1.02fr)_minmax(270px,0.98fr)]"
>
<
div
className=
"grid items-stretch gap-3
md
:grid-cols-[minmax(0,1.02fr)_minmax(270px,0.98fr)]"
>
{
featuredEvent
?
(
<
Link
href=
{
featuredEvent
.
externalLink
}
className=
"
flex h-full
flex-col overflow-hidden rounded-[22px] bg-white text-[#20408f] shadow-[0_14px_28px_rgba(10,39,95,0.18)]"
className=
"
group flex h-full cursor-pointer
flex-col overflow-hidden rounded-[22px] bg-white text-[#20408f] shadow-[0_14px_28px_rgba(10,39,95,0.18)]"
>
<
div
className=
"
h-[220px] overflow-hidden md:h-[235
px] xl:h-[248px]"
>
<
div
className=
"
relative h-[180px] overflow-hidden md:h-[220
px] xl:h-[248px]"
>
<
ImageNext
src=
{
featuredEvent
.
thumbnail
?.
url
??
"/thumbnail.png"
}
alt=
{
featuredEvent
.
thumbnail
?.
alt
||
featuredEvent
.
title
}
...
...
@@ -46,10 +46,13 @@ function Events() {
height=
{
520
}
className=
"h-full w-full object-cover"
/>
<
span
className=
"absolute left-3 top-3 inline-flex rounded-full bg-[#f7b500] px-3 py-1 text-[12px] font-bold text-[#15357a]"
>
{
featuredEvent
.
categories
[
0
]?.
name
||
"Sự kiện"
}
</
span
>
</
div
>
<
div
className=
"flex flex-col p-3 pt-2.5"
>
<
h3
className=
"text-[16px] font-bold uppercase leading-[1.28] text-[#22459b] line-clamp-2 md:text-[18px]"
>
<
h3
className=
"text-[16px] font-bold uppercase leading-[1.28] text-[#22459b] line-clamp-2
transition-colors duration-200 group-hover:text-[#f7b500]
md:text-[18px]"
>
{
featuredEvent
.
title
}
</
h3
>
{
(()
=>
{
...
...
@@ -85,7 +88,7 @@ function Events() {
</
Link
>
)
:
(
<
div
className=
"flex h-full flex-col overflow-hidden rounded-[22px] bg-white text-[#20408f] shadow-[0_14px_28px_rgba(10,39,95,0.12)]"
>
<
div
className=
"h-[
220px] bg-[#d7e3f9] md:h-[235
px] xl:h-[248px]"
/>
<
div
className=
"h-[
180px] bg-[#d7e3f9] md:h-[220
px] xl:h-[248px]"
/>
<
div
className=
"space-y-2 p-3 pt-2.5"
>
<
div
className=
"h-6 w-5/6 rounded bg-[#e7eefb]"
/>
<
div
className=
"h-4 w-24 rounded bg-[#eef3fb]"
/>
...
...
@@ -93,13 +96,13 @@ function Events() {
</
div
>
)
}
<
div
className=
"
flex h-full flex-col gap-3
"
>
<
div
className=
"
grid h-full grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-1
"
>
{
sideSlots
.
map
((
item
,
index
)
=>
item
?
(
<
Link
key=
{
item
.
id
}
href=
{
item
.
externalLink
}
className=
"
flex flex-1
items-center gap-3 rounded-[18px] bg-white/10 p-2.5 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.08)] backdrop-blur-sm transition-colors hover:bg-white/14"
className=
"
group flex flex-1 cursor-pointer
items-center gap-3 rounded-[18px] bg-white/10 p-2.5 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.08)] backdrop-blur-sm transition-colors hover:bg-white/14"
>
<
div
className=
"h-[64px] w-[64px] shrink-0 overflow-hidden rounded-[12px]"
>
<
ImageNext
...
...
@@ -112,7 +115,7 @@ function Events() {
</
div
>
<
div
className=
"min-w-0"
>
<
h4
className=
"line-clamp-1 text-[15px] font-semibold leading-[1.35] text-white"
>
<
h4
className=
"line-clamp-1 text-[15px] font-semibold leading-[1.35] text-white
transition-colors duration-200 group-hover:text-[#f7b500]
"
>
{
item
.
title
}
</
h4
>
{
(()
=>
{
...
...
@@ -139,12 +142,22 @@ function Events() {
</
p
>
)
:
null
;
})()
}
<
p
className=
"mt-1 text-[12px] text-white/78"
>
<
div
className=
"mt-1 flex items-center gap-2"
>
{
item
.
categories
[
0
]?.
name
&&
(
<
span
className=
"text-[12px] font-medium text-[#f7b500]"
>
{
item
.
categories
[
0
].
name
}
</
span
>
)
}
{
item
.
categories
[
0
]?.
name
&&
(
<
span
className=
"text-[12px] text-white/50"
>
•
</
span
>
)
}
<
p
className=
"text-[12px] text-white/78"
>
{
dayjs
(
item
.
startedAt
||
item
.
publishedAt
||
item
.
createdAt
).
format
(
"DD/MM/YYYY"
,
)
}
</
p
>
</
div
>
</
div
>
</
Link
>
)
:
(
<
div
...
...
src/app/(main)/(home)/components/featured-news/index.tsx
View file @
02f1714c
...
...
@@ -36,32 +36,32 @@ function FeaturedNews() {
</
Link
>
</
div
>
<
div
className=
"grid gap-5
xl
:grid-cols-[minmax(0,1.14fr)_minmax(0,0.96fr)]"
>
<
div
className=
"grid gap-5
lg
:grid-cols-[minmax(0,1.14fr)_minmax(0,0.96fr)]"
>
{
primaryItem
?
(
<
Link
href=
{
primaryItem
.
externalLink
}
className=
"group relative block
min-h-[260px] overflow-hidden rounded-[24px] bg-[#0d2f5f] shadow-[0_18px_38px_rgba(28,52,120,0.22)] md:min-h-[320px] xl:min-h-[35
0px]"
className=
"group relative block
cursor-pointer overflow-hidden rounded-[20px] bg-[#0d2f5f] shadow-[0_16px_32px_rgba(28,52,120,0.2)] md:rounded-[24px] md:min-h-[320px] lg:min-h-[38
0px]"
>
<
div
className=
"relative h-full min-h-[
260px] md:min-h-[320px] xl:min-h-[35
0px]"
>
<
div
className=
"relative h-full min-h-[
195px] md:min-h-[320px] lg:min-h-[38
0px]"
>
<
ImageNext
src=
{
primaryItem
.
thumbnail
?.
url
??
"/thumbnail.png"
}
alt=
{
primaryItem
.
thumbnail
?.
alt
||
primaryItem
.
title
}
width=
{
1200
}
height=
{
800
}
className=
"absolute inset-0 h-full w-full object-cover
transition-transform duration-500 group-hover:scale-[1.04]
"
className=
"absolute inset-0 h-full w-full object-cover"
/>
<
div
className=
"absolute inset-0 bg-linear-to-t from-[#26356d] via-[#53669b]/34 to-transparent"
/>
<
div
className=
"relative flex h-full flex-col justify-end p-
4
md:p-5"
>
<
div
className=
"relative flex h-full flex-col justify-end p-
3.5
md:p-5"
>
<
span
className=
"mb-2 inline-flex w-fit rounded-[10px] bg-[#ffc400] px-3 py-1 text-sm font-bold text-[#1d3f90]"
>
{
primaryItem
.
categories
[
0
]?.
name
||
"Tin nổi bật"
}
</
span
>
<
h3
className=
"max-w-3xl line-clamp-
3 text-[20px] font-bold leading-[1.28] text-white md:text-[28px] xl
:text-[32px]"
>
<
h3
className=
"max-w-3xl line-clamp-
2 text-[16px] font-bold leading-[1.32] text-white transition-colors duration-200 group-hover:text-[#f7b500] md:line-clamp-3 md:text-[28px] lg
:text-[32px]"
>
{
primaryItem
.
title
}
</
h3
>
<
p
className=
"mt-
2 text-base font-medium text-white/78
md:text-[17px]"
>
<
p
className=
"mt-
1.5 text-[15px] font-medium text-white/78 md:mt-2
md:text-[17px]"
>
{
dayjs
(
primaryItem
.
publishedAt
||
primaryItem
.
createdAt
).
format
(
"DD/MM/YYYY"
,
)
}
...
...
@@ -70,8 +70,8 @@ function FeaturedNews() {
</
div
>
</
Link
>
)
:
(
<
div
className=
"relative
min-h-[260px] overflow-hidden rounded-3xl bg-[#e9eef8] shadow-[0_18px_38px_rgba(28,52,120,0.12)] md:min-h-[320px] xl:min-h-[35
0px]"
>
<
div
className=
"flex h-full min-h-[
260px] flex-col justify-end p-4 md:min-h-80 md:p-5 xl:min-h-[35
0px]"
>
<
div
className=
"relative
overflow-hidden rounded-[20px] bg-[#e9eef8] shadow-[0_16px_32px_rgba(28,52,120,0.12)] md:rounded-3xl md:min-h-[320px] lg:min-h-[38
0px]"
>
<
div
className=
"flex h-full min-h-[
195px] flex-col justify-end p-3.5 md:min-h-80 md:p-5 lg:min-h-[38
0px]"
>
<
span
className=
"mb-2 h-8 w-28 rounded-[10px] bg-white/80"
/>
<
div
className=
"h-8 w-3/4 rounded bg-white/90 md:h-10"
/>
<
div
className=
"mt-2 h-5 w-28 rounded bg-white/70"
/>
...
...
@@ -86,15 +86,15 @@ function FeaturedNews() {
<
Link
key=
{
item
.
id
}
href=
{
item
.
externalLink
}
className=
"group relative block
min-h-[195px] overflow-hidden rounded-[20px] bg-[#27447f] shadow-[0_16px_32px_rgba(28,52,120,0.2)] md:min-h-[205px] xl
:min-h-[215px]"
className=
"group relative block
cursor-pointer overflow-hidden rounded-[20px] bg-[#27447f] shadow-[0_16px_32px_rgba(28,52,120,0.2)] md:min-h-[205px] lg
:min-h-[215px]"
>
<
div
className=
"relative h-full min-h-[195px] md:min-h-[205px]
xl
:min-h-[215px]"
>
<
div
className=
"relative h-full min-h-[195px] md:min-h-[205px]
lg
:min-h-[215px]"
>
<
ImageNext
src=
{
item
.
thumbnail
?.
url
??
"/thumbnail.png"
}
alt=
{
item
.
thumbnail
?.
alt
||
item
.
title
}
width=
{
600
}
height=
{
420
}
className=
"absolute inset-0 h-full w-full object-cover
transition-transform duration-500 group-hover:scale-[1.05]
"
className=
"absolute inset-0 h-full w-full object-cover"
/>
<
div
className=
"absolute inset-0 bg-linear-to-t from-[#5a6796] via-[#405083]/34 to-transparent"
/>
...
...
@@ -103,7 +103,7 @@ function FeaturedNews() {
{
item
.
categories
[
0
]?.
name
||
"Tin nổi bật"
}
</
span
>
<
h4
className=
"line-clamp-2 text-[16px] font-bold leading-[1.32] text-white md:text-[17px]"
>
<
h4
className=
"line-clamp-2 text-[16px] font-bold leading-[1.32] text-white
transition-colors duration-200 group-hover:text-[#f7b500]
md:text-[17px]"
>
{
item
.
title
}
</
h4
>
...
...
@@ -118,9 +118,9 @@ function FeaturedNews() {
)
:
(
<
div
key=
{
`featured-placeholder-${index}`
}
className=
"
min-h-[195px] rounded-[20px] bg-[#dde5f3] shadow-[0_16px_32px_rgba(28,52,120,0.1)] md:min-h-[205px] xl
:min-h-[215px]"
className=
"
rounded-[20px] bg-[#dde5f3] shadow-[0_16px_32px_rgba(28,52,120,0.1)] md:min-h-[205px] lg
:min-h-[215px]"
>
<
div
className=
"flex h-full min-h-[195px] flex-col justify-end p-3.5 md:min-h-[205px]
xl
:min-h-[215px]"
>
<
div
className=
"flex h-full min-h-[195px] flex-col justify-end p-3.5 md:min-h-[205px]
lg
:min-h-[215px]"
>
<
span
className=
"mb-2 h-7 w-24 rounded-[10px] bg-white/80"
/>
<
div
className=
"h-6 w-5/6 rounded bg-white/90"
/>
<
div
className=
"mt-2 h-4 w-24 rounded bg-white/70"
/>
...
...
@@ -130,25 +130,28 @@ function FeaturedNews() {
)
}
</
div
>
<
div
className=
"overflow-hidden rounded-[28px] bg-linear-to-r from-[#214b95] to-[#2b66bb] px-5 py-5 text-white shadow-[0_18px_38px_rgba(28,52,120,0.2)] md:px-7"
>
<
div
className=
"flex
flex-col gap-4 lg:flex-row lg:items-center lg:justify-between
"
>
<
div
>
<
p
className=
"text-[1
2px] uppercase tracking-[0.4em] text-white/80
"
>
<
div
className=
"
flex h-full min-h-full items-center justify-center
overflow-hidden rounded-[28px] bg-linear-to-r from-[#214b95] to-[#2b66bb] px-5 py-5 text-white shadow-[0_18px_38px_rgba(28,52,120,0.2)] md:px-7"
>
<
div
className=
"flex
w-full flex-col items-center justify-center gap-4 text-center md:flex-row md:gap-6 md:text-left lg:gap-8 xl:gap-12
"
>
<
div
className=
"flex flex-col items-center md:items-start"
>
<
p
className=
"text-[1
1px] uppercase tracking-[0.2em] text-white/80 lg:text-[12px] lg:tracking-[0.4em]
"
>
Quảng bá
&
tiếp cận
</
p
>
<
h3
className=
"mt-2 max-w-[520px] text-[20px] font-extrabold uppercase leading-[1.02] xl:text-[28px]"
>
Cộng đồng doanh nghiệp
<
h3
className=
"mt-2 text-[20px] font-extrabold uppercase leading-[1.1] lg:text-[18px] xl:text-[22px]"
>
<
span
>
Cộng đồng
</
span
>
<
br
className=
"hidden lg:block"
/>
<
span
className=
"lg:hidden"
>
</
span
>
<
span
>
doanh nghiệp
</
span
>
</
h3
>
</
div
>
<
div
className=
"
w-full max-w-60 rounded-[999px] bg-white px-4 py-3 text-[#173f88] shadow-[0_10px_24px_rgba(8,25,74,0.12)
]"
>
<
div
className=
"flex items-center gap-
3 text-sm font-mediu
m"
>
<
Mail
className=
"h-
5 w-5 shrink-0
"
/>
<
span
>
info@vcci-hcm.org.vn
</
span
>
<
div
className=
"
shrink-0 flex flex-col gap-2 rounded-[20px] bg-white px-4 py-3 text-[#173f88] shadow-[0_10px_24px_rgba(8,25,74,0.12)] sm:min-w-fit lg:w-auto lg:rounded-[999px
]"
>
<
div
className=
"flex items-center gap-
2 text-[13px] font-medium sm:text-s
m"
>
<
Mail
className=
"h-
4 w-4 shrink-0 sm:h-5 sm:w-5
"
/>
<
span
className=
"whitespace-nowrap"
>
info@vcci-hcm.org.vn
</
span
>
</
div
>
<
div
className=
"
mt-2 flex items-center gap-3 text-sm font-mediu
m"
>
<
Phone
className=
"h-
5 w-5 shrink-0
"
/>
<
span
>
+84 28 3932 6598
</
span
>
<
div
className=
"
flex items-center gap-2 text-[13px] font-medium sm:text-s
m"
>
<
Phone
className=
"h-
4 w-4 shrink-0 sm:h-5 sm:w-5
"
/>
<
span
className=
"whitespace-nowrap"
>
+84 28 3932 6598
</
span
>
</
div
>
</
div
>
</
div
>
...
...
src/app/(main)/(home)/components/members/index.tsx
View file @
02f1714c
...
...
@@ -9,6 +9,7 @@ import { useEffect, useState } from "react";
import
{
Autoplay
}
from
"swiper/modules"
;
import
{
Swiper
,
SwiperSlide
}
from
"swiper/react"
;
import
"swiper/css"
;
import
dayjs
from
"dayjs"
;
const
MEMBER_CONNECTION_FALLBACK_IMAGE
=
"/home/20-2048x1365.webp"
;
const
FEATURED_MEMBER_API_URL
=
`
${
links
.
siteURL
}
api/featured-members`
;
...
...
@@ -50,13 +51,9 @@ function Members() {
const
[
featuredMembers
,
setFeaturedMembers
]
=
useState
<
FeaturedMemberState
>
({
status
:
"loading"
,
});
const
featuredConnection
=
memberConnectionPosts
[
0
]
;
const
connectionPosts
=
memberConnectionPosts
.
slice
(
0
,
2
)
;
const
sectionLink
=
categoryLinks
.
get
(
categoryNames
.
ketNoiHoiVien
.
toLowerCase
())
??
"/hoi-vien/ket-noi-hoi-vien"
;
const
connectionImage
=
featuredConnection
?.
thumbnail
?.
url
??
MEMBER_CONNECTION_FALLBACK_IMAGE
;
const
connectionImageAlt
=
featuredConnection
?.
thumbnail
?.
alt
||
featuredConnection
?.
title
||
"VCCI HCM"
;
const
displayMembers
=
featuredMembers
.
status
===
"ready"
?
featuredMembers
.
rows
.
slice
(
0
,
9
)
:
[];
...
...
@@ -187,22 +184,113 @@ function Members() {
</
h2
>
<
div
className=
"mt-2.5 h-[4px] w-[40px] rounded-full bg-[#f7b500]"
/>
</
div
>
</
div
>
<
Link
href=
{
sectionLink
}
className=
"block overflow-hidden rounded-[20px] shadow-[0_16px_32px_rgba(31,59,124,0.12)]"
className=
"pt-1 text-sm font-semibold text-[#24469c] transition-colors hover:text-[#1b55a1]"
>
Xem tất cả
</
Link
>
</
div
>
<
div
>
{
connectionPosts
.
length
>
0
?
(
<>
{
/* Mobile + xl+: Swiper */
}
<
div
className=
"md:hidden xl:block"
>
<
Swiper
modules=
{
[
Autoplay
]
}
autoplay=
{
{
delay
:
4000
,
disableOnInteraction
:
false
}
}
loop=
{
connectionPosts
.
length
>
1
}
slidesPerView=
{
1
}
className=
"w-full overflow-hidden rounded-[20px]"
>
{
connectionPosts
.
map
((
item
)
=>
(
<
SwiperSlide
key=
{
item
.
id
}
>
<
Link
href=
{
item
.
externalLink
}
className=
"group relative block cursor-pointer overflow-hidden rounded-[20px] shadow-[0_16px_32px_rgba(31,59,124,0.12)]"
>
<
div
className=
"aspect-[16/10] overflow-hidden xl:aspect-[1.25/1]"
>
<
ImageNext
src=
{
item
.
thumbnail
?.
url
??
MEMBER_CONNECTION_FALLBACK_IMAGE
}
alt=
{
item
.
thumbnail
?.
alt
||
item
.
title
}
width=
{
520
}
height=
{
420
}
className=
"h-full w-full object-cover object-[center_80%]"
/>
</
div
>
<
div
className=
"absolute inset-0 bg-linear-to-t from-[#0d2f5f]/85 via-[#0d2f5f]/30 to-transparent"
/>
<
div
className=
"absolute inset-x-0 bottom-0 p-4"
>
<
h4
className=
"line-clamp-2 text-[15px] font-bold leading-[1.32] text-white transition-colors duration-200 group-hover:text-[#f7b500]"
>
{
item
.
title
}
</
h4
>
<
div
className=
"mt-1.5 flex items-center gap-2"
>
{
item
.
categories
[
0
]?.
name
&&
(
<>
<
span
className=
"text-[12px] font-medium text-[#f7b500]"
>
{
item
.
categories
[
0
].
name
}
</
span
>
<
span
className=
"text-[12px] text-white/50"
>
•
</
span
>
</>
)
}
<
p
className=
"text-[12px] font-medium text-white/78"
>
{
dayjs
(
item
.
publishedAt
||
item
.
createdAt
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
</
div
>
</
div
>
</
Link
>
</
SwiperSlide
>
))
}
</
Swiper
>
</
div
>
{
/* md to < xl: Grid 2 columns */
}
<
div
className=
"hidden gap-4 md:grid md:grid-cols-2 xl:hidden"
>
{
connectionPosts
.
map
((
item
)
=>
(
<
Link
key=
{
item
.
id
}
href=
{
item
.
externalLink
}
className=
"group relative block cursor-pointer overflow-hidden rounded-[20px] shadow-[0_16px_32px_rgba(31,59,124,0.12)]"
>
<
div
className=
"aspect-[1.25/1] overflow-hidden rounded-[20px]
"
>
<
div
className=
"aspect-[16/10] overflow-hidden
"
>
<
ImageNext
src=
{
connectionImage
}
alt=
{
connectionImageAlt
}
src=
{
item
.
thumbnail
?.
url
??
MEMBER_CONNECTION_FALLBACK_IMAGE
}
alt=
{
item
.
thumbnail
?.
alt
||
item
.
title
}
width=
{
520
}
height=
{
420
}
className=
"h-full w-full object-cover
"
className=
"h-full w-full object-cover object-[center_80%]
"
/>
</
div
>
<
div
className=
"absolute inset-0 bg-linear-to-t from-[#0d2f5f]/85 via-[#0d2f5f]/30 to-transparent"
/>
<
div
className=
"absolute inset-x-0 bottom-0 p-4"
>
<
h4
className=
"line-clamp-2 text-[15px] font-bold leading-[1.32] text-white transition-colors duration-200 group-hover:text-[#f7b500]"
>
{
item
.
title
}
</
h4
>
<
div
className=
"mt-1.5 flex items-center gap-2"
>
{
item
.
categories
[
0
]?.
name
&&
(
<>
<
span
className=
"text-[12px] font-medium text-[#f7b500]"
>
{
item
.
categories
[
0
].
name
}
</
span
>
<
span
className=
"text-[12px] text-white/50"
>
•
</
span
>
</>
)
}
<
p
className=
"text-[12px] font-medium text-white/78"
>
{
dayjs
(
item
.
publishedAt
||
item
.
createdAt
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
</
div
>
</
div
>
</
Link
>
))
}
</
div
>
</>
)
:
(
<
div
className=
"rounded-[16px] bg-[#eef3fb] px-5 py-10 text-center text-sm text-[#7f8eab]"
>
Chưa có thông tin.
</
div
>
)
}
</
div
>
</
aside
>
</
section
>
);
...
...
src/app/(main)/(home)/components/news/index.tsx
View file @
02f1714c
This diff is collapsed.
Click to expand it.
src/app/(main)/(home)/components/policies-and-laws/index.tsx
View file @
02f1714c
...
...
@@ -43,10 +43,10 @@ function PolicyAndLaws() {
<
span
className=
"mt-1 h-[40px] w-[2px] shrink-0 rounded-full bg-[#f7b500] transition-opacity duration-200 group-hover:opacity-0"
/>
<
div
className=
"hidden min-w-0 group-hover:block"
>
<
h3
className=
"line-clamp-2 text-[1
6px] font-bold leading-[1.45] text-[#264798] md:text-[17
px]"
>
<
h3
className=
"line-clamp-2 text-[1
5px] font-bold leading-[1.45] text-[#264798] md:text-[16
px]"
>
{
item
.
title
}
</
h3
>
<
p
className=
"mt-
2
text-[13px] text-[#9aa8c1]"
>
<
p
className=
"mt-
1.5
text-[13px] text-[#9aa8c1]"
>
{
dayjs
(
item
.
publishedAt
||
item
.
createdAt
).
format
(
"DD/MM/YYYY"
)
}
</
p
>
</
div
>
...
...
src/app/(main)/(home)/components/quick-links/index.tsx
View file @
02f1714c
'use client'
;
import
{
useHomePosts
}
from
"@/app/(main)/(home)/lib/use-home-posts"
;
import
ImageNext
from
"@/components/shared/image-next"
;
import
Link
from
"next/link"
;
function
QuickLinks
()
{
const
{
quickLinkPosts
}
=
useHomePosts
();
const
linkSlots
=
Array
.
from
({
length
:
4
},
(
_
,
index
)
=>
quickLinkPosts
[
index
]
??
null
);
function
Advertisements
({
count
=
2
}:
{
count
?:
number
})
{
const
mdCols
=
count
>=
3
?
"md:grid-cols-3"
:
"md:grid-cols-2"
;
return
(
<
aside
className=
"w-full xl:grid xl:w-[32%] xl:grid-rows-[0.74fr_0.88fr] xl:gap-4"
>
<
div
className=
"rounded-[22px] border border-[#dbe4f2] bg-white p-4 shadow-[0_8px_24px_rgba(31,59,124,0.08)] xl:h-full"
>
<
h2
className=
"client-section-title uppercase text-[#24469c]"
>
Liên kết nhanh
</
h2
>
<
div
className=
"mt-3 h-[5px] w-[68px] rounded-full bg-[#f7b500]"
/>
<
div
className=
"mt-4 space-y-3"
>
{
linkSlots
.
map
((
item
,
index
)
=>
item
?
(
<
aside
className=
{
`flex w-full flex-col gap-4 md:grid ${mdCols} xl:grid xl:order-2 xl:w-[22%] xl:grid-cols-1 xl:gap-4 xl:self-center`
}
>
<
Link
key=
{
item
.
id
}
href=
{
item
.
externalLink
}
className=
"flex items-start gap-3 text-[15px] leading-[1.32] text-[#556684] transition-colors hover:text-[#21408f]"
href=
"https://hardwaretools.com.vn/"
className=
"block overflow-hidden rounded-[28px] shadow-[0_12px_28px_rgba(31,59,124,0.14)]"
>
<
span
className=
"mt-1 text-[#e2a500]"
>
›
</
span
>
<
span
className=
"line-clamp-1"
>
{
item
.
title
}
</
span
>
<
div
className=
"aspect-[16/10] overflow-hidden sm:aspect-[16/10] lg:aspect-[7/4] xl:aspect-[3/2]"
>
<
ImageNext
src=
"/home/20-2048x1365.webp"
alt=
"Quảng cáo 1"
width=
{
2048
}
height=
{
1365
}
className=
"h-full w-full object-cover object-[center_80%]"
/>
</
div
>
</
Link
>
)
:
(
<
div
key=
{
`quick-link-placeholder-${index}`
}
className=
"flex items-start gap-3
"
<
Link
href=
"https://hardwaretools.com.vn/"
className=
"block overflow-hidden rounded-[28px] shadow-[0_12px_28px_rgba(31,59,124,0.14)]
"
>
<
span
className=
"mt-1 h-4 w-2 shrink-0 rounded bg-[#f5d774]"
/>
<
span
className=
"h-5 w-5/6 rounded bg-[#eef3fb]"
/>
</
div
>
),
)
}
</
div
>
<
div
className=
"aspect-[16/10] overflow-hidden sm:aspect-[16/10] lg:aspect-[7/4] xl:aspect-[3/2]"
>
<
ImageNext
src=
"/home/20-2048x1365.webp"
alt=
"Quảng cáo 2"
width=
{
2048
}
height=
{
1365
}
className=
"h-full w-full object-cover object-[center_80%]"
/>
</
div
>
</
Link
>
{
count
>=
3
&&
(
<
Link
href=
"https://hardwaretools.com.vn/"
className=
"mt-4 block overflow-hidden rounded-[28px] shadow-[0_12px_28px_rgba(31,59,124,0.14)] xl:mt-0 xl:h-full
"
className=
"block overflow-hidden rounded-[28px] shadow-[0_12px_28px_rgba(31,59,124,0.14)]
"
>
<
div
className=
"aspect-[1.55/1] overflow-hidden xl:h-full xl:aspect-auto
"
>
<
div
className=
"aspect-[16/10] overflow-hidden sm:aspect-[16/10] lg:aspect-[7/4] xl:aspect-[3/2]
"
>
<
ImageNext
src=
"/home/20-2048x1365.webp"
alt=
"Liên kết nhanh
"
alt=
"Quảng cáo 3
"
width=
{
2048
}
height=
{
1365
}
className=
"h-full w-full object-cover
"
className=
"h-full w-full object-cover object-[center_80%]
"
/>
</
div
>
</
Link
>
)
}
</
aside
>
);
}
export
default
QuickLink
s
;
export
default
Advertisement
s
;
src/app/(main)/(home)/components/video-and-patners/index.tsx
View file @
02f1714c
...
...
@@ -169,7 +169,7 @@ function VideoAndPartners() {
alt=
{
video
.
name
}
width=
{
640
}
height=
{
440
}
className=
"h-full w-full object-cover
transition-transform duration-500 group-hover:scale-[1.03]
"
className=
"h-full w-full object-cover"
/>
<
div
className=
"absolute inset-0 bg-black/18"
/>
<
div
className=
"absolute inset-0 flex items-center justify-center"
>
...
...
src/app/(main)/(home)/lib/use-home-posts.ts
View file @
02f1714c
...
...
@@ -267,6 +267,21 @@ function createCategoryPostsQuery(categoryId: string, pageSize: string) {
});
}
function
createMultiCategoryPostsQuery
(
categoryIds
:
string
[],
pageSize
:
string
)
{
return
new
URLSearchParams
({
page
:
"1"
,
pageSize
,
sortField
:
"release_at"
,
sortOrder
:
"desc"
,
filters
:
[
`category.id==(
${
categoryIds
.
join
(
"|"
)}
)`
,
"is_hidden==false"
,
"is_active==true"
,
"type==news"
,
].
join
(
","
),
});
}
function
createEventCalendarQuery
(
currentMonth
:
Date
)
{
// We'll filter by date on client-side for more flexibility
return
new
URLSearchParams
({
...
...
@@ -310,7 +325,10 @@ async function fetchHomePostsFromApi() {
const
tinVcciQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
tinVcci
,
"6"
);
const
tinKinhTeQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
tinKinhTe
,
"6"
);
const
chuyenDeQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
chuyenDe
,
"6"
);
const
eventQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
suKien
,
"5"
);
const
eventQuery
=
createMultiCategoryPostsQuery
(
[
HOME_CATEGORY_IDS
.
suKien
,
HOME_CATEGORY_IDS
.
daoTao
],
"5"
);
const
policyQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
chinhSachPhapLuat
,
"6"
);
const
quickLinksQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
lienKetNhanh
,
"6"
);
const
trainingQuery
=
createCategoryPostsQuery
(
HOME_CATEGORY_IDS
.
daoTao
,
"10"
);
...
...
src/app/(main)/(home)/page.tsx
View file @
02f1714c
'use client'
import
FeaturedNews
from
"./components/featured-news"
;
import
QuickLink
s
from
"./components/quick-links"
;
import
Advertisement
s
from
"./components/quick-links"
;
import
News
from
"./components/news"
;
import
Events
from
"./components/events"
;
import
BusinessOpportunities
from
"./components/business-opportunities"
;
...
...
@@ -29,9 +29,9 @@ const Page = () => {
</Link>
</div> */
}
<
section
className=
"flex flex-col
lg
:flex-row pb-8 gap-5 mb-0"
>
<
section
className=
"flex flex-col
xl
:flex-row pb-8 gap-5 mb-0"
>
<
News
/>
<
QuickLinks
/>
<
Advertisements
count=
{
3
}
/>
</
section
>
<
section
className=
"flex flex-col gap-5 xl:flex-row xl:items-stretch"
>
...
...
@@ -39,7 +39,7 @@ const Page = () => {
<
EventsCalendar
/>
</
section
>
<
div
className=
"flex flex-col lg:flex-row gap-5
pb-10 mb-0
"
>
<
div
className=
"flex flex-col lg:flex-row gap-5"
>
<
div
className=
"flex flex-col flex-1"
>
{
/* <div>
<Link href="https://vcci-hcm.org.vn/wp-content/uploads/2022/11/MEDIA-KIT_VCCI-HCM-2022-Final.pdf">
...
...
@@ -52,9 +52,12 @@ const Page = () => {
</Link>
</div> */
}
<
section
className=
"flex flex-col md:flex-row gap-5 pt-8"
>
<
section
className=
"flex flex-col xl:flex-row gap-5"
>
<
div
className=
"flex flex-col md:flex-row gap-5 pt-8 flex-1 order-2 xl:order-1"
>
<
BusinessOpportunities
/>
<
PolicyAndLaws
/>
</
div
>
<
Advertisements
/>
</
section
>
</
div
>
...
...
src/app/(main)/[...slug]/templates/information-pages/MarketProfilePage.tsx
View file @
02f1714c
'use client'
;
import
{
useMemo
,
useState
}
from
"react"
;
import
{
Globe2
,
Newspaper
,
TrendingUp
}
from
"lucide-react"
;
import
{
FileText
,
Globe2
,
Newspaper
,
TrendingUp
}
from
"lucide-react"
;
import
ImageNext
from
"@/components/shared/image-next"
;
import
type
{
DynamicPostItem
}
from
"../types"
;
...
...
@@ -236,7 +236,9 @@ export default function MarketProfilePage({ post }: MarketProfilePageProps) {
<
div
className=
"mt-7 overflow-hidden rounded-[30px] border border-[#dce7f7] bg-white shadow-[0_18px_42px_rgba(17,24,39,0.06)]"
>
<
div
className=
"relative min-h-[280px] bg-[#f3f7ff] p-4 sm:p-5"
>
<
div
className=
"absolute inset-x-4 top-4 z-10 flex flex-wrap gap-2 sm:inset-x-6 sm:top-6"
>
{
activeRegion
.
markets
.
map
((
item
)
=>
(
{
activeRegion
.
markets
.
map
((
item
)
=>
{
const
hasDoc
=
item
.
href
&&
item
.
href
!==
"#"
;
return
(
<
a
key=
{
`${activeRegion.key}-${item.name}`
}
href=
{
item
.
href
}
...
...
@@ -246,8 +248,12 @@ export default function MarketProfilePage({ post }: MarketProfilePageProps) {
>
<
span
className=
{
`h-2.5 w-2.5 rounded-full ${item.tone}`
}
/>
<
span
>
{
item
.
name
}
</
span
>
{
hasDoc
&&
(
<
FileText
className=
"h-3.5 w-3.5 text-[#2450b5]"
/>
)
}
</
a
>
))
}
);
})
}
</
div
>
<
ImageNext
...
...
src/app/admin/contact-management/newsletter-emails/page.tsx
View file @
02f1714c
...
...
@@ -143,6 +143,28 @@ export default function AdminNewsletterEmailsPage() {
return
(
<
div
className=
"space-y-8"
>
<
div
className=
"flex items-start gap-3 rounded-xl border border-red-300 bg-red-50 px-4 py-3 text-red-800"
>
<
svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 24 24"
fill=
"currentColor"
className=
"mt-0.5 h-5 w-5 shrink-0 text-red-500"
>
<
path
fillRule=
"evenodd"
d=
"M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25Zm-1.5 5.25a.75.75 0 0 0-.75.75v6a.75.75 0 0 0 1.5 0v-6a.75.75 0 0 0-.75-.75Zm0 9a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z"
clipRule=
"evenodd"
/>
</
svg
>
<
div
className=
"text-sm"
>
<
p
className=
"font-semibold"
>
Cảnh báo xóa dữ liệu
</
p
>
<
p
className=
"mt-0.5 text-red-700"
>
Việc xóa email sẽ làm mất dữ liệu hoàn toàn và không thể hoàn tác
được. Vui lòng cân nhắc thật kỹ trước khi xóa.
</
p
>
</
div
>
</
div
>
<
AdminTableLayout
searchValue=
{
search
}
searchPlaceholder=
"Tìm kiếm email đăng ký..."
...
...
src/app/admin/header-config/page.tsx
View file @
02f1714c
...
...
@@ -326,6 +326,30 @@ export default function HeaderConfigPage() {
return
(
<
div
className=
"space-y-8"
>
<
div
className=
"flex items-start gap-3 rounded-xl border border-amber-300 bg-amber-50 px-4 py-3 text-amber-800"
>
<
svg
xmlns=
"http://www.w3.org/2000/svg"
viewBox=
"0 0 24 24"
fill=
"currentColor"
className=
"mt-0.5 h-5 w-5 shrink-0 text-amber-500"
>
<
path
fillRule=
"evenodd"
d=
"M9.401 3.003c1.155-2 4.043-2 5.197 0l7.355 12.748c1.154 2-.29 4.5-2.599 4.5H4.645c-2.309 0-3.752-2.5-2.598-4.5L9.4 3.003ZM12 8.25a.75.75 0 0 1 .75.75v3.75a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75Zm0 8.25a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Z"
clipRule=
"evenodd"
/>
</
svg
>
<
div
className=
"text-sm"
>
<
p
className=
"font-semibold"
>
Lưu ý quan trọng
</
p
>
<
p
className=
"mt-0.5 text-amber-700"
>
Việc chỉnh sửa hoặc xóa danh mục sẽ ảnh hưởng trực tiếp đến cấu trúc
Website và có thể gây mất dữ liệu trang liên quan. Vui lòng thao tác
cẩn thận và kiểm tra kỹ trước khi xác nhận. Nếu phát sinh lỗi, xin vui
lòng báo ngay cho bên kỹ thuật để được hỗ trợ.
</
p
>
</
div
>
</
div
>
<
HeaderCategoryStats
total=
{
flatRows
.
length
}
root=
{
flatRows
.
filter
((
item
)
=>
!
item
.
parentId
).
length
}
...
...
src/app/admin/media/page.tsx
View file @
02f1714c
...
...
@@ -33,6 +33,24 @@ import {
const
PAGE_SIZE
=
10
;
function
resolveApiError
(
error
:
unknown
,
fallback
:
string
)
{
if
(
error
&&
typeof
error
===
"object"
&&
"response"
in
error
)
{
const
axiosError
=
error
as
{
response
?:
{
status
?:
number
;
data
?:
{
message
?:
string
;
error
?:
string
}
}
};
const
status
=
axiosError
.
response
?.
status
;
const
apiMessage
=
axiosError
.
response
?.
data
?.
message
||
axiosError
.
response
?.
data
?.
error
;
if
(
status
&&
apiMessage
)
{
return
`[Lỗi
${
status
}
]
${
apiMessage
}
`
;
}
if
(
status
)
{
return
`[Lỗi
${
status
}
]
${
fallback
}
`
;
}
}
if
(
error
instanceof
Error
&&
error
.
message
)
{
return
error
.
message
;
}
return
fallback
;
}
const
inputClassName
=
"rounded-2xl border-[#063e8e]/15 bg-white text-gray-700 shadow-sm placeholder:text-gray-400 focus-visible:ring-[#063e8e]/20"
;
...
...
@@ -305,7 +323,7 @@ export default function AdminMediaPage() {
setItems
(
result
.
rows
);
setTotal
(
result
.
count
);
}
catch
(
error
)
{
toast
.
error
(
error
instanceof
Error
?
error
.
message
:
"Không thể tải danh sách ảnh"
);
toast
.
error
(
resolveApiError
(
error
,
"Không thể tải danh sách ảnh"
)
);
setItems
([]);
setTotal
(
0
);
}
finally
{
...
...
@@ -337,11 +355,11 @@ export default function AdminMediaPage() {
file
:
data
.
file
,
original
:
data
.
name
,
});
toast
.
success
(
"Đã tải ảnh lên"
);
toast
.
success
(
"Đã tải ảnh lên
thành công
"
);
setDialogOpen
(
false
);
await
load
();
}
catch
(
error
)
{
toast
.
error
(
error
instanceof
Error
?
error
.
message
:
"Không thể tải ảnh lên"
);
toast
.
error
(
resolveApiError
(
error
,
"Không thể tải ảnh lên"
)
);
}
finally
{
setSaving
(
false
);
}
...
...
@@ -352,11 +370,11 @@ export default function AdminMediaPage() {
try
{
await
deleteCmsFile
(
deleteTarget
.
id
);
toast
.
success
(
"Đã xóa ảnh"
);
toast
.
success
(
"Đã xóa ảnh
thành công
"
);
setDeleteTarget
(
null
);
await
load
();
}
catch
(
error
)
{
toast
.
error
(
error
instanceof
Error
?
error
.
message
:
"Không thể xóa ảnh"
);
toast
.
error
(
resolveApiError
(
error
,
"Không thể xóa ảnh"
)
);
}
};
...
...
src/links/index.ts
View file @
02f1714c
...
...
@@ -9,20 +9,6 @@ const LEGACY_MEDIA_HOSTS = new Set([
const
normalizeOrigin
=
(
value
?:
string
|
null
)
=>
value
?.
trim
().
replace
(
/
\/
+$/
,
""
).
replace
(
/
\/
api
\/
v
\d
+
\.\d
+$/
,
""
)
||
""
;
const
extractUploadPath
=
(
pathname
:
string
)
=>
{
const
markers
=
[
"/api/uploads/"
,
"/uploads/"
,
"/images/"
,
"/wp-content/uploads/"
];
for
(
const
marker
of
markers
)
{
const
index
=
pathname
.
indexOf
(
marker
);
if
(
index
>=
0
)
{
const
cleanPath
=
pathname
.
slice
(
index
).
replace
(
/^
\/
api
\/
uploads
\/
/
,
"/uploads/"
);
return
cleanPath
;
}
}
return
null
;
};
const
normalizeUploadPath
=
(
pathname
:
string
)
=>
{
if
(
pathname
.
includes
(
"/api/uploads/"
))
{
return
pathname
.
replace
(
/^.*
\/
api
\/
uploads
\/
/
,
"/uploads/"
);
...
...
@@ -107,6 +93,13 @@ export const resolveUploadUrl = (value?: string | null) => {
if
(
/^https
?
:
\/\/
/i
.
test
(
trimmed
))
{
try
{
const
url
=
new
URL
(
trimmed
);
// Keep URLs from current backend/frontend origins as-is
const
currentOrigins
=
[
backendOrigin
,
frontendOrigin
].
filter
(
Boolean
);
if
(
currentOrigins
.
some
(
origin
=>
url
.
origin
===
origin
))
{
return
trimmed
;
}
const
normalizedPath
=
normalizeUploadPath
(
url
.
pathname
);
if
(
normalizedPath
!==
url
.
pathname
)
{
...
...
@@ -114,10 +107,8 @@ export const resolveUploadUrl = (value?: string | null) => {
}
if
(
LEGACY_MEDIA_HOSTS
.
has
(
url
.
hostname
))
{
const
uploadPath
=
extractUploadPath
(
url
.
pathname
);
if
(
uploadPath
)
{
return
backendOrigin
?
`
${
backendOrigin
}${
uploadPath
}
`
:
uploadPath
;
}
// Keep legacy media URLs as-is since they already have correct domain
return
trimmed
;
}
}
catch
{
return
trimmed
;
...
...
src/types/swiper-css.d.ts
0 → 100644
View file @
02f1714c
declare
module
"swiper/css"
;
declare
module
"swiper/css/bundle"
;
declare
module
"swiper/css/effect-fade"
;
declare
module
"swiper/css/navigation"
;
declare
module
"swiper/css/pagination"
;
declare
module
"swiper/css/scrollbar"
;
declare
module
"swiper/css/thumbs"
;
declare
module
"swiper/css/free-mode"
;
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