Skip to content

Enhance carousel functionality with new thumbnail options and validation #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

<h1 align="center">
JS carousel | Cloudimage (DMO)
</h1>
Expand All @@ -12,11 +11,9 @@
src="https://scaleflex.cloudimg.io/v7/plugins/js-carousel/carousel_exemple.png">
</p>



### Introduction:

Meet `js-carousel` by Scaleflex—a minimal, no-nonsense JavaScript carousel plugin that does *exactly* what you need it to do: load fast, look slick, and play nice with performance. Designed with zero dependencies and a featherlight footprint, this carousel is tailor-made for developers and performance-obsessed teams who don’t want to trade speed for style. Whether you're running a headless CMS or optimizing for that last Lighthouse point, `js-carousel` by Scaleflex is the go-to solution.
Meet `js-carousel` by Scaleflex—a minimal, no-nonsense JavaScript carousel plugin that does _exactly_ what you need it to do: load fast, look slick, and play nice with performance. Designed with zero dependencies and a featherlight footprint, this carousel is tailor-made for developers and performance-obsessed teams who don’t want to trade speed for style. Whether you're running a headless CMS or optimizing for that last Lighthouse point, `js-carousel` by Scaleflex is the go-to solution.

`js-carousel` by Scaleflex does not bundle in more features than you'll ever use, it focuses on doing one thing exceptionally well: delivering a fast, responsive, and ultra-smooth image slider & zoomer experience with minimal setup. It’s the smart choice for frontend engineers who value UX as much as DX. Simple to integrate, easy to customize, and built for scale.

Expand Down Expand Up @@ -173,6 +170,34 @@ carousel.init()
}
```

### `thumbnailFitMode` (string)

- **Default**: `'crop-fit'`
- **Options**: `'crop-fit'`, `'fit'`
- **Description**: Controls how thumbnail images are fitted within their containers
- **Example**:

```javascript
{
thumbnailFitMode: 'fit' // Makes thumbnails fit within their container without cropping
}
```

### `thumbnailAlignment` (string)

- **Default**: `'space-evenly'`
- **Options**: `'left'`, `'center'`, `'right'`, `'space-evenly'`, `'space-between'`
- **Description**: Controls the horizontal alignment of thumbnails in the thumbnail container
- **Example**:

```javascript
{
thumbnailAlignment: 'space-between' // Distributes thumbnails with equal space between them
}
```

Let me verify this by checking the constants file for thumbnail alignment.

## Complete Example

Here's an example showing all options with their default values:
Expand All @@ -191,6 +216,8 @@ const carousel = new CloudImageCarousel('#my-carousel', {
showControls: true,
showBullets: false,
transitionEffect: 'fade',
thumbnailFitMode: 'crop-fit',
thumbnailAlignment: 'space-evenly',
images: ['path/to/image1.jpg', 'path/to/image2.jpg', 'path/to/image3.jpg'],
})

Expand Down
2 changes: 1 addition & 1 deletion dist/js-carousel.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/js-carousel.min.js

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
autoplay: false,
autoplayInterval: 3000,
cycle: true,
showFilenames: false,
showFilenames: true,
showThumbnails: true,
showControls: true,
showBullets: false,
transitionEffect: 'slide',
thumbnailFitMode: 'fit',
thumbnailAlignment: 'center',
images: [
'https://demo.cloudimg.io/v7/https://samples.scaleflex.com/hotel.jpg',
'https://demo.cloudimg.io/v7/https://samples.scaleflex.com/birds.jpg',
Expand All @@ -35,6 +37,7 @@
'https://demo.cloudimg.io/v7/https://samples.scaleflex.com/Image02.jpg',
'https://demo.cloudimg.io/v7/https://samples.scaleflex.com/Image04.jpg',
'https://demo.cloudimg.io/v7/https://samples.scaleflex.com/plate1.jpg',
'https://assets.scaleflex.com/Corporate+Branding/VXP+logo/VXP+logo+BLACK.png',
],
})

Expand Down
29 changes: 25 additions & 4 deletions src/css/carousel.css
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,28 @@
.ci-carousel-thumbnail:hover {
opacity: 0.9;
transform: translateY(-2px);
box-shadow: 0 0 0 2px #000000;
}

.ci-carousel-thumbnail.active {
opacity: 1;
box-shadow: 0 0 0 2px #000000;
transform: translateY(-2px);
animation: fadeBoxShadow 5s ease-out forwards;
}

@keyframes fadeBoxShadow {
0% {
box-shadow: 0 0 0 2px #000000;
}
100% {
box-shadow: 0 0 0 0 transparent;
}
}

.ci-carousel-thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
}

/* Minimal Filename Display */
Expand All @@ -152,12 +162,13 @@
font-size: 13px;
font-weight: 500;
letter-spacing: 0.3px;
opacity: 0;
transform: translateY(8px);
transition: all 0.4s cubic-bezier(0.16, 1, 0.3, 1);
opacity: 0;
transition: all 0.5s ease-in-out;
box-sizing: border-box;
}

.ci-carousel-image-wrapper:hover .ci-carousel-filename {
.ci-carousel-has-filenames .ci-carousel-filename {
opacity: 1;
transform: translateY(0);
}
Expand Down Expand Up @@ -207,3 +218,13 @@
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(8px);
}

.ci-carousel.is-fullscreen.ci-carousel-has-filenames .ci-carousel-filename {
font-size: 20px;
}

.ci-carousel.is-fullscreen.ci-carousel-has-filenames:hover .ci-carousel-filename {
opacity: 1;
font-size: 20px;
bottom: 100px;
}
6 changes: 4 additions & 2 deletions src/css/controls.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
position: relative;
}

.ci-carousel-has-filenames .ci-carousel-controls {
top: -110px;
}

.ci-carousel-controls {
align-items: center;
display: flex;
justify-content: space-between;
width: 280px;
z-index: 10;
border-radius: 20px;
width: 100%;
padding: 30px;
box-sizing: border-box;
Expand Down
16 changes: 16 additions & 0 deletions src/js/carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import {
} from './constants/classes.constants'
import { CLICK_EVENT } from './constants/events.constants'
import { ICONS } from './constants/icons.contants'
import { THUMBNAIL_ALIGNMENT, THUMBNAIL_FIT_MODE } from './constants/thumbnails.contants'
import { TRANSITION_EFFECTS } from './constants/transition.constants'
import { CarouselControls } from './controls/controls'
import { SwipeControls } from './controls/swipe.controls'
import { ZoomPanControls } from './controls/zoom-pan.controls'
import { getFilenameWithoutExtension } from './utils/image.utils'
import { validateOptions } from './utils/validation.utils'

class CloudImageCarousel {
/**
Expand All @@ -42,6 +44,9 @@ class CloudImageCarousel {
)
}

// Validate options before setting them
validateOptions(options)

this.options = {
images: options.images || [],
autoplay: options.autoplay || false,
Expand All @@ -52,6 +57,8 @@ class CloudImageCarousel {
showBullets: options.showBullets || false,
showControls: options.showControls || true,
transitionEffect: options.transitionEffect || TRANSITION_EFFECTS.FADE, // slide, fade
thumbnailFitMode: options.thumbnailFitMode || THUMBNAIL_FIT_MODE.CROP_FIT, // fit, crop-fit
thumbnailAlignment: options.thumbnailAlignment || THUMBNAIL_ALIGNMENT.SPACE_EVENLY, // left, center, right, space-evenly
...options,
}

Expand Down Expand Up @@ -150,6 +157,11 @@ class CloudImageCarousel {
this.bottomContainer.appendChild(this.bulletsContainer)
}

// Bullets container
if (this.options.showFilenames) {
this.container.classList.add('ci-carousel-has-filenames')
}

// Add containers to main view
this.mainView.appendChild(this.imagesContainer)
this.container.appendChild(this.mainView)
Expand Down Expand Up @@ -282,6 +294,9 @@ class CloudImageCarousel {
// Create a document fragment for better performance
const fragment = document.createDocumentFragment()

// Set the alignment for the thumbnails container
this.thumbnailsContainer.style.justifyContent = this.options.thumbnailAlignment

this.images.forEach((img, index) => {
const thumb = document.createElement('div')
thumb.classList.add('ci-carousel-thumbnail')
Expand All @@ -292,6 +307,7 @@ class CloudImageCarousel {

const thumbImg = new Image()
thumbImg.src = img.src
thumbImg.style.objectFit = this.options.thumbnailFitMode === THUMBNAIL_FIT_MODE.CROP_FIT ? 'cover' : 'contain'
thumb.appendChild(thumbImg)
fragment.appendChild(thumb)
})
Expand Down
1 change: 1 addition & 0 deletions src/js/constants/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './events.constants'
export * from './controls.constants'
export * from './transition.constants'
export * from './icons.contants'
export * from './thumbnails.contants'
14 changes: 14 additions & 0 deletions src/js/constants/thumbnails.contants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const THUMBNAIL_FIT_MODE = {
CROP_FIT: 'crop-fit',
FIT: 'fit',
}

const THUMBNAIL_ALIGNMENT = {
LEFT: 'left',
CENTER: 'center',
RIGHT: 'right',
SPACE_EVENLY: 'space-evenly',
SPACE_BETWEEN: 'space-between',
}

export { THUMBNAIL_FIT_MODE, THUMBNAIL_ALIGNMENT }
1 change: 1 addition & 0 deletions src/js/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './image.utils.js'
export * from './throttling.utils.js'
export * from './dom.utils.js'
export * from './validation.utils.js'
Loading