Skip to content

Commit

Permalink
Slots for start/end and options.position.start (#41)
Browse files Browse the repository at this point in the history
* Implement additional slots (#34)

* Implement additional slots
* Upgrade readme

* You can now start horizontal slides from nth item instead of always starting from 0 (#39)

Co-authored-by: Fuxing Loh <[email protected]>

* Implement additional slots (#34)

* Implement additional slots
* Upgrade readme

* You can now start horizontal slides from nth item instead of always starting from 0 (#39)

Co-authored-by: Fuxing Loh <[email protected]>

* Prettier formatted

* Unified start position into options as {position: {start: 0} }
Converted start and end provided by slots into computed _items

Co-authored-by: Adam Richter <[email protected]>
Co-authored-by: Vikas Kedia <[email protected]>
  • Loading branch information
3 people authored Nov 12, 2020
1 parent f81af47 commit 262bd56
Show file tree
Hide file tree
Showing 7 changed files with 827 additions and 546 deletions.
195 changes: 117 additions & 78 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,118 @@
# vue-horizontal-list
A pure vue horizontal list implementation with minimal dependencies, ssr support, mobile friendly, touch friendly and responsive.

A pure vue horizontal list implementation with minimal dependencies, ssr support, mobile friendly, touch friendly and responsive.
I created this because I like how AirBnb does their horizontal list, I couldn't find a library that is simple and close to it.

Check it out: [LIVE DEMO](https://nuxt-app.now.sh/vue-horizontal-list),
Source is here: [source code](https://github.com/fuxingloh/nuxt-app/blob/master/components/examples/ExampleHorizontalList.vue).

[![vue-horizontal-list screenshot](demo.png)](https://nuxt-app.now.sh/vue-horizontal-list)


## Installation

```shell script
npm i vue-horizontal-list
# or
yarn add vue-horizontal-list
```

## Features
* Lightweight implementation with 1 dependencies.
* SSR supported
* Mobile touch screen friendly
* Invisible scroll bar for consistent Windows and MacOS browsing experience.
* Snap to the nearest item in the horizontal-list when scrolling.
* Windowed & Full-screen mode
* The windowed mode will respect the container and not show overflowing item
* Full-screen mode will show overflowing item, best result for small screen
* Dynamic responsive breakpoint configuration
* Navigation control will show up dynamically for larger screen
* Touch screen friendly
* Minimal config setup
* Tested on chrome, edge and safari

- Lightweight implementation with 1 dependencies.
- SSR supported
- Mobile touch screen friendly
- Invisible scroll bar for consistent Windows and MacOS browsing experience.
- Snap to the nearest item in the horizontal-list when scrolling.
- Windowed & Full-screen mode
- The windowed mode will respect the container and not show overflowing item
- Full-screen mode will show overflowing item, best result for small screen
- Dynamic responsive breakpoint configuration
- Navigation control will show up dynamically for larger screen
- Touch screen friendly
- Let's get slideshow autoplayed
- Slot different content at the beginning or the ending of the items list.
- Minimal config setup
- Tested on chrome, edge and safari

## Options

```js
const options = {
item: {
// css class to inject into each individual item
class: '',
class: "",
// padding between each item
padding: 12
padding: 12,
},
list: {
// css class for the parent of item
class: '',
class: "",
// maximum width of the list it can extend to before switching to windowed mode, basically think of the bootstrap container max-width
// windowed is used to toggle between full-screen mode and container mode
windowed: 1200,
// padding of the list, if container < windowed what is the left-right padding of the list
// during full-screen mode the padding will added to left & right to centralise the item
padding: 24
padding: 24,
},
responsive: [
// responsive breakpoints to calculate how many items to show in the list at each width interval
// it will always fall back to these:
{end: 576, size: 1},
{start: 576, end: 768, size: 2},
{start: 768, end: 992, size: 3},
{start: 992, end: 1200, size: 4},
{start: 1200, size: 5}
// it will always fall back to these:
{ end: 576, size: 1 },
{ start: 576, end: 768, size: 2 },
{ start: 768, end: 992, size: 3 },
{ start: 992, end: 1200, size: 4 },
{ start: 1200, size: 5 },
],
navigation: {
// when to show navigation
start: 992,
color: '#000'
}
}
color: "#000",
},
position: {
// Start from '1' on mounted.
start: 1,
},
autoplay: {
// enable/disable playing slideshow
play: true,
// the delay duration between slides in milliseconds
speed: 1800,
// if setup, the slideshow will be in the loop.
repeat: true,
},
};
```

## Examples

### Basic Responsive Usage

- Width between 0 - 576, show 1
- Width between 576 - 768, show 2
- Width fallback, show 3

### Slotting

- default slot of the items is tagged `v-slot:default`, is required.
- additional optional slots could be binding via `v-slot:start` or `v-slot:end`

```vue
<vue-horizontal-list :items="items" :options="{responsive: [{end: 576, size: 1}, {start: 576, end: 768, size: 2},{size: 3}]}">
<vue-horizontal-list
:items="items"
:options="{
responsive: [
{ end: 576, size: 1 },
{ start: 576, end: 768, size: 2 },
{ size: 3 },
],
}"
>
<template v-slot:start>
<div class="start-item" style="background:red;">
<p>Start item</p>
</div>
</template>
<template v-slot:default="{item}">
<div class="item">
<h5>{{item.title}}</h5>
Expand All @@ -85,15 +123,16 @@ const options = {
```

### Full Example

```vue
<template>
<div id="app">
<section>
<vue-horizontal-list :items="items" :options="options">
<template v-slot:default="{item}">
<template v-slot:default="{ item }">
<div class="item">
<h5>{{item.title}}</h5>
<p>{{item.content}}</p>
<h5>{{ item.title }}</h5>
<p>{{ item.content }}</p>
</div>
</template>
</vue-horizontal-list>
Expand All @@ -102,62 +141,62 @@ const options = {
</template>
<script>
import Vue from 'vue';
import VueHorizontalList from '@/vue-horizontal-list.vue';
export default Vue.extend({
name: 'ServeDev',
components: {
VueHorizontalList
},
data() {
return {
options: {
responsive: [
{end: 576, size: 1},
{start: 576, end: 768, size: 2},
{start: 768, end: 992, size: 3},
{size: 4}
],
list: {
// 1200 because @media (min-width: 1200px) and therefore I want to switch to windowed mode
windowed: 1200,
// Because: #app {padding: 80px 24px;}
padding: 24
}
},
items: [
{title: 'Item 0', content: 'Content item with description'},
]
}
}
});
import Vue from "vue";
import VueHorizontalList from "@/vue-horizontal-list.vue";
export default Vue.extend({
name: "ServeDev",
components: {
VueHorizontalList,
},
data() {
return {
options: {
responsive: [
{ end: 576, size: 1 },
{ start: 576, end: 768, size: 2 },
{ start: 768, end: 992, size: 3 },
{ size: 4 },
],
list: {
// 1200 because @media (min-width: 1200px) and therefore I want to switch to windowed mode
windowed: 1200,
// Because: #app {padding: 80px 24px;}
padding: 24,
},
autoplay: { play: true, repeat: true }, // 2 seconds delay is by default
},
items: [{ title: "Item 0", content: "Content item with description" }],
};
},
});
</script>
<style>
body {
margin: 0;
padding: 0;
}
body {
margin: 0;
padding: 0;
}
#app {
max-width: 1400px;
#app {
max-width: 1400px;
margin-left: auto;
margin-right: auto;
margin-left: auto;
margin-right: auto;
padding: 80px 24px;
}
padding: 80px 24px;
}
@media (min-width: 1200px) {
#app {
padding-left: 80px;
padding-right: 80px;
}
@media (min-width: 1200px) {
#app {
padding-left: 80px;
padding-right: 80px;
}
}
</style>
```

## Contributing

For any question or feature request please feel free to create an [issue](https://github.com/fuxingloh/vue-horizontal-list/issues/new) or [pull request](https://github.com/fuxingloh/vue-horizontal-list/pulls).
6 changes: 3 additions & 3 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const devPresets = ['@vue/babel-preset-app'];
const buildPresets = ['@babel/preset-env'];
const devPresets = ["@vue/babel-preset-app"];
const buildPresets = ["@babel/preset-env"];
module.exports = {
presets: (process.env.NODE_ENV === 'development' ? devPresets : buildPresets),
presets: process.env.NODE_ENV === "development" ? devPresets : buildPresets,
};
Loading

0 comments on commit 262bd56

Please sign in to comment.