diff --git a/web/app/components/plugins/marketplace/home/__tests__/home-trending-layout.browser.spec.tsx b/web/app/components/plugins/marketplace/home/__tests__/home-trending-layout.browser.spec.tsx
index 80b1155be2a..824240fe62c 100644
--- a/web/app/components/plugins/marketplace/home/__tests__/home-trending-layout.browser.spec.tsx
+++ b/web/app/components/plugins/marketplace/home/__tests__/home-trending-layout.browser.spec.tsx
@@ -34,6 +34,20 @@ const adBanner: PluginBanner = {
alt_text: 'Partner campaign',
},
}
+const eventBanner: PluginBanner = {
+ id: 'event',
+ style_type: 'event',
+ title: 'Launch event',
+ sort: 2,
+ language: 'en',
+ content: {
+ images: {
+ desktop: '/api/v1/banners/images/banners/event.png',
+ },
+ link: 'https://dify.ai/event',
+ alt_text: 'Launch event',
+ },
+}
const carouselBanners = [
createBlogBanner('first', 'First banner', 0),
createBlogBanner('second', 'Second banner', 1),
@@ -61,21 +75,29 @@ describe('Marketplace home trending layout', () => {
expect(adSlide.getBoundingClientRect().height).toBe(blogSlide.getBoundingClientRect().height)
})
- it('keeps the ad artwork left-aligned so responsive cropping stays on the right', async () => {
+ it('keeps event and ad artwork left-aligned so responsive cropping stays on the right', async () => {
await page.viewport(600, 900)
const screen = await render(
-
+
+
,
)
- const artwork = screen
- .getByRole('link', { name: 'Partner campaign' })
- .element()
- .querySelector('img')
+ const assertLeftCoverCrop = () => {
+ for (const name of ['Partner campaign', 'Launch event']) {
+ const artwork = screen.getByRole('link', { name }).element().querySelector('img')
- expect(artwork).not.toBeNull()
- expect(getComputedStyle(artwork!).objectPosition).toBe('0% 50%')
+ expect(artwork).not.toBeNull()
+ expect(getComputedStyle(artwork!).objectFit).toBe('cover')
+ expect(getComputedStyle(artwork!).objectPosition).toBe('0% 50%')
+ }
+ }
+
+ assertLeftCoverCrop()
+
+ await page.viewport(1000, 900)
+ assertLeftCoverCrop()
})
it('keeps the blog artwork left corners rounded when its image is cropped', async () => {
diff --git a/web/app/components/plugins/marketplace/home/home-trending-slides.tsx b/web/app/components/plugins/marketplace/home/home-trending-slides.tsx
index 3eb13335aaa..550086c28b8 100644
--- a/web/app/components/plugins/marketplace/home/home-trending-slides.tsx
+++ b/web/app/components/plugins/marketplace/home/home-trending-slides.tsx
@@ -452,8 +452,7 @@ function ImageBannerSlide({
height={200}
alt=""
aria-hidden
- className="size-full object-cover"
- style={{ objectPosition: banner.style_type === 'ad' ? 'left center' : undefined }}
+ className="size-full object-cover object-left"
/>
diff --git a/web/app/components/plugins/marketplace/home/home-trending.module.css b/web/app/components/plugins/marketplace/home/home-trending.module.css
index 38591bc3d47..dca60ffac5f 100644
--- a/web/app/components/plugins/marketplace/home/home-trending.module.css
+++ b/web/app/components/plugins/marketplace/home/home-trending.module.css
@@ -77,6 +77,12 @@
max-width: 400px;
}
+/* Crop from the right so left-side artwork stays visible when the frame
+ is narrower than the image (PC resize and mobile cover). */
+.imageSlide :is(picture, img) {
+ object-position: left;
+}
+
.readMoreMobile {
display: none;
}
@@ -241,7 +247,8 @@
gap: 4px;
}
- /* Event/ad mobile: match the fixed 197px artwork + 160px copy height. */
+ /* Event/ad mobile: match the fixed 197px artwork + 160px copy height.
+ Cover + left so shrinking the frame crops the right, not the copy. */
:global([data-marketplace-standalone]) .imageSlide {
height: 357px;
}
@@ -250,7 +257,7 @@
width: 100%;
height: 100%;
object-fit: cover;
- object-position: center;
+ object-position: left;
}
:global([data-marketplace-standalone]) .readMoreDesktop {