Skip to content

Commit

Permalink
Merge pull request #1 from Travelopia/feature/slider
Browse files Browse the repository at this point in the history
New Component: Slider
  • Loading branch information
junaidbhura authored Nov 10, 2023
2 parents bd995d6 + 3fbe074 commit c1c7ce9
Show file tree
Hide file tree
Showing 13 changed files with 690 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/modal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ import '@travelopia/web-components/dist/modal/style.css';

// TypeScript usage:
import { TPModalElement, TPModalCloseElement } from '@travelopia/web-components';

...

const modal: TPModalElement = document.querySelector( 'tp-modal' );
modal.open();
```

```html
<tp-modal overlay-click-close="yes">
<tp-modal-close>
<button>Close</button> <-- There must be a button inside inside this component.
<button>Close</button> <-- There must be a button inside this component.
</tp-modal-close>
<tp-modal-content>
<p>Any modal content here.</p>
Expand All @@ -42,3 +47,20 @@ import { TPModalElement, TPModalCloseElement } from '@travelopia/web-components'
| Attribute | Required | Values | Notes |
|----------------------|----------|--------|----------------------------------------------|
| overlay-click-close | No | `yes` | Closes the modal when the overlay is clicked |

## Events

| Event | Notes |
|-------|--------------------------|
| open | When the modal is opened |
| close | When the modal is closed |

## Methods

### `open`

Open the modal.

### `close`

Close the modal.
85 changes: 85 additions & 0 deletions src/slider/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Slider

<table width="100%">
<tr>
<td align="left" width="70%">
<p>Built by the super talented team at <strong><a href="https://www.travelopia.com/work-with-us/">Travelopia</a></strong>.</p>
</td>
<td align="center" width="30%">
<img src="https://www.travelopia.com/wp-content/themes/travelopia/assets/svg/logo-travelopia-circle.svg" width="50" />
</td>
</tr>
</table>

## Sample Usage

This is a highly customizable slider component. Pick and choose subcomponents to use, and style as needed!

Example:

```js
// Import the component as needed:
import '@travelopia/web-components/dist/slider';
import '@travelopia/web-components/dist/slider/style.css';

// TypeScript usage:
import { TPSliderElement } from '@travelopia/web-components';

...

const slider: TPSliderElement = document.querySelector( 'tp-slider' );
slider.setCurrentSlide( 2 );
```

```html
<tp-slider flexible-height="yes" infinite="yes" swipe="yes">
<tp-slider-arrow direction="previous"><button>&laquo; Previous</button></tp-slider-arrow> <-- There must be a button inside this component
<tp-slider-arrow direction="next"><button>Next &raquo;</button></tp-slider-arrow> <-- There must be a button inside this component
<tp-slider-track>
<tp-slider-slides>
<tp-slider-slide><img src="image.jpg" width="600" height="300" alt=""></tp-slider-slide>
<tp-slider-slide>
<p>Any content you want here.</p>
</tp-slider-slide>
</tp-slider-slides>
</tp-slider-track>
<tp-slider-nav>
<tp-slider-nav-item><button>1</button></tp-slider-nav-item> <-- There must be a button inside this component
<tp-slider-nav-item><button>2</button></tp-slider-nav-item> <-- There must be a button inside this component
</tp-slider-nav>
<tp-slider-count current="1" total="2" format="$current / $total">1 / 2</tp-slider-count>
</tp-slider>
```

## Attributes

| Attribute | Required | Values | Notes |
|-----------------|----------|--------|--------------------------------------------------------------------------------------------------------|
| flexible-height | No | `yes` | Whether the height of the slider changes depending on the content inside the slides |
| infinite | No | `yes` | Go back to the first slide at the end of all slides, and open the last slide when navigating backwards |
| swipe | No | `yes` | Whether to add support for swiping gestures on touch devices |

## Events

| Event | Notes |
|----------------|---------------------------------------------------|
| slide-set | When the current slide is set, but before sliding |
| slide-complete | After sliding is complete |

## Methods

### `next`

Navigate to the next slide.

### `previous`

Navigate to the previous slide.

### `getCurrentSlide`

Gets the current slide's index.

### `setCurrentSlide`

Sets the current slide based on its index.
62 changes: 62 additions & 0 deletions src/slider/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Web Component: Slider</title>

<link rel="stylesheet" href="../../dist/slider/style.css" media="all">
<script type="module" src="../../dist/slider/index.js"></script>

<style>
tp-slider-slide {
background-color: #eee
}

tp-slider-slide img {
width: 100%;
height: auto;
}

img {
display: block;
}

main {
max-width: 600px;
margin: 0 auto;
padding: 0 20px;
}
</style>
</head>
<body>
<main>
<tp-slider flexible-height="yes" infinite="yes" swipe="yes">
<tp-slider-arrow direction="previous"><button>&laquo; Previous</button></tp-slider-arrow>
<tp-slider-arrow direction="next"><button>Next &raquo;</button></tp-slider-arrow>
<tp-slider-track>
<tp-slider-slides>
<tp-slider-slide><img src="https://picsum.photos/600/300" width="600" height="300" alt=""></tp-slider-slide>
<tp-slider-slide><img src="https://picsum.photos/600/300" width="600" height="300" alt=""></tp-slider-slide>
<tp-slider-slide><img src="https://picsum.photos/600/300" width="600" height="300" alt=""></tp-slider-slide>
<tp-slider-slide>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</tp-slider-slide>
</tp-slider-slides>
</tp-slider-track>
<tp-slider-nav>
<tp-slider-nav-item><button>1</button></tp-slider-nav-item>
<tp-slider-nav-item><button>2</button></tp-slider-nav-item>
<tp-slider-nav-item><button>3</button></tp-slider-nav-item>
<tp-slider-nav-item><button>4</button></tp-slider-nav-item>
</tp-slider-nav>
<tp-slider-count current="1" total="4" format="$current / $total">1 / 4</tp-slider-count>
</tp-slider>
</main>
</body>
</html>
26 changes: 26 additions & 0 deletions src/slider/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Styles.
*/
import './style.scss';

/**
* Components.
*/
import { TPSliderElement } from './tp-slider';
import { TPSliderSlidesElement } from './tp-slider-slides';
import { TPSliderSlideElement } from './tp-slider-slide';
import { TPSliderArrowElement } from './tp-slider-arrow';
import { TPSliderNavElement } from './tp-slider-nav';
import { TPSliderNavItemElement } from './tp-slider-nav-item';
import { TPSliderCountElement } from './tp-slider-count';

/**
* Register Components.
*/
customElements.define( 'tp-slider', TPSliderElement );
customElements.define( 'tp-slider-slides', TPSliderSlidesElement );
customElements.define( 'tp-slider-slide', TPSliderSlideElement );
customElements.define( 'tp-slider-arrow', TPSliderArrowElement );
customElements.define( 'tp-slider-nav', TPSliderNavElement );
customElements.define( 'tp-slider-nav-item', TPSliderNavItemElement );
customElements.define( 'tp-slider-count', TPSliderCountElement );
35 changes: 35 additions & 0 deletions src/slider/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
tp-slider {
display: block;
}

tp-slider-track {
display: block;
overflow-y: visible;
overflow-x: clip;
position: relative;
}

tp-slider-slides {
position: relative;
display: flex;
align-items: flex-start;

tp-slider:not([resizing="yes"]) & {
transition-duration: 0.6s;
transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1);
}
}

tp-slider-slide {
flex: 0 0 100%;
scroll-snap-align: start;

tp-slider[flexible-height="yes"]:not([initialized]) &:not(:first-child) {
display: none;
}
}

tp-slider-nav {
display: flex;
gap: 10px;
}
36 changes: 36 additions & 0 deletions src/slider/tp-slider-arrow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Internal dependencies.
*/
import { TPSliderElement } from './tp-slider';

/**
* TP Slider Arrow.
*/
export class TPSliderArrowElement extends HTMLElement {
/**
* Connected callback.
*/
connectedCallback(): void {
this.querySelector( 'button' )?.addEventListener( 'click', this.handleClick.bind( this ) );
}

/**
* Handle when the button is clicked.
*/
handleClick(): void {
if ( 'yes' === this.getAttribute( 'disabled' ) ) {
return;
}

const slider: TPSliderElement | null = this.closest( 'tp-slider' );
if ( ! slider ) {
return;
}

if ( 'previous' === this.getAttribute( 'direction' ) ) {
slider.previous();
} else if ( 'next' === this.getAttribute( 'direction' ) ) {
slider.next();
}
}
}
48 changes: 48 additions & 0 deletions src/slider/tp-slider-count.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* TP Slider Count.
*/
export class TPSliderCountElement extends HTMLElement {
/**
* Get observed attributes.
*
* @return {Array} Observed attributes.
*/
static get observedAttributes(): string[] {
return [ 'current', 'total', 'format' ];
}

/**
* Get format.
*
* @return {string} Format.
*/
get format(): string {
return this.getAttribute( 'format' ) ?? '$current / $total';
}

/**
* Set format.
*
* @param {string} format Format.
*/
set format( format: string ) {
this.setAttribute( 'format', format );
}

/**
* Attribute changed callback.
*/
attributeChangedCallback(): void {
this.update();
}

/**
* Update component.
*/
update(): void {
this.innerHTML =
this.format
.replace( '$current', this.getAttribute( 'current' ) ?? '' )
.replace( '$total', this.getAttribute( 'total' ) ?? '' );
}
}
43 changes: 43 additions & 0 deletions src/slider/tp-slider-nav-item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* Internal dependencies.
*/
import { TPSliderElement } from './tp-slider';
import { TPSliderNavElement } from './tp-slider-nav';

/**
* TP Slider Nav Item.
*/
export class TPSliderNavItemElement extends HTMLElement {
/**
* Connected callback.
*/
connectedCallback(): void {
this.querySelector( 'button' )?.addEventListener( 'click', this.handleClick.bind( this ) );
}

/**
* Handle when the button is clicked.
*/
handleClick(): void {
const slider: TPSliderElement | null = this.closest( 'tp-slider' );
if ( ! slider ) {
return;
}

slider.setCurrentSlide( this.getIndex() );
}

/**
* Get index of this item inside the navigation.
*
* @return {number} Index.
*/
getIndex(): number {
if ( this.getAttribute( 'index' ) ) {
return parseInt( this.getAttribute( 'index' ) ?? '0' );
}

const slideNav: TPSliderNavElement | null = this.closest( 'tp-slider-nav' );
return Array.from( slideNav?.children ?? [] ).indexOf( this ) + 1;
}
}
5 changes: 5 additions & 0 deletions src/slider/tp-slider-nav.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* TP Slider Nav.
*/
export class TPSliderNavElement extends HTMLElement {
}
5 changes: 5 additions & 0 deletions src/slider/tp-slider-slide.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* TP Slider Slide.
*/
export class TPSliderSlideElement extends HTMLElement {
}
5 changes: 5 additions & 0 deletions src/slider/tp-slider-slides.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* TP Slider Slides.
*/
export class TPSliderSlidesElement extends HTMLElement {
}
Loading

0 comments on commit c1c7ce9

Please sign in to comment.